remotivelabs-cli 0.0.1a3__tar.gz → 0.0.13__tar.gz
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-0.0.13/LICENSE +17 -0
- remotivelabs_cli-0.0.13/PKG-INFO +33 -0
- remotivelabs_cli-0.0.13/README.md +7 -0
- {remotivelabs_cli-0.0.1a3 → remotivelabs_cli-0.0.13}/cli/__about__.py +1 -1
- remotivelabs_cli-0.0.13/cli/__init__.py +0 -0
- {remotivelabs_cli-0.0.1a3/cli → remotivelabs_cli-0.0.13/cli/broker}/brokers.py +27 -29
- remotivelabs_cli-0.0.13/cli/broker/export.py +110 -0
- remotivelabs_cli-0.0.13/cli/broker/files.py +119 -0
- {remotivelabs_cli-0.0.1a3/cli → remotivelabs_cli-0.0.13/cli/broker}/lib/__about__.py +1 -1
- remotivelabs_cli-0.0.13/cli/broker/lib/broker.py +522 -0
- remotivelabs_cli-0.0.13/cli/broker/playback.py +137 -0
- remotivelabs_cli-0.0.13/cli/broker/record.py +41 -0
- remotivelabs_cli-0.0.13/cli/broker/scripting.py +119 -0
- remotivelabs_cli-0.0.13/cli/broker/signals.py +189 -0
- {remotivelabs_cli-0.0.1a3 → remotivelabs_cli-0.0.13}/cli/cloud/auth.py +57 -54
- remotivelabs_cli-0.0.13/cli/cloud/auth_tokens.py +116 -0
- remotivelabs_cli-0.0.13/cli/cloud/brokers.py +121 -0
- remotivelabs_cli-0.0.13/cli/cloud/cloud_cli.py +39 -0
- {remotivelabs_cli-0.0.1a3 → remotivelabs_cli-0.0.13}/cli/cloud/configs.py +45 -11
- remotivelabs_cli-0.0.13/cli/cloud/projects.py +40 -0
- remotivelabs_cli-0.0.13/cli/cloud/recordings.py +487 -0
- remotivelabs_cli-0.0.13/cli/cloud/rest_helper.py +194 -0
- remotivelabs_cli-0.0.13/cli/cloud/sample_recordings.py +24 -0
- remotivelabs_cli-0.0.13/cli/cloud/service_account_tokens.py +67 -0
- remotivelabs_cli-0.0.13/cli/cloud/service_accounts.py +43 -0
- remotivelabs_cli-0.0.13/cli/connect/__init__.py +1 -0
- remotivelabs_cli-0.0.13/cli/connect/connect.py +106 -0
- remotivelabs_cli-0.0.13/cli/connect/protopie/protopie.py +173 -0
- remotivelabs_cli-0.0.13/cli/errors.py +36 -0
- remotivelabs_cli-0.0.13/cli/remotive.py +64 -0
- {remotivelabs_cli-0.0.1a3 → remotivelabs_cli-0.0.13}/cli/requirements.txt +1 -1
- remotivelabs_cli-0.0.13/cli/settings.py +25 -0
- remotivelabs_cli-0.0.13/cli/tools/__init__.py +1 -0
- remotivelabs_cli-0.0.13/cli/tools/can/__init__.py +1 -0
- remotivelabs_cli-0.0.13/cli/tools/can/can.py +79 -0
- remotivelabs_cli-0.0.13/cli/tools/tools.py +10 -0
- remotivelabs_cli-0.0.13/pyproject.toml +39 -0
- remotivelabs_cli-0.0.1a3/PKG-INFO +0 -46
- remotivelabs_cli-0.0.1a3/README.md +0 -26
- remotivelabs_cli-0.0.1a3/cli/__init__.py +0 -1
- remotivelabs_cli-0.0.1a3/cli/cloud/brokers.py +0 -57
- remotivelabs_cli-0.0.1a3/cli/cloud/cloud_cli.py +0 -49
- remotivelabs_cli-0.0.1a3/cli/cloud/recordings.py +0 -164
- remotivelabs_cli-0.0.1a3/cli/cloud/rest_helper.py +0 -99
- remotivelabs_cli-0.0.1a3/cli/cloud/service_account_keys.py +0 -43
- remotivelabs_cli-0.0.1a3/cli/cloud/service_accounts.py +0 -36
- remotivelabs_cli-0.0.1a3/cli/lib/broker.py +0 -138
- remotivelabs_cli-0.0.1a3/cli/remotive.py +0 -8
- remotivelabs_cli-0.0.1a3/cli/test/test_simple.py +0 -5
- remotivelabs_cli-0.0.1a3/pyproject.toml +0 -25
- {remotivelabs_cli-0.0.1a3 → remotivelabs_cli-0.0.13}/cli/cloud/__init__.py +0 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
Apache-2.0
|
2
|
+
|
3
|
+
RemotiveLabs CLI
|
4
|
+
Copyright 2022 RemotiveLabs <hello@remotivelabs.com>
|
5
|
+
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
you may not use this file except in compliance with the License.
|
8
|
+
You may obtain a copy of the License at
|
9
|
+
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
|
12
|
+
Unless required by applicable law or agreed to in writing, software
|
13
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
See the License for the specific language governing permissions and
|
16
|
+
limitations under the License.
|
17
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: remotivelabs-cli
|
3
|
+
Version: 0.0.13
|
4
|
+
Summary: CLI for operating RemotiveCloud and RemotiveBroker
|
5
|
+
Author: Johan Rask
|
6
|
+
Author-email: johan.rask@remotivelabs.com
|
7
|
+
Requires-Python: >=3.8,<4.0
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
14
|
+
Requires-Dist: plotext (>=5.2,<6.0)
|
15
|
+
Requires-Dist: pyjwt (>=2.6,<3.0)
|
16
|
+
Requires-Dist: python-can (>=4.3.1)
|
17
|
+
Requires-Dist: python-socketio (>=4.6.1)
|
18
|
+
Requires-Dist: remotivelabs-broker (>=0.1.17)
|
19
|
+
Requires-Dist: rich (>=13.7.0,<13.8.0)
|
20
|
+
Requires-Dist: trogon (>=0.5.0)
|
21
|
+
Requires-Dist: typer (>=0.9.0,<0.10.0)
|
22
|
+
Requires-Dist: websocket-client (>=1.6,<2.0)
|
23
|
+
Requires-Dist: zeroconf (>=0.127.0,<0.128.0)
|
24
|
+
Description-Content-Type: text/markdown
|
25
|
+
|
26
|
+
# RemotiveLabs - CLI
|
27
|
+
[](https://pypi.org/project/remotivelabs-cli)
|
28
|
+
|
29
|
+
Use this CLI with our cloud and broker as a compliment to code and web tools.
|
30
|
+
|
31
|
+
Read more at https://docs.remotivelabs.com/docs/remotive-cli
|
32
|
+
|
33
|
+
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# RemotiveLabs - CLI
|
2
|
+
[](https://pypi.org/project/remotivelabs-cli)
|
3
|
+
|
4
|
+
Use this CLI with our cloud and broker as a compliment to code and web tools.
|
5
|
+
|
6
|
+
Read more at https://docs.remotivelabs.com/docs/remotive-cli
|
7
|
+
|
File without changes
|
@@ -1,4 +1,6 @@
|
|
1
|
-
import
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import os
|
2
4
|
from time import sleep
|
3
5
|
|
4
6
|
import typer
|
@@ -9,30 +11,20 @@ from zeroconf import (
|
|
9
11
|
Zeroconf,
|
10
12
|
)
|
11
13
|
|
12
|
-
from .
|
14
|
+
from . import export, files, playback, record, scripting, signals
|
13
15
|
|
14
|
-
app = typer.Typer()
|
16
|
+
app = typer.Typer(rich_markup_mode="rich")
|
15
17
|
|
16
18
|
|
17
|
-
@app.
|
18
|
-
def
|
19
|
-
|
20
|
-
api_key: str = typer.Option("offline", help="Cloud Broker API-KEY", envvar='REMOTIVE_BROKER_API_KEY')
|
19
|
+
@app.callback()
|
20
|
+
def main(
|
21
|
+
url: str = typer.Option(None, is_eager=False, help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
21
22
|
):
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@app.command(help="List namespaces on broker")
|
29
|
-
def namespaces(
|
30
|
-
url: str = typer.Option(..., help="Broker URL", envvar='REMOTIVE_BROKER_URL'),
|
31
|
-
api_key: str = typer.Option("offline", help="Cloud Broker API-KEY", envvar='REMOTIVE_BROKER_API_KEY')
|
32
|
-
):
|
33
|
-
broker = Broker(url, api_key)
|
34
|
-
namespaces_json = broker.list_namespaces()
|
35
|
-
print(json.dumps(namespaces_json))
|
23
|
+
# This can be used to override the --url per command, lets see if this is a better approach
|
24
|
+
if url is not None:
|
25
|
+
os.environ["REMOTIVE_BROKER_URL"] = url
|
26
|
+
# Do other global stuff, handle other global options here
|
27
|
+
return
|
36
28
|
|
37
29
|
|
38
30
|
@app.command(help="Discover brokers on this network")
|
@@ -41,11 +33,11 @@ def discover():
|
|
41
33
|
|
42
34
|
zeroconf = Zeroconf(ip_version=IPVersion.V4Only)
|
43
35
|
|
44
|
-
services = ["_remotivebroker._tcp.local."
|
36
|
+
services = ["_remotivebroker._tcp.local."]
|
45
37
|
# services = list(ZeroconfServiceTypes.find(zc=zeroconf))
|
46
38
|
|
47
39
|
print("\nLooking for RemotiveBrokers on your network, press Ctrl-C to exit...\n")
|
48
|
-
|
40
|
+
ServiceBrowser(zeroconf, services, handlers=[on_service_state_change])
|
49
41
|
|
50
42
|
try:
|
51
43
|
while True:
|
@@ -56,9 +48,7 @@ def discover():
|
|
56
48
|
zeroconf.close()
|
57
49
|
|
58
50
|
|
59
|
-
def on_service_state_change(
|
60
|
-
zeroconf: Zeroconf, service_type: str, name: str, state_change: ServiceStateChange
|
61
|
-
) -> None:
|
51
|
+
def on_service_state_change(zeroconf: Zeroconf, service_type: str, name: str, state_change: ServiceStateChange) -> None:
|
62
52
|
# print(f"Service {name} state changed: {state_change}")
|
63
53
|
|
64
54
|
if state_change is ServiceStateChange.Removed:
|
@@ -68,14 +58,15 @@ def on_service_state_change(
|
|
68
58
|
print(f"Service {name} was updated")
|
69
59
|
|
70
60
|
if state_change is ServiceStateChange.Added:
|
71
|
-
print(f"
|
61
|
+
print(f"[ {name} ]")
|
72
62
|
info = zeroconf.get_service_info(service_type, name)
|
73
63
|
# print("Info from zeroconf.get_service_info: %r" % (info))
|
74
64
|
|
75
65
|
if info:
|
76
66
|
# addresses = ["%s:%d" % (addr, cast(int, info.port)) for addr in info.parsed_scoped_addresses()]
|
77
67
|
for addr in info.parsed_scoped_addresses():
|
78
|
-
print(addr)
|
68
|
+
print(f"RemotiveBrokerApp: http://{addr}:8080")
|
69
|
+
print(f"RemotiveBroker http://{addr}:50051")
|
79
70
|
# print(" Weight: %d, priority: %d" % (info.weight, info.priority))
|
80
71
|
# print(f" Server: {info.server}")
|
81
72
|
# if info.properties:
|
@@ -86,8 +77,15 @@ def on_service_state_change(
|
|
86
77
|
# print(" No properties")
|
87
78
|
else:
|
88
79
|
print(" No info")
|
89
|
-
print(
|
80
|
+
print("\n")
|
81
|
+
|
90
82
|
|
83
|
+
app.add_typer(playback.app, name="playback", help="Manage playing recordings")
|
84
|
+
app.add_typer(record.app, name="record", help="Record data on buses")
|
85
|
+
app.add_typer(files.app, name="files", help="Upload/Download configurations and recordings")
|
86
|
+
app.add_typer(signals.app, name="signals", help="Find and subscribe to signals")
|
87
|
+
app.add_typer(export.app, name="export", help="Export to external formats")
|
88
|
+
app.add_typer(scripting.app, name="scripting")
|
91
89
|
|
92
90
|
if __name__ == "__main__":
|
93
91
|
app()
|
@@ -0,0 +1,110 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import os
|
4
|
+
import signal as os_signal
|
5
|
+
from typing import List
|
6
|
+
|
7
|
+
import grpc
|
8
|
+
import typer
|
9
|
+
|
10
|
+
from cli.errors import ErrorPrinter
|
11
|
+
|
12
|
+
from .lib.broker import Broker
|
13
|
+
|
14
|
+
app = typer.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"),
|
28
|
+
namespace: str = typer.Option(..., help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
29
|
+
on_change_only: bool = typer.Option(default=False, help="Only get signal if value is changed"),
|
30
|
+
output: str = typer.Option(None, help="Write results to file, defaults to stdout"),
|
31
|
+
):
|
32
|
+
"""
|
33
|
+
Exports subscribed signals to InfluxDB line-protocol, really useful to dump some signals into
|
34
|
+
influxdb for offline analysis and insights.
|
35
|
+
|
36
|
+
This is a sample for exporting and importing to InfluxDB using remotive-cli and influx-cli
|
37
|
+
|
38
|
+
Export:
|
39
|
+
remotive broker export influxdb --url [URL] --output signals.influx --namespace VehicleBus \\
|
40
|
+
--signal Control.SteeringWheel_Position --signal Control.Accelerator_PedalPosition \\
|
41
|
+
--signal GpsPosition.GPS_Longitude --signal GpsPosition.GPS_Latitude
|
42
|
+
|
43
|
+
Output:
|
44
|
+
Control, SteeringWheel_Position=1.0,Accelerator_PedalPosition=0,Speed=0 1664787032944374000
|
45
|
+
GpsPosition, GPS_Longitude=12.982076,GPS_Latitude=55.618748 1664787032948256000
|
46
|
+
|
47
|
+
Import:
|
48
|
+
influx write --org myorg -b my-bucket -p ns --format=lp -f signals.influx
|
49
|
+
|
50
|
+
|
51
|
+
"""
|
52
|
+
|
53
|
+
if output is not None:
|
54
|
+
f = open(output, "w")
|
55
|
+
|
56
|
+
def exit_on_ctrlc(sig, frame):
|
57
|
+
if output is not None:
|
58
|
+
f.close()
|
59
|
+
os._exit(0)
|
60
|
+
|
61
|
+
def per_frame_influx_line_protocol(x):
|
62
|
+
signals = list(x)
|
63
|
+
if len(signals) == 0:
|
64
|
+
return
|
65
|
+
|
66
|
+
frame_name = signals[0]["name"].split(".")[0]
|
67
|
+
signals_str = ",".join(list(map(lambda s: f'{s["name"].split(".")[1]}={s["value"]}', signals)))
|
68
|
+
influx_lp = f"{frame_name},namespace={namespace} {signals_str} {round(signals[0]['timestamp_us'] * 1000)}"
|
69
|
+
if output is not None:
|
70
|
+
f.write(f"{influx_lp}\n")
|
71
|
+
else:
|
72
|
+
print(f"{influx_lp}")
|
73
|
+
|
74
|
+
# TODO - support for csv
|
75
|
+
# def csv(x):
|
76
|
+
# list = list(x)
|
77
|
+
# print(x)
|
78
|
+
# l = list(x)
|
79
|
+
# print(l)
|
80
|
+
# ll=list(map(lambda s : s, l))
|
81
|
+
# for s in l:
|
82
|
+
# dt = datetime.fromtimestamp(s["timestamp_nanos"] / 1000000)
|
83
|
+
# t=datetime.isoformat(dt)
|
84
|
+
# t=rfc3339.format_millisecond(dt)
|
85
|
+
# rich_rprint(len(l))
|
86
|
+
# lat = (l[0])
|
87
|
+
# lon = l[1]
|
88
|
+
# dt = datetime.fromtimestamp(lat["timestamp_nanos"] / 1000000)
|
89
|
+
# t=datetime.isoformat(dt)
|
90
|
+
# t = rfc3339.format_millisecond(dt)
|
91
|
+
# name = s["name"]
|
92
|
+
# value = s["value"]
|
93
|
+
# if output is not None:
|
94
|
+
# f.write(f'coord,{lat["value"]},{lon["value"]},{t}\n')
|
95
|
+
# else:
|
96
|
+
# print(f'coord,{lat["value"]},{lon["value"]},{t}')
|
97
|
+
# if output is not None:
|
98
|
+
# f.flush()
|
99
|
+
# print(x["timestamp_nanos"])
|
100
|
+
# rich_rprint(json.dumps(list(x)))
|
101
|
+
|
102
|
+
os_signal.signal(os_signal.SIGINT, exit_on_ctrlc)
|
103
|
+
|
104
|
+
# print(namespace)
|
105
|
+
# signals2 = list(map( lambda s: s['signal'], broker.list_signal_names2(namespace)))
|
106
|
+
try:
|
107
|
+
broker = Broker(url, api_key)
|
108
|
+
broker.subscribe(signal, namespace, per_frame_influx_line_protocol, on_change_only)
|
109
|
+
except grpc.RpcError as rpc_error:
|
110
|
+
ErrorPrinter.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 cli.errors import ErrorPrinter
|
11
|
+
|
12
|
+
from .lib.broker import Broker
|
13
|
+
|
14
|
+
app = typer.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
|
+
):
|
22
|
+
try:
|
23
|
+
broker = Broker(url, api_key)
|
24
|
+
broker.reload_config()
|
25
|
+
print("Configuration successfully reloaded")
|
26
|
+
except grpc.RpcError as err:
|
27
|
+
ErrorPrinter.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
|
+
):
|
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("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
|
+
ErrorPrinter.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
|
+
):
|
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(f"File already exist {output_file}, please use another output file name")
|
75
|
+
else:
|
76
|
+
broker.download(path, output_file)
|
77
|
+
print(f"Successfully saved {output_file}")
|
78
|
+
except grpc.RpcError as err:
|
79
|
+
ErrorPrinter.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
|
+
):
|
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(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(f"Successfully uploaded {path}")
|
112
|
+
else:
|
113
|
+
output_file = os.path.basename(path)
|
114
|
+
if output != "":
|
115
|
+
output_file = output
|
116
|
+
broker.upload(path, output_file)
|
117
|
+
print(f"Successfully uploaded {path}")
|
118
|
+
except grpc.RpcError as err:
|
119
|
+
ErrorPrinter.print_grpc_error(err)
|