sima-cli 0.0.25__py3-none-any.whl → 0.0.27__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.25"
2
+ __version__ = "0.0.27"
sima_cli/cli.py CHANGED
@@ -149,7 +149,7 @@ def download(ctx, url, dest):
149
149
  default='edgeai',
150
150
  help="Optional SSH password for remote board (default is 'edgeai')."
151
151
  )
152
- @click.option("-f", "--flavor", type=click.Choice(["headless", "full"], case_sensitive=False), default="headless", show_default=True, help="firmware flavor.")
152
+ @click.option("-f", "--flavor", type=click.Choice(["headless", "full"], case_sensitive=False), default="headless", show_default=True, help="firmware flavor, full image supports NVMe, GUI on Modalix DevKit.")
153
153
  @click.pass_context
154
154
  def update(ctx, version_or_url, ip, yes, passwd, flavor):
155
155
  """
@@ -7,6 +7,7 @@ import sys
7
7
  import shutil
8
8
  import tarfile
9
9
  import zipfile
10
+ import stat
10
11
  from urllib.parse import urlparse
11
12
 
12
13
  from typing import Dict
@@ -205,31 +206,68 @@ def _extract_tar_streaming(tar_path: Path, extract_dir: Path):
205
206
 
206
207
  print(f"✅ Extracted {extracted_files} files to {extract_dir}/")
207
208
 
208
- def _extract_zip_streaming(zip_path: Path, extract_dir: Path):
209
+ def _extract_zip_streaming(zip_path: Path, extract_dir: Path, overwrite: bool = True):
209
210
  """
210
- Extract a .zip file using streaming to avoid NFS slowness from metadata calls,
211
- and flatten one top-level directory if present.
211
+ Extract a .zip file using streaming and flatten one top-level directory if present.
212
+ - Handles directory entries correctly
213
+ - Preserves unix perms when available
214
+ - Zip-slip safe
212
215
  """
213
- with zipfile.ZipFile(zip_path, "r") as zipf:
214
- members = zipf.infolist()
216
+ def strip_top_level(p: str) -> Path:
217
+ parts = Path(p).parts
218
+ if not parts:
219
+ return Path()
220
+ return Path(*parts[1:]) if len(parts) > 1 else Path(parts[0])
221
+
222
+ extract_dir.mkdir(parents=True, exist_ok=True)
223
+
224
+ with zipfile.ZipFile(zip_path, "r") as zf:
225
+ members = zf.infolist()
215
226
  with tqdm(total=len(members), desc=f"📦 Extracting {zip_path.name}", unit="file") as pbar:
216
- for member in members:
217
- # Strip one top-level directory if it exists
218
- parts = Path(member.filename).parts
219
- if len(parts) > 1:
220
- stripped_path = Path(*parts[1:])
221
- else:
222
- stripped_path = Path(parts[-1])
227
+ for info in members:
228
+ # Compute flattened path
229
+ stripped = strip_top_level(info.filename)
230
+
231
+ # Some zips can have '' or '.' entries; skip them
232
+ if str(stripped).strip() in {"", ".", "./"}:
233
+ pbar.update(1)
234
+ continue
235
+
236
+ target = (extract_dir / stripped).resolve()
223
237
 
224
- target_path = extract_dir / stripped_path
225
- target_path.parent.mkdir(parents=True, exist_ok=True)
238
+ # Zip-slip guard: ensure target stays under extract_dir
239
+ if not str(target).startswith(str(extract_dir.resolve()) + os.sep):
240
+ pbar.update(1)
241
+ continue # or raise RuntimeError("Unsafe zip path detected")
226
242
 
227
- with zipf.open(member) as src, open(target_path, "wb") as dst:
243
+ if info.is_dir():
244
+ target.mkdir(parents=True, exist_ok=True)
245
+ pbar.update(1)
246
+ continue
247
+
248
+ # Ensure parent exists
249
+ target.parent.mkdir(parents=True, exist_ok=True)
250
+
251
+ # Skip if exists and not overwriting
252
+ if target.exists() and not overwrite:
253
+ pbar.update(1)
254
+ continue
255
+
256
+ # Stream copy the file
257
+ with zf.open(info) as src, open(target, "wb") as dst:
228
258
  shutil.copyfileobj(src, dst)
229
259
 
260
+ # Preserve unix permissions if present
261
+ perms = info.external_attr >> 16
262
+ if perms and not stat.S_ISDIR(perms):
263
+ try:
264
+ os.chmod(target, perms)
265
+ except Exception:
266
+ pass
267
+
230
268
  pbar.update(1)
231
269
 
232
- print(f"✅ Extracted {len(members)} files to {extract_dir}/")
270
+ print(f"✅ Extracted {len(members)} entries to {extract_dir}/")
233
271
 
234
272
  def _combine_multipart_files(folder: str):
235
273
  """
sima_cli/serial/serial.py CHANGED
@@ -2,6 +2,7 @@ import platform
2
2
  import subprocess
3
3
  import shutil
4
4
  import click
5
+ import os
5
6
  from sima_cli.utils.env import is_sima_board
6
7
 
7
8
  def connect_serial(ctx, baud):
@@ -74,11 +75,41 @@ def _connect_linux(baud):
74
75
  if not shutil.which(terminal):
75
76
  click.echo("⚙️ 'picocom' is not installed. Attempting to install via apt...")
76
77
  if shutil.which("apt-get"):
77
- subprocess.run(["sudo", "apt-get", "update"], check=True)
78
- subprocess.run(["sudo", "apt-get", "install", "-y", "picocom"], check=True)
78
+ try:
79
+ subprocess.run(["sudo", "apt-get", "update"], check=True)
80
+ subprocess.run(["sudo", "apt-get", "install", "-y", "picocom"], check=True)
81
+ except subprocess.CalledProcessError:
82
+ click.echo("❌ Failed to install picocom (possibly due to lack of sudo privileges). Checking for minicom...")
83
+ terminal = "minicom"
84
+ if not shutil.which(terminal):
85
+ click.echo("❌ Neither 'picocom' nor 'minicom' is available. Please request the admin to install one manually.")
86
+ raise SystemExit(1)
87
+ # Create minicom config file to match working settings
88
+ config_file = os.path.expanduser("~/.minirc.custom")
89
+ with open(config_file, "w") as f:
90
+ f.write("pu port /dev/ttyUSB0\n")
91
+ f.write(f"pu baudrate {baud}\n")
92
+ f.write("pu bits 8\n")
93
+ f.write("pu parity N\n")
94
+ f.write("pu stopbits 1\n")
95
+ f.write("pu rtscts No\n")
96
+ f.write("pu xonxoff No\n")
79
97
  else:
80
- click.echo("❌ 'apt-get' not found. Please install picocom manually.")
81
- raise SystemExit(1)
98
+ click.echo("❌ 'apt-get' not found. Checking for minicom...")
99
+ terminal = "minicom"
100
+ if not shutil.which(terminal):
101
+ click.echo("❌ Neither 'picocom' nor 'minicom' is available. Please request the admin to install one manually.")
102
+ raise SystemExit(1)
103
+ # Create minicom config file to match working settings
104
+ config_file = os.path.expanduser("~/.minirc.custom")
105
+ with open(config_file, "w") as f:
106
+ f.write("pu port /dev/ttyUSB0\n")
107
+ f.write(f"pu baudrate {baud}\n")
108
+ f.write("pu bits 8\n")
109
+ f.write("pu parity N\n")
110
+ f.write("pu stopbits 1\n")
111
+ f.write("pu rtscts No\n")
112
+ f.write("pu xonxoff No\n")
82
113
 
83
114
  ports = sorted(
84
115
  subprocess.getoutput("ls /dev/ttyUSB* 2>/dev/null").splitlines()
@@ -88,11 +119,19 @@ def _connect_linux(baud):
88
119
  raise SystemExit(1)
89
120
 
90
121
  port = ports[0]
91
- click.echo(f"🔌 Connecting to {port} with picocom ({baud} 8N1)...")
122
+ click.echo(f"🔌 Connecting to {port} with {terminal} ({baud} 8N1)...")
92
123
  try:
93
- subprocess.run(
94
- ["sudo", terminal, "-b", f"{baud}", "--databits", "8", "--parity", "n", "--stopbits", "1", port]
95
- )
124
+ if terminal == "picocom":
125
+ click.echo("🧷 To exit: Press Ctrl + A, then Ctrl + X")
126
+ subprocess.run(
127
+ ["sudo", terminal, "-b", f"{baud}", "--databits", "8", "--parity", "n", "--stopbits", "1", port]
128
+ )
129
+ else: # minicom
130
+ config_file = os.path.expanduser("~/.minirc.custom")
131
+ click.echo("🧷 To exit: Press Ctrl + A, then Q")
132
+ subprocess.run(
133
+ ["sudo", terminal, "-C", config_file, "-D", port]
134
+ )
96
135
  except KeyboardInterrupt:
97
136
  click.echo("\n❎ Serial connection interrupted by user.")
98
137
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sima-cli
3
- Version: 0.0.25
3
+ Version: 0.0.27
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,7 +1,7 @@
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=R5i7Gn8i8_CnLil8QLKcejGs0ESjVKw6151FmEBxzqU,49
4
- sima_cli/cli.py,sha256=3tTXP7n9891OL5Rz-ytMdftBTqhhJg2VA-riWRA6Kfo,17077
3
+ sima_cli/__version__.py,sha256=gxBLTfuQW1ckn_VwGnJeXR1eVJD4qo__oTN9DM-b2n8,49
4
+ sima_cli/cli.py,sha256=GYmQ7_XObl9VgFwuWWkWDo-_Y_Vn6lM53F7mKiYGubI,17126
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
@@ -14,7 +14,7 @@ sima_cli/download/downloader.py,sha256=nCBrr_0WdnKTIyecwKpg1sCdfm_4PSQTRPwEbiezy
14
14
  sima_cli/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  sima_cli/install/hostdriver.py,sha256=kAWDLebs60mbWIyTbUxmNrChcKW1uD5r7FtWNSUVUE4,5852
16
16
  sima_cli/install/metadata_info.py,sha256=wmMqwzGfXbuilkqaxRVrFOzOtTOiONkmPCyA2oDAQpA,2168
17
- sima_cli/install/metadata_installer.py,sha256=vC7FamvGnE-WbI2AC3PAjJmMkP33IUW8D8ZzKrePPzs,16615
17
+ sima_cli/install/metadata_installer.py,sha256=itAvglQO4ZAJBGB2nBuyYJdsMb41gN183MaBEDgU2_Y,17935
18
18
  sima_cli/install/metadata_validator.py,sha256=7954rp9vFRNnqmIMvCVTjq40kUIEbGXzfc8HmQmChe0,5221
19
19
  sima_cli/install/optiview.py,sha256=i5eWVor-9MScEfrQm3Ty9OP4VpSsCgWvNh7AvYdZu7s,3365
20
20
  sima_cli/install/palette.py,sha256=uRznoHa4Mv9ZXHp6AoqknfC3RxpYNKi9Ins756Cyifk,3930
@@ -25,7 +25,7 @@ sima_cli/network/network.py,sha256=ToDCQBfX0bUFEWWtfS8srImK5T11MX6R4MBQFM80faY,7
25
25
  sima_cli/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  sima_cli/sdk/syscheck.py,sha256=h9zCULW67y4i2hqiGc-hc1ucBDShA5FAe9NxwBGq-fM,4575
27
27
  sima_cli/serial/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- sima_cli/serial/serial.py,sha256=6xRta_PzE_DmmooYq35lbK76TYpAny5SEJAdYC_3fH0,4141
28
+ sima_cli/serial/serial.py,sha256=1We85F9-l1FZcsLFxRzxbfPxAHeSCVlBOUyOUpqNf_s,6202
29
29
  sima_cli/storage/nvme.py,sha256=cCzYWcyPwcFu5pSMBkovsS4EwovaIMGolhEFStogXMA,4739
30
30
  sima_cli/storage/sdcard.py,sha256=-WULjdV31-n8v5OOqfxR77qBbIK4hJnrD3xWxUVMoGI,6324
31
31
  sima_cli/update/__init__.py,sha256=0P-z-rSaev40IhfJXytK3AFWv2_sdQU4Ry6ei2sEus0,66
@@ -44,7 +44,7 @@ sima_cli/utils/disk.py,sha256=66Kr631yhc_ny19up2aijfycWfD35AeLQOJgUsuH2hY,446
44
44
  sima_cli/utils/env.py,sha256=IP5HrH0lE7RMSiBeXcEt5GCLMT5p-QQroG-uGzl5XFU,8181
45
45
  sima_cli/utils/net.py,sha256=WVntA4CqipkNrrkA4tBVRadJft_pMcGYh4Re5xk3rqo,971
46
46
  sima_cli/utils/network.py,sha256=UvqxbqbWUczGFyO-t1SybG7Q-x9kjUVRNIn_D6APzy8,1252
47
- sima_cli-0.0.25.dist-info/licenses/LICENSE,sha256=a260OFuV4SsMZ6sQCkoYbtws_4o2deFtbnT9kg7Rfd4,1082
47
+ sima_cli-0.0.27.dist-info/licenses/LICENSE,sha256=a260OFuV4SsMZ6sQCkoYbtws_4o2deFtbnT9kg7Rfd4,1082
48
48
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  tests/test_app_zoo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  tests/test_auth.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -53,8 +53,8 @@ tests/test_download.py,sha256=t87DwxlHs26_ws9rpcHGwr_OrcRPd3hz6Zmm0vRee2U,4465
53
53
  tests/test_firmware.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  tests/test_model_zoo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  tests/test_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
- sima_cli-0.0.25.dist-info/METADATA,sha256=2_wrl0eMxkscHwmaKn2XgMlPQC8dY76KGBSjL5-gT70,3705
57
- sima_cli-0.0.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
58
- sima_cli-0.0.25.dist-info/entry_points.txt,sha256=xRYrDq1nCs6R8wEdB3c1kKuimxEjWJkHuCzArQPT0Xk,47
59
- sima_cli-0.0.25.dist-info/top_level.txt,sha256=FtrbAUdHNohtEPteOblArxQNwoX9_t8qJQd59fagDlc,15
60
- sima_cli-0.0.25.dist-info/RECORD,,
56
+ sima_cli-0.0.27.dist-info/METADATA,sha256=lzAzsKQImaK7MEelhD0MDkPGTf2x8dyaRsXR3dj27bA,3705
57
+ sima_cli-0.0.27.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
58
+ sima_cli-0.0.27.dist-info/entry_points.txt,sha256=xRYrDq1nCs6R8wEdB3c1kKuimxEjWJkHuCzArQPT0Xk,47
59
+ sima_cli-0.0.27.dist-info/top_level.txt,sha256=FtrbAUdHNohtEPteOblArxQNwoX9_t8qJQd59fagDlc,15
60
+ sima_cli-0.0.27.dist-info/RECORD,,