remotivelabs-cli 0.2.3__py3-none-any.whl → 0.3.1__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.
Potentially problematic release.
This version of remotivelabs-cli might be problematic. Click here for more details.
- cli/broker/__init__.py +36 -0
- cli/broker/discovery.py +43 -0
- cli/broker/export.py +6 -36
- cli/broker/files.py +12 -12
- cli/broker/lib/broker.py +132 -106
- cli/broker/lib/client.py +224 -0
- cli/broker/lib/helper.py +277 -0
- cli/broker/lib/signalcreator.py +196 -0
- cli/broker/license_flows.py +11 -13
- cli/broker/playback.py +10 -10
- cli/broker/record.py +4 -4
- cli/broker/scripting.py +6 -9
- cli/broker/signals.py +17 -19
- cli/cloud/__init__.py +17 -0
- cli/cloud/auth/cmd.py +74 -33
- cli/cloud/auth/login.py +42 -54
- cli/cloud/auth_tokens.py +40 -247
- cli/cloud/brokers.py +5 -9
- cli/cloud/configs.py +4 -17
- cli/cloud/licenses/__init__.py +0 -0
- cli/cloud/licenses/cmd.py +14 -0
- cli/cloud/organisations.py +12 -17
- cli/cloud/projects.py +3 -3
- cli/cloud/recordings.py +35 -61
- cli/cloud/recordings_playback.py +22 -22
- cli/cloud/resumable_upload.py +6 -6
- cli/cloud/service_account_tokens.py +4 -3
- cli/cloud/storage/cmd.py +2 -3
- cli/cloud/storage/copy.py +2 -1
- cli/connect/connect.py +4 -4
- cli/connect/protopie/protopie.py +22 -30
- cli/remotive.py +16 -26
- cli/settings/__init__.py +1 -2
- cli/settings/config_file.py +2 -0
- cli/settings/core.py +146 -146
- cli/settings/migration/migrate_config_file.py +13 -6
- cli/settings/migration/migration_tools.py +6 -4
- cli/settings/state_file.py +12 -4
- cli/tools/can/can.py +4 -7
- cli/topology/__init__.py +3 -0
- cli/topology/cmd.py +60 -83
- cli/topology/start_trial.py +105 -0
- cli/typer/typer_utils.py +3 -6
- cli/utils/console.py +61 -0
- cli/utils/rest_helper.py +33 -31
- cli/utils/versions.py +7 -19
- {remotivelabs_cli-0.2.3.dist-info → remotivelabs_cli-0.3.1.dist-info}/METADATA +3 -2
- remotivelabs_cli-0.3.1.dist-info/RECORD +74 -0
- cli/broker/brokers.py +0 -93
- cli/cloud/cloud_cli.py +0 -29
- cli/errors.py +0 -44
- remotivelabs_cli-0.2.3.dist-info/RECORD +0 -67
- {remotivelabs_cli-0.2.3.dist-info → remotivelabs_cli-0.3.1.dist-info}/LICENSE +0 -0
- {remotivelabs_cli-0.2.3.dist-info → remotivelabs_cli-0.3.1.dist-info}/WHEEL +0 -0
- {remotivelabs_cli-0.2.3.dist-info → remotivelabs_cli-0.3.1.dist-info}/entry_points.txt +0 -0
cli/broker/license_flows.py
CHANGED
|
@@ -7,14 +7,12 @@ from typing import Union
|
|
|
7
7
|
import grpc
|
|
8
8
|
import requests
|
|
9
9
|
import typer
|
|
10
|
-
from rich.console import Console
|
|
11
10
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
12
11
|
|
|
13
12
|
from cli.broker.lib.broker import Broker, LicenseInfo
|
|
13
|
+
from cli.utils.console import print_unformatted_to_stderr
|
|
14
14
|
from cli.utils.rest_helper import RestHelper as Rest
|
|
15
15
|
|
|
16
|
-
console = Console(stderr=True)
|
|
17
|
-
|
|
18
16
|
|
|
19
17
|
class LicenseFlow:
|
|
20
18
|
def describe_with_url(self, url: str) -> LicenseInfo:
|
|
@@ -35,7 +33,7 @@ class LicenseFlow:
|
|
|
35
33
|
return b.get_license()
|
|
36
34
|
|
|
37
35
|
def request_with_url_with_internet(self, url: str) -> None:
|
|
38
|
-
|
|
36
|
+
print_unformatted_to_stderr("This requires internet connection from your computer during the entire licensing process")
|
|
39
37
|
|
|
40
38
|
email = LicenseFlow.__try_authenticate_and_get_email_from_cloud()
|
|
41
39
|
|
|
@@ -52,7 +50,7 @@ class LicenseFlow:
|
|
|
52
50
|
if not apply:
|
|
53
51
|
return
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
print_unformatted_to_stderr(
|
|
56
54
|
":point_right: [bold yellow]This will request a new license or use an existing license if "
|
|
57
55
|
"this hardware has already been licensed[/bold yellow]"
|
|
58
56
|
)
|
|
@@ -66,7 +64,7 @@ class LicenseFlow:
|
|
|
66
64
|
with use_progress("Applying license to broker..."):
|
|
67
65
|
new_license = broker_to_license.apply_license(license_data_b64)
|
|
68
66
|
if new_license.valid:
|
|
69
|
-
|
|
67
|
+
print_unformatted_to_stderr(f":thumbsup: Successfully applied license, it remains valid until {new_license.expires}")
|
|
70
68
|
|
|
71
69
|
def request_with_hotspot(self, url: Union[str, None] = "http://192.168.4.1:50051") -> None:
|
|
72
70
|
"""
|
|
@@ -76,7 +74,7 @@ class LicenseFlow:
|
|
|
76
74
|
if url is None:
|
|
77
75
|
url = "http://192.168.4.1:50051"
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
print_unformatted_to_stderr(
|
|
80
78
|
"Licensing a broker over its wifi hotspot will require you to switch between internet connectivity "
|
|
81
79
|
"and remotivelabs-xxx wifi hotspot"
|
|
82
80
|
)
|
|
@@ -95,7 +93,7 @@ class LicenseFlow:
|
|
|
95
93
|
if not apply:
|
|
96
94
|
return
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
print_unformatted_to_stderr(
|
|
99
97
|
":point_right: [bold yellow]This will request a new license or use an existing license if "
|
|
100
98
|
"this hardware has already been licensed[/bold yellow]"
|
|
101
99
|
)
|
|
@@ -110,7 +108,7 @@ class LicenseFlow:
|
|
|
110
108
|
progress_label="Applying license to broker... Make sure to switch back to remotivelabs-xxx wifi hotspot",
|
|
111
109
|
)
|
|
112
110
|
new_license = broker_to_license.apply_license(license_data_b64)
|
|
113
|
-
|
|
111
|
+
print_unformatted_to_stderr(f":thumbsup: Successfully applied license, expires {new_license.expires}")
|
|
114
112
|
|
|
115
113
|
@staticmethod
|
|
116
114
|
def __try_connect_to_broker(url: str, progress_label: str, on_error_progress_label: Union[str, None] = None) -> Broker:
|
|
@@ -127,9 +125,9 @@ class LicenseFlow:
|
|
|
127
125
|
)
|
|
128
126
|
time.sleep(1)
|
|
129
127
|
if on_error_progress_label is None:
|
|
130
|
-
|
|
128
|
+
print_unformatted_to_stderr(f":white_check_mark: {progress_label}")
|
|
131
129
|
else:
|
|
132
|
-
|
|
130
|
+
print_unformatted_to_stderr(f":white_check_mark: {on_error_progress_label}")
|
|
133
131
|
return broker_to_license
|
|
134
132
|
|
|
135
133
|
@staticmethod
|
|
@@ -141,7 +139,7 @@ class LicenseFlow:
|
|
|
141
139
|
break
|
|
142
140
|
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout):
|
|
143
141
|
time.sleep(1)
|
|
144
|
-
|
|
142
|
+
print_unformatted_to_stderr(":white_check_mark: Fetching user info from cloud... Make sure you are connected to internet")
|
|
145
143
|
if r is None:
|
|
146
144
|
return ""
|
|
147
145
|
return str(r.json()["email"])
|
|
@@ -159,7 +157,7 @@ class LicenseFlow:
|
|
|
159
157
|
break
|
|
160
158
|
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout):
|
|
161
159
|
time.sleep(1)
|
|
162
|
-
|
|
160
|
+
print_unformatted_to_stderr(f":white_check_mark: {progress_label}")
|
|
163
161
|
return bytes(license_data_b64)
|
|
164
162
|
|
|
165
163
|
|
cli/broker/playback.py
CHANGED
|
@@ -5,8 +5,8 @@ from typing import Dict, List
|
|
|
5
5
|
import grpc
|
|
6
6
|
import typer
|
|
7
7
|
|
|
8
|
-
from cli.errors import ErrorPrinter
|
|
9
8
|
from cli.typer import typer_utils
|
|
9
|
+
from cli.utils.console import print_generic_error, print_generic_message, print_grpc_error, print_success
|
|
10
10
|
|
|
11
11
|
from .lib.broker import Broker
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ app = typer_utils.create_typer(help=help)
|
|
|
16
16
|
def recording_and_namespace(recording: str) -> Dict[str, str]:
|
|
17
17
|
splitted = recording.split("::")
|
|
18
18
|
if len(splitted) != 2:
|
|
19
|
-
|
|
19
|
+
print_generic_error("Invalid --recording option, expected file_name::namespace")
|
|
20
20
|
raise typer.Exit(1)
|
|
21
21
|
return {"recording": splitted[0], "namespace": splitted[1]}
|
|
22
22
|
|
|
@@ -39,10 +39,10 @@ def play(
|
|
|
39
39
|
try:
|
|
40
40
|
broker = Broker(url, api_key)
|
|
41
41
|
status = broker.play(rec)
|
|
42
|
-
print
|
|
42
|
+
# TODO: use log instead of print for debug information?
|
|
43
|
+
print_generic_message(str(status))
|
|
43
44
|
except grpc.RpcError as err:
|
|
44
|
-
|
|
45
|
-
# print(status)
|
|
45
|
+
print_grpc_error(err)
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
@app.command()
|
|
@@ -64,9 +64,9 @@ def stop(
|
|
|
64
64
|
try:
|
|
65
65
|
broker = Broker(url, api_key)
|
|
66
66
|
broker.stop_play(rec)
|
|
67
|
-
|
|
67
|
+
print_success("Recording stopped")
|
|
68
68
|
except grpc.RpcError as err:
|
|
69
|
-
|
|
69
|
+
print_grpc_error(err)
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
@app.command()
|
|
@@ -87,9 +87,9 @@ def pause(
|
|
|
87
87
|
try:
|
|
88
88
|
broker = Broker(url, api_key)
|
|
89
89
|
broker.pause_play(rec)
|
|
90
|
-
|
|
90
|
+
print_success("Recording paused")
|
|
91
91
|
except grpc.RpcError as err:
|
|
92
|
-
|
|
92
|
+
print_grpc_error(err)
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
@app.command()
|
|
@@ -115,4 +115,4 @@ def seek(
|
|
|
115
115
|
broker = Broker(url, api_key)
|
|
116
116
|
broker.seek(rec, int(seconds * 1000000))
|
|
117
117
|
except grpc.RpcError as err:
|
|
118
|
-
|
|
118
|
+
print_grpc_error(err)
|
cli/broker/record.py
CHANGED
|
@@ -5,8 +5,8 @@ from typing import List
|
|
|
5
5
|
import grpc
|
|
6
6
|
import typer
|
|
7
7
|
|
|
8
|
-
from cli.errors import ErrorPrinter
|
|
9
8
|
from cli.typer import typer_utils
|
|
9
|
+
from cli.utils.console import print_grpc_error, print_success
|
|
10
10
|
|
|
11
11
|
from .lib.broker import Broker
|
|
12
12
|
|
|
@@ -24,7 +24,7 @@ def start(
|
|
|
24
24
|
broker = Broker(url, api_key)
|
|
25
25
|
broker.record_multiple(namespace, filename)
|
|
26
26
|
except grpc.RpcError as rpc_error:
|
|
27
|
-
|
|
27
|
+
print_grpc_error(rpc_error)
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
@app.command()
|
|
@@ -37,6 +37,6 @@ def stop(
|
|
|
37
37
|
try:
|
|
38
38
|
broker = Broker(url, api_key)
|
|
39
39
|
broker.stop_multiple(namespace, filename)
|
|
40
|
-
|
|
40
|
+
print_success("Recording stopped")
|
|
41
41
|
except grpc.RpcError as rpc_error:
|
|
42
|
-
|
|
42
|
+
print_grpc_error(rpc_error)
|
cli/broker/scripting.py
CHANGED
|
@@ -5,10 +5,9 @@ from string import Template
|
|
|
5
5
|
from typing import List
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
|
-
from rich import print as rich_print
|
|
9
8
|
|
|
10
|
-
from cli.errors import ErrorPrinter
|
|
11
9
|
from cli.typer import typer_utils
|
|
10
|
+
from cli.utils.console import print_generic_message, print_hint
|
|
12
11
|
|
|
13
12
|
app = typer_utils.create_typer(
|
|
14
13
|
rich_markup_mode="rich",
|
|
@@ -20,10 +19,9 @@ app = typer_utils.create_typer(
|
|
|
20
19
|
|
|
21
20
|
def write(signal_name: str, script: str) -> None:
|
|
22
21
|
path = f"{signal_name}.lua"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
f
|
|
26
|
-
print(f"Secret token written to {path}")
|
|
22
|
+
with open(path, "w") as f:
|
|
23
|
+
f.write(script)
|
|
24
|
+
print_generic_message(f"Secret token written to {path}")
|
|
27
25
|
|
|
28
26
|
|
|
29
27
|
@app.command("new-script")
|
|
@@ -35,7 +33,7 @@ def new_script(
|
|
|
35
33
|
def to_subscribable_signal(sig: str) -> tuple[str, str]:
|
|
36
34
|
arr = sig.split(":")
|
|
37
35
|
if len(arr) != 2:
|
|
38
|
-
|
|
36
|
+
print_hint(f"--input-signal must have format namespace:signal ({sig})")
|
|
39
37
|
sys.exit(1)
|
|
40
38
|
return arr[0], arr[1]
|
|
41
39
|
|
|
@@ -121,7 +119,6 @@ end
|
|
|
121
119
|
|
|
122
120
|
script = template.substitute(
|
|
123
121
|
local_signals=local_signals,
|
|
124
|
-
# signle_input_signal=signals_to_subscribe_to[0][1], # Take one signal and use signal name in tuple
|
|
125
122
|
subscribe_pattern=subscribe_pattern,
|
|
126
123
|
output_signal=output_signal,
|
|
127
124
|
)
|
|
@@ -129,4 +126,4 @@ end
|
|
|
129
126
|
if save:
|
|
130
127
|
write(output_signal, script)
|
|
131
128
|
else:
|
|
132
|
-
|
|
129
|
+
print_generic_message(script)
|
cli/broker/signals.py
CHANGED
|
@@ -12,10 +12,9 @@ from typing import Any, Dict, Iterable, List, TypedDict, Union
|
|
|
12
12
|
import grpc
|
|
13
13
|
import plotext as plt # type: ignore
|
|
14
14
|
import typer
|
|
15
|
-
from rich import print as rich_rprint
|
|
16
15
|
|
|
17
|
-
from cli.errors import ErrorPrinter
|
|
18
16
|
from cli.typer import typer_utils
|
|
17
|
+
from cli.utils.console import print_generic_error, print_generic_message, print_grpc_error, print_hint
|
|
19
18
|
|
|
20
19
|
from .lib.broker import Broker, SubscribableSignal
|
|
21
20
|
|
|
@@ -23,8 +22,6 @@ app = typer_utils.create_typer(help=help)
|
|
|
23
22
|
|
|
24
23
|
DEFAULT_GRPC_URL = "http://localhost:50051"
|
|
25
24
|
|
|
26
|
-
# signal_values:list = list()
|
|
27
|
-
|
|
28
25
|
|
|
29
26
|
class Signals(TypedDict):
|
|
30
27
|
name: str
|
|
@@ -49,18 +46,18 @@ def list_signals(
|
|
|
49
46
|
try:
|
|
50
47
|
broker = Broker(url, api_key)
|
|
51
48
|
available_signals = broker.list_signal_names(prefix=name_starts_with, suffix=name_ends_with)
|
|
52
|
-
|
|
49
|
+
print_generic_message(json.dumps(available_signals))
|
|
53
50
|
except grpc.RpcError as rpc_error:
|
|
54
|
-
|
|
51
|
+
print_grpc_error(rpc_error)
|
|
55
52
|
|
|
56
53
|
|
|
57
54
|
def read_scripted_code_file(file_path: Path) -> bytes:
|
|
58
55
|
try:
|
|
59
|
-
|
|
56
|
+
print_generic_message(str(file_path))
|
|
60
57
|
with open(file_path, "rb") as file:
|
|
61
58
|
return file.read()
|
|
62
59
|
except FileNotFoundError:
|
|
63
|
-
|
|
60
|
+
print_generic_error("File not found. Please check your file path.")
|
|
64
61
|
sys.exit(1)
|
|
65
62
|
|
|
66
63
|
|
|
@@ -100,12 +97,12 @@ def subscribe( # noqa: C901, PLR0913, PLR0915
|
|
|
100
97
|
|
|
101
98
|
if script is None:
|
|
102
99
|
if len(signal) == 0:
|
|
103
|
-
|
|
100
|
+
print_generic_error("You must use --signal or use --script when subscribing")
|
|
104
101
|
sys.exit(1)
|
|
105
102
|
|
|
106
103
|
if script is not None:
|
|
107
104
|
if len(signal) > 0:
|
|
108
|
-
|
|
105
|
+
print_generic_error("You must must not specify --signal when using --script")
|
|
109
106
|
sys.exit(1)
|
|
110
107
|
|
|
111
108
|
plt.title("Signals")
|
|
@@ -153,7 +150,8 @@ def subscribe( # noqa: C901, PLR0913, PLR0915
|
|
|
153
150
|
plt.show()
|
|
154
151
|
|
|
155
152
|
def on_frame_print(x: Iterable[Any]) -> None:
|
|
156
|
-
|
|
153
|
+
# TODO: use log instead of print for debug information?
|
|
154
|
+
print_generic_message(json.dumps(list(x)))
|
|
157
155
|
|
|
158
156
|
os_signal.signal(os_signal.SIGINT, exit_on_ctrlc)
|
|
159
157
|
|
|
@@ -172,7 +170,7 @@ def subscribe( # noqa: C901, PLR0913, PLR0915
|
|
|
172
170
|
def to_subscribable_signal(sig: str):
|
|
173
171
|
arr = sig.split(":")
|
|
174
172
|
if len(arr) != 2:
|
|
175
|
-
|
|
173
|
+
print_hint(f"--signal must have format namespace:signal ({sig})")
|
|
176
174
|
sys.exit(1)
|
|
177
175
|
return SubscribableSignal(namespace=arr[0], name=arr[1])
|
|
178
176
|
|
|
@@ -180,9 +178,9 @@ def subscribe( # noqa: C901, PLR0913, PLR0915
|
|
|
180
178
|
|
|
181
179
|
broker = Broker(url, api_key)
|
|
182
180
|
broker.long_name_subscribe(signals_to_subscribe_to, on_frame_func, on_change_only)
|
|
183
|
-
|
|
181
|
+
print_generic_message("Subscribing to signals, press Ctrl+C to exit")
|
|
184
182
|
except grpc.RpcError as rpc_error:
|
|
185
|
-
|
|
183
|
+
print_grpc_error(rpc_error)
|
|
186
184
|
|
|
187
185
|
|
|
188
186
|
@app.command(help="List namespaces on broker")
|
|
@@ -193,9 +191,9 @@ def namespaces(
|
|
|
193
191
|
try:
|
|
194
192
|
broker = Broker(url, api_key)
|
|
195
193
|
namespaces_json = broker.list_namespaces()
|
|
196
|
-
|
|
194
|
+
print_generic_message(json.dumps(namespaces_json))
|
|
197
195
|
except grpc.RpcError as rpc_error:
|
|
198
|
-
|
|
196
|
+
print_grpc_error(rpc_error)
|
|
199
197
|
|
|
200
198
|
|
|
201
199
|
@app.command()
|
|
@@ -214,11 +212,11 @@ def frame_distribution(
|
|
|
214
212
|
timestamp: str = datetime.now().strftime("%H:%M:%S")
|
|
215
213
|
distribution = data["countsByFrameId"]
|
|
216
214
|
if len(distribution) == 0:
|
|
217
|
-
|
|
215
|
+
print_hint(f"{timestamp} - No frames available")
|
|
218
216
|
else:
|
|
219
217
|
for d in distribution:
|
|
220
|
-
|
|
218
|
+
print_generic_message(f"{timestamp}: {d}")
|
|
221
219
|
|
|
222
220
|
broker.listen_on_frame_distribution(namespace, on_data)
|
|
223
221
|
except grpc.RpcError as rpc_error:
|
|
224
|
-
|
|
222
|
+
print_grpc_error(rpc_error)
|
cli/cloud/__init__.py
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from cli.cloud import auth, brokers, configs, organisations, projects, recordings, sample_recordings, service_accounts, storage
|
|
2
|
+
from cli.cloud.licenses.cmd import licenses
|
|
3
|
+
from cli.typer import typer_utils
|
|
4
|
+
|
|
5
|
+
app = typer_utils.create_typer()
|
|
6
|
+
|
|
7
|
+
app.command(name="licenses", help="List licenses for an organization")(licenses)
|
|
8
|
+
|
|
9
|
+
app.add_typer(organisations.app, name="organizations", help="Manage organizations")
|
|
10
|
+
app.add_typer(projects.app, name="projects", help="Manage projects")
|
|
11
|
+
app.add_typer(auth.app, name="auth")
|
|
12
|
+
app.add_typer(brokers.app, name="brokers", help="Manage cloud broker lifecycle")
|
|
13
|
+
app.add_typer(recordings.app, name="recordings", help="Manage recordings")
|
|
14
|
+
app.add_typer(configs.app, name="signal-databases", help="Manage signal databases")
|
|
15
|
+
app.add_typer(storage.app, name="storage")
|
|
16
|
+
app.add_typer(service_accounts.app, name="service-accounts", help="Manage project service account keys")
|
|
17
|
+
app.add_typer(sample_recordings.app, name="samples", help="Manage sample recordings")
|
cli/cloud/auth/cmd.py
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
import sys
|
|
4
5
|
|
|
5
6
|
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.table import Table
|
|
6
9
|
|
|
7
10
|
from cli.cloud.auth.login import login as do_login
|
|
8
|
-
from cli.
|
|
9
|
-
from cli.settings import TokenNotFoundError, settings
|
|
11
|
+
from cli.settings import settings
|
|
10
12
|
from cli.typer import typer_utils
|
|
13
|
+
from cli.utils.console import print_generic_error, print_generic_message, print_success, print_unformatted
|
|
11
14
|
from cli.utils.rest_helper import RestHelper as Rest
|
|
12
15
|
|
|
13
16
|
from .. import auth_tokens
|
|
14
17
|
|
|
18
|
+
console = Console(stderr=False)
|
|
19
|
+
|
|
15
20
|
HELP = """
|
|
16
21
|
Manage how you authenticate with our cloud platform
|
|
17
22
|
"""
|
|
18
23
|
app = typer_utils.create_typer(help=HELP)
|
|
19
|
-
# app.add_typer(auth_tokens.app, name="credentials", help="Manage account credentials")
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
@app.command(name="login")
|
|
@@ -36,11 +40,7 @@ def whoami() -> None:
|
|
|
36
40
|
"""
|
|
37
41
|
Validates authentication and fetches your account information
|
|
38
42
|
"""
|
|
39
|
-
|
|
40
|
-
Rest.handle_get("/api/whoami")
|
|
41
|
-
except TokenNotFoundError as e:
|
|
42
|
-
ErrorPrinter.print_hint(str(e))
|
|
43
|
-
sys.exit(1)
|
|
43
|
+
Rest.handle_get("/api/whoami")
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
@app.command()
|
|
@@ -50,39 +50,80 @@ def print_access_token(
|
|
|
50
50
|
"""
|
|
51
51
|
Print current active access token or the token for the specified account
|
|
52
52
|
"""
|
|
53
|
-
if account
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
53
|
+
if not account:
|
|
54
|
+
active_token = settings.get_active_token() or os.getenv("REMOTIVE_CLOUD_ACCESS_TOKEN", None)
|
|
55
|
+
if not active_token:
|
|
56
|
+
print_generic_error("You have no active account")
|
|
57
|
+
sys.exit(1)
|
|
58
|
+
|
|
59
|
+
print_generic_message(active_token)
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
accounts = settings.list_accounts()
|
|
63
|
+
if account not in accounts:
|
|
64
|
+
print_generic_error(f"No account for {account} was found")
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
|
|
67
|
+
token_file_name = accounts[account].credentials_file
|
|
68
|
+
token_file = settings.get_token_file(token_file_name)
|
|
69
|
+
if not token_file:
|
|
70
|
+
print_generic_error(f"Token file for {account} could not be found")
|
|
71
|
+
sys.exit(1)
|
|
72
|
+
|
|
73
|
+
print_generic_message(token_file.token)
|
|
68
74
|
|
|
69
75
|
|
|
70
76
|
def print_access_token_file() -> None:
|
|
71
77
|
"""
|
|
72
78
|
Print current active token and its metadata
|
|
73
79
|
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
ErrorPrinter.print_hint(str(e))
|
|
80
|
+
active_token_file = settings.get_active_token_file()
|
|
81
|
+
if not active_token_file:
|
|
82
|
+
print_generic_error("You have no active account")
|
|
78
83
|
sys.exit(1)
|
|
79
84
|
|
|
85
|
+
print_generic_message(str(active_token_file))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@app.command(name="deactivate")
|
|
89
|
+
def deactivate() -> None:
|
|
90
|
+
"""
|
|
91
|
+
Clears active account
|
|
92
|
+
"""
|
|
93
|
+
settings.clear_active_account()
|
|
94
|
+
print_success("Account no longer active")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@app.command("activate")
|
|
98
|
+
def activate(token_name: str = typer.Argument(None, help="Name, filename or path to a credentials file")) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Set the active account
|
|
101
|
+
"""
|
|
102
|
+
auth_tokens.do_activate(token_name)
|
|
80
103
|
|
|
81
|
-
# @app.command(help="Clears active credentials")
|
|
82
|
-
def logout() -> None:
|
|
83
|
-
settings.clear_active_token()
|
|
84
|
-
print("Access token removed")
|
|
85
104
|
|
|
105
|
+
@app.command(name="list")
|
|
106
|
+
def list() -> None:
|
|
107
|
+
"""
|
|
108
|
+
Lists available credential files on filesystem
|
|
86
109
|
|
|
87
|
-
|
|
88
|
-
|
|
110
|
+
TODO: Support output format
|
|
111
|
+
"""
|
|
112
|
+
accounts = settings.list_accounts()
|
|
113
|
+
|
|
114
|
+
table = Table("#", "Active", "Type", "Token", "Account", "Organization", "Created", "Expires")
|
|
115
|
+
for idx, (email, account) in enumerate(accounts.items(), start=1):
|
|
116
|
+
token_file = settings.get_token_file_by_email(email)
|
|
117
|
+
is_active = settings.is_active_account(email)
|
|
118
|
+
|
|
119
|
+
table.add_row(
|
|
120
|
+
f"[yellow]{idx}",
|
|
121
|
+
":white_check_mark:" if is_active else "",
|
|
122
|
+
"unknown" if not token_file else "user" if token_file.type == "authorized_user" else "sa",
|
|
123
|
+
token_file.name if token_file else "",
|
|
124
|
+
f"[bold]{email}[/bold]",
|
|
125
|
+
account.default_organization if account.default_organization else "",
|
|
126
|
+
str(token_file.created) if token_file else "",
|
|
127
|
+
str(token_file.expires) if token_file else "",
|
|
128
|
+
)
|
|
129
|
+
print_unformatted(table)
|