mposcli 0.4.1__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.1 → mposcli-0.5.0}/PKG-INFO +17 -10
- {mposcli-0.4.1 → mposcli-0.5.0}/README.md +16 -9
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/__init__.py +1 -1
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_app/build.py +1 -1
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_app/copy_mpos.py +24 -44
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_app/flash.py +15 -7
- mposcli-0.5.0/mposcli/tests/test_mpremote_cp_utils.py +74 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/tools.py +3 -0
- {mposcli-0.4.1 → 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.1 → mposcli-0.5.0}/.editorconfig +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.github/workflows/tests.yml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.idea/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.pre-commit-config.yaml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.pre-commit-hooks.yaml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.run/Template Python tests.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.run/Template Python.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.run/Unittests __all__.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.run/cli --help.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.run/dev-cli --help.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.run/dev-cli test.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.venv-app/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/.venv-app/lib/python3.14/site-packages/cli_base/tests/shell_complete_snapshots/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/cli.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/dev-cli.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/dist/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/__main__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_app/__init__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_app/run_deskop.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_app/update.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_dev/__init__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_dev/__main__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_dev/code_style.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_dev/packaging.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_dev/shell_completion.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_dev/testing.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/cli_dev/update_readme_history.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/constants.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/fs_utils.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/mpos_utils.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/tests/__init__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/tests/test_doctests.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/tests/test_project_setup.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/tests/test_readme.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/mposcli/tests/test_readme_history.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/noxfile.py +0 -0
- {mposcli-0.4.1 → mposcli-0.5.0}/pyproject.toml +0 -0
- {mposcli-0.4.1 → 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,11 @@ 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
|
|
320
327
|
* [v0.4.1](https://github.com/jedie/mposcli/compare/v0.4.0...v0.4.1)
|
|
321
328
|
* 2026-02-27 - Use "--force" for pulling submodules to overwrite local changes
|
|
322
329
|
* [v0.4.0](https://github.com/jedie/mposcli/compare/v0.3.0...v0.4.0)
|
|
@@ -329,13 +336,13 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
329
336
|
* 2026-02-18 - Add "update" beside "update-submodules"
|
|
330
337
|
* 2026-02-17 - Update requirements
|
|
331
338
|
* 2026-02-16 - update README
|
|
339
|
+
|
|
340
|
+
<details><summary>Expand older history entries ...</summary>
|
|
341
|
+
|
|
332
342
|
* [v0.2.0](https://github.com/jedie/mposcli/compare/v0.1.0...v0.2.0)
|
|
333
343
|
* 2026-02-16 - New CLI command: "cp" with convenience features.
|
|
334
344
|
* 2026-02-16 - New command: "flash" with file selector
|
|
335
345
|
* 2026-02-16 - Update README.md
|
|
336
|
-
|
|
337
|
-
<details><summary>Expand older history entries ...</summary>
|
|
338
|
-
|
|
339
346
|
* [v0.1.0](https://github.com/jedie/mposcli/compare/1695026...v0.1.0)
|
|
340
347
|
* 2026-02-16 - Add "update-submodules" command
|
|
341
348
|
* 2026-02-16 - Add "build" command
|
|
@@ -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,11 @@ 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
|
|
305
312
|
* [v0.4.1](https://github.com/jedie/mposcli/compare/v0.4.0...v0.4.1)
|
|
306
313
|
* 2026-02-27 - Use "--force" for pulling submodules to overwrite local changes
|
|
307
314
|
* [v0.4.0](https://github.com/jedie/mposcli/compare/v0.3.0...v0.4.0)
|
|
@@ -314,13 +321,13 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
314
321
|
* 2026-02-18 - Add "update" beside "update-submodules"
|
|
315
322
|
* 2026-02-17 - Update requirements
|
|
316
323
|
* 2026-02-16 - update README
|
|
324
|
+
|
|
325
|
+
<details><summary>Expand older history entries ...</summary>
|
|
326
|
+
|
|
317
327
|
* [v0.2.0](https://github.com/jedie/mposcli/compare/v0.1.0...v0.2.0)
|
|
318
328
|
* 2026-02-16 - New CLI command: "cp" with convenience features.
|
|
319
329
|
* 2026-02-16 - New command: "flash" with file selector
|
|
320
330
|
* 2026-02-16 - Update README.md
|
|
321
|
-
|
|
322
|
-
<details><summary>Expand older history entries ...</summary>
|
|
323
|
-
|
|
324
331
|
* [v0.1.0](https://github.com/jedie/mposcli/compare/1695026...v0.1.0)
|
|
325
332
|
* 2026-02-16 - Add "update-submodules" command
|
|
326
333
|
* 2026-02-16 - Add "build" command
|
|
@@ -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,
|
|
@@ -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
|
|
File without changes
|