remotivelabs-cli 0.5.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- remotivelabs/cli/__init__.py +0 -0
- remotivelabs/cli/api/cloud/tokens.py +62 -0
- remotivelabs/cli/broker/__init__.py +33 -0
- remotivelabs/cli/broker/defaults.py +1 -0
- remotivelabs/cli/broker/discovery.py +43 -0
- remotivelabs/cli/broker/export.py +92 -0
- remotivelabs/cli/broker/files.py +119 -0
- remotivelabs/cli/broker/lib/__about__.py +4 -0
- remotivelabs/cli/broker/lib/broker.py +625 -0
- remotivelabs/cli/broker/lib/client.py +224 -0
- remotivelabs/cli/broker/lib/helper.py +277 -0
- remotivelabs/cli/broker/lib/signalcreator.py +196 -0
- remotivelabs/cli/broker/license_flows.py +167 -0
- remotivelabs/cli/broker/licenses.py +98 -0
- remotivelabs/cli/broker/playback.py +117 -0
- remotivelabs/cli/broker/record.py +41 -0
- remotivelabs/cli/broker/recording_session/__init__.py +3 -0
- remotivelabs/cli/broker/recording_session/client.py +67 -0
- remotivelabs/cli/broker/recording_session/cmd.py +254 -0
- remotivelabs/cli/broker/recording_session/time.py +49 -0
- remotivelabs/cli/broker/scripting.py +129 -0
- remotivelabs/cli/broker/signals.py +220 -0
- remotivelabs/cli/broker/version.py +31 -0
- remotivelabs/cli/cloud/__init__.py +17 -0
- remotivelabs/cli/cloud/auth/__init__.py +3 -0
- remotivelabs/cli/cloud/auth/cmd.py +128 -0
- remotivelabs/cli/cloud/auth/login.py +283 -0
- remotivelabs/cli/cloud/auth_tokens.py +149 -0
- remotivelabs/cli/cloud/brokers.py +109 -0
- remotivelabs/cli/cloud/configs.py +109 -0
- remotivelabs/cli/cloud/licenses/__init__.py +0 -0
- remotivelabs/cli/cloud/licenses/cmd.py +14 -0
- remotivelabs/cli/cloud/organisations.py +112 -0
- remotivelabs/cli/cloud/projects.py +44 -0
- remotivelabs/cli/cloud/recordings.py +580 -0
- remotivelabs/cli/cloud/recordings_playback.py +274 -0
- remotivelabs/cli/cloud/resumable_upload.py +87 -0
- remotivelabs/cli/cloud/sample_recordings.py +25 -0
- remotivelabs/cli/cloud/service_account_tokens.py +62 -0
- remotivelabs/cli/cloud/service_accounts.py +72 -0
- remotivelabs/cli/cloud/storage/__init__.py +5 -0
- remotivelabs/cli/cloud/storage/cmd.py +76 -0
- remotivelabs/cli/cloud/storage/copy.py +86 -0
- remotivelabs/cli/cloud/storage/uri_or_path.py +45 -0
- remotivelabs/cli/cloud/uri.py +113 -0
- remotivelabs/cli/connect/__init__.py +0 -0
- remotivelabs/cli/connect/connect.py +118 -0
- remotivelabs/cli/connect/protopie/protopie.py +185 -0
- remotivelabs/cli/py.typed +0 -0
- remotivelabs/cli/remotive.py +123 -0
- remotivelabs/cli/settings/__init__.py +20 -0
- remotivelabs/cli/settings/config_file.py +113 -0
- remotivelabs/cli/settings/core.py +333 -0
- remotivelabs/cli/settings/migration/__init__.py +0 -0
- remotivelabs/cli/settings/migration/migrate_all_token_files.py +80 -0
- remotivelabs/cli/settings/migration/migrate_config_file.py +64 -0
- remotivelabs/cli/settings/migration/migrate_legacy_dirs.py +50 -0
- remotivelabs/cli/settings/migration/migrate_token_file.py +52 -0
- remotivelabs/cli/settings/migration/migration_tools.py +38 -0
- remotivelabs/cli/settings/state_file.py +67 -0
- remotivelabs/cli/settings/token_file.py +128 -0
- remotivelabs/cli/tools/__init__.py +0 -0
- remotivelabs/cli/tools/can/__init__.py +0 -0
- remotivelabs/cli/tools/can/can.py +78 -0
- remotivelabs/cli/tools/tools.py +9 -0
- remotivelabs/cli/topology/__init__.py +28 -0
- remotivelabs/cli/topology/all.py +322 -0
- remotivelabs/cli/topology/cli/__init__.py +3 -0
- remotivelabs/cli/topology/cli/run_in_docker.py +58 -0
- remotivelabs/cli/topology/cli/topology_cli.py +16 -0
- remotivelabs/cli/topology/cmd.py +130 -0
- remotivelabs/cli/topology/start_trial.py +134 -0
- remotivelabs/cli/typer/__init__.py +0 -0
- remotivelabs/cli/typer/typer_utils.py +27 -0
- remotivelabs/cli/utils/__init__.py +0 -0
- remotivelabs/cli/utils/console.py +99 -0
- remotivelabs/cli/utils/rest_helper.py +369 -0
- remotivelabs/cli/utils/time.py +11 -0
- remotivelabs/cli/utils/versions.py +120 -0
- remotivelabs_cli-0.5.0a1.dist-info/METADATA +51 -0
- remotivelabs_cli-0.5.0a1.dist-info/RECORD +84 -0
- remotivelabs_cli-0.5.0a1.dist-info/WHEEL +4 -0
- remotivelabs_cli-0.5.0a1.dist-info/entry_points.txt +3 -0
- remotivelabs_cli-0.5.0a1.dist-info/licenses/LICENSE +17 -0
|
File without changes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
from remotivelabs.cli.utils.rest_helper import RestHelper as Rest
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# Attempt to start cloud-api.
|
|
10
|
+
# Might be better to generate somehow instead.
|
|
11
|
+
# Lets discuss further
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclasses.dataclass
|
|
16
|
+
class EmptyResponse:
|
|
17
|
+
is_success: bool
|
|
18
|
+
status_code: int
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclasses.dataclass
|
|
22
|
+
class JsonResponse:
|
|
23
|
+
is_success: bool
|
|
24
|
+
status_code: int
|
|
25
|
+
__response: requests.Response
|
|
26
|
+
|
|
27
|
+
def json(self) -> Any:
|
|
28
|
+
return self.__response.json()
|
|
29
|
+
|
|
30
|
+
def text(self) -> str:
|
|
31
|
+
return self.__response.text
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def __delete_response_from_response(response: requests.Response) -> EmptyResponse:
|
|
35
|
+
if 200 > response.status_code > 299:
|
|
36
|
+
ok = False
|
|
37
|
+
else:
|
|
38
|
+
ok = True
|
|
39
|
+
return EmptyResponse(is_success=ok, status_code=response.status_code)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def __json_response_from_response(response: requests.Response) -> JsonResponse:
|
|
43
|
+
if 200 > response.status_code > 299:
|
|
44
|
+
ok = False
|
|
45
|
+
else:
|
|
46
|
+
ok = True
|
|
47
|
+
return JsonResponse(is_success=ok, status_code=response.status_code, __response=response)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def create() -> JsonResponse:
|
|
51
|
+
response = Rest.handle_post(url="/api/me/keys", return_response=True)
|
|
52
|
+
return __json_response_from_response(response)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def revoke(name: str) -> EmptyResponse:
|
|
56
|
+
res_revoke = Rest.handle_patch(f"/api/me/keys/{name}/revoke", quiet=True, allow_status_codes=[404, 401])
|
|
57
|
+
return __delete_response_from_response(res_revoke)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def delete(name: str) -> EmptyResponse:
|
|
61
|
+
res_delete = Rest.handle_delete(f"/api/me/keys/{name}", quiet=True, allow_status_codes=[404, 401])
|
|
62
|
+
return __delete_response_from_response(res_delete)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from remotivelabs.cli.broker import export, files, licenses, record, recording_session, scripting, signals
|
|
8
|
+
from remotivelabs.cli.broker.discovery import discover as discover_cmd
|
|
9
|
+
from remotivelabs.cli.typer import typer_utils
|
|
10
|
+
|
|
11
|
+
app = typer_utils.create_typer(rich_markup_mode="rich")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# TODO: remove this?
|
|
15
|
+
def cb(url: str = typer.Option(None, is_eager=False, help="Broker URL", envvar="REMOTIVE_BROKER_URL")) -> None:
|
|
16
|
+
# This can be used to override the --url per command, lets see if this is a better approach
|
|
17
|
+
if url is not None:
|
|
18
|
+
os.environ["REMOTIVE_BROKER_URL"] = url
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# TODO: move broker commands to subcommand instead?
|
|
22
|
+
app.command(help="Discover brokers on this network")(discover_cmd)
|
|
23
|
+
app.callback()(cb)
|
|
24
|
+
|
|
25
|
+
# subcommands
|
|
26
|
+
|
|
27
|
+
app.add_typer(recording_session.app, name="playback")
|
|
28
|
+
app.add_typer(record.app, name="record", help="Record data on buses")
|
|
29
|
+
app.add_typer(files.app, name="files", help="Upload/Download configurations and recordings")
|
|
30
|
+
app.add_typer(signals.app, name="signals", help="Find and subscribe to signals")
|
|
31
|
+
app.add_typer(export.app, name="export", help="Export to external formats")
|
|
32
|
+
app.add_typer(scripting.app, name="scripting", help="LUA scripting utilities")
|
|
33
|
+
app.add_typer(licenses.app, name="license", help="View and request license to broker")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DEFAULT_GRPC_URL = "http://localhost:50051"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from time import sleep
|
|
4
|
+
|
|
5
|
+
from zeroconf import IPVersion, ServiceBrowser, ServiceStateChange, Zeroconf
|
|
6
|
+
|
|
7
|
+
from remotivelabs.cli.utils.console import print_generic_message, print_newline
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def discover() -> None:
|
|
11
|
+
zeroconf = Zeroconf(ip_version=IPVersion.V4Only)
|
|
12
|
+
services = ["_remotivebroker._tcp.local."]
|
|
13
|
+
|
|
14
|
+
print_generic_message("Looking for RemotiveBrokers on your network, press Ctrl-C to exit...")
|
|
15
|
+
ServiceBrowser(zeroconf, services, handlers=[on_service_state_change])
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
while True:
|
|
19
|
+
sleep(0.1)
|
|
20
|
+
except KeyboardInterrupt:
|
|
21
|
+
pass
|
|
22
|
+
finally:
|
|
23
|
+
zeroconf.close()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def on_service_state_change(zeroconf: Zeroconf, service_type: str, name: str, state_change: ServiceStateChange) -> None:
|
|
27
|
+
"""TODO: use log instead of print for debug information?"""
|
|
28
|
+
if state_change is ServiceStateChange.Removed:
|
|
29
|
+
print_generic_message(f"Service {name} was removed")
|
|
30
|
+
|
|
31
|
+
if state_change is ServiceStateChange.Updated:
|
|
32
|
+
print_generic_message(f"Service {name} was updated")
|
|
33
|
+
|
|
34
|
+
if state_change is ServiceStateChange.Added:
|
|
35
|
+
print_generic_message(f"[ {name} ]")
|
|
36
|
+
info = zeroconf.get_service_info(service_type, name)
|
|
37
|
+
if info:
|
|
38
|
+
for addr in info.parsed_scoped_addresses():
|
|
39
|
+
print_generic_message(f"RemotiveBrokerApp: http://{addr}:8080")
|
|
40
|
+
print_generic_message(f"RemotiveBroker http://{addr}:50051")
|
|
41
|
+
else:
|
|
42
|
+
print_generic_message(" No info")
|
|
43
|
+
print_newline()
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import signal as os_signal
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Any, List
|
|
6
|
+
|
|
7
|
+
import grpc
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from remotivelabs.cli.broker.lib.broker import Broker, SubscribableSignal
|
|
11
|
+
from remotivelabs.cli.typer import typer_utils
|
|
12
|
+
from remotivelabs.cli.utils.console import print_generic_message, print_grpc_error, print_hint
|
|
13
|
+
|
|
14
|
+
app = typer_utils.create_typer(
|
|
15
|
+
rich_markup_mode="rich",
|
|
16
|
+
help="""
|
|
17
|
+
Export subscribed signals to different formats, currently only InfluxDB line protocol
|
|
18
|
+
but more formats will come soon
|
|
19
|
+
""",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@app.command()
|
|
24
|
+
def influxdb(
|
|
25
|
+
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
|
26
|
+
api_key: str = typer.Option(None, help="Cloud Broker API-KEY", envvar="REMOTIVE_BROKER_API_KEY"),
|
|
27
|
+
signal: List[str] = typer.Option(..., help="List of signal names to subscribe to in format namespace:signal_name"),
|
|
28
|
+
on_change_only: bool = typer.Option(default=False, help="Only get signal if value is changed"),
|
|
29
|
+
output: str = typer.Option(None, help="Write results to file, defaults to stdout"),
|
|
30
|
+
) -> None:
|
|
31
|
+
"""
|
|
32
|
+
Exports subscribed signals to InfluxDB line-protocol, really useful to dump some signals into
|
|
33
|
+
influxdb for offline analysis and insights.
|
|
34
|
+
|
|
35
|
+
This is a sample for exporting and importing to InfluxDB using remotive-cli and influx-cli
|
|
36
|
+
|
|
37
|
+
Export:
|
|
38
|
+
remotive broker export influxdb --url [URL] --output signals.influx \\
|
|
39
|
+
--signal vehiclebus:Control.SteeringWheel_Position --signal Control.Accelerator_PedalPosition \\
|
|
40
|
+
--signal vehiclebus:GpsPosition.GPS_Longitude --signal vehiclebus:GpsPosition.GPS_Latitude
|
|
41
|
+
|
|
42
|
+
Output:
|
|
43
|
+
Control, namespace:vehiclebus SteeringWheel_Position=1.0,Accelerator_PedalPosition=0,Speed=0 1664787032944374000
|
|
44
|
+
GpsPosition, namespace:vehiclebus GPS_Longitude=12.982076,GPS_Latitude=55.618748 1664787032948256000
|
|
45
|
+
|
|
46
|
+
Import:
|
|
47
|
+
influx write --org myorg -b my-bucket -p ns --format=lp -f signals.influx
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
# TODO: file is not properly opened using a context manager
|
|
53
|
+
if output is not None:
|
|
54
|
+
f = open(output, "w")
|
|
55
|
+
|
|
56
|
+
def exit_on_ctrlc(_sig: Any, _frame: Any) -> None:
|
|
57
|
+
if output is not None:
|
|
58
|
+
f.close()
|
|
59
|
+
sys.exit(0)
|
|
60
|
+
|
|
61
|
+
def per_frame_influx_line_protocol(x: Any) -> None:
|
|
62
|
+
signals = list(x)
|
|
63
|
+
if len(signals) == 0:
|
|
64
|
+
return
|
|
65
|
+
sig: str = signals[0]["name"].rpartition(".")[-1]
|
|
66
|
+
frame = signals[0]["name"].rsplit(".", 1)[0]
|
|
67
|
+
namespace = signals[0]["namespace"]
|
|
68
|
+
signals_str = ",".join(list(map(lambda s: f"{sig}={s['value']}", signals)))
|
|
69
|
+
influx_lp = f"{frame},namespace={namespace} {signals_str} {round(signals[0]['timestamp_us'] * 1000)}"
|
|
70
|
+
if output is not None:
|
|
71
|
+
f.write(f"{influx_lp}\n")
|
|
72
|
+
else:
|
|
73
|
+
# TODO: Use log instead of print for debug information?
|
|
74
|
+
print_generic_message(f"{influx_lp}")
|
|
75
|
+
|
|
76
|
+
os_signal.signal(os_signal.SIGINT, exit_on_ctrlc)
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
|
|
80
|
+
def to_subscribable_signal(sig: str) -> SubscribableSignal:
|
|
81
|
+
arr = sig.split(":")
|
|
82
|
+
if len(arr) != 2:
|
|
83
|
+
print_hint(f"--signal must have format namespace:signal ({sig})")
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
|
|
86
|
+
return SubscribableSignal(namespace=arr[0], name=arr[1])
|
|
87
|
+
|
|
88
|
+
signals_to_subscribe_to = list(map(to_subscribable_signal, signal))
|
|
89
|
+
broker = Broker(url, api_key)
|
|
90
|
+
broker.long_name_subscribe(signals_to_subscribe_to, per_frame_influx_line_protocol, on_change_only)
|
|
91
|
+
except grpc.RpcError as rpc_error:
|
|
92
|
+
print_grpc_error(rpc_error)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
import grpc
|
|
7
|
+
import typer
|
|
8
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
9
|
+
|
|
10
|
+
from remotivelabs.cli.broker.lib.broker import Broker
|
|
11
|
+
from remotivelabs.cli.typer import typer_utils
|
|
12
|
+
from remotivelabs.cli.utils.console import print_generic_error, print_grpc_error, print_success
|
|
13
|
+
|
|
14
|
+
app = typer_utils.create_typer(help=help)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.command()
|
|
18
|
+
def reload_configuration(
|
|
19
|
+
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
|
20
|
+
api_key: str = typer.Option("offline", help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
|
21
|
+
) -> None:
|
|
22
|
+
try:
|
|
23
|
+
broker = Broker(url, api_key)
|
|
24
|
+
broker.reload_config()
|
|
25
|
+
print_success("Configuration reloaded")
|
|
26
|
+
except grpc.RpcError as err:
|
|
27
|
+
print_grpc_error(err)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.command()
|
|
31
|
+
def delete(
|
|
32
|
+
path: List[str] = typer.Argument(..., help="Paths to files on broker to delete"),
|
|
33
|
+
exit_on_failure: bool = typer.Option(False, help="Exits if there was a problem deleting a file"),
|
|
34
|
+
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
|
35
|
+
api_key: str = typer.Option("offline", help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
|
36
|
+
) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Deletes the specified files from the broker
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
broker = Broker(url, api_key)
|
|
42
|
+
|
|
43
|
+
if len(path) == 0:
|
|
44
|
+
print_generic_error("At least one path must be suppled")
|
|
45
|
+
raise typer.Exit(1)
|
|
46
|
+
|
|
47
|
+
broker.delete_files(path, exit_on_failure)
|
|
48
|
+
except grpc.RpcError as err:
|
|
49
|
+
print_grpc_error(err)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@app.command()
|
|
53
|
+
def download(
|
|
54
|
+
path: str = typer.Argument(..., help="Path to file on broker to download"),
|
|
55
|
+
output: str = typer.Option("", help="Optional output file name"),
|
|
56
|
+
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
|
57
|
+
api_key: str = typer.Option("offline", help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
|
58
|
+
) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Downloads a file from a broker
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
with Progress(
|
|
64
|
+
SpinnerColumn(),
|
|
65
|
+
TextColumn("[progress.description]{task.description}"),
|
|
66
|
+
transient=True,
|
|
67
|
+
) as progress:
|
|
68
|
+
progress.add_task(description=f"Downloading {path}...", total=None)
|
|
69
|
+
broker = Broker(url, api_key)
|
|
70
|
+
output_file = os.path.basename(path)
|
|
71
|
+
if output != "":
|
|
72
|
+
output_file = output
|
|
73
|
+
if os.path.exists(output_file):
|
|
74
|
+
print_generic_error(f"File already exist {output_file}, please use another output file name")
|
|
75
|
+
else:
|
|
76
|
+
broker.download(path, output_file)
|
|
77
|
+
print_success(f"{output_file} saved")
|
|
78
|
+
except grpc.RpcError as err:
|
|
79
|
+
print_grpc_error(err)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@app.command()
|
|
83
|
+
def upload(
|
|
84
|
+
path: str = typer.Argument(..., help="Path to local file to upload"),
|
|
85
|
+
output: str = typer.Option("", help="Optional output path on broker"),
|
|
86
|
+
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
|
87
|
+
api_key: str = typer.Option("offline", help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
|
88
|
+
) -> None:
|
|
89
|
+
"""
|
|
90
|
+
Uploads a file to a broker - physical or in cloud.
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
with Progress(
|
|
94
|
+
SpinnerColumn(),
|
|
95
|
+
TextColumn("[progress.description]{task.description}"),
|
|
96
|
+
transient=True,
|
|
97
|
+
) as progress:
|
|
98
|
+
progress.add_task(description=f"Uploading {path}...", total=None)
|
|
99
|
+
|
|
100
|
+
if path == ".":
|
|
101
|
+
path = "./" ## Does not work otherwise
|
|
102
|
+
|
|
103
|
+
if not os.path.exists(path):
|
|
104
|
+
print_generic_error(f"File {path} does not exist")
|
|
105
|
+
raise typer.Exit(1)
|
|
106
|
+
|
|
107
|
+
broker = Broker(url, api_key)
|
|
108
|
+
|
|
109
|
+
if os.path.isdir(path):
|
|
110
|
+
broker.upload_folder(path)
|
|
111
|
+
print_success(f"{path} uploaded")
|
|
112
|
+
else:
|
|
113
|
+
output_file = os.path.basename(path)
|
|
114
|
+
if output != "":
|
|
115
|
+
output_file = output
|
|
116
|
+
broker.upload(path, output_file)
|
|
117
|
+
print_success(f"{path} uploaded")
|
|
118
|
+
except grpc.RpcError as err:
|
|
119
|
+
print_grpc_error(err)
|