remotivelabs-cli 0.0.27__py3-none-any.whl → 0.0.29__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.
cli/broker/export.py CHANGED
@@ -53,7 +53,7 @@ def influxdb(
53
53
  if output is not None:
54
54
  f = open(output, "w")
55
55
 
56
- def exit_on_ctrlc(sig: Any, frame: Any) -> None:
56
+ def exit_on_ctrlc(_sig: Any, _frame: Any) -> None:
57
57
  if output is not None:
58
58
  f.close()
59
59
  os._exit(0)
cli/broker/lib/broker.py CHANGED
@@ -50,7 +50,7 @@ class Broker:
50
50
 
51
51
  if api_key is None or api_key == "":
52
52
  if url.startswith("https"):
53
- self.intercept_channel = br.create_channel(url, None, settings.read_token())
53
+ self.intercept_channel = br.create_channel(url, None, settings.read_secret_token())
54
54
  # TODO - Temporary solution to print proper error message, remove ENV once api-key is gone
55
55
  os.environ["ACCESS_TOKEN"] = "true"
56
56
  else:
@@ -261,7 +261,7 @@ class Broker:
261
261
  keep_running = True
262
262
  keep_running_during_recording = True
263
263
 
264
- def exit_on_ctrlc(sig: Any, frame: Any) -> None:
264
+ def exit_on_ctrlc(_sig: Any, _frame: Any) -> None:
265
265
  nonlocal keep_running
266
266
  keep_running = False
267
267
  nonlocal keep_running_during_recording
@@ -416,8 +416,7 @@ class Broker:
416
416
  )
417
417
  thread.start()
418
418
  # wait for subscription to settle
419
- subscription = self.q.get()
420
- return subscription # , thread
419
+ return self.q.get()
421
420
 
422
421
  def validate_and_get_subscribed_signals(
423
422
  self, subscribed_namespaces: List[str], subscribed_signals: List[str]
cli/broker/signals.py CHANGED
@@ -108,7 +108,7 @@ def subscribe( # noqa: C901
108
108
 
109
109
  plt.title("Signals")
110
110
 
111
- def exit_on_ctrlc(sig: Any, frame: Any) -> None:
111
+ def exit_on_ctrlc(_sig: Any, _frame: Any) -> None:
112
112
  os._exit(0)
113
113
 
114
114
  def on_frame_plot(x: Iterable[Any]) -> None:
cli/cloud/auth.py CHANGED
@@ -1,8 +1,6 @@
1
- import os
2
1
  import time
3
2
  import webbrowser
4
3
  from http.server import BaseHTTPRequestHandler, HTTPServer
5
- from pathlib import Path
6
4
  from threading import Thread
7
5
  from typing import Any
8
6
 
@@ -14,8 +12,6 @@ from cli import settings
14
12
  from . import auth_tokens
15
13
  from .rest_helper import RestHelper as Rest
16
14
 
17
- APA = settings.CONFIG_DIR_NAME
18
-
19
15
  HELP = """
20
16
  Manage how you authenticate with our cloud platform
21
17
  """
@@ -23,22 +19,17 @@ Manage how you authenticate with our cloud platform
23
19
  httpd: HTTPServer
24
20
 
25
21
  app = typer.Typer(help=HELP)
26
-
27
22
  app.add_typer(auth_tokens.app, name="tokens", help="Manage users personal access tokens")
28
- CONFIG_DIR_NAME = settings.CONFIG_DIR_NAME # str(Path.home()) + "/.config/.remotive/"
29
- TOKEN_FILE_NAME = settings.TOKEN_FILE_NAME # str(Path.home()) + "/.config/.remotive/cloud.secret.token"
30
23
 
31
24
 
32
25
  class S(BaseHTTPRequestHandler):
33
26
  def _set_response(self) -> None:
34
27
  self.send_response(200)
35
- # self.send_response(301)
36
- # self.send_header('Location', 'https://cloud.remotivelabs.com')
37
- # self.end_headers()
38
28
  self.send_header("Content-type", "text/html")
39
29
  self.end_headers()
40
30
 
41
- def log_message(self, format: Any, *args: Any) -> None: # pylint: disable=W0622
31
+ @override
32
+ def log_message(self, format: Any, *args: Any) -> None: # pylint: disable=W0622,
42
33
  return
43
34
 
44
35
  # Please do not change this into lowercase!
@@ -54,9 +45,7 @@ class S(BaseHTTPRequestHandler):
54
45
  killerthread = Thread(target=httpd.shutdown)
55
46
  killerthread.start()
56
47
 
57
- if not os.path.exists(CONFIG_DIR_NAME):
58
- os.makedirs(CONFIG_DIR_NAME)
59
- write_token(path[1:])
48
+ settings.write_secret_token(path[1:])
60
49
  print("Successfully logged on, you are ready to go with cli")
61
50
 
62
51
 
@@ -80,7 +69,11 @@ def login() -> None:
80
69
  be the same as activating a personal access key or service-account access key.
81
70
  """
82
71
  start_local_webserver()
83
- webbrowser.open(f"{Rest.get_base_url()}/login?redirectUrl=http://localhost:{httpd.server_address[1]}", new=1, autoraise=True)
72
+ webbrowser.open(
73
+ f"{Rest.get_base_url()}/login?redirectUrl=http://localhost:{httpd.server_address[1]}",
74
+ new=1,
75
+ autoraise=True,
76
+ )
84
77
 
85
78
  httpd.serve_forever()
86
79
 
@@ -98,46 +91,10 @@ def print_access_token() -> None:
98
91
  """
99
92
  Print current active access token
100
93
  """
101
- print(read_token())
94
+ print(settings.read_secret_token())
102
95
 
103
96
 
104
97
  @app.command(help="Clear access token")
105
98
  def logout() -> None:
106
- os.remove(settings.TOKEN_FILE_NAME)
99
+ settings.clear_secret_token()
107
100
  print("Access token removed")
108
-
109
-
110
- def read_token() -> str:
111
- # f = open(token_file_name, "r")
112
- # token = f.read()
113
- # f.close()
114
- return settings.read_token()
115
-
116
-
117
- def read_file_with_path(file: str) -> str:
118
- with open(file, "r", encoding="utf8") as f:
119
- token = f.read()
120
- return token
121
-
122
-
123
- def read_file(file: str) -> str:
124
- with open(str(Path.home()) + f"/.config/.remotive/{file}", "r", encoding="utf8") as f:
125
- token = f.read()
126
- return token
127
-
128
-
129
- def write_token(token: str) -> None:
130
- with open(TOKEN_FILE_NAME, "w", encoding="utf8") as f:
131
- f.write(token)
132
-
133
-
134
- # Key stuff
135
- # f = open(str(Path.home())+ "/.remotivelabs/privatekey.json", "r")
136
- # j = json.loads(f.read())
137
- # print(j['privateKey'])
138
- # key = load_pem_private_key(bytes(j['privateKey'],'UTF-8'), None)
139
- # print(key.key_size)
140
- #
141
- # "exp": datetime.now(tz=timezone.utc)
142
- # encoded = jwt.encode({"some": "payload"}, j['privateKey'] , algorithm="RS256", headers={"kid": j["keyId"]})
143
- # print(encoded)
cli/cloud/auth_tokens.py CHANGED
@@ -1,18 +1,16 @@
1
1
  import json
2
- import os
3
2
  import sys
4
3
  from json.decoder import JSONDecodeError
5
4
  from pathlib import Path
6
5
 
7
6
  import typer
8
7
 
8
+ from cli import settings
9
+
9
10
  from .rest_helper import RestHelper as Rest
10
11
 
11
12
  app = typer.Typer()
12
13
 
13
- TOKEN_FILE_NAME = str(Path.home()) + "/.config/.remotive/cloud.secret.token"
14
- CONFIG_DIR_NAME = str(Path.home()) + "/.config/.remotive/"
15
-
16
14
 
17
15
  @app.command(name="create", help="Create and download a new personal access token")
18
16
  def get_personal_access_token(activate: bool = typer.Option(False, help="Activate the token for use after download")) -> None: # pylint: disable=W0621
@@ -24,12 +22,12 @@ def get_personal_access_token(activate: bool = typer.Option(False, help="Activat
24
22
 
25
23
  if response.status_code == 200:
26
24
  name = response.json()["name"]
27
- path_to_file = write_personal_token(f"personal-token-{name}.json", response.text)
28
- print(f"Personal access token written to {path_to_file}")
25
+ pat_path = write_personal_token(name, response.text)
26
+ print(f"Personal access token written to {pat_path}")
29
27
  if not activate:
30
- print(f"Use 'remotive cloud auth tokens activate {os.path.basename(path_to_file)}' to use this access token from cli")
28
+ print(f"Use 'remotive cloud auth tokens activate {pat_path.name}' to use this access token from cli")
31
29
  else:
32
- do_activate(path_to_file)
30
+ do_activate(str(pat_path))
33
31
  print("Token file activated and ready for use")
34
32
  print("\033[93m This file contains secrets and must be kept safe")
35
33
  else:
@@ -46,16 +44,17 @@ def list_personal_access_tokens() -> None:
46
44
  @app.command(name="revoke")
47
45
  def revoke(name_or_file: str = typer.Argument(help="Name or file path of the access token to revoke")) -> None:
48
46
  """
49
- Revoke an access token by token name or path to a file containing that token
50
-
51
- Name is found in the json file
52
-
53
- {
54
- "expires": "2034-07-31",
55
- "token": "xxx",
56
- "created": "2024-07-31T09:18:50.406+02:00",
57
- "name": "token_name"
47
+ Revoke an access token by token name or path to a file containing that token
48
+
49
+ Name is found in the json file
50
+ ```
51
+ {
52
+ "expires": "2034-07-31",
53
+ "token": "xxx",
54
+ "created": "2024-07-31T09:18:50.406+02:00",
55
+ "name": "token_name"
58
56
  }
57
+ ```
59
58
  """
60
59
  name = name_or_file
61
60
  if "." in name_or_file:
@@ -93,14 +92,15 @@ def activate(file: str = typer.Argument(..., help="File name")) -> None:
93
92
  do_activate(file)
94
93
 
95
94
 
95
+ # TODO: Move parts of this to settings # pylint: disable=W0511
96
96
  def do_activate(file: str) -> None:
97
97
  # Best effort to read file
98
- if os.path.exists(file):
99
- token_file = json.loads(read_file_with_path(file))
100
- write_token(token_file["token"])
101
- elif os.path.exists(str(Path.home()) + f"/.config/.remotive/{file}"):
98
+ if Path(file).exists():
99
+ token_file = json.loads(read_file_with_path(Path(file)))
100
+ settings.write_secret_token(token_file["token"])
101
+ elif (settings.CONFIG_DIR_PATH / file).exists():
102
102
  token_file = json.loads(read_file(file))
103
- write_token(token_file["token"])
103
+ settings.write_secret_token(token_file["token"])
104
104
  else:
105
105
  sys.stderr.write("File could not be found \n")
106
106
 
@@ -110,43 +110,34 @@ def list_files() -> None:
110
110
  """
111
111
  List personal access token files in remotivelabs config directory
112
112
  """
113
- personal_files = filter(lambda f: f.startswith("personal"), os.listdir(CONFIG_DIR_NAME))
113
+ personal_files = settings.list_personal_token_files()
114
114
  for file in personal_files:
115
115
  print(file)
116
116
 
117
117
 
118
+ # TODO: Move to settings # pylint: disable=W0511
118
119
  def read_file(file: str) -> str:
119
120
  """
120
- Reads a file using file path or if that does not exist check under ~/.config/.remotive
121
+ Reads a file using file path or if that does not exist check in config directory
121
122
  """
122
- path = file
123
- if not Path(file).exists():
124
- path = str(Path.home()) + f"/.config/.remotive/{file}"
125
- if not Path(path).exists():
123
+ path = Path(file)
124
+ if not path.exists():
125
+ path = settings.CONFIG_DIR_PATH / file
126
+ if not path.exists():
126
127
  sys.stderr.write(f"Failed to find file using {file} or {path}\n")
127
128
  sys.exit(1)
128
- with open(path, "r", encoding="utf8") as f:
129
- token = f.read()
130
- f.close()
131
- return token
132
-
133
129
 
134
- def read_file_with_path(file: str) -> str:
135
- with open(file, "r", encoding="utf8") as f:
136
- token = f.read()
137
- f.close()
138
- return token
130
+ return read_file_with_path(path)
139
131
 
140
132
 
141
- def write_token(token: str) -> None:
142
- with open(TOKEN_FILE_NAME, "w", encoding="utf8") as f:
143
- f.write(token)
144
- f.close()
133
+ # TODO: Move to settings # pylint: disable=W0511
134
+ def read_file_with_path(path: Path) -> str:
135
+ with open(path, "r", encoding="utf8") as f:
136
+ return f.read()
145
137
 
146
138
 
147
- def write_personal_token(file: str, token: str) -> str:
148
- path = str(Path.home()) + f"/.config/.remotive/{file}"
149
- with open(path, "w", encoding="utf8") as f:
150
- f.write(token)
151
- f.close()
152
- return path
139
+ # TODO: Move to settings # pylint: disable=W0511
140
+ def write_personal_token(name: str, token: str) -> Path:
141
+ file = f"personal-token-{name}.json"
142
+ path = settings.CONFIG_DIR_PATH / file
143
+ return settings._write_settings_file(path, token) # pylint: disable=W0212
cli/cloud/brokers.py CHANGED
@@ -83,16 +83,16 @@ def logs(
83
83
 
84
84
  """
85
85
 
86
- def exit_on_ctrlc(__sig: Any, __frame: Any) -> None:
86
+ def exit_on_ctrlc(_sig: Any, _frame: Any) -> None:
87
87
  wsapp.close()
88
88
  os._exit(0)
89
89
 
90
90
  os_signal.signal(os_signal.SIGINT, exit_on_ctrlc)
91
91
 
92
- def on_message(__wsapp: Any, message: str) -> None:
92
+ def on_message(_wsapp: Any, message: str) -> None:
93
93
  print(message)
94
94
 
95
- def on_error(wsapp: Any, err: str) -> None: # pylint: disable=W0613
95
+ def on_error(_wsapp: Any, err: str) -> None: # pylint: disable=W0613
96
96
  print("EXAMPLE error encountered: ", err)
97
97
 
98
98
  Rest.ensure_auth_token()
cli/cloud/filestorage.py CHANGED
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import os.path
2
4
  import sys
3
5
  from pathlib import Path
@@ -96,11 +98,24 @@ def copy_file( # noqa: C901 # type: ignore[too-many-branches] # pylint: disabl
96
98
  if source.startswith("rcs://"):
97
99
  __copy_to_local(source=source, dest=dest, project=project)
98
100
  else:
99
- __copy_to_remote(source=source, dest=dest, project=project)
101
+ path = Path(source)
102
+ if path.is_dir():
103
+ print("is dir")
104
+ for file_path in path.rglob("*"):
105
+ if file_path.is_file():
106
+ print(file_path)
107
+ __copy_to_remote(source=source, dest=dest, project=project)
108
+ sys.exit(1)
109
+ else:
110
+ __copy_to_remote(source=source, dest=dest, project=project)
100
111
 
101
112
 
102
113
  def __copy_to_remote(source: str, dest: str, project: str) -> None:
103
114
  path = Path(source)
115
+ if path.is_dir():
116
+ print("is dir")
117
+ sys.exit(1)
118
+
104
119
  if not path.exists():
105
120
  ErrorPrinter.print_hint("Source file does not exist")
106
121
  sys.exit(1)
@@ -111,11 +126,11 @@ def __copy_to_remote(source: str, dest: str, project: str) -> None:
111
126
  res = Rest.handle_post(f"/api/project/{project}/files/storage{rcs_path}", return_response=True)
112
127
  if res is None:
113
128
  return
114
- json = res.json()
115
- url = json["url"]
116
- content_type = json["contentType"]
129
+ json_res = res.json()
130
+ url = json_res["url"]
131
+ headers = json_res["headers"]
117
132
  try:
118
- upload.upload_signed_url(url, source, content_type)
133
+ upload.upload_signed_url(url, source, headers)
119
134
  except IsADirectoryError:
120
135
  ErrorPrinter.print_hint(f"Supplied source file '{source}' is a directory but must be a file")
121
136
 
cli/cloud/rest_helper.py CHANGED
@@ -8,7 +8,7 @@ import shutil
8
8
  import sys
9
9
  from importlib.metadata import version
10
10
  from pathlib import Path
11
- from typing import Any, Dict, List, Union
11
+ from typing import Any, BinaryIO, Dict, List, Union, cast
12
12
 
13
13
  import requests
14
14
  from requests.exceptions import JSONDecodeError
@@ -87,7 +87,7 @@ class RestHelper:
87
87
  # raise typer.Exit()
88
88
 
89
89
  # f = open(str(Path.home()) + "/.config/.remotive/cloud.secret.token", "r")
90
- token = settings.read_token()
90
+ token = settings.read_secret_token()
91
91
  # os.environ['REMOTIVE_CLOUD_AUTH_TOKEN'] = token
92
92
 
93
93
  RestHelper.__headers["Authorization"] = "Bearer " + token.strip()
@@ -256,8 +256,12 @@ class RestHelper:
256
256
  if download_resp.status_code == 200:
257
257
  content_length = int(download_resp.headers["Content-Length"])
258
258
  with open(save_file_name, "wb") as out_file:
259
+ stream = cast(BinaryIO, download_resp.raw) # we know this is a binary stream, as stream=True is set in the request
259
260
  with wrap_file(
260
- download_resp.raw, content_length, refresh_per_second=100, description=f"Downloading to {save_file_name}"
261
+ stream,
262
+ content_length,
263
+ refresh_per_second=100,
264
+ description=f"Downloading to {save_file_name}",
261
265
  ) as stream_with_progress:
262
266
  shutil.copyfileobj(stream_with_progress, out_file)
263
267
  else:
@@ -1,5 +1,8 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
4
  import sys
5
+ from typing import Dict
3
6
 
4
7
  import requests
5
8
  from rich.progress import wrap_file
@@ -21,11 +24,12 @@ def __get_uploaded_bytes(upload_url: str) -> int:
21
24
  return 0
22
25
 
23
26
 
24
- def upload_signed_url(signed_url: str, source_file_name: str, content_type: str) -> None:
27
+ def with_resumable_upload_signed_url(signed_url: str, source_file_name: str, content_type: str) -> None:
25
28
  """
26
29
  Upload file to file storage with signed url and resumable upload.
27
30
  Resumable upload will only work with the same URL and not if a new signed URL is requested with the
28
31
  same object id.
32
+ :param content_type:
29
33
  :param signed_url:
30
34
  :param source_file_name:
31
35
  :return:
@@ -60,3 +64,22 @@ def upload_signed_url(signed_url: str, source_file_name: str, content_type: str)
60
64
  sys.exit(1)
61
65
 
62
66
  print(f"File {source_file_name} uploaded successfully.")
67
+
68
+
69
+ def upload_signed_url(signed_url: str, source_file_name: str, headers: Dict[str, str]) -> None:
70
+ """
71
+ Upload file to file storage with signed url and resumable upload.
72
+ Resumable upload will only work with the same URL and not if a new signed URL is requested with the
73
+ same object id.
74
+ :param headers:
75
+ :param signed_url:
76
+ :param source_file_name:
77
+ :return:
78
+ """
79
+ with open(source_file_name, "rb") as f:
80
+ response = requests.put(signed_url, headers=headers, timeout=60, data=f)
81
+ if response.status_code not in (200, 201, 308):
82
+ ErrorPrinter.print_generic_error(f"Failed to upload file: {response.status_code} - {response.text}")
83
+ sys.exit(1)
84
+
85
+ print(f"File {source_file_name} uploaded successfully.")
@@ -1,16 +1,14 @@
1
1
  import json
2
- import os
3
2
  from pathlib import Path
4
3
 
5
4
  import typer
6
5
 
6
+ from cli import settings
7
+
7
8
  from .rest_helper import RestHelper as Rest
8
9
 
9
10
  app = typer.Typer()
10
11
 
11
- CONFIG_DIR_NAME = str(Path.home()) + "/.config/.remotive/"
12
- TOKEN_FILE_NAME = str(Path.home()) + "/.config/.remotive/cloud.secret.token2"
13
-
14
12
 
15
13
  @app.command(name="create", help="Create new access token")
16
14
  def create(
@@ -29,7 +27,7 @@ def create(
29
27
 
30
28
  if response.status_code == 200:
31
29
  name = response.json()["name"]
32
- write_token(f"service-account-{service_account}-{name}-token.json", response.text)
30
+ write_sa_token(service_account, name, response.text)
33
31
  else:
34
32
  print(f"Got status code: {response.status_code}")
35
33
  print(response.text)
@@ -48,8 +46,8 @@ def list_files() -> None:
48
46
  """
49
47
  List personal access token files in remotivelabs config directory
50
48
  """
51
- personal_files = filter(lambda f: f.startswith("service-account"), os.listdir(CONFIG_DIR_NAME))
52
- for file in personal_files:
49
+ sa_files = settings.list_service_account_token_files()
50
+ for file in sa_files:
53
51
  print(file)
54
52
 
55
53
 
@@ -62,8 +60,8 @@ def revoke(
62
60
  Rest.handle_delete(f"/api/project/{project}/admin/accounts/{service_account}/keys/{name}")
63
61
 
64
62
 
65
- def write_token(file: str, token: str) -> None:
66
- path = str(Path.home()) + f"/.config/.remotive/{file}"
67
- with open(path, "w", encoding="utf8") as f:
68
- f.write(token)
69
- print(f"Secret token written to {path}")
63
+ # TODO: Move to settings # pylint: disable=W0511
64
+ def write_sa_token(service_account: str, name: str, token: str) -> Path:
65
+ file = f"service-account-{service_account}-{name}-token.json"
66
+ path = settings.CONFIG_DIR_PATH / file
67
+ return settings._write_settings_file(path, token) # pylint: disable=W0212
@@ -167,7 +167,7 @@ def do_connect(
167
167
  if broker_url.startswith("https"):
168
168
  if api_key is None:
169
169
  print("No --api-key, reading token from file")
170
- x_api_key = settings.read_token()
170
+ x_api_key = settings.read_secret_token()
171
171
  else:
172
172
  x_api_key = api_key
173
173
  elif api_key is not None:
cli/remotive.py CHANGED
@@ -42,8 +42,7 @@ def test_callback(value: int) -> None:
42
42
 
43
43
  @app.callback()
44
44
  def main(
45
- # pylint: disable=unused-argument
46
- the_version: bool = typer.Option(None, "--version", callback=version_callback, is_eager=False, help="Print current version"),
45
+ _the_version: bool = typer.Option(None, "--version", callback=version_callback, is_eager=False, help="Print current version"),
47
46
  ) -> None:
48
47
  # Do other global stuff, handle other global options here
49
48
  return
cli/settings.py CHANGED
@@ -1,4 +1,5 @@
1
- import os
1
+ from __future__ import annotations
2
+
2
3
  import sys
3
4
  from pathlib import Path
4
5
 
@@ -6,12 +7,19 @@ from rich.console import Console
6
7
 
7
8
  err_console = Console(stderr=True)
8
9
 
9
- CONFIG_DIR_NAME = str(Path.home()) + "/.config/.remotive/"
10
- TOKEN_FILE_NAME = str(Path.home()) + "/.config/.remotive/cloud.secret.token"
10
+ # pylint: disable-next=W0511
11
+ # TODO: We probably want this to be both configurable, and testable. The best solution would probably be to refactor this module into a
12
+ # proper class, and configure it similar to logging.
13
+ CONFIG_DIR_PATH = Path.home() / ".config" / ".remotive/"
14
+ TOKEN_SECRET_FILE_PATH = CONFIG_DIR_PATH / "cloud.secret.token"
15
+
16
+
17
+ class InvalidSettingsFileError(Exception):
18
+ """Raised when trying to access an invalid settings file or file path"""
11
19
 
12
20
 
13
- def read_token() -> str:
14
- if not os.path.exists(TOKEN_FILE_NAME):
21
+ def read_secret_token() -> str:
22
+ if not TOKEN_SECRET_FILE_PATH.exists():
15
23
  err_console.print(":boom: [bold red]Access failed[/bold red] - No access token found")
16
24
  err_console.print("Login with [italic]remotive cloud auth login[/italic]")
17
25
  err_console.print(
@@ -20,6 +28,37 @@ def read_token() -> str:
20
28
  )
21
29
  sys.exit(1)
22
30
 
23
- with open(TOKEN_FILE_NAME, "r", encoding="utf-8") as f:
24
- token = f.read()
25
- return token
31
+ return _read_file(TOKEN_SECRET_FILE_PATH)
32
+
33
+
34
+ def list_personal_token_files() -> list[Path]:
35
+ return [f for f in CONFIG_DIR_PATH.iterdir() if f.is_file() and f.name.startswith("personal-")]
36
+
37
+
38
+ def list_service_account_token_files() -> list[Path]:
39
+ return [f for f in CONFIG_DIR_PATH.iterdir() if f.is_file() and f.name.startswith("service-account-")]
40
+
41
+
42
+ def write_secret_token(secret: str) -> Path:
43
+ return _write_settings_file(TOKEN_SECRET_FILE_PATH, secret)
44
+
45
+
46
+ def clear_secret_token() -> None:
47
+ TOKEN_SECRET_FILE_PATH.unlink()
48
+
49
+
50
+ def _read_file(path: Path) -> str:
51
+ with open(path, "r", encoding="utf-8") as f:
52
+ return f.read()
53
+
54
+
55
+ def _write_settings_file(path: Path, data: str) -> Path:
56
+ if CONFIG_DIR_PATH not in path.parents:
57
+ raise InvalidSettingsFileError(f"file {path} not in settings dir {CONFIG_DIR_PATH}")
58
+
59
+ path.parent.mkdir(parents=True, exist_ok=True)
60
+
61
+ with open(path, "w", encoding="utf8") as f:
62
+ f.write(data)
63
+
64
+ return path
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: remotivelabs-cli
3
- Version: 0.0.27
3
+ Version: 0.0.29
4
4
  Summary: CLI for operating RemotiveCloud and RemotiveBroker
5
5
  Author: Johan Rask
6
6
  Author-email: johan.rask@remotivelabs.com
@@ -1,45 +1,43 @@
1
- cli/__about__.py,sha256=qXVkxWb3aPCF-4MjQhB0wqL2GEblEH4Qwk70o29UkJk,122
2
1
  cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
2
  cli/broker/brokers.py,sha256=oUadEL6xQ4bhXucBH-ZjL67VuERf19kn1g240v_lEpg,3197
4
- cli/broker/export.py,sha256=LBWEu1hS9z4fPuu847numbCJe9ebaXjfHqqhplII4vg,4429
3
+ cli/broker/export.py,sha256=3sG9i6ZwOQW6snu87NSzOL2_giQTYQMzQlpPg7z8n78,4431
5
4
  cli/broker/files.py,sha256=_MVwitQ5Z9-lNDb3biXqnlkKti8rizTEw0nnAViussU,4181
6
5
  cli/broker/lib/__about__.py,sha256=xnZ5V6ZcHW9dhWLWdMzVjYJbEnMKpeXm0_S_mbNzypE,141
7
- cli/broker/lib/broker.py,sha256=7-MA3VJlWwfTGz8R9VYwQ2wmdwCczroDcIqa7rzkpGc,23988
6
+ cli/broker/lib/broker.py,sha256=iBv-uegVD6awnhkukV50CcZywIybEO3qvI0YU47KcGo,23949
8
7
  cli/broker/license_flows.py,sha256=qJplaeugkUiypFGPdEIl5Asqlf7W3geJ-wU-QbYMP_8,7216
9
8
  cli/broker/licenses.py,sha256=Ddl243re8RoeP9CoWWbIzwDePQ9l8r7ixmbd1gqn8f0,3973
10
9
  cli/broker/playback.py,sha256=hdDKXGPuIE3gcT-kgQltgn5jsPzK19Yh9hiNcgtkLX0,3992
11
10
  cli/broker/record.py,sha256=Oa6hUpS0Dgnt0f6Ig33vl0Jy8wN7wMXfemaxXWjRVoQ,1414
12
11
  cli/broker/scripting.py,sha256=8577_C6siOk90s4G1ItIfAoFIUAkS0ItUl5kqR0cD-k,3792
13
- cli/broker/signals.py,sha256=G54RrCUP9vonLouWL7IG0j7YqszVyM5jPr1WKHGZK34,7073
12
+ cli/broker/signals.py,sha256=llok_jUGWOzAiiQUK54uRDnDuonBOAYBDbPdnzCFdog,7075
14
13
  cli/cloud/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- cli/cloud/auth.py,sha256=CgIg_y7oBbRmOHtWEsmUrNrbBDf-Req0R7i_laKt_z8,3907
16
- cli/cloud/auth_tokens.py,sha256=I72Xkai1bR7h938W2jcT7gtW4gtebbtrHpKgQDDs1Eo,4801
17
- cli/cloud/brokers.py,sha256=56MX74axZUhULzXSPnDfiq5uB8bpS1DXWskxOF2_tcQ,3892
14
+ cli/cloud/auth.py,sha256=RBTDUGRBVsK28u-aeqzRIzHnW7FqH4KADlVlQEgBCww,2534
15
+ cli/cloud/auth_tokens.py,sha256=0U60Gk2-TnAUff5anZmTB1rOEninNvYy1o5ihCqgj8A,4525
16
+ cli/cloud/brokers.py,sha256=DNj79MTkPylKUQbr-iPUhQgfNJLAW8UehnvgpEmNH_k,3890
18
17
  cli/cloud/cloud_cli.py,sha256=09YCHs8IivYsVJOsxlM5OMEqBdq3QUXtDsktcO8Kjyw,1263
19
18
  cli/cloud/configs.py,sha256=xg3J-kaS-Pp0p9otV2cWl_oOWJzs_jZhXwFHz0gQxvc,4625
20
- cli/cloud/filestorage.py,sha256=fnzQ6Q95p82LssHfYlYWG50XWwnWwh1GUbvfRCVoq8A,5017
19
+ cli/cloud/filestorage.py,sha256=cCPDYwCyJxP4V_qK1_Gnsg_T-zVsw6QaZdY_l4s4vC0,5445
21
20
  cli/cloud/organisations.py,sha256=txKQmSQEpTmeqlqngai8pwgQQEvRgeDd0dT_VzZ7RNc,752
22
21
  cli/cloud/projects.py,sha256=YrwPJClC2Sq_y1HjPd_tzaiv4GEnnsXSXHBhtQCPdK0,1431
23
22
  cli/cloud/recordings.py,sha256=jnsc39CmIQQ3DUu5Mpe7wrr6aLCK870TRi6TcgGmiY0,24137
24
23
  cli/cloud/recordings_playback.py,sha256=PRzftmvG2iePrL9f6qTEXVOnyJ-etcyzn5w9CCxcSto,11539
25
- cli/cloud/rest_helper.py,sha256=Sky-Lc0YaKbSUdSy3O5AK2FffKAVjAeVMrZLHiUILyU,11294
26
- cli/cloud/resumable_upload.py,sha256=utLiUzYQZFQZ-TaI732HNYqBoVOZQG9h0aNfyKU-5oc,2677
24
+ cli/cloud/rest_helper.py,sha256=8XgqmxoeW8zM0tYWNAn7rABJdvgJFYfy0adOo66kys4,11499
25
+ cli/cloud/resumable_upload.py,sha256=sYThyhseXRniOMbctbO5p4BGVb9b7BXVBcmcZXwnClM,3550
27
26
  cli/cloud/sample_recordings.py,sha256=OVX32U1dkkkJZysbgr5Dy515oOQKnwBAbZYzV_QUu1g,690
28
- cli/cloud/service_account_tokens.py,sha256=bchcyK0tRo-mTF312tZsvlHgNB2Azza_snbT2di1Oqg,2413
27
+ cli/cloud/service_account_tokens.py,sha256=263u1bRmBKfYsxL6TV6YjReUBUaVHWc3ETCd7AS3DTU,2297
29
28
  cli/cloud/service_accounts.py,sha256=XOIPobUamCLIaufjyvb33XJDwy6uRqW5ZljZx3GYEfo,1659
30
29
  cli/connect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
30
  cli/connect/connect.py,sha256=U--6dtHxUlvE81J37rABFez4TbF7AXWOpZYZnL7sPMY,3994
32
- cli/connect/protopie/protopie.py,sha256=5ZVacK2XWfExMR-7x4Hi2aMAjVnmHn6cMsT8pKEUteI,6342
31
+ cli/connect/protopie/protopie.py,sha256=KBMbBwdkUVgV2X7AXTHweVqYVHv4akG875FVc36gsyg,6349
33
32
  cli/errors.py,sha256=CXYArw1W82bRFwJkJ3tD-Ek1huKeah502DGMvPxHYFo,1366
34
- cli/remotive.py,sha256=vJ2WsiuMZs5WSWMk-C29IOTVg8xXt96sUYv2keCsmi4,1826
35
- cli/requirements.txt,sha256=lO6iu07ROwWXOpmiAYGoyXEmIFWrvh3fJeem2Y74QWw,133
36
- cli/settings.py,sha256=MikGisXMNJTGtICBcLhfLZc2_ELCOaZmJspdLNwNRvY,833
33
+ cli/remotive.py,sha256=z834JeOwENyUM4bS74_zE95sGwu1efgfDVtCLKV5rV0,1789
34
+ cli/settings.py,sha256=A5rtp_1oix7Com5aHCAHdwJqxoV2LgxpYXwCe40v7oY,2072
37
35
  cli/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
36
  cli/tools/can/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
37
  cli/tools/can/can.py,sha256=8uATViSFlpkdSiIm4fzbuQi1_m7V9Pym-K17TaJQRHU,2262
40
38
  cli/tools/tools.py,sha256=0KU-hXR1f9xHP4BOG9A9eXfmICLmNuQCOU8ueF6iGg0,198
41
- remotivelabs_cli-0.0.27.dist-info/LICENSE,sha256=qDPP_yfuv1fF-u7EfexN-cN3M8aFgGVndGhGLovLKz0,608
42
- remotivelabs_cli-0.0.27.dist-info/METADATA,sha256=iGsSma4rkwT8WDsIBAuDSQzVCFbjtBJezGEr5X_9nb4,1318
43
- remotivelabs_cli-0.0.27.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
44
- remotivelabs_cli-0.0.27.dist-info/entry_points.txt,sha256=lvDhPgagLqW_KTnLPCwKSqfYlEp-1uYVosRiPjsVj10,45
45
- remotivelabs_cli-0.0.27.dist-info/RECORD,,
39
+ remotivelabs_cli-0.0.29.dist-info/LICENSE,sha256=qDPP_yfuv1fF-u7EfexN-cN3M8aFgGVndGhGLovLKz0,608
40
+ remotivelabs_cli-0.0.29.dist-info/METADATA,sha256=72C3NkomgtEga_Fwr-zzm-N-93nYvflrGr51ulAuh4Q,1318
41
+ remotivelabs_cli-0.0.29.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
42
+ remotivelabs_cli-0.0.29.dist-info/entry_points.txt,sha256=lvDhPgagLqW_KTnLPCwKSqfYlEp-1uYVosRiPjsVj10,45
43
+ remotivelabs_cli-0.0.29.dist-info/RECORD,,
cli/__about__.py DELETED
@@ -1,4 +0,0 @@
1
- # SPDX-FileCopyrightText: 2022-present U.N. Owen <void@some.where>
2
- #
3
- # SPDX-License-Identifier: MIT
4
- __version__ = "0.0.1"
cli/requirements.txt DELETED
@@ -1,12 +0,0 @@
1
- remotivelabs-broker
2
- typer
3
- requests
4
- types-requests
5
- rich
6
- pycom
7
- network
8
- #cryptography
9
- zeroconf
10
- plotext
11
- python-socketio
12
- websocket-client