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 +1 -1
- sima_cli/auth/basic_auth.py +2 -2
- sima_cli/auth/login.py +7 -4
- sima_cli/cli.py +34 -4
- sima_cli/data/resources_public.yaml +1 -1
- sima_cli/download/downloader.py +15 -6
- sima_cli/sdk/__init__.py +0 -0
- sima_cli/sdk/syscheck.py +120 -0
- sima_cli/update/local.py +19 -14
- sima_cli/update/query.py +30 -1
- sima_cli/update/remote.py +14 -9
- sima_cli/update/updater.py +4 -2
- sima_cli/utils/env.py +31 -26
- {sima_cli-0.0.16.dist-info → sima_cli-0.0.18.dist-info}/METADATA +1 -1
- {sima_cli-0.0.16.dist-info → sima_cli-0.0.18.dist-info}/RECORD +19 -17
- {sima_cli-0.0.16.dist-info → sima_cli-0.0.18.dist-info}/WHEEL +0 -0
- {sima_cli-0.0.16.dist-info → sima_cli-0.0.18.dist-info}/entry_points.txt +0 -0
- {sima_cli-0.0.16.dist-info → sima_cli-0.0.18.dist-info}/licenses/LICENSE +0 -0
- {sima_cli-0.0.16.dist-info → sima_cli-0.0.18.dist-info}/top_level.txt +0 -0
sima_cli/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# sima_cli/__version__.py
|
2
|
-
__version__ = "0.0.
|
2
|
+
__version__ = "0.0.18"
|
sima_cli/auth/basic_auth.py
CHANGED
@@ -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("🚀
|
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
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
# ----------------------
|
sima_cli/download/downloader.py
CHANGED
@@ -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
|
-
|
77
|
-
|
78
|
-
|
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 =
|
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
|
101
|
-
with
|
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
|
|
sima_cli/sdk/__init__.py
ADDED
File without changes
|
sima_cli/sdk/syscheck.py
ADDED
@@ -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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
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
|
-
|
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"
|
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"
|
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
|
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, "
|
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}")
|
sima_cli/update/updater.py
CHANGED
@@ -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
|
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
|
15
|
-
|
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
|
-
|
22
|
-
if not os.path.exists(build_file_path):
|
23
|
-
return False
|
21
|
+
build_file_paths = ["/etc/build", "/etc/buildinfo"]
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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,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=
|
4
|
-
sima_cli/cli.py,sha256=
|
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=
|
9
|
-
sima_cli/auth/login.py,sha256=
|
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=
|
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=
|
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=
|
19
|
-
sima_cli/update/query.py,sha256=
|
20
|
-
sima_cli/update/remote.py,sha256=
|
21
|
-
sima_cli/update/updater.py,sha256=
|
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=
|
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.
|
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.
|
38
|
-
sima_cli-0.0.
|
39
|
-
sima_cli-0.0.
|
40
|
-
sima_cli-0.0.
|
41
|
-
sima_cli-0.0.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|