mposcli 0.4.0__tar.gz → 0.5.0__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.
- {mposcli-0.4.0 → mposcli-0.5.0}/PKG-INFO +22 -7
- {mposcli-0.4.0 → mposcli-0.5.0}/README.md +21 -6
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/__init__.py +1 -1
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_app/build.py +1 -1
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_app/copy_mpos.py +24 -44
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_app/flash.py +15 -7
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_app/update.py +1 -1
- mposcli-0.5.0/mposcli/tests/test_mpremote_cp_utils.py +74 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/tools.py +3 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/user_input.py +5 -4
- mposcli-0.5.0/mposcli/utilities/__init__.py +0 -0
- mposcli-0.5.0/mposcli/utilities/mpremote.py +64 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.editorconfig +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.github/workflows/tests.yml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.gitignore +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.idea/.gitignore +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.pre-commit-config.yaml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.pre-commit-hooks.yaml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.run/Template Python tests.run.xml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.run/Template Python.run.xml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.run/Unittests __all__.run.xml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.run/cli --help.run.xml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.run/dev-cli --help.run.xml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.run/dev-cli test.run.xml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.venv-app/.gitignore +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/.venv-app/lib/python3.14/site-packages/cli_base/tests/shell_complete_snapshots/.gitignore +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/cli.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/dev-cli.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/dist/.gitignore +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/__main__.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_app/__init__.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_app/run_deskop.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_dev/__init__.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_dev/__main__.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_dev/code_style.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_dev/packaging.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_dev/shell_completion.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_dev/testing.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/cli_dev/update_readme_history.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/constants.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/fs_utils.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/mpos_utils.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/tests/__init__.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/tests/test_doctests.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/tests/test_project_setup.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/tests/test_readme.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/mposcli/tests/test_readme_history.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/noxfile.py +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/pyproject.toml +0 -0
- {mposcli-0.4.0 → mposcli-0.5.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mposcli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: CLI helper for MicroPythonOS: https://github.com/MicroPythonOS/MicroPythonOS
|
|
5
5
|
Project-URL: Documentation, https://github.com/jedie/mposcli
|
|
6
6
|
Project-URL: Source, https://github.com/jedie/mposcli
|
|
@@ -61,8 +61,8 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
61
61
|
│ • cp Copy/update internal_filesystem/lib/mpos files to the device │
|
|
62
62
|
│ via "mpremote fs cp". Display a file chooser to select which │
|
|
63
63
|
│ files to copy/update. But can also be used to copy/update all │
|
|
64
|
-
│ files. see:
|
|
65
|
-
│
|
|
64
|
+
│ files. see: │
|
|
65
|
+
│ https://docs.micropythonos.com/architecture/filesystem/ │
|
|
66
66
|
│ • cp-app Copy/update internal_filesystem/apps to the device via │
|
|
67
67
|
│ "mpremote fs cp". Display a file chooser to select which app to │
|
|
68
68
|
│ copy/update. But can also be used to copy/update all files. │
|
|
@@ -93,13 +93,13 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
93
93
|
|
|
94
94
|
[comment]: <> (✂✂✂ auto generated build start ✂✂✂)
|
|
95
95
|
```
|
|
96
|
-
usage: mposcli build [-h] [{esp32,esp32s3,unix,macOS}] [-v]
|
|
96
|
+
usage: mposcli build [-h] [{esp32,esp32s3,unphone,unix,macOS}] [-v]
|
|
97
97
|
|
|
98
98
|
Build MicroPythonOS by calling: ./scripts/build_mpos.sh <target> see:
|
|
99
99
|
https://docs.micropythonos.com/os-development/
|
|
100
100
|
|
|
101
101
|
╭─ positional arguments ───────────────────────────────────────────────────╮
|
|
102
|
-
│ [{esp32,esp32s3,unix,macOS}]
|
|
102
|
+
│ [{esp32,esp32s3,unphone,unix,macOS}] │
|
|
103
103
|
│ Target platform to build for. (default: unix) │
|
|
104
104
|
╰──────────────────────────────────────────────────────────────────────────╯
|
|
105
105
|
╭─ options ────────────────────────────────────────────────────────────────╮
|
|
@@ -119,7 +119,7 @@ usage: mposcli cp [-h] [CP OPTIONS]
|
|
|
119
119
|
|
|
120
120
|
Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp". Display
|
|
121
121
|
a file chooser to select which files to copy/update. But can also be used to copy/update
|
|
122
|
-
all files. see: https://docs.micropythonos.com/
|
|
122
|
+
all files. see: https://docs.micropythonos.com/architecture/filesystem/
|
|
123
123
|
|
|
124
124
|
╭─ positional arguments ─────────────────────────────────────────────────────────────────╮
|
|
125
125
|
│ [{None}|PATH] Optional file or directory path. (default: None) │
|
|
@@ -173,7 +173,9 @@ https://docs.micropythonos.com/os-development/installing-on-esp32/
|
|
|
173
173
|
|
|
174
174
|
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
|
|
175
175
|
│ -h, --help show this help message and exit │
|
|
176
|
-
│ --port STR
|
|
176
|
+
│ --port {None}|STR Port used for esptool and mpremote, e.g.: "/dev/ttyUSB0" or │
|
|
177
|
+
│ "/dev/ttyACM0" etc. Leave empty for autodetection (default: │
|
|
178
|
+
│ None) │
|
|
177
179
|
│ --address STR Address (default: 0x0) │
|
|
178
180
|
│ --flash-size STR Flash Size (default: detect) │
|
|
179
181
|
│ --verify, --no-verify Verify after flashing? (default: True) │
|
|
@@ -317,6 +319,13 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
317
319
|
|
|
318
320
|
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
|
319
321
|
|
|
322
|
+
* [v0.5.0](https://github.com/jedie/mposcli/compare/v0.4.1...v0.5.0)
|
|
323
|
+
* 2026-03-08 - update README
|
|
324
|
+
* 2026-03-05 - Enhance "cp" command and auto restart "mpremote repl"
|
|
325
|
+
* 2026-03-03 - Refactor "cp" command
|
|
326
|
+
* 2026-03-03 - flash command: use port auto detection as default
|
|
327
|
+
* [v0.4.1](https://github.com/jedie/mposcli/compare/v0.4.0...v0.4.1)
|
|
328
|
+
* 2026-02-27 - Use "--force" for pulling submodules to overwrite local changes
|
|
320
329
|
* [v0.4.0](https://github.com/jedie/mposcli/compare/v0.3.0...v0.4.0)
|
|
321
330
|
* 2026-02-24 - NEW command: "cp-app" to install/update internal_filesystem/apps
|
|
322
331
|
* 2026-02-24 - Log skipped files
|
|
@@ -327,6 +336,9 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
327
336
|
* 2026-02-18 - Add "update" beside "update-submodules"
|
|
328
337
|
* 2026-02-17 - Update requirements
|
|
329
338
|
* 2026-02-16 - update README
|
|
339
|
+
|
|
340
|
+
<details><summary>Expand older history entries ...</summary>
|
|
341
|
+
|
|
330
342
|
* [v0.2.0](https://github.com/jedie/mposcli/compare/v0.1.0...v0.2.0)
|
|
331
343
|
* 2026-02-16 - New CLI command: "cp" with convenience features.
|
|
332
344
|
* 2026-02-16 - New command: "flash" with file selector
|
|
@@ -337,4 +349,7 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
337
349
|
* 2026-02-16 - CLI command: "run-desktop"
|
|
338
350
|
* 2026-02-16 - first commit
|
|
339
351
|
|
|
352
|
+
</details>
|
|
353
|
+
|
|
354
|
+
|
|
340
355
|
[comment]: <> (✂✂✂ auto generated history end ✂✂✂)
|
|
@@ -46,8 +46,8 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
46
46
|
│ • cp Copy/update internal_filesystem/lib/mpos files to the device │
|
|
47
47
|
│ via "mpremote fs cp". Display a file chooser to select which │
|
|
48
48
|
│ files to copy/update. But can also be used to copy/update all │
|
|
49
|
-
│ files. see:
|
|
50
|
-
│
|
|
49
|
+
│ files. see: │
|
|
50
|
+
│ https://docs.micropythonos.com/architecture/filesystem/ │
|
|
51
51
|
│ • cp-app Copy/update internal_filesystem/apps to the device via │
|
|
52
52
|
│ "mpremote fs cp". Display a file chooser to select which app to │
|
|
53
53
|
│ copy/update. But can also be used to copy/update all files. │
|
|
@@ -78,13 +78,13 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
78
78
|
|
|
79
79
|
[comment]: <> (✂✂✂ auto generated build start ✂✂✂)
|
|
80
80
|
```
|
|
81
|
-
usage: mposcli build [-h] [{esp32,esp32s3,unix,macOS}] [-v]
|
|
81
|
+
usage: mposcli build [-h] [{esp32,esp32s3,unphone,unix,macOS}] [-v]
|
|
82
82
|
|
|
83
83
|
Build MicroPythonOS by calling: ./scripts/build_mpos.sh <target> see:
|
|
84
84
|
https://docs.micropythonos.com/os-development/
|
|
85
85
|
|
|
86
86
|
╭─ positional arguments ───────────────────────────────────────────────────╮
|
|
87
|
-
│ [{esp32,esp32s3,unix,macOS}]
|
|
87
|
+
│ [{esp32,esp32s3,unphone,unix,macOS}] │
|
|
88
88
|
│ Target platform to build for. (default: unix) │
|
|
89
89
|
╰──────────────────────────────────────────────────────────────────────────╯
|
|
90
90
|
╭─ options ────────────────────────────────────────────────────────────────╮
|
|
@@ -104,7 +104,7 @@ usage: mposcli cp [-h] [CP OPTIONS]
|
|
|
104
104
|
|
|
105
105
|
Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp". Display
|
|
106
106
|
a file chooser to select which files to copy/update. But can also be used to copy/update
|
|
107
|
-
all files. see: https://docs.micropythonos.com/
|
|
107
|
+
all files. see: https://docs.micropythonos.com/architecture/filesystem/
|
|
108
108
|
|
|
109
109
|
╭─ positional arguments ─────────────────────────────────────────────────────────────────╮
|
|
110
110
|
│ [{None}|PATH] Optional file or directory path. (default: None) │
|
|
@@ -158,7 +158,9 @@ https://docs.micropythonos.com/os-development/installing-on-esp32/
|
|
|
158
158
|
|
|
159
159
|
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
|
|
160
160
|
│ -h, --help show this help message and exit │
|
|
161
|
-
│ --port STR
|
|
161
|
+
│ --port {None}|STR Port used for esptool and mpremote, e.g.: "/dev/ttyUSB0" or │
|
|
162
|
+
│ "/dev/ttyACM0" etc. Leave empty for autodetection (default: │
|
|
163
|
+
│ None) │
|
|
162
164
|
│ --address STR Address (default: 0x0) │
|
|
163
165
|
│ --flash-size STR Flash Size (default: detect) │
|
|
164
166
|
│ --verify, --no-verify Verify after flashing? (default: True) │
|
|
@@ -302,6 +304,13 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
302
304
|
|
|
303
305
|
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
|
304
306
|
|
|
307
|
+
* [v0.5.0](https://github.com/jedie/mposcli/compare/v0.4.1...v0.5.0)
|
|
308
|
+
* 2026-03-08 - update README
|
|
309
|
+
* 2026-03-05 - Enhance "cp" command and auto restart "mpremote repl"
|
|
310
|
+
* 2026-03-03 - Refactor "cp" command
|
|
311
|
+
* 2026-03-03 - flash command: use port auto detection as default
|
|
312
|
+
* [v0.4.1](https://github.com/jedie/mposcli/compare/v0.4.0...v0.4.1)
|
|
313
|
+
* 2026-02-27 - Use "--force" for pulling submodules to overwrite local changes
|
|
305
314
|
* [v0.4.0](https://github.com/jedie/mposcli/compare/v0.3.0...v0.4.0)
|
|
306
315
|
* 2026-02-24 - NEW command: "cp-app" to install/update internal_filesystem/apps
|
|
307
316
|
* 2026-02-24 - Log skipped files
|
|
@@ -312,6 +321,9 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
312
321
|
* 2026-02-18 - Add "update" beside "update-submodules"
|
|
313
322
|
* 2026-02-17 - Update requirements
|
|
314
323
|
* 2026-02-16 - update README
|
|
324
|
+
|
|
325
|
+
<details><summary>Expand older history entries ...</summary>
|
|
326
|
+
|
|
315
327
|
* [v0.2.0](https://github.com/jedie/mposcli/compare/v0.1.0...v0.2.0)
|
|
316
328
|
* 2026-02-16 - New CLI command: "cp" with convenience features.
|
|
317
329
|
* 2026-02-16 - New command: "flash" with file selector
|
|
@@ -322,4 +334,7 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
322
334
|
* 2026-02-16 - CLI command: "run-desktop"
|
|
323
335
|
* 2026-02-16 - first commit
|
|
324
336
|
|
|
337
|
+
</details>
|
|
338
|
+
|
|
339
|
+
|
|
325
340
|
[comment]: <> (✂✂✂ auto generated history end ✂✂✂)
|
|
@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
|
|
|
18
18
|
@app.command
|
|
19
19
|
def build(
|
|
20
20
|
target: Annotated[
|
|
21
|
-
Literal['esp32', 'esp32s3', 'unix', 'macOS'],
|
|
21
|
+
Literal['esp32', 'esp32s3', 'unphone', 'unix', 'macOS'],
|
|
22
22
|
tyro.conf.arg(
|
|
23
23
|
help='Target platform to build for.',
|
|
24
24
|
),
|
|
@@ -14,6 +14,7 @@ from mposcli.cli_app import app
|
|
|
14
14
|
from mposcli.mpos_utils import get_mpos_path
|
|
15
15
|
from mposcli.tools import get_mpremote_bin
|
|
16
16
|
from mposcli.user_input import choose_newest_modified_directory, get_newest_files
|
|
17
|
+
from mposcli.utilities.mpremote import MpOsPathResolver, start_mpremote_repl
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
logger = logging.getLogger(__name__)
|
|
@@ -44,58 +45,45 @@ def cp(
|
|
|
44
45
|
Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp".
|
|
45
46
|
Display a file chooser to select which files to copy/update.
|
|
46
47
|
But can also be used to copy/update all files.
|
|
47
|
-
see: https://docs.micropythonos.com/
|
|
48
|
+
see: https://docs.micropythonos.com/architecture/filesystem/
|
|
48
49
|
"""
|
|
49
50
|
setup_logging(verbosity=verbosity)
|
|
50
51
|
|
|
51
52
|
mpos_path = get_mpos_path()
|
|
52
|
-
|
|
53
|
-
internal_fs = mpos_path / 'internal_filesystem'
|
|
54
|
-
lib_mpos = internal_fs / 'lib' / 'mpos'
|
|
55
|
-
assert_is_dir(lib_mpos)
|
|
56
|
-
apps_path = internal_fs / 'apps'
|
|
57
|
-
assert_is_dir(apps_path)
|
|
53
|
+
resolver = MpOsPathResolver(mpos=mpos_path)
|
|
58
54
|
|
|
59
55
|
mpremote_bin = get_mpremote_bin()
|
|
60
56
|
|
|
61
57
|
print('\n')
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if not local_path
|
|
67
|
-
|
|
59
|
+
if not local_path:
|
|
60
|
+
# Let's the user select from the list of the newest modified files in internal_filesystem/lib/mpos:
|
|
61
|
+
local_path = get_newest_files(resolver.lib_mpos, limit=new_file_limit)
|
|
62
|
+
if not local_path:
|
|
63
|
+
print('Copy/update all files in lib/mpos to the device')
|
|
64
|
+
local_path = resolver.lib_mpos
|
|
68
65
|
|
|
69
|
-
|
|
66
|
+
print(f'Copy/update app: "{local_path}" ...')
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
if not local_path.exists():
|
|
69
|
+
print(f'[red]Error: The specified source path "{local_path}" does not exist.[/red]')
|
|
70
|
+
return
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
if local_path.is_relative_to(apps_path):
|
|
77
|
-
local_rel_path = local_path.relative_to(mpos_path)
|
|
78
|
-
remote_path = f':/{local_path.relative_to(internal_fs)}'
|
|
79
|
-
else:
|
|
80
|
-
raise NotImplementedError
|
|
81
|
-
else:
|
|
82
|
-
local_path = get_newest_files(lib_mpos, limit=new_file_limit)
|
|
83
|
-
if not local_path:
|
|
84
|
-
print('Copy/update all files in lib/mpos to the device')
|
|
85
|
-
local_path = lib_mpos
|
|
72
|
+
local_path_str, remote_str = resolver.resolve(local_path)
|
|
86
73
|
|
|
87
|
-
|
|
88
|
-
remote_path = f':/{local_path.relative_to(lib_mpos.parent)}'
|
|
74
|
+
popenargs = (mpremote_bin, 'fs')
|
|
89
75
|
|
|
90
76
|
if local_path.is_dir():
|
|
91
77
|
popenargs += ('-r',)
|
|
92
|
-
print(f'Copying directory "[bold]{
|
|
78
|
+
print(f'Copying directory "[bold]{local_path_str}[/bold]" to device at "[bold]{remote_str}[/bold]" ...')
|
|
93
79
|
else:
|
|
94
|
-
print(f'Copying file "[bold]{
|
|
80
|
+
print(f'Copying file "[bold]{local_path_str}[/bold]" to device at "[bold]{remote_str}[/bold]" ...')
|
|
95
81
|
|
|
96
|
-
popenargs += (local_rel_path, remote_path)
|
|
97
82
|
verbose_check_call(
|
|
98
83
|
*popenargs,
|
|
84
|
+
'cp',
|
|
85
|
+
local_path_str,
|
|
86
|
+
remote_str,
|
|
99
87
|
verbose=True,
|
|
100
88
|
cwd=mpos_path,
|
|
101
89
|
text=None,
|
|
@@ -112,15 +100,7 @@ def cp(
|
|
|
112
100
|
)
|
|
113
101
|
|
|
114
102
|
if repl:
|
|
115
|
-
|
|
116
|
-
verbose_check_call(
|
|
117
|
-
mpremote_bin,
|
|
118
|
-
'repl',
|
|
119
|
-
verbose=True,
|
|
120
|
-
cwd=mpos_path,
|
|
121
|
-
timeout=None,
|
|
122
|
-
text=None,
|
|
123
|
-
)
|
|
103
|
+
start_mpremote_repl()
|
|
124
104
|
|
|
125
105
|
|
|
126
106
|
@app.command
|
|
@@ -158,14 +138,14 @@ def cp_app(
|
|
|
158
138
|
|
|
159
139
|
if not app:
|
|
160
140
|
print('Copy/update all apps in "internal_filesystem/apps" to the device')
|
|
161
|
-
|
|
141
|
+
local_path = 'internal_filesystem/apps'
|
|
162
142
|
remote_path = ':/apps'
|
|
163
143
|
else:
|
|
164
144
|
print(f'Copy/update {app=} ...')
|
|
165
|
-
|
|
145
|
+
local_path = f'internal_filesystem/apps/{app.name}'
|
|
166
146
|
remote_path = f':/apps/{app.name}'
|
|
167
147
|
|
|
168
|
-
popenargs += (
|
|
148
|
+
popenargs += (local_path, remote_path)
|
|
169
149
|
verbose_check_call(
|
|
170
150
|
*popenargs,
|
|
171
151
|
verbose=True,
|
|
@@ -18,7 +18,15 @@ logger = logging.getLogger(__name__)
|
|
|
18
18
|
|
|
19
19
|
@app.command
|
|
20
20
|
def flash(
|
|
21
|
-
port: Annotated[
|
|
21
|
+
port: Annotated[
|
|
22
|
+
str | None,
|
|
23
|
+
tyro.conf.arg(
|
|
24
|
+
help=(
|
|
25
|
+
'Port used for esptool and mpremote, e.g.: "/dev/ttyUSB0" or "/dev/ttyACM0" etc.'
|
|
26
|
+
' Leave empty for autodetection'
|
|
27
|
+
)
|
|
28
|
+
),
|
|
29
|
+
] = None,
|
|
22
30
|
address: Annotated[str, tyro.conf.arg(help='Address')] = '0x0',
|
|
23
31
|
flash_size: Annotated[str, tyro.conf.arg(help='Flash Size')] = 'detect',
|
|
24
32
|
verify: Annotated[bool, tyro.conf.arg(help='Verify after flashing?')] = True,
|
|
@@ -46,10 +54,12 @@ def flash(
|
|
|
46
54
|
image_files = lvgl_micropython_build_path.glob('*.bin')
|
|
47
55
|
image_file = file_chooser(image_files)
|
|
48
56
|
|
|
57
|
+
popenargs = (esptool_bin,)
|
|
58
|
+
if port:
|
|
59
|
+
popenargs += ('--port', port)
|
|
60
|
+
|
|
49
61
|
verbose_check_call(
|
|
50
|
-
|
|
51
|
-
'--port',
|
|
52
|
-
port,
|
|
62
|
+
*popenargs,
|
|
53
63
|
'write-flash',
|
|
54
64
|
'--flash-size',
|
|
55
65
|
flash_size,
|
|
@@ -63,9 +73,7 @@ def flash(
|
|
|
63
73
|
|
|
64
74
|
if verify:
|
|
65
75
|
verbose_check_call(
|
|
66
|
-
|
|
67
|
-
'--port',
|
|
68
|
-
port,
|
|
76
|
+
*popenargs,
|
|
69
77
|
'verify-flash',
|
|
70
78
|
address,
|
|
71
79
|
image_file,
|
|
@@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
|
|
|
14
14
|
|
|
15
15
|
def _update_submodules(git: Git):
|
|
16
16
|
git.git_verbose_check_call('submodule', 'foreach', '--recursive', 'git', 'clean', '-f', ';', 'git', 'checkout', '.')
|
|
17
|
-
git.git_verbose_check_call('pull', '--recurse-submodules')
|
|
17
|
+
git.git_verbose_check_call('pull', '--recurse-submodules', '--force')
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
@app.command
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from unittest import TestCase
|
|
4
|
+
|
|
5
|
+
from mposcli.utilities.mpremote import MpOsPathResolver
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ProjectSetupTestCase(TestCase):
|
|
9
|
+
def test_mpos_path_resolver(self):
|
|
10
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
11
|
+
mpos_path = Path(temp_dir).resolve()
|
|
12
|
+
|
|
13
|
+
camera_assets = mpos_path / 'internal_filesystem/apps/com.micropythonos.camera/assets/'
|
|
14
|
+
camera_assets.mkdir(parents=True)
|
|
15
|
+
(camera_assets / 'camera_app.py').touch()
|
|
16
|
+
|
|
17
|
+
board_path = mpos_path / 'internal_filesystem/lib/mpos/board/'
|
|
18
|
+
board_path.mkdir(parents=True)
|
|
19
|
+
(board_path / 'unphone.py').touch()
|
|
20
|
+
|
|
21
|
+
(mpos_path / 'internal_filesystem/lib/drivers/display/hx8357d/').mkdir(parents=True)
|
|
22
|
+
|
|
23
|
+
resolver = MpOsPathResolver(mpos=mpos_path)
|
|
24
|
+
self.assertEqual(
|
|
25
|
+
resolver.resolve(mpos_path / 'internal_filesystem/apps/com.micropythonos.camera'),
|
|
26
|
+
(
|
|
27
|
+
'internal_filesystem/apps/com.micropythonos.camera/',
|
|
28
|
+
':apps/',
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
self.assertEqual(
|
|
32
|
+
resolver.resolve(mpos_path / 'internal_filesystem/apps/com.micropythonos.camera/assets/'),
|
|
33
|
+
(
|
|
34
|
+
'internal_filesystem/apps/com.micropythonos.camera/assets/',
|
|
35
|
+
':apps/com.micropythonos.camera/',
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
self.assertEqual(
|
|
39
|
+
resolver.resolve(mpos_path / 'internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py'),
|
|
40
|
+
(
|
|
41
|
+
'internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py',
|
|
42
|
+
':apps/com.micropythonos.camera/assets/camera_app.py',
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
self.assertEqual(
|
|
47
|
+
resolver.resolve(mpos_path / 'internal_filesystem/lib/mpos/board/'),
|
|
48
|
+
(
|
|
49
|
+
'internal_filesystem/lib/mpos/board/',
|
|
50
|
+
':mpos/',
|
|
51
|
+
),
|
|
52
|
+
)
|
|
53
|
+
self.assertEqual(
|
|
54
|
+
resolver.resolve(mpos_path / 'internal_filesystem/lib/mpos/board/unphone.py'),
|
|
55
|
+
(
|
|
56
|
+
'internal_filesystem/lib/mpos/board/unphone.py',
|
|
57
|
+
':mpos/board/unphone.py',
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
self.assertEqual(
|
|
62
|
+
resolver.resolve(mpos_path / 'internal_filesystem/lib/drivers/display/hx8357d'),
|
|
63
|
+
(
|
|
64
|
+
'internal_filesystem/lib/drivers/display/hx8357d/',
|
|
65
|
+
':lib/drivers/display/',
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
self.assertEqual(
|
|
69
|
+
resolver.resolve(mpos_path / 'internal_filesystem/lib/drivers/display'),
|
|
70
|
+
(
|
|
71
|
+
'internal_filesystem/lib/drivers/display/',
|
|
72
|
+
':lib/drivers/',
|
|
73
|
+
),
|
|
74
|
+
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import functools
|
|
1
2
|
import shutil
|
|
2
3
|
import sys
|
|
3
4
|
from pathlib import Path
|
|
@@ -15,12 +16,14 @@ def get_bin(name: str) -> Path:
|
|
|
15
16
|
return Path(bin_path)
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
@functools.cache
|
|
18
20
|
def get_esptool_bin() -> Path:
|
|
19
21
|
esptool_bin = get_bin('esptool')
|
|
20
22
|
verbose_check_call(esptool_bin, 'version')
|
|
21
23
|
return esptool_bin
|
|
22
24
|
|
|
23
25
|
|
|
26
|
+
@functools.cache
|
|
24
27
|
def get_mpremote_bin():
|
|
25
28
|
mpremote_bin = get_bin('mpremote')
|
|
26
29
|
verbose_check_call(mpremote_bin, '--version')
|
|
@@ -46,7 +46,7 @@ def file_chooser(paths) -> Path | None:
|
|
|
46
46
|
return selection
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def get_newest_files(directory, limit=10) -> Path | None:
|
|
49
|
+
def get_newest_files(directory: Path, limit=10) -> Path | None:
|
|
50
50
|
files = []
|
|
51
51
|
|
|
52
52
|
def scan(dir_path):
|
|
@@ -60,7 +60,7 @@ def get_newest_files(directory, limit=10) -> Path | None:
|
|
|
60
60
|
scan(directory)
|
|
61
61
|
files.sort(key=lambda x: x[1], reverse=True)
|
|
62
62
|
|
|
63
|
-
print(f'[bold]Choose a file[/bold] (only from the newest {limit}):\n')
|
|
63
|
+
print(f'[bold]Choose a file[/bold] (only from the newest {limit} from {directory}):\n')
|
|
64
64
|
for idx, (entry, mtime) in enumerate(files[:limit]):
|
|
65
65
|
dt = datetime.datetime.fromtimestamp(mtime).astimezone().strftime('%Y-%m-%d %H:%M:%S')
|
|
66
66
|
rel_path = Path(entry.path).relative_to(directory)
|
|
@@ -85,8 +85,9 @@ def get_newest_files(directory, limit=10) -> Path | None:
|
|
|
85
85
|
print(f'[red]Invalid selection: {number}[/red]')
|
|
86
86
|
sys.exit(1)
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
absolute_path = directory / selection
|
|
89
|
+
print(f'Selected file: {absolute_path}')
|
|
90
|
+
return absolute_path
|
|
90
91
|
|
|
91
92
|
|
|
92
93
|
def choose_newest_modified_directory(base_dir: Path) -> Path:
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import shlex
|
|
2
|
+
import subprocess
|
|
3
|
+
import time
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from bx_py_utils.path import assert_is_dir
|
|
7
|
+
from rich import print
|
|
8
|
+
|
|
9
|
+
from mposcli.tools import get_mpremote_bin
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MpOsPathResolver:
|
|
13
|
+
def __init__(self, mpos: Path):
|
|
14
|
+
self.mpos = mpos # e.g.: ~/repos/MicroPythonOS
|
|
15
|
+
self.internal_fs = mpos / 'internal_filesystem'
|
|
16
|
+
self.lib_mpos = self.internal_fs / 'lib' / 'mpos'
|
|
17
|
+
assert_is_dir(self.lib_mpos)
|
|
18
|
+
self.apps_path = self.internal_fs / 'apps'
|
|
19
|
+
assert_is_dir(self.apps_path)
|
|
20
|
+
|
|
21
|
+
def resolve(self, source: Path):
|
|
22
|
+
source = source.resolve()
|
|
23
|
+
assert source.exists(), f'Not existing path: {source=}'
|
|
24
|
+
assert source.is_relative_to(self.mpos), f'{source=} is not inside {self.mpos=}'
|
|
25
|
+
|
|
26
|
+
if source.is_relative_to(self.apps_path):
|
|
27
|
+
device_base_path = self.apps_path.parent
|
|
28
|
+
elif source.is_relative_to(self.lib_mpos):
|
|
29
|
+
device_base_path = self.lib_mpos.parent
|
|
30
|
+
elif source.is_relative_to(self.internal_fs):
|
|
31
|
+
device_base_path = self.internal_fs
|
|
32
|
+
else:
|
|
33
|
+
raise ValueError(f'Path {source} is not in a recognized location')
|
|
34
|
+
|
|
35
|
+
remote_path = source.relative_to(device_base_path)
|
|
36
|
+
source_path = source.relative_to(self.mpos)
|
|
37
|
+
if source.is_dir():
|
|
38
|
+
remote_path = remote_path.parent
|
|
39
|
+
local_path_str = f'{source_path}/'
|
|
40
|
+
remote_str = f':{remote_path}/'
|
|
41
|
+
else:
|
|
42
|
+
local_path_str = f'{source_path}'
|
|
43
|
+
remote_str = f':{remote_path}'
|
|
44
|
+
|
|
45
|
+
return local_path_str, remote_str
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def start_mpremote_repl(max_try=10, wait_time=1):
|
|
49
|
+
print('Starting mpremote REPL...')
|
|
50
|
+
time.sleep(wait_time)
|
|
51
|
+
mpremote_bin = get_mpremote_bin()
|
|
52
|
+
|
|
53
|
+
popen_args = (mpremote_bin, 'repl')
|
|
54
|
+
|
|
55
|
+
for try_count in range(max_try):
|
|
56
|
+
print(f'\n+ {shlex.join(str(arg) for arg in popen_args)}')
|
|
57
|
+
try:
|
|
58
|
+
return subprocess.check_call(popen_args)
|
|
59
|
+
except subprocess.CalledProcessError as err:
|
|
60
|
+
print(
|
|
61
|
+
f'[yellow]mpremote finished with [red]exit code {err.returncode!r}[/red]'
|
|
62
|
+
f' Retrying in {wait_time} seconds... (try {try_count + 1}/{max_try})'
|
|
63
|
+
)
|
|
64
|
+
time.sleep(wait_time)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|