Skip to content

Commit 28efd7d

Browse files
committed
cli: add simple CLI to use ONEKEY platform API
1 parent 026eec1 commit 28efd7d

5 files changed

Lines changed: 177 additions & 0 deletions

File tree

onekey_client/cli/__init__.py

Whitespace-only changes.

onekey_client/cli/cli.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import sys
2+
3+
import click
4+
import httpx
5+
6+
from onekey_client import Client
7+
from .firmware_upload import upload_firmware
8+
from .misc import list_tenants, get_tenant_token
9+
10+
11+
@click.group()
12+
@click.option(
13+
"--api-url",
14+
default="https://app.eu.onekey.com/api",
15+
show_default=True,
16+
help="ONEKEY platform API endpoint",
17+
)
18+
@click.option(
19+
"--disable-tls-verify",
20+
default=False,
21+
show_default=True,
22+
help="Disable verifying server certificate, use only for testing",
23+
is_flag=True,
24+
)
25+
@click.option(
26+
"--email", help="Email to authenticate on the ONEKEY platform", required=True
27+
)
28+
@click.option(
29+
"--password",
30+
hide_input=True,
31+
required=True,
32+
prompt=True,
33+
help="Password to authenticate on the ONEKEY platform",
34+
)
35+
@click.option(
36+
"--tenant", "tenant_name", required=True, help="Tenant name on ONEKEY platform"
37+
)
38+
@click.pass_context
39+
def cli(ctx, api_url, disable_tls_verify, email, password, tenant_name):
40+
client = Client(api_url=api_url, disable_tls_verify=disable_tls_verify)
41+
try:
42+
client.login(email, password)
43+
except httpx.HTTPStatusError as e:
44+
if e.response.status_code == httpx.codes.UNAUTHORIZED:
45+
click.echo(f"Authentication failed on {email} @ {api_url}")
46+
sys.exit(1)
47+
else:
48+
click.echo(
49+
f"Error connecting to ONEKEY platform: '{api_url}', error: {e.response.status_code}"
50+
)
51+
sys.exit(2)
52+
53+
try:
54+
tenant = client.get_tenant(tenant_name)
55+
except KeyError:
56+
click.echo(f"Invalid tenant: {tenant_name}")
57+
tenants = client.get_all_tenants()
58+
click.echo("Available tenants:")
59+
for tenant in tenants:
60+
click.echo(f"- {tenant.name} ({tenant.id}")
61+
sys.exit(3)
62+
63+
client.use_tenant(tenant)
64+
ctx.obj = client
65+
66+
67+
cli.add_command(list_tenants)
68+
cli.add_command(get_tenant_token)
69+
cli.add_command(upload_firmware)
70+
71+
72+
def main():
73+
cli(auto_envvar_prefix="ONEKEY")
74+
75+
76+
if __name__ == "__main__":
77+
main()
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import sys
2+
from pathlib import Path
3+
from typing import Optional
4+
5+
import click
6+
7+
from onekey_client import FirmwareMetadata, Client
8+
from onekey_client.errors import QueryError
9+
10+
11+
@click.command()
12+
@click.option(
13+
"--product", "product_name", required=True, help="Product name to add the firmware"
14+
)
15+
@click.option(
16+
"--vendor", "vendor_name", required=True, help="Vendor name to add the firmware"
17+
)
18+
@click.option(
19+
"--product-group",
20+
"product_group_name",
21+
default="Default",
22+
show_default=True,
23+
required=True,
24+
help="Product group name to add the firmware",
25+
)
26+
@click.option("--version", help="Firmware version")
27+
@click.option("--name", help="Firmware name")
28+
@click.argument("filename", type=click.Path(exists=True, path_type=Path))
29+
@click.pass_obj
30+
def upload_firmware(
31+
client: Client,
32+
product_name: str,
33+
vendor_name: str,
34+
product_group_name: str,
35+
version: Optional[str],
36+
name: Optional[str],
37+
filename: Path,
38+
):
39+
"""Uploads a firmware to the ONEKEY platform"""
40+
41+
product_groups = client.get_product_groups()
42+
43+
try:
44+
product_group_id = product_groups[product_group_name]
45+
except KeyError:
46+
click.echo(f"Missing product group: {product_group_name}")
47+
click.echo("Available product groups:")
48+
for pg in product_groups.keys():
49+
click.echo(f"- {pg}")
50+
sys.exit(10)
51+
52+
if name is None:
53+
name = (
54+
f"{vendor_name}-{product_name}-{filename.name}"
55+
if version is None
56+
else f"{vendor_name}-{product_name}-{version}"
57+
)
58+
59+
metadata = FirmwareMetadata(
60+
name=name,
61+
vendor_name=vendor_name,
62+
product_name=product_name,
63+
product_group_id=product_group_id,
64+
version=version,
65+
)
66+
67+
try:
68+
res = client.upload_firmware(metadata, filename, enable_monitoring=False)
69+
click.echo(res["id"])
70+
except QueryError as e:
71+
click.echo("Error during firmware upload:")
72+
for error in e._errors:
73+
click.echo(f"- {error['message']}")
74+
sys.exit(11)

onekey_client/cli/misc.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import json
2+
3+
import click
4+
5+
from onekey_client import Client
6+
7+
8+
@click.command()
9+
@click.pass_obj
10+
def list_tenants(client: Client):
11+
"""List available tenants"""
12+
13+
tenants = client.get_all_tenants()
14+
for tenant in tenants:
15+
click.echo(f"{tenant.name} ({tenant.id}")
16+
17+
18+
@click.command()
19+
@click.pass_obj
20+
def get_tenant_token(client: Client):
21+
"""Get tenant specific Bearer token"""
22+
23+
click.echo(json.dumps(client.get_auth_headers()))

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ black = "^22.3.0"
3333
[build-system]
3434
requires = ["poetry-core>=1.0.0"]
3535
build-backend = "poetry.core.masonry.api"
36+
37+
[tool.poetry.scripts]
38+
onekey = "onekey_client.cli.cli:main"

0 commit comments

Comments
 (0)