sima-cli 0.0.16__py3-none-any.whl → 0.0.18__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.
sima_cli/__version__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # sima_cli/__version__.py
2
- __version__ = "0.0.16"
2
+ __version__ = "0.0.18"
@@ -96,12 +96,12 @@ def login_external():
96
96
  session.headers["X-CSRF-Token"] = csrf_token
97
97
 
98
98
  if _is_session_valid(session):
99
- click.echo("🚀 Reusing existing session.")
99
+ click.echo("🚀 You are already logged in.")
100
100
  return session
101
101
 
102
102
  # Prompt user login
103
103
  _delete_auth_files()
104
- click.echo(f"🔐 Login attempt {attempt}/3")
104
+ click.echo(f"🔐 Sima.ai Developer Portal Login Attempt {attempt}/3")
105
105
  username = click.prompt("Email or Username")
106
106
  password = getpass.getpass("Password: ")
107
107
 
sima_cli/auth/login.py CHANGED
@@ -13,10 +13,13 @@ def login(method: str = "external"):
13
13
  Args:
14
14
  method (str): 'external' (public developer portal) or 'internal' (Artifactory).
15
15
  """
16
- if method == "internal":
17
- return login_internal()
18
- else:
19
- return login_external()
16
+ try:
17
+ if method == "internal":
18
+ return login_internal()
19
+ else:
20
+ return login_external()
21
+ except Exception as e:
22
+ print(f'Unable to login: {e}')
20
23
 
21
24
  def login_internal():
22
25
  """
sima_cli/cli.py CHANGED
@@ -6,6 +6,7 @@ from sima_cli.model_zoo.model import list_models, download_model, describe_model
6
6
  from sima_cli.utils.config_loader import internal_resource_exists
7
7
  from sima_cli.mla.meminfo import monitor_simaai_mem_chart
8
8
  from sima_cli.__version__ import __version__
9
+ from sima_cli.utils.config import CONFIG_PATH
9
10
 
10
11
  # Entry point for the CLI tool using Click's command group decorator
11
12
  @click.group()
@@ -20,6 +21,8 @@ def main(ctx, internal):
20
21
  """
21
22
  ctx.ensure_object(dict)
22
23
 
24
+ os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True)
25
+
23
26
  # Allow env override if --internal not explicitly passed
24
27
  if not internal:
25
28
  internal = os.getenv("SIMA_CLI_INTERNAL", "0") in ("1", "true", "yes")
@@ -59,6 +62,37 @@ def version_cmd():
59
62
  """Show the version of the CLI tool."""
60
63
  click.echo(f"SiMa CLI version: {__version__}")
61
64
 
65
+ # ----------------------
66
+ # Logout Command
67
+ # ----------------------
68
+ @main.command(name="logout")
69
+ @click.pass_context
70
+ def logout_cmd(ctx):
71
+ """Log out by deleting cached credentials and config files."""
72
+ sima_cli_dir = os.path.expanduser("~/.sima-cli")
73
+ internal = ctx.obj.get("internal", False)
74
+ deleted_any = False
75
+
76
+ if not os.path.isdir(sima_cli_dir):
77
+ click.echo("⚠️ No ~/.sima-cli directory found.")
78
+ return
79
+
80
+ if internal:
81
+ target_files = ["config.json"]
82
+ else:
83
+ target_files = [".sima-cli-cookies.txt", ".sima-cli-csrf.json"]
84
+
85
+ for filename in target_files:
86
+ full_path = os.path.join(sima_cli_dir, filename)
87
+ if os.path.exists(full_path):
88
+ try:
89
+ os.remove(full_path)
90
+ deleted_any = True
91
+ except Exception as e:
92
+ click.echo(f"⚠️ Failed to delete {full_path}: {e}", err=True)
93
+
94
+ click.echo("✅ Logged out successfully.")
95
+
62
96
  # ----------------------
63
97
  # Download Command
64
98
  # ----------------------
@@ -116,10 +150,6 @@ def update(ctx, version_or_url, ip, yes, passwd):
116
150
  version_or_url: The version string (e.g. '1.5.0') or a direct URL to the firmware package.
117
151
  """
118
152
  internal = ctx.obj.get("internal", False)
119
- if not internal:
120
- click.echo("External environment is not supported yet.")
121
- exit(0)
122
-
123
153
  perform_update(version_or_url, ip, internal, passwd=passwd, auto_confirm=yes)
124
154
 
125
155
  # ----------------------
@@ -6,4 +6,4 @@ auth:
6
6
  validate_url: "artifactory/api/security/encryptedPassword"
7
7
 
8
8
  download:
9
- download_url: "artifactory/"
9
+ download_url: "https://docs.sima.ai/pkg_downloads/"
@@ -4,6 +4,7 @@ from urllib.parse import urlparse
4
4
  from tqdm import tqdm
5
5
  from typing import List
6
6
  from sima_cli.utils.config import get_auth_token
7
+ from sima_cli.auth.basic_auth import login_external
7
8
 
8
9
  def _list_directory_files(url: str, internal: bool = False) -> List[str]:
9
10
  """
@@ -73,12 +74,19 @@ def download_file_from_url(url: str, dest_folder: str = ".", internal: bool = Fa
73
74
  existing_size = 0
74
75
 
75
76
  try:
76
- auth_token = get_auth_token(internal)
77
- if auth_token:
78
- headers["Authorization"] = f"Bearer {auth_token}"
77
+ if internal:
78
+ auth_token = get_auth_token(internal=True)
79
+ if auth_token:
80
+ headers["Authorization"] = f"Bearer {auth_token}"
81
+ request_fn = requests.get
82
+ head_fn = requests.head
83
+ else:
84
+ session = login_external()
85
+ request_fn = session.get
86
+ head_fn = session.head
79
87
 
80
88
  # HEAD request to get total file size
81
- head = requests.head(url, headers=headers, timeout=10)
89
+ head = head_fn(url, headers=headers, timeout=10)
82
90
  head.raise_for_status()
83
91
  total_size = int(head.headers.get('content-length', 0))
84
92
 
@@ -97,8 +105,8 @@ def download_file_from_url(url: str, dest_folder: str = ".", internal: bool = Fa
97
105
  existing_size = 0
98
106
  mode = 'wb'
99
107
 
100
- # Begin download with headers
101
- with requests.get(url, stream=True, headers=headers, timeout=30) as r:
108
+ # Begin download with appropriate handler
109
+ with request_fn(url, stream=True, headers=headers, timeout=30) as r:
102
110
  r.raise_for_status()
103
111
 
104
112
  content_length = int(r.headers.get('content-length', 0))
@@ -119,6 +127,7 @@ def download_file_from_url(url: str, dest_folder: str = ".", internal: bool = Fa
119
127
 
120
128
  except Exception as e:
121
129
  raise RuntimeError(f"Download failed: {e}")
130
+
122
131
 
123
132
  return dest_path
124
133
 
File without changes
@@ -0,0 +1,120 @@
1
+ import json
2
+ import platform
3
+ import psutil
4
+ import shutil
5
+ import subprocess
6
+ import sys
7
+ import re
8
+ try:
9
+ from packaging import version
10
+ except ImportError:
11
+ version = None
12
+
13
+ def load_requirements(file_path='system_requirements.json'):
14
+ try:
15
+ with open(file_path, 'r') as f:
16
+ return json.load(f)
17
+ except FileNotFoundError:
18
+ print(f"Error: Requirements file '{file_path}' not found.")
19
+ sys.exit(1)
20
+ except json.JSONDecodeError:
21
+ print(f"Error: Invalid JSON format in '{file_path}'.")
22
+ sys.exit(1)
23
+
24
+ def check_cpu_cores(required_cores):
25
+ actual_cores = psutil.cpu_count(logical=False)
26
+ return actual_cores >= required_cores, f"CPU Cores: {actual_cores} (Required: {required_cores})"
27
+
28
+ def check_memory(required_memory_gb):
29
+ actual_memory = psutil.virtual_memory().total / (1024 ** 3) # Convert bytes to GB
30
+ return actual_memory >= required_memory_gb, f"Memory: {actual_memory:.2f} GB (Required: {required_memory_gb} GB)"
31
+
32
+ def check_storage(required_storage_gb):
33
+ _, _, free = shutil.disk_usage('/')
34
+ free_gb = free / (1024 ** 3) # Convert bytes to GB
35
+ return free_gb >= required_storage_gb, f"Free Storage: {free_gb:.2f} GB (Required: {required_storage_gb} GB)"
36
+
37
+ def check_os(supported_os):
38
+ current_os = platform.system()
39
+ current_version = platform.version()
40
+ system_name = current_os.lower()
41
+
42
+ if system_name == "linux":
43
+ if "Ubuntu 22.04" in supported_os:
44
+ try:
45
+ with open('/etc/os-release') as f:
46
+ os_info = f.read()
47
+ if "Ubuntu 22.04" in os_info:
48
+ return True, "OS: Ubuntu 22.04 (Supported)"
49
+ except FileNotFoundError:
50
+ pass
51
+ elif system_name == "windows":
52
+ if "10" in current_version and "Windows 10" in supported_os:
53
+ return True, "OS: Windows 10 (Supported)"
54
+ if "11" in current_version and "Windows 11" in supported_os:
55
+ return True, "OS: Windows 11 (Supported)"
56
+
57
+ return False, f"OS: {current_os} {current_version} (Not supported)"
58
+
59
+ def check_docker_version(required_version):
60
+ try:
61
+ result = subprocess.run(['docker', '--version'], capture_output=True, text=True)
62
+ match = re.search(r'(\d+\.\d+\.\d+)', result.stdout)
63
+ if not match:
64
+ return False, "Docker: Could not parse version"
65
+ current_version = match.group(1)
66
+ current_os = platform.system().lower()
67
+ required = required_version.get(current_os, None)
68
+ if required is None:
69
+ return True, f"Docker: {current_version} (No version requirement for {current_os})"
70
+ if version:
71
+ result = version.parse(current_version) >= version.parse(required)
72
+ else:
73
+ current_parts = tuple(map(int, current_version.split('.')))
74
+ required_parts = tuple(map(int, required.split('.')))
75
+ result = current_parts >= required_parts
76
+ return result, f"Docker: {current_version} (Required: {required})"
77
+ except FileNotFoundError:
78
+ return False, "Docker: Not installed"
79
+
80
+ def check_python_version(required_version):
81
+ current_version = platform.python_version()
82
+ if version:
83
+ # Use packaging.version for proper version comparison
84
+ result = version.parse(current_version) >= version.parse(required_version)
85
+ else:
86
+ # Fallback to tuple comparison if packaging is not available
87
+ current_parts = tuple(map(int, current_version.split('.')))
88
+ required_parts = tuple(map(int, required_version.split('.')))
89
+ result = current_parts >= required_parts
90
+ return result, f"Python: {current_version} (Required: {required_version})"
91
+
92
+ def main():
93
+ requirements = load_requirements()
94
+
95
+ checks = [
96
+ check_cpu_cores(requirements['cpu_cores']),
97
+ check_memory(requirements['memory_gb']),
98
+ check_storage(requirements['storage_gb']),
99
+ check_os(requirements['supported_os']),
100
+ check_docker_version(requirements['docker_version']),
101
+ check_python_version(requirements['python_min_version'])
102
+ ]
103
+
104
+ print("System Check Results:")
105
+ print("-" * 50)
106
+ all_passed = True
107
+
108
+ for passed, message in checks:
109
+ status = "✓" if passed else "✗"
110
+ print(f"{status} {message}")
111
+ if not passed:
112
+ all_passed = False
113
+
114
+ print("-" * 50)
115
+ print("System Check: " + ("PASSED" if all_passed else "FAILED"))
116
+ if not all_passed:
117
+ print("Please address the failed requirements.")
118
+
119
+ if __name__ == "__main__":
120
+ main()
sima_cli/update/local.py CHANGED
@@ -46,26 +46,31 @@ def _run_local_cmd(command: str, passwd: str) -> bool:
46
46
 
47
47
  def get_local_board_info() -> Tuple[str, str]:
48
48
  """
49
- Retrieve the local board type and build version by reading /etc/build.
49
+ Retrieve the local board type and build version by reading /etc/build or /etc/buildinfo.
50
50
 
51
51
  Returns:
52
52
  (board_type, build_version): Tuple of strings, or ('', '') on failure.
53
53
  """
54
54
  board_type = ""
55
55
  build_version = ""
56
- build_file_path = "/etc/build"
57
-
58
- try:
59
- with open(build_file_path, "r") as f:
60
- for line in f:
61
- line = line.strip()
62
- if line.startswith("MACHINE"):
63
- board_type = line.split("=")[-1].strip()
64
- elif line.startswith("SIMA_BUILD_VERSION"):
65
- build_version = line.split("=")[-1].strip()
66
- return board_type, build_version
67
- except Exception:
68
- return "", ""
56
+ build_file_paths = ["/etc/build", "/etc/buildinfo"]
57
+
58
+ for path in build_file_paths:
59
+ try:
60
+ if os.path.isfile(path):
61
+ with open(path, "r") as f:
62
+ for line in f:
63
+ line = line.strip()
64
+ if line.startswith("MACHINE"):
65
+ board_type = line.split("=", 1)[-1].strip()
66
+ elif line.startswith("SIMA_BUILD_VERSION"):
67
+ build_version = line.split("=", 1)[-1].strip()
68
+ if board_type or build_version:
69
+ break # Exit early if data found
70
+ except Exception:
71
+ continue
72
+
73
+ return board_type, build_version
69
74
 
70
75
 
71
76
  def push_and_update_local_board(troot_path: str, palette_path: str, passwd: str):
sima_cli/update/query.py CHANGED
@@ -1,3 +1,4 @@
1
+ import re
1
2
  import requests
2
3
  from sima_cli.utils.config_loader import load_resource_config, artifactory_url
3
4
  from sima_cli.utils.config import get_auth_token
@@ -45,6 +46,34 @@ def _list_available_firmware_versions_internal(board: str, match_keyword: str =
45
46
 
46
47
  return top_level_folders
47
48
 
49
+ def _list_available_firmware_versions_external(board: str, match_keyword: str = None):
50
+ """
51
+ Construct and return a list containing a single firmware download URL for a given board.
52
+
53
+ If match_keyword is provided and matches a 'major.minor' version pattern (e.g., '1.6'),
54
+ it is normalized to 'major.minor.patch' format (e.g., '1.6.0') to ensure consistent URL construction.
55
+
56
+ Args:
57
+ board (str): The name of the hardware board.
58
+ match_keyword (str, optional): A version string to match (e.g., '1.6' or '1.6.0').
59
+
60
+ Returns:
61
+ list[str]: A list containing one formatted firmware download URL.
62
+ """
63
+ fwtype = 'yocto'
64
+ cfg = load_resource_config()
65
+ download_url_base = cfg.get('public').get('download').get('download_url')
66
+
67
+ if match_keyword:
68
+ if re.fullmatch(r'\d+\.\d+', match_keyword):
69
+ match_keyword += '.0'
70
+
71
+ firmware_download_url = (
72
+ f'{download_url_base}SDK{match_keyword}/devkit/{board}/{fwtype}/'
73
+ f'simaai-devkit-fw-{board}-{fwtype}-{match_keyword}.tar.gz'
74
+ )
75
+ return [firmware_download_url]
76
+
48
77
 
49
78
  def list_available_firmware_versions(board: str, match_keyword: str = None, internal: bool = False):
50
79
  """
@@ -59,6 +88,6 @@ def list_available_firmware_versions(board: str, match_keyword: str = None, inte
59
88
  - List[str] of firmware version folder names, or None if access is not allowed
60
89
  """
61
90
  if not internal:
62
- raise PermissionError("Internal access required to list firmware versions.")
91
+ return _list_available_firmware_versions_external(board, match_keyword)
63
92
 
64
93
  return _list_available_firmware_versions_internal(board, match_keyword)
sima_cli/update/remote.py CHANGED
@@ -57,7 +57,6 @@ def get_remote_board_info(ip: str, passwd: str = DEFAULT_PASSWORD) -> Tuple[str,
57
57
 
58
58
  Args:
59
59
  ip (str): IP address of the board.
60
- timeout (int): SSH timeout in seconds.
61
60
 
62
61
  Returns:
63
62
  (board_type, build_version): Tuple of strings, or ('', '') on failure.
@@ -70,16 +69,17 @@ def get_remote_board_info(ip: str, passwd: str = DEFAULT_PASSWORD) -> Tuple[str,
70
69
  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
71
70
  ssh.connect(ip, username=DEFAULT_USER, password=passwd, timeout=10)
72
71
 
73
- stdin, stdout, stderr = ssh.exec_command("cat /etc/build")
72
+ # Try /etc/build first then /etc/buildinfo
73
+ stdin, stdout, stderr = ssh.exec_command("cat /etc/build 2>/dev/null || cat /etc/buildinfo 2>/dev/null")
74
74
  output = stdout.read().decode()
75
75
  ssh.close()
76
76
 
77
77
  for line in output.splitlines():
78
78
  line = line.strip()
79
79
  if line.startswith("MACHINE"):
80
- board_type = line.split("=")[-1].strip()
80
+ board_type = line.split("=", 1)[-1].strip()
81
81
  elif line.startswith("SIMA_BUILD_VERSION"):
82
- build_version = line.split("=")[-1].strip()
82
+ build_version = line.split("=", 1)[-1].strip()
83
83
 
84
84
  return board_type, build_version
85
85
 
@@ -124,7 +124,7 @@ def _run_remote_command(ssh, command: str, password: str = DEFAULT_PASSWORD):
124
124
  if stdout.channel.recv_ready():
125
125
  output = stdout.channel.recv(4096).decode("utf-8", errors="replace")
126
126
  for line in output.splitlines():
127
- click.echo(f"📄 {line}")
127
+ click.echo(f" {line}")
128
128
  if stdout.channel.recv_stderr_ready():
129
129
  err_output = stdout.channel.recv_stderr(4096).decode("utf-8", errors="replace")
130
130
  for line in err_output.splitlines():
@@ -133,7 +133,7 @@ def _run_remote_command(ssh, command: str, password: str = DEFAULT_PASSWORD):
133
133
  # Final remaining output
134
134
  remaining = stdout.read().decode("utf-8", errors="replace")
135
135
  for line in remaining.splitlines():
136
- click.echo(f"📄 {line}")
136
+ click.echo(f" {line}")
137
137
 
138
138
  remaining_err = stderr.read().decode("utf-8", errors="replace")
139
139
  for line in remaining_err.splitlines():
@@ -180,9 +180,13 @@ def push_and_update_remote_board(ip: str, troot_path: str, palette_path: str, pa
180
180
  ssh,
181
181
  f"sudo swupdate -H simaai-image-troot:1.0 -i /tmp/{troot_name}", password=passwd
182
182
  )
183
- click.echo("✅ tRoot update complete.")
183
+ click.echo("✅ tRoot update complete, the board needs to be rebooted to proceed to the next phase of update.")
184
+ click.confirm("⚠️ Have you rebooted the board?", default=True, abort=True)
185
+ _wait_for_ssh(ip, timeout=120)
184
186
 
185
187
  # Upload Palette image
188
+ ssh.connect(ip, username=DEFAULT_USER, password=passwd, timeout=10)
189
+ sftp = ssh.open_sftp()
186
190
  _scp_file(sftp, palette_path, os.path.join(remote_dir, palette_name))
187
191
  click.echo("🚀 Uploaded system image.")
188
192
 
@@ -205,7 +209,7 @@ def push_and_update_remote_board(ip: str, troot_path: str, palette_path: str, pa
205
209
  _run_remote_command(ssh, "sudo bash -c 'echo b > /proc/sysrq-trigger'", password=passwd)
206
210
 
207
211
  except Exception as reboot_err:
208
- click.echo(f"⚠️ SSH connection lost due to reboot (expected): {reboot_err}, please powercycle the device...")
212
+ click.echo(f"⚠️ SSH connection lost due to reboot (expected): {reboot_err}, please powercycle the board...")
209
213
 
210
214
  try:
211
215
  ssh.close()
@@ -219,11 +223,12 @@ def push_and_update_remote_board(ip: str, troot_path: str, palette_path: str, pa
219
223
  # Reconnect and verify version
220
224
  try:
221
225
  click.echo("🔍 Reconnecting to verify build version...")
226
+ time.sleep(10)
222
227
  ssh = paramiko.SSHClient()
223
228
  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
224
229
  ssh.connect(ip, username=DEFAULT_USER, password=passwd, timeout=10)
225
230
 
226
- _run_remote_command(ssh, "cat /etc/build | grep SIMA_BUILD_VERSION", password=passwd)
231
+ _run_remote_command(ssh, "grep SIMA_BUILD_VERSION /etc/build 2>/dev/null || grep SIMA_BUILD_VERSION /etc/buildinfo 2>/dev/null", password=passwd)
227
232
  ssh.close()
228
233
  except Exception as e:
229
234
  click.echo(f"❌ Unable to validate the version: {e}")
@@ -54,7 +54,7 @@ def _pick_from_available_versions(board: str, version_or_url: str, internal: boo
54
54
  if "http" in version_or_url:
55
55
  return version_or_url
56
56
 
57
- available_versions = list_available_firmware_versions(board, version_or_url, internal=True)
57
+ available_versions = list_available_firmware_versions(board, version_or_url, internal)
58
58
 
59
59
  if len(available_versions) > 1:
60
60
  click.echo("Multiple firmware versions found matching your input:")
@@ -202,6 +202,7 @@ def _download_image(version_or_url: str, board: str, internal: bool = False):
202
202
 
203
203
  except Exception as e:
204
204
  click.echo(f"❌ Host update failed: {e}")
205
+ exit(0)
205
206
 
206
207
  def _update_host(script_path: str, board: str, boardip: str, passwd: str):
207
208
  """
@@ -252,6 +253,7 @@ def _update_host(script_path: str, board: str, boardip: str, passwd: str):
252
253
 
253
254
  except Exception as e:
254
255
  click.echo(f"❌ Host update failed: {e}")
256
+ exit(0)
255
257
 
256
258
 
257
259
  def _update_sdk(version_or_url: str, board: str):
@@ -356,7 +358,7 @@ def perform_update(version_or_url: str, ip: str = None, internal: bool = False,
356
358
  if board in ['davinci', 'modalix']:
357
359
  click.echo(f"🔧 Target board: {board}, board currently running: {version}")
358
360
 
359
- if 'http' not in version_or_url:
361
+ if 'http' not in version_or_url and not os.path.exists(version_or_url):
360
362
  version_or_url = _pick_from_available_versions(board, version_or_url, internal)
361
363
 
362
364
  extracted_paths = _download_image(version_or_url, board, internal)
sima_cli/utils/env.py CHANGED
@@ -11,23 +11,26 @@ def is_sima_board() -> bool:
11
11
  """
12
12
  Detect if running on a SiMa board.
13
13
 
14
- This is done by checking for the existence of a known build info file
15
- located at /etc/build and looking for specific identifiers like
14
+ This is done by checking for the existence of known build info files
15
+ (/etc/build or /etc/buildinfo) and looking for specific identifiers like
16
16
  SIMA_BUILD_VERSION and MACHINE.
17
17
 
18
18
  Returns:
19
19
  bool: True if running on a SiMa board, False otherwise.
20
20
  """
21
- build_file_path = "/etc/build"
22
- if not os.path.exists(build_file_path):
23
- return False
21
+ build_file_paths = ["/etc/build", "/etc/buildinfo"]
24
22
 
25
- try:
26
- with open(build_file_path, "r") as f:
27
- content = f.read()
28
- return "SIMA_BUILD_VERSION" in content and "MACHINE" in content
29
- except Exception:
30
- return False
23
+ for path in build_file_paths:
24
+ if os.path.exists(path):
25
+ try:
26
+ with open(path, "r") as f:
27
+ content = f.read()
28
+ if "SIMA_BUILD_VERSION" in content and "MACHINE" in content:
29
+ return True
30
+ except Exception:
31
+ continue
32
+
33
+ return False
31
34
 
32
35
  def is_pcie_host() -> bool:
33
36
  """
@@ -44,25 +47,27 @@ def is_pcie_host() -> bool:
44
47
 
45
48
  def get_sima_board_type() -> str:
46
49
  """
47
- If running on a SiMa board, extract the board type from the MACHINE field in /etc/build.
50
+ If running on a SiMa board, extract the board type from the MACHINE field
51
+ in /etc/build or /etc/buildinfo.
48
52
 
49
53
  Returns:
50
54
  str: The board type (e.g., "modalix", "davinci"), or an empty string if not found or not a SiMa board.
51
55
  """
52
- build_file_path = "/etc/build"
53
- if not os.path.exists(build_file_path):
54
- return ""
55
-
56
- try:
57
- with open(build_file_path, "r") as f:
58
- for line in f:
59
- if line.startswith("MACHINE"):
60
- # Format: MACHINE = modalix
61
- parts = line.split("=")
62
- if len(parts) == 2:
63
- return parts[1].strip()
64
- except Exception:
65
- pass
56
+ build_file_paths = ["/etc/build", "/etc/buildinfo"]
57
+
58
+ for path in build_file_paths:
59
+ if os.path.exists(path):
60
+ try:
61
+ with open(path, "r") as f:
62
+ for line in f:
63
+ line = line.strip()
64
+ if line.startswith("MACHINE"):
65
+ # Format: MACHINE = modalix
66
+ parts = line.split("=", 1)
67
+ if len(parts) == 2:
68
+ return parts[1].strip()
69
+ except Exception:
70
+ continue
66
71
 
67
72
  return ""
68
73
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sima-cli
3
- Version: 0.0.16
3
+ Version: 0.0.18
4
4
  Summary: CLI tool for SiMa Developer Portal to download models, firmware, and apps.
5
5
  Home-page: https://developer.sima.ai/
6
6
  Author: SiMa.ai
@@ -1,31 +1,33 @@
1
1
  sima_cli/__init__.py,sha256=Nb2jSg9-CX1XvSc1c21U9qQ3atINxphuNkNfmR-9P3o,332
2
2
  sima_cli/__main__.py,sha256=ehzD6AZ7zGytC2gLSvaJatxeD0jJdaEvNJvwYeGsWOg,69
3
- sima_cli/__version__.py,sha256=vAhp43Edr6wuTaEENyL0LyBoxrulPSTR3yIbNNY1qQQ,49
4
- sima_cli/cli.py,sha256=E-zFtDbArh5o3hHsgB7hxyqE-f3brZ9xyGI-aP_s3IA,7290
3
+ sima_cli/__version__.py,sha256=8-9gPM1y6DdoYBg3txOjyT5ldXc4k9e8BvBxlen4c6g,49
4
+ sima_cli/cli.py,sha256=EZkY0FaGLc2krp5Rf0AuUT8t3qktoE5h9vIY8-wkHKk,8263
5
5
  sima_cli/app_zoo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  sima_cli/app_zoo/app.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  sima_cli/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- sima_cli/auth/basic_auth.py,sha256=xS_EC0iYyozDSrZEoz44lU5dLBk6covxiCv09WiQECw,4264
9
- sima_cli/auth/login.py,sha256=Tpe5ZRau4QrlQ6Zxg1rBco4qZ2nr4rkfZAohiTPBbVk,3687
8
+ sima_cli/auth/basic_auth.py,sha256=pcocI6v496vC7v5MLYPZq3AEgD-2DdkzNFZiKsbx3eQ,4290
9
+ sima_cli/auth/login.py,sha256=e9wBEeo_60qplODHBeK84R7zusT3K07kdFoZC1mkSrQ,3778
10
10
  sima_cli/data/resources_internal.yaml,sha256=zlQD4cSnZK86bLtTWuvEudZTARKiuIKmB--Jv4ajL8o,200
11
- sima_cli/data/resources_public.yaml,sha256=ZT1CzPrGMfSLVWiRJfW2-jb-ilmh7yNlkqyO5Fvqk58,178
11
+ sima_cli/data/resources_public.yaml,sha256=U7hmUomGeQ2ULdo1BU2OQHr0PyKBamIdK9qrutDlX8o,201
12
12
  sima_cli/download/__init__.py,sha256=6y4O2FOCYFR2jdnQoVi3hRtEoZ0Gw6rydlTy1SGJ5FE,218
13
- sima_cli/download/downloader.py,sha256=zL8daM7Fqj1evzfQ9EHL1CVbuYL0_aQNhromqm7LkE0,4863
13
+ sima_cli/download/downloader.py,sha256=pHfqcg_ujBQjds_EkcRV85M2mRYGrysoZaiR-FIrpf4,5161
14
14
  sima_cli/mla/meminfo.py,sha256=ndc8kQJmWGEIdvNh6iIhATGdrkqM2pbddr_eHxaPNfg,1466
15
15
  sima_cli/model_zoo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  sima_cli/model_zoo/model.py,sha256=q91Nrg62j1TqwPO8HiX4nlEFCCmzNEFcyFTBVMbJm8w,9836
17
+ sima_cli/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ sima_cli/sdk/syscheck.py,sha256=h9zCULW67y4i2hqiGc-hc1ucBDShA5FAe9NxwBGq-fM,4575
17
19
  sima_cli/update/__init__.py,sha256=0P-z-rSaev40IhfJXytK3AFWv2_sdQU4Ry6ei2sEus0,66
18
- sima_cli/update/local.py,sha256=jiGrwuU2Z1HV_RT1_dYuI_Ish-f818AvCEk7sAM3l94,3032
19
- sima_cli/update/query.py,sha256=eOTC2ZAWbFFf_0h8D-MO1HrIsQYRc7fu5OyeFNEAv48,2168
20
- sima_cli/update/remote.py,sha256=ePlnvlGHrASMMjYGM9w-6hMeDMgGiJu_BlHLamU1YtI,8420
21
- sima_cli/update/updater.py,sha256=8NcXl_bWcjOo3ucl7WgShSLTbTga8cWpxJeUR5tnj2E,15546
20
+ sima_cli/update/local.py,sha256=CyUFLs5Lz5w4VyM6ip4wndKBBLz3_KZ-3scEvSiOrcg,3299
21
+ sima_cli/update/query.py,sha256=cVkUMLZkONJ2XMEwqEC-JqLVB38hOqfWM2hB2ehBK6Y,3272
22
+ sima_cli/update/remote.py,sha256=wMS39qhXV99fjkeh_0C5dDx1RdE8ooGniEHl_W6v3MA,8877
23
+ sima_cli/update/updater.py,sha256=8CxRcIRnCYRx80Xy2zBJ_Ni5dYejASQvgSV6KWXCDTk,15613
22
24
  sima_cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
25
  sima_cli/utils/artifactory.py,sha256=6YyVpzVm8ATy7NEwT9nkWx-wptkXrvG7Wl_zDT6jmLs,2390
24
26
  sima_cli/utils/config.py,sha256=wE-cPQqY_gOqaP8t01xsRHD9tBUGk9MgBUm2GYYxI3E,1616
25
27
  sima_cli/utils/config_loader.py,sha256=7I5we1yiCai18j9R9jvhfUzAmT3OjAqVK35XSLuUw8c,2005
26
- sima_cli/utils/env.py,sha256=LJy2eO8cfEYsLuC7p3BT_FAoaZc9emtq6NYhHRBpiBE,5512
28
+ sima_cli/utils/env.py,sha256=INOAVfCFwh0BHeqSMmEHXfpIyepNha4-SMI1iOOplOo,5795
27
29
  sima_cli/utils/network.py,sha256=UvqxbqbWUczGFyO-t1SybG7Q-x9kjUVRNIn_D6APzy8,1252
28
- sima_cli-0.0.16.dist-info/licenses/LICENSE,sha256=a260OFuV4SsMZ6sQCkoYbtws_4o2deFtbnT9kg7Rfd4,1082
30
+ sima_cli-0.0.18.dist-info/licenses/LICENSE,sha256=a260OFuV4SsMZ6sQCkoYbtws_4o2deFtbnT9kg7Rfd4,1082
29
31
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
32
  tests/test_app_zoo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
33
  tests/test_auth.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -34,8 +36,8 @@ tests/test_download.py,sha256=t87DwxlHs26_ws9rpcHGwr_OrcRPd3hz6Zmm0vRee2U,4465
34
36
  tests/test_firmware.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
37
  tests/test_model_zoo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
38
  tests/test_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- sima_cli-0.0.16.dist-info/METADATA,sha256=fiQixUEICboG26ibwugfpvz3qsU3FsCV8rTueKA3s4g,3631
38
- sima_cli-0.0.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
- sima_cli-0.0.16.dist-info/entry_points.txt,sha256=xRYrDq1nCs6R8wEdB3c1kKuimxEjWJkHuCzArQPT0Xk,47
40
- sima_cli-0.0.16.dist-info/top_level.txt,sha256=FtrbAUdHNohtEPteOblArxQNwoX9_t8qJQd59fagDlc,15
41
- sima_cli-0.0.16.dist-info/RECORD,,
39
+ sima_cli-0.0.18.dist-info/METADATA,sha256=8o5Si6o1A3Nja7M4V3mTfY97TiEY12U7z-mCrQOpf-Q,3631
40
+ sima_cli-0.0.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
41
+ sima_cli-0.0.18.dist-info/entry_points.txt,sha256=xRYrDq1nCs6R8wEdB3c1kKuimxEjWJkHuCzArQPT0Xk,47
42
+ sima_cli-0.0.18.dist-info/top_level.txt,sha256=FtrbAUdHNohtEPteOblArxQNwoX9_t8qJQd59fagDlc,15
43
+ sima_cli-0.0.18.dist-info/RECORD,,