sima-cli 2.1.5__tar.gz → 2.1.6__tar.gz
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-2.1.5/sima_cli.egg-info → sima_cli-2.1.6}/PKG-INFO +34 -2
- {sima_cli-2.1.5 → sima_cli-2.1.6}/README.md +33 -1
- {sima_cli-2.1.5 → sima_cli-2.1.6}/pyproject.toml +1 -1
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/__version__.py +1 -1
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/cli.py +2 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/commands.py +14 -1
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/install.py +20 -7
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/neat.py +28 -10
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/utils.py +30 -5
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/elxr.py +116 -10
- sima_cli-2.1.6/sima_cli/vulcan/__init__.py +3 -0
- sima_cli-2.1.6/sima_cli/vulcan/artifacts.py +332 -0
- sima_cli-2.1.6/sima_cli/vulcan/commands.py +115 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6/sima_cli.egg-info}/PKG-INFO +34 -2
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli.egg-info/SOURCES.txt +5 -1
- sima_cli-2.1.6/tests/unit/test_elxr_update.py +408 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_sdk_image_detection.py +166 -5
- sima_cli-2.1.6/tests/unit/test_vulcan.py +180 -0
- sima_cli-2.1.5/tests/unit/test_elxr_update.py +0 -110
- {sima_cli-2.1.5 → sima_cli-2.1.6}/LICENSE +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/MANIFEST.in +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/requirements.txt +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/setup.cfg +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/setup.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/__main__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/app_zoo/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/app_zoo/app.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/app_zoo/commands.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/auth/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/auth/auth0.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/auth/devportal.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/auth/login.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/auth/oauth.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/data/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/data/resources_internal.yaml +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/data/resources_public.yaml +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/deploy_only/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/deploy_only/device/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/deploy_only/device/commands.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/deploy_only/mpk/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/deploy_only/mpk/commands.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/discover/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/discover/discover.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/discover/linuxll.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/download/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/download/downloader.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/github_assets.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/hostdriver.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/metadata_info.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/metadata_installer.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/metadata_validator.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/optiview.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/palette.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/install/registry.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/mla/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/mla/meminfo.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/model_zoo/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/model_zoo/model.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/network/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/network/network.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/playbooks/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/playbooks/commands.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/playbooks/manager.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/cmdexec.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/config.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/linux_shared_network.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/preinstall.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/requirements.json +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/script.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/stop.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/sdk/uninstall.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/serial/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/serial/serial.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/storage/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/storage/nvme.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/storage/sdcard.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/bmaptool.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/bootimg.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/cleanlog.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/local.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/netboot.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/query.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/remote.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/update/updater.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/upgrade/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/upgrade/selfupdate.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/api_common.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/artifactory.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/common.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/config.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/config_loader.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/container_registries.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/device_api.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/disk.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/docker.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/env.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/errors.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/mpk_api.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/net.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/network.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/pcie.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/pkg_update_check.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/serializers.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/services.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli/utils/tag.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli.egg-info/dependency_links.txt +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli.egg-info/entry_points.txt +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli.egg-info/requires.txt +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/sima_cli.egg-info/top_level.txt +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/e2e/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/__init__.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_app_zoo.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_auth.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_cli.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_cli_stdio.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_download.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_firmware.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_install_stub.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_model_zoo.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_pkg_update_check.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_sdk_preinstall.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_sdk_uninstall.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_selfupdate.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_skills_commands.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_skills_manager.py +0 -0
- {sima_cli-2.1.5 → sima_cli-2.1.6}/tests/unit/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sima-cli
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.6
|
|
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
|
|
@@ -152,6 +152,34 @@ sima-cli download <URL> [-d DEST]
|
|
|
152
152
|
|
|
153
153
|
---
|
|
154
154
|
|
|
155
|
+
## 🔥 Vulcan Artifacts
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
sima-cli vulcan download --env production core main
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- Downloads tested artifacts from Vulcan artifact hosting.
|
|
162
|
+
- Environment URLs:
|
|
163
|
+
- `dev`: `https://artifacts.neat.paconsultings.com`
|
|
164
|
+
- `staging`: `https://artifacts.stg.neat.sima.ai`
|
|
165
|
+
- `production`: `https://artifacts.neat.sima.ai`
|
|
166
|
+
- `staging` and `production` are not yet available for Vulcan downloads; use `--env dev` for now.
|
|
167
|
+
- Usage:
|
|
168
|
+
- `sima-cli vulcan --env {dev|staging|production} download [REPO] [BRANCH_OR_TAG]`
|
|
169
|
+
- `sima-cli vulcan download --env {dev|staging|production} [REPO] [BRANCH_OR_TAG]`
|
|
170
|
+
- If `REPO` is omitted, the CLI prompts for a repository.
|
|
171
|
+
- If `BRANCH_OR_TAG` is omitted, the CLI downloads `branches.json` and prompts for a branch.
|
|
172
|
+
- For automation, pass both values and add `--json` for structured output.
|
|
173
|
+
- Each download reads `latest.tag`, fetches `manifest.json`, downloads manifest-listed artifacts, and verifies size and SHA256 values when present.
|
|
174
|
+
|
|
175
|
+
Example:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
sima-cli vulcan --env dev download internals develop --output ./artifacts --json
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
155
183
|
## 🔧 Firmware Update
|
|
156
184
|
|
|
157
185
|
```bash
|
|
@@ -379,10 +407,14 @@ sima-cli packages show <PACKAGE_NAME> [--version VERSION]
|
|
|
379
407
|
### Setup SDK
|
|
380
408
|
|
|
381
409
|
```bash
|
|
382
|
-
sima-cli sdk setup [--noninteractive] [-y]
|
|
410
|
+
sima-cli sdk setup [--noninteractive] [-y] [--workspace PATH] [--no-model-sdk] [--no-insight] [--minimal]
|
|
383
411
|
```
|
|
384
412
|
|
|
385
413
|
- Initialize SDK environment and select components to start.
|
|
414
|
+
- Use `--workspace PATH` to mount a host directory other than `~/workspace` into SDK containers.
|
|
415
|
+
- Use `--no-model-sdk` to skip Model SDK extension setup.
|
|
416
|
+
- Use `--no-insight` to start Neat SDK without Insight UI/video/WebRTC port mappings.
|
|
417
|
+
- Use `--minimal` for CI compilation jobs. It skips optional Neat SDK setup extras, including Insight setup, installing `sima-cli`, Model SDK extensions, and coding agent playbooks inside the container.
|
|
386
418
|
|
|
387
419
|
### Start SDK Containers
|
|
388
420
|
|
|
@@ -118,6 +118,34 @@ sima-cli download <URL> [-d DEST]
|
|
|
118
118
|
|
|
119
119
|
---
|
|
120
120
|
|
|
121
|
+
## 🔥 Vulcan Artifacts
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
sima-cli vulcan download --env production core main
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- Downloads tested artifacts from Vulcan artifact hosting.
|
|
128
|
+
- Environment URLs:
|
|
129
|
+
- `dev`: `https://artifacts.neat.paconsultings.com`
|
|
130
|
+
- `staging`: `https://artifacts.stg.neat.sima.ai`
|
|
131
|
+
- `production`: `https://artifacts.neat.sima.ai`
|
|
132
|
+
- `staging` and `production` are not yet available for Vulcan downloads; use `--env dev` for now.
|
|
133
|
+
- Usage:
|
|
134
|
+
- `sima-cli vulcan --env {dev|staging|production} download [REPO] [BRANCH_OR_TAG]`
|
|
135
|
+
- `sima-cli vulcan download --env {dev|staging|production} [REPO] [BRANCH_OR_TAG]`
|
|
136
|
+
- If `REPO` is omitted, the CLI prompts for a repository.
|
|
137
|
+
- If `BRANCH_OR_TAG` is omitted, the CLI downloads `branches.json` and prompts for a branch.
|
|
138
|
+
- For automation, pass both values and add `--json` for structured output.
|
|
139
|
+
- Each download reads `latest.tag`, fetches `manifest.json`, downloads manifest-listed artifacts, and verifies size and SHA256 values when present.
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
sima-cli vulcan --env dev download internals develop --output ./artifacts --json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
121
149
|
## 🔧 Firmware Update
|
|
122
150
|
|
|
123
151
|
```bash
|
|
@@ -345,10 +373,14 @@ sima-cli packages show <PACKAGE_NAME> [--version VERSION]
|
|
|
345
373
|
### Setup SDK
|
|
346
374
|
|
|
347
375
|
```bash
|
|
348
|
-
sima-cli sdk setup [--noninteractive] [-y]
|
|
376
|
+
sima-cli sdk setup [--noninteractive] [-y] [--workspace PATH] [--no-model-sdk] [--no-insight] [--minimal]
|
|
349
377
|
```
|
|
350
378
|
|
|
351
379
|
- Initialize SDK environment and select components to start.
|
|
380
|
+
- Use `--workspace PATH` to mount a host directory other than `~/workspace` into SDK containers.
|
|
381
|
+
- Use `--no-model-sdk` to skip Model SDK extension setup.
|
|
382
|
+
- Use `--no-insight` to start Neat SDK without Insight UI/video/WebRTC port mappings.
|
|
383
|
+
- Use `--minimal` for CI compilation jobs. It skips optional Neat SDK setup extras, including Insight setup, installing `sima-cli`, Model SDK extensions, and coding agent playbooks inside the container.
|
|
352
384
|
|
|
353
385
|
### Start SDK Containers
|
|
354
386
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# sima_cli/__version__.py
|
|
2
|
-
__version__ = "2.1.
|
|
2
|
+
__version__ = "2.1.6"
|
|
@@ -29,6 +29,7 @@ from sima_cli.app_zoo.commands import register_appzoo_commands
|
|
|
29
29
|
from sima_cli.install.registry import register_packages_commands
|
|
30
30
|
from sima_cli.upgrade.selfupdate import register_selfupdate_command
|
|
31
31
|
from sima_cli.playbooks import register_playbook_commands
|
|
32
|
+
from sima_cli.vulcan import register_vulcan_commands
|
|
32
33
|
|
|
33
34
|
def _configure_stdio_errors() -> None:
|
|
34
35
|
for stream in (getattr(sys, "stdout", None), getattr(sys, "stderr", None)):
|
|
@@ -89,6 +90,7 @@ def main(ctx, internal):
|
|
|
89
90
|
# ----------------------
|
|
90
91
|
register_sdk_commands(main)
|
|
91
92
|
register_playbook_commands(main)
|
|
93
|
+
register_vulcan_commands(main)
|
|
92
94
|
|
|
93
95
|
|
|
94
96
|
# ----------------------
|
|
@@ -173,8 +173,19 @@ def launch_sdk_tool(tool: str, cmd, ctx):
|
|
|
173
173
|
is_flag=True,
|
|
174
174
|
help="Skip Model SDK extension setup. Intended for CI installation tests.",
|
|
175
175
|
)
|
|
176
|
+
@click.option(
|
|
177
|
+
"--minimal",
|
|
178
|
+
is_flag=True,
|
|
179
|
+
help="Skip optional Neat SDK container extras for CI compilation jobs.",
|
|
180
|
+
)
|
|
181
|
+
@click.option(
|
|
182
|
+
"--workspace",
|
|
183
|
+
type=click.Path(file_okay=False, dir_okay=True),
|
|
184
|
+
default=None,
|
|
185
|
+
help="Host workspace directory to mount into SDK containers instead of ~/workspace.",
|
|
186
|
+
)
|
|
176
187
|
@click.pass_context
|
|
177
|
-
def setup(ctx, yes, noninteractive, devkit, no_insight, no_model_sdk):
|
|
188
|
+
def setup(ctx, yes, noninteractive, devkit, no_insight, no_model_sdk, minimal, workspace):
|
|
178
189
|
"""Initialize SDK environment and select components to start."""
|
|
179
190
|
devkit_ip = _resolve_devkit_ip(devkit)
|
|
180
191
|
try:
|
|
@@ -184,6 +195,8 @@ def setup(ctx, yes, noninteractive, devkit, no_insight, no_model_sdk):
|
|
|
184
195
|
devkit_ip=devkit_ip,
|
|
185
196
|
no_insight=no_insight,
|
|
186
197
|
no_model_sdk=no_model_sdk,
|
|
198
|
+
minimal=minimal,
|
|
199
|
+
workspace=workspace,
|
|
187
200
|
)
|
|
188
201
|
except subprocess.CalledProcessError as e:
|
|
189
202
|
raise click.ClickException(f"SDK setup failed while running: {' '.join(e.cmd)}") from e
|
|
@@ -656,6 +656,8 @@ def setup_and_start(
|
|
|
656
656
|
devkit_ip: str = "",
|
|
657
657
|
no_insight: bool = False,
|
|
658
658
|
no_model_sdk: bool = False,
|
|
659
|
+
minimal: bool = False,
|
|
660
|
+
workspace: Optional[str] = None,
|
|
659
661
|
):
|
|
660
662
|
"""Main entry for SDK setup and container start."""
|
|
661
663
|
|
|
@@ -693,20 +695,29 @@ def setup_and_start(
|
|
|
693
695
|
# ──────────────────────────────────────────────
|
|
694
696
|
# Start containers
|
|
695
697
|
# ──────────────────────────────────────────────
|
|
696
|
-
workspace = get_workspace(
|
|
698
|
+
workspace = get_workspace(
|
|
699
|
+
yes_to_all,
|
|
700
|
+
noninteractive=noninteractive,
|
|
701
|
+
workspace_override=workspace,
|
|
702
|
+
)
|
|
697
703
|
uid = os.getuid() if hasattr(os, "getuid") else 900
|
|
698
704
|
gid = os.getgid() if hasattr(os, "getgid") else 900
|
|
699
705
|
devkit_env = _setup_devkit_share(devkit_ip, workspace, selected_images, noninteractive=noninteractive)
|
|
700
|
-
|
|
706
|
+
skip_model_sdk = no_model_sdk or minimal
|
|
707
|
+
skip_insight = no_insight or minimal
|
|
708
|
+
if skip_model_sdk:
|
|
701
709
|
sdk_extensions_dir = ""
|
|
702
710
|
if any(is_neat_sdk_image(img) for img in selected_images):
|
|
703
|
-
|
|
711
|
+
reason = "--minimal" if minimal else "--no-model-sdk"
|
|
712
|
+
click.echo(f"ℹ️ Skipping Model SDK extension setup because {reason} was specified.")
|
|
704
713
|
else:
|
|
705
714
|
sdk_extensions_dir = _setup_sdk_extensions(
|
|
706
715
|
selected_images,
|
|
707
716
|
noninteractive=noninteractive,
|
|
708
717
|
yes_to_all=yes_to_all,
|
|
709
718
|
)
|
|
719
|
+
if minimal and any(is_neat_sdk_image(img) for img in selected_images):
|
|
720
|
+
click.echo("ℹ️ Skipping Insight setup because --minimal was specified.")
|
|
710
721
|
|
|
711
722
|
for img in selected_images:
|
|
712
723
|
container_name = sanitize_container_name(img)
|
|
@@ -739,13 +750,15 @@ def setup_and_start(
|
|
|
739
750
|
sdk_extensions_dir=sdk_extensions_dir,
|
|
740
751
|
noninteractive=noninteractive,
|
|
741
752
|
yes_to_all=yes_to_all,
|
|
742
|
-
no_insight=
|
|
743
|
-
no_model_sdk=
|
|
753
|
+
no_insight=skip_insight,
|
|
754
|
+
no_model_sdk=skip_model_sdk,
|
|
755
|
+
minimal=minimal,
|
|
744
756
|
)
|
|
745
757
|
else:
|
|
746
|
-
if
|
|
758
|
+
if skip_insight and is_neat_sdk_image(img):
|
|
759
|
+
option = "--minimal" if minimal else "--no-insight"
|
|
747
760
|
raise RuntimeError(
|
|
748
|
-
"Cannot apply
|
|
761
|
+
f"Cannot apply {option} to an existing Neat SDK container because Docker "
|
|
749
762
|
"port mappings are immutable. Remove and recreate the container when prompted, "
|
|
750
763
|
f"or run: docker rm -f {existing_container}"
|
|
751
764
|
)
|
|
@@ -157,16 +157,16 @@ def allocate_neat_ports(no_insight: bool = False) -> Tuple[Dict, List[str]]:
|
|
|
157
157
|
|
|
158
158
|
port_map = {
|
|
159
159
|
"schema": NEAT_PORT_MAP_SCHEMA,
|
|
160
|
-
"cert": {
|
|
161
|
-
"mount": "/sdk-cert",
|
|
162
|
-
"certFile": "/sdk-cert/neat-sdk.pem",
|
|
163
|
-
"keyFile": "/sdk-cert/neat-sdk-key.pem",
|
|
164
|
-
},
|
|
165
160
|
}
|
|
166
161
|
|
|
167
162
|
port_args = []
|
|
168
163
|
|
|
169
164
|
if not no_insight:
|
|
165
|
+
port_map["cert"] = {
|
|
166
|
+
"mount": "/sdk-cert",
|
|
167
|
+
"certFile": "/sdk-cert/neat-sdk.pem",
|
|
168
|
+
"keyFile": "/sdk-cert/neat-sdk-key.pem",
|
|
169
|
+
}
|
|
170
170
|
web_ssh = _allocate_single_port(8022, "tcp", reserved)
|
|
171
171
|
rtsp_tcp = _allocate_single_port(8554, "tcp", reserved)
|
|
172
172
|
main_ui = _allocate_single_port(9900, "tcp", reserved)
|
|
@@ -454,11 +454,24 @@ def prepare_neat_container_run(
|
|
|
454
454
|
yes_to_all: bool = False,
|
|
455
455
|
noninteractive: bool = False,
|
|
456
456
|
no_insight: bool = False,
|
|
457
|
+
minimal: bool = False,
|
|
457
458
|
) -> NeatRunConfig:
|
|
459
|
+
no_insight = no_insight or minimal
|
|
458
460
|
container_dir = Path(workspace) / f".{container_name}"
|
|
459
461
|
config_dir = container_dir / "insight-config"
|
|
460
462
|
cert_dir = container_dir / "sdk-cert"
|
|
461
463
|
port_map, port_args = allocate_neat_ports(no_insight=no_insight)
|
|
464
|
+
if no_insight:
|
|
465
|
+
return NeatRunConfig(
|
|
466
|
+
port_map=port_map,
|
|
467
|
+
port_args=port_args,
|
|
468
|
+
config_host_dir="",
|
|
469
|
+
cert_host_dir="",
|
|
470
|
+
port_map_host_path="",
|
|
471
|
+
cert_file_host_path="",
|
|
472
|
+
key_file_host_path="",
|
|
473
|
+
webrtc_host_ip="",
|
|
474
|
+
)
|
|
462
475
|
webrtc_host_ip = _detect_webrtc_host_ip(devkit_env)
|
|
463
476
|
cert_file, key_file = _ensure_certificates(
|
|
464
477
|
cert_dir,
|
|
@@ -480,13 +493,16 @@ def prepare_neat_container_run(
|
|
|
480
493
|
|
|
481
494
|
|
|
482
495
|
def append_neat_docker_args(docker_cmd: List[str], config: NeatRunConfig) -> None:
|
|
483
|
-
|
|
496
|
+
if config.port_args or config.config_host_dir:
|
|
497
|
+
docker_cmd.extend(["-e", f"MTX_RTSPTRANSPORTS={NEAT_MEDIAMTX_RTSP_TRANSPORTS}"])
|
|
484
498
|
if config.webrtc_host_ip:
|
|
485
499
|
docker_cmd.extend(["-e", f"CONTAINER_HOST_IP={config.webrtc_host_ip}"])
|
|
486
500
|
for mapping in config.port_args:
|
|
487
501
|
docker_cmd.extend(["-p", mapping])
|
|
488
|
-
|
|
489
|
-
|
|
502
|
+
if config.config_host_dir:
|
|
503
|
+
docker_cmd.extend(["-v", f"{config.config_host_dir}:/home/docker/.insight-config"])
|
|
504
|
+
if config.cert_host_dir:
|
|
505
|
+
docker_cmd.extend(["-v", f"{config.cert_host_dir}:/sdk-cert"])
|
|
490
506
|
|
|
491
507
|
|
|
492
508
|
def print_neat_setup_summary(config: NeatRunConfig) -> None:
|
|
@@ -529,8 +545,10 @@ def print_neat_setup_summary(config: NeatRunConfig) -> None:
|
|
|
529
545
|
)
|
|
530
546
|
if config.webrtc_host_ip:
|
|
531
547
|
print(f" iceHost: {config.webrtc_host_ip}")
|
|
532
|
-
|
|
533
|
-
|
|
548
|
+
if config.port_map_host_path:
|
|
549
|
+
print(f" config: {config.port_map_host_path}")
|
|
550
|
+
if config.cert_host_dir:
|
|
551
|
+
print(f" certs: {config.cert_host_dir}")
|
|
534
552
|
|
|
535
553
|
|
|
536
554
|
def is_docker_port_collision_error(error_text: str) -> bool:
|
|
@@ -504,7 +504,7 @@ def get_running_containers():
|
|
|
504
504
|
return running
|
|
505
505
|
|
|
506
506
|
|
|
507
|
-
def get_workspace(yes_to_all=False, noninteractive=False):
|
|
507
|
+
def get_workspace(yes_to_all=False, noninteractive=False, workspace_override=None):
|
|
508
508
|
"""
|
|
509
509
|
Determine the workspace:
|
|
510
510
|
- If at least one container is running, read from ~/.simaai/.mount
|
|
@@ -515,6 +515,17 @@ def get_workspace(yes_to_all=False, noninteractive=False):
|
|
|
515
515
|
simaai_dir = os.path.join(home, ".simaai")
|
|
516
516
|
mount_file = os.path.join(simaai_dir, ".mount")
|
|
517
517
|
|
|
518
|
+
if workspace_override:
|
|
519
|
+
workspace = os.path.realpath(os.path.expanduser(workspace_override))
|
|
520
|
+
if not os.path.isdir(workspace):
|
|
521
|
+
os.makedirs(workspace, exist_ok=True)
|
|
522
|
+
print(f"📂 Created workspace: {workspace}")
|
|
523
|
+
print(f"✅ Workspace set to: {workspace}")
|
|
524
|
+
os.makedirs(simaai_dir, exist_ok=True)
|
|
525
|
+
with open(mount_file, "w") as f:
|
|
526
|
+
f.write(workspace)
|
|
527
|
+
return workspace
|
|
528
|
+
|
|
518
529
|
running_containers = get_running_containers()
|
|
519
530
|
|
|
520
531
|
# Case 1: At least one container running → read workspace
|
|
@@ -920,6 +931,7 @@ def configure_container(
|
|
|
920
931
|
noninteractive=False,
|
|
921
932
|
yes_to_all=False,
|
|
922
933
|
no_model_sdk=False,
|
|
934
|
+
minimal=False,
|
|
923
935
|
):
|
|
924
936
|
"""
|
|
925
937
|
Configure container user mappings and permissions:
|
|
@@ -930,6 +942,7 @@ def configure_container(
|
|
|
930
942
|
- If configure_network=True, computes and stores .hash for /usr/local/simaai/plugins
|
|
931
943
|
"""
|
|
932
944
|
platform_os = check_os()
|
|
945
|
+
no_model_sdk = no_model_sdk or minimal
|
|
933
946
|
|
|
934
947
|
# Detect current host user
|
|
935
948
|
if platform_os in ["linux", "macos"]:
|
|
@@ -1016,10 +1029,15 @@ def configure_container(
|
|
|
1016
1029
|
|
|
1017
1030
|
_copy_sima_cli_auth_cache_to_container(sdk_container_name, login_name, uid, gid)
|
|
1018
1031
|
|
|
1019
|
-
# Ensure sima-cli is available for the configured default user
|
|
1020
|
-
|
|
1032
|
+
# Ensure sima-cli is available for the configured default user unless this
|
|
1033
|
+
# setup is only preparing a lightweight CI compilation container.
|
|
1034
|
+
if minimal:
|
|
1035
|
+
print("ℹ️ Skipping sima-cli installation because --minimal was specified.")
|
|
1036
|
+
else:
|
|
1037
|
+
ensure_sima_cli_installed(sdk_container_name, login_name)
|
|
1021
1038
|
if no_model_sdk:
|
|
1022
|
-
|
|
1039
|
+
reason = "--minimal" if minimal else "--no-model-sdk"
|
|
1040
|
+
print(f"ℹ️ Skipping Model SDK extension installation because {reason} was specified.")
|
|
1023
1041
|
else:
|
|
1024
1042
|
ensure_model_sdk_extension_installed(
|
|
1025
1043
|
sdk_container_name,
|
|
@@ -1027,7 +1045,10 @@ def configure_container(
|
|
|
1027
1045
|
auto_install=(noninteractive or yes_to_all),
|
|
1028
1046
|
)
|
|
1029
1047
|
_sync_codex_skills(sdk_container_name, login_name, uid, gid)
|
|
1030
|
-
|
|
1048
|
+
if minimal:
|
|
1049
|
+
print("ℹ️ Skipping Neat coding agent playbook installation because --minimal was specified.")
|
|
1050
|
+
else:
|
|
1051
|
+
install_neat_playbooks(sdk_container_name, login_name)
|
|
1031
1052
|
|
|
1032
1053
|
# ---- Optional Network & Syslog Configuration ----
|
|
1033
1054
|
if configure_network:
|
|
@@ -1141,6 +1162,7 @@ def start_docker_container(
|
|
|
1141
1162
|
yes_to_all=False,
|
|
1142
1163
|
no_insight=False,
|
|
1143
1164
|
no_model_sdk=False,
|
|
1165
|
+
minimal=False,
|
|
1144
1166
|
):
|
|
1145
1167
|
"""
|
|
1146
1168
|
Start a Docker container using an image pulled from either JFrog or AWS ECR.
|
|
@@ -1152,6 +1174,7 @@ def start_docker_container(
|
|
|
1152
1174
|
# ─────────────────────────────────────────────
|
|
1153
1175
|
# Generate container name
|
|
1154
1176
|
# ─────────────────────────────────────────────
|
|
1177
|
+
no_insight = no_insight or minimal
|
|
1155
1178
|
container_name = sanitize_container_name(image)
|
|
1156
1179
|
hostname = sanitize_container_hostname(container_name)
|
|
1157
1180
|
print(f"🚀 Starting container '{container_name}' using image '{image}'")
|
|
@@ -1262,6 +1285,7 @@ def start_docker_container(
|
|
|
1262
1285
|
yes_to_all=yes_to_all,
|
|
1263
1286
|
noninteractive=noninteractive,
|
|
1264
1287
|
no_insight=no_insight,
|
|
1288
|
+
minimal=minimal,
|
|
1265
1289
|
)
|
|
1266
1290
|
launch_cmd = list(base_docker_cmd)
|
|
1267
1291
|
append_neat_docker_args(launch_cmd, neat_run_config)
|
|
@@ -1311,6 +1335,7 @@ def start_docker_container(
|
|
|
1311
1335
|
noninteractive=noninteractive,
|
|
1312
1336
|
yes_to_all=yes_to_all,
|
|
1313
1337
|
no_model_sdk=no_model_sdk,
|
|
1338
|
+
minimal=minimal,
|
|
1314
1339
|
)
|
|
1315
1340
|
|
|
1316
1341
|
if devkit_env and neat_sdk_image:
|
|
@@ -4,15 +4,20 @@ from typing import Optional, List, Tuple
|
|
|
4
4
|
import re
|
|
5
5
|
import os
|
|
6
6
|
import shutil
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
from rich.text import Text
|
|
7
10
|
|
|
8
11
|
from sima_cli.utils.env import is_devkit_running_elxr
|
|
9
12
|
|
|
10
13
|
APT_SOURCE_FILE = "/etc/apt/sources.list.d/0000mirror.list"
|
|
14
|
+
BUILDINFO_FILES = ["/etc/build", "/etc/buildinfo"]
|
|
11
15
|
EXTERNAL_REPO_URL = "https://repo.sima.ai/elxr/deb/release"
|
|
12
16
|
INTERNAL_REPO_URL = "http://sw-web.eng.sima.ai/deb/pre-release"
|
|
13
17
|
DEFAULT_REPO_SUITE = "bookworm"
|
|
14
18
|
REPO_COMPONENT = "non-free"
|
|
15
19
|
SIMAAI_OTA_FALLBACK = "/usr/bin/simaai-ota"
|
|
20
|
+
ELXR_UPDATE_DOC_URL = "https://docs.sima.ai/pages/tech-notes/elxr-conversion.html"
|
|
16
21
|
|
|
17
22
|
|
|
18
23
|
def _repo_line(repo_url: str, suite: str) -> str:
|
|
@@ -181,6 +186,35 @@ def _get_installed_palette_version() -> Optional[str]:
|
|
|
181
186
|
return version if version else None
|
|
182
187
|
|
|
183
188
|
|
|
189
|
+
def _get_installed_elxr_distro_version() -> Optional[str]:
|
|
190
|
+
"""Return ELXR DISTRO_VERSION from /etc/build or /etc/buildinfo, if available."""
|
|
191
|
+
pattern = re.compile(r"^\s*DISTRO_VERSION\s*=\s*(\S+)\s*$")
|
|
192
|
+
|
|
193
|
+
for path in BUILDINFO_FILES:
|
|
194
|
+
try:
|
|
195
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
196
|
+
for line in f:
|
|
197
|
+
match = pattern.match(line)
|
|
198
|
+
if match:
|
|
199
|
+
return match.group(1)
|
|
200
|
+
except OSError:
|
|
201
|
+
continue
|
|
202
|
+
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _is_current_elxr_version(
|
|
207
|
+
requested_version: str,
|
|
208
|
+
installed_palette_version: Optional[str],
|
|
209
|
+
installed_distro_version: Optional[str],
|
|
210
|
+
) -> bool:
|
|
211
|
+
return requested_version in {
|
|
212
|
+
version
|
|
213
|
+
for version in (installed_palette_version, installed_distro_version)
|
|
214
|
+
if version
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
184
218
|
def _get_available_palette_versions() -> List[str]:
|
|
185
219
|
"""Parse apt policy output and return available simaai-palette-modalix versions."""
|
|
186
220
|
try:
|
|
@@ -230,6 +264,37 @@ def _get_available_palette_versions() -> List[str]:
|
|
|
230
264
|
return versions
|
|
231
265
|
|
|
232
266
|
|
|
267
|
+
def _show_unsupported_specific_elxr_update(
|
|
268
|
+
requested_version: str,
|
|
269
|
+
current_version: Optional[str] = None,
|
|
270
|
+
latest_version: Optional[str] = None,
|
|
271
|
+
) -> None:
|
|
272
|
+
details = [
|
|
273
|
+
"Updating ELXR to a specific version is not currently supported by `sima-cli update`.",
|
|
274
|
+
"Downgrades and non-latest upgrade paths are not reliable enough to automate safely.",
|
|
275
|
+
]
|
|
276
|
+
if current_version:
|
|
277
|
+
details.append(f"Current simaai-palette-modalix version: {current_version}")
|
|
278
|
+
if requested_version:
|
|
279
|
+
details.append(f"Requested simaai-palette-modalix version: {requested_version}")
|
|
280
|
+
if latest_version:
|
|
281
|
+
details.append(f"Latest available simaai-palette-modalix version: {latest_version}")
|
|
282
|
+
details.extend([
|
|
283
|
+
"",
|
|
284
|
+
"Use `sima-cli update` without a version to update to the latest supported build.",
|
|
285
|
+
f"For full-system conversion/update guidance, see: {ELXR_UPDATE_DOC_URL}",
|
|
286
|
+
])
|
|
287
|
+
|
|
288
|
+
Console().print(
|
|
289
|
+
Panel(
|
|
290
|
+
Text("\n".join(details), style="yellow"),
|
|
291
|
+
title="[yellow]Unsupported ELXR Update Path[/yellow]",
|
|
292
|
+
border_style="yellow",
|
|
293
|
+
expand=False,
|
|
294
|
+
)
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
233
298
|
def print_current_versions():
|
|
234
299
|
p1 = subprocess.Popen(
|
|
235
300
|
["dpkg", "-l"],
|
|
@@ -265,8 +330,6 @@ def update_elxr(version_or_url: Optional[str], internal: bool = False):
|
|
|
265
330
|
|
|
266
331
|
print_current_versions()
|
|
267
332
|
|
|
268
|
-
from InquirerPy import inquirer
|
|
269
|
-
|
|
270
333
|
if not _ensure_elxr_repo_channel(internal):
|
|
271
334
|
return
|
|
272
335
|
|
|
@@ -292,6 +355,9 @@ def update_elxr(version_or_url: Optional[str], internal: bool = False):
|
|
|
292
355
|
# Main interaction loop
|
|
293
356
|
# -----------------------------
|
|
294
357
|
simaai_ota = _resolve_simaai_ota()
|
|
358
|
+
if version_or_url is None:
|
|
359
|
+
from InquirerPy import inquirer
|
|
360
|
+
|
|
295
361
|
while True:
|
|
296
362
|
|
|
297
363
|
# If user did not pass a version, show the update type menu
|
|
@@ -321,6 +387,8 @@ def update_elxr(version_or_url: Optional[str], internal: bool = False):
|
|
|
321
387
|
# -----------------------------
|
|
322
388
|
versions = _get_available_palette_versions()
|
|
323
389
|
installed_version = _get_installed_palette_version()
|
|
390
|
+
installed_distro_version = _get_installed_elxr_distro_version()
|
|
391
|
+
latest_version = versions[0] if versions else None
|
|
324
392
|
|
|
325
393
|
if not versions:
|
|
326
394
|
click.echo("❌ No versions found in APT policy, aborting.")
|
|
@@ -346,8 +414,7 @@ def update_elxr(version_or_url: Optional[str], internal: bool = False):
|
|
|
346
414
|
click.echo("❌ Update cancelled")
|
|
347
415
|
return
|
|
348
416
|
|
|
349
|
-
|
|
350
|
-
if installed_version and selected == installed_version:
|
|
417
|
+
if _is_current_elxr_version(selected, installed_version, installed_distro_version):
|
|
351
418
|
same_version_choice = inquirer.select(
|
|
352
419
|
message=(
|
|
353
420
|
f"Version {selected} is already running. "
|
|
@@ -365,16 +432,55 @@ def update_elxr(version_or_url: Optional[str], internal: bool = False):
|
|
|
365
432
|
|
|
366
433
|
cmd = [simaai_ota, "-f", "-o", "-v", selected]
|
|
367
434
|
desc = f"Force reinstall specific version {selected}"
|
|
368
|
-
|
|
435
|
+
break
|
|
436
|
+
|
|
437
|
+
if latest_version and selected == latest_version:
|
|
369
438
|
cmd = [simaai_ota, "-f", "-o", "-v", selected]
|
|
370
|
-
desc = f"Update to
|
|
371
|
-
|
|
439
|
+
desc = f"Update to latest version {selected}"
|
|
440
|
+
break
|
|
441
|
+
|
|
442
|
+
_show_unsupported_specific_elxr_update(
|
|
443
|
+
requested_version=selected,
|
|
444
|
+
current_version=installed_distro_version or installed_version,
|
|
445
|
+
latest_version=latest_version,
|
|
446
|
+
)
|
|
447
|
+
warning_choice = inquirer.select(
|
|
448
|
+
message="What would you like to do next?",
|
|
449
|
+
choices=[
|
|
450
|
+
{"name": "⬅️ Back to previous menu", "value": "back"},
|
|
451
|
+
{"name": "❌ Cancel", "value": "cancel"},
|
|
452
|
+
],
|
|
453
|
+
default="back",
|
|
454
|
+
).execute()
|
|
455
|
+
|
|
456
|
+
if warning_choice == "cancel":
|
|
457
|
+
click.echo("❌ Update cancelled")
|
|
458
|
+
return
|
|
459
|
+
|
|
460
|
+
continue
|
|
372
461
|
|
|
373
462
|
else:
|
|
374
463
|
# version_or_url specified by user (non-interactive)
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
464
|
+
versions = _get_available_palette_versions()
|
|
465
|
+
installed_version = _get_installed_palette_version()
|
|
466
|
+
installed_distro_version = _get_installed_elxr_distro_version()
|
|
467
|
+
latest_version = versions[0] if versions else None
|
|
468
|
+
if _is_current_elxr_version(version_or_url, installed_version, installed_distro_version):
|
|
469
|
+
cmd = [simaai_ota, "-f", "-o", "-v", version_or_url]
|
|
470
|
+
desc = f"Force reinstall specific version {version_or_url}"
|
|
471
|
+
break
|
|
472
|
+
|
|
473
|
+
if latest_version and version_or_url == latest_version:
|
|
474
|
+
cmd = [simaai_ota, "-f", "-o", "-v", version_or_url]
|
|
475
|
+
desc = f"Update to latest version {version_or_url}"
|
|
476
|
+
break
|
|
477
|
+
|
|
478
|
+
_show_unsupported_specific_elxr_update(
|
|
479
|
+
requested_version=version_or_url,
|
|
480
|
+
current_version=installed_distro_version or installed_version,
|
|
481
|
+
latest_version=latest_version,
|
|
482
|
+
)
|
|
483
|
+
return
|
|
378
484
|
|
|
379
485
|
# -----------------------------
|
|
380
486
|
# Execute update
|