mposcli 0.1.0__tar.gz → 0.2.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.
Files changed (47) hide show
  1. {mposcli-0.1.0 → mposcli-0.2.0}/PKG-INFO +76 -3
  2. {mposcli-0.1.0 → mposcli-0.2.0}/README.md +75 -2
  3. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/__init__.py +1 -1
  4. mposcli-0.2.0/mposcli/cli_app/copy_mpos.py +92 -0
  5. mposcli-0.2.0/mposcli/cli_app/flash.py +87 -0
  6. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/tests/test_readme.py +1 -1
  7. mposcli-0.2.0/mposcli/tools.py +27 -0
  8. mposcli-0.2.0/mposcli/user_input.py +87 -0
  9. mposcli-0.1.0/mposcli/user_input.py +0 -37
  10. {mposcli-0.1.0 → mposcli-0.2.0}/.editorconfig +0 -0
  11. {mposcli-0.1.0 → mposcli-0.2.0}/.github/workflows/tests.yml +0 -0
  12. {mposcli-0.1.0 → mposcli-0.2.0}/.gitignore +0 -0
  13. {mposcli-0.1.0 → mposcli-0.2.0}/.idea/.gitignore +0 -0
  14. {mposcli-0.1.0 → mposcli-0.2.0}/.pre-commit-config.yaml +0 -0
  15. {mposcli-0.1.0 → mposcli-0.2.0}/.pre-commit-hooks.yaml +0 -0
  16. {mposcli-0.1.0 → mposcli-0.2.0}/.run/Template Python tests.run.xml +0 -0
  17. {mposcli-0.1.0 → mposcli-0.2.0}/.run/Template Python.run.xml +0 -0
  18. {mposcli-0.1.0 → mposcli-0.2.0}/.run/Unittests __all__.run.xml +0 -0
  19. {mposcli-0.1.0 → mposcli-0.2.0}/.run/cli --help.run.xml +0 -0
  20. {mposcli-0.1.0 → mposcli-0.2.0}/.run/dev-cli --help.run.xml +0 -0
  21. {mposcli-0.1.0 → mposcli-0.2.0}/.run/dev-cli test.run.xml +0 -0
  22. {mposcli-0.1.0 → mposcli-0.2.0}/.venv-app/.gitignore +0 -0
  23. {mposcli-0.1.0 → mposcli-0.2.0}/cli.py +0 -0
  24. {mposcli-0.1.0 → mposcli-0.2.0}/dev-cli.py +0 -0
  25. {mposcli-0.1.0 → mposcli-0.2.0}/dist/.gitignore +0 -0
  26. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/__main__.py +0 -0
  27. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_app/__init__.py +0 -0
  28. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_app/build.py +0 -0
  29. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_app/run_deskop.py +0 -0
  30. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_app/update.py +0 -0
  31. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_dev/__init__.py +0 -0
  32. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_dev/__main__.py +0 -0
  33. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_dev/code_style.py +0 -0
  34. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_dev/packaging.py +0 -0
  35. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_dev/shell_completion.py +0 -0
  36. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_dev/testing.py +0 -0
  37. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/cli_dev/update_readme_history.py +0 -0
  38. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/constants.py +0 -0
  39. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/fs_utils.py +0 -0
  40. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/mpos_utils.py +0 -0
  41. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/tests/__init__.py +0 -0
  42. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/tests/test_doctests.py +0 -0
  43. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/tests/test_project_setup.py +0 -0
  44. {mposcli-0.1.0 → mposcli-0.2.0}/mposcli/tests/test_readme_history.py +0 -0
  45. {mposcli-0.1.0 → mposcli-0.2.0}/noxfile.py +0 -0
  46. {mposcli-0.1.0 → mposcli-0.2.0}/pyproject.toml +0 -0
  47. {mposcli-0.1.0 → mposcli-0.2.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mposcli
3
- Version: 0.1.0
3
+ Version: 0.2.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
@@ -25,11 +25,29 @@ Experimental CLI helper for MicroPythonOS: https://github.com/MicroPythonOS/Micr
25
25
 
26
26
  Main Idea: Install it via pipx (see below) and use `mposcli` command in MicroPythonOS repository path.
27
27
 
28
+ Install, e.g.:
29
+
30
+ ```
31
+ sudo apt install pipx
32
+
33
+ pipx install mposcli
34
+ ```
35
+
36
+ To upgrade an existing installation: Just call: `pipx upgrade PyHardLinkBackup`
37
+
38
+ Usage e.g.:
39
+
40
+ ```
41
+ cd ~/MicroPythonOS
42
+ ~/MicroPythonOS$ mposcli run-desktop
43
+ ```
44
+
45
+
28
46
  ## CLI
29
47
 
30
48
  [comment]: <> (✂✂✂ auto generated main help start ✂✂✂)
31
49
  ```
32
- usage: mposcli [-h] {build,run-desktop,update-submodules,version}
50
+ usage: mposcli [-h] {build,cp,flash,run-desktop,update-submodules,version}
33
51
 
34
52
 
35
53
 
@@ -40,6 +58,12 @@ usage: mposcli [-h] {build,run-desktop,update-submodules,version}
40
58
  │ (required) │
41
59
  │ • build Build MicroPythonOS by calling: ./scripts/build_mpos.sh <target> see: │
42
60
  │ https://docs.micropythonos.com/os-development/ │
61
+ │ • cp Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp". Display a │
62
+ │ file chooser to select which files to copy/update. But can also be used to copy/update all │
63
+ │ files. see: https://docs.micropythonos.com/os-development/installing-on-esp32/ │
64
+ │ • flash Flash MicroPythonOS to the device. Display a file chooser to select the image to flash. All │
65
+ │ lvgl_micropython/build/*.bin files will be shown in the file chooser. see: │
66
+ │ https://docs.micropythonos.com/os-development/installing-on-esp32/ │
43
67
  │ • run-desktop Run MicroPythonOS on desktop. see: │
44
68
  │ https://docs.micropythonos.com/getting-started/running/#running-on-desktop │
45
69
  │ • update-submodules Update MicroPythonOS repository and all submodules see: │
@@ -50,6 +74,7 @@ usage: mposcli [-h] {build,run-desktop,update-submodules,version}
50
74
  [comment]: <> (✂✂✂ auto generated main help end ✂✂✂)
51
75
 
52
76
 
77
+
53
78
  ## CLI - build
54
79
 
55
80
  [comment]: <> (✂✂✂ auto generated build start ✂✂✂)
@@ -69,6 +94,50 @@ Build MicroPythonOS by calling: ./scripts/build_mpos.sh <target> see: https://do
69
94
 
70
95
 
71
96
 
97
+ ## CLI - cp
98
+
99
+ [comment]: <> (✂✂✂ auto generated cp start ✂✂✂)
100
+ ```
101
+ usage: mposcli cp [-h] [--new-file-limit INT] [--reset | --no-reset] [--repl | --no-repl] [-v]
102
+
103
+ Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp". Display a file chooser to select which files to copy/update. But can also be used to copy/update all files. see: https://docs.micropythonos.com/os-development/installing-on-esp32/
104
+
105
+ ╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
106
+ │ -h, --help show this help message and exit │
107
+ │ --new-file-limit INT How many of the newest files to show in the file chooser? (default: 10) │
108
+ │ --reset, --no-reset Reset the device after copy/update? (default: True) │
109
+ │ --repl, --no-repl After flashing/verify start REPL with mpremote to see the output of the device? (default: │
110
+ │ True) │
111
+ │ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
112
+ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
113
+ ```
114
+ [comment]: <> (✂✂✂ auto generated cp end ✂✂✂)
115
+
116
+
117
+
118
+ ## CLI - flash
119
+
120
+ [comment]: <> (✂✂✂ auto generated flash start ✂✂✂)
121
+ ```
122
+ usage: mposcli flash [-h] [FLASH OPTIONS]
123
+
124
+ Flash MicroPythonOS to the device. Display a file chooser to select the image to flash. All lvgl_micropython/build/*.bin files will be shown in the file chooser. see: https://docs.micropythonos.com/os-development/installing-on-esp32/
125
+
126
+ ╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
127
+ │ -h, --help show this help message and exit │
128
+ │ --port STR Port used for esptool and mpremote (default: /dev/ttyUSB0) │
129
+ │ --address STR Address (default: 0x0) │
130
+ │ --flash-size STR Flash Size (default: detect) │
131
+ │ --verify, --no-verify Verify after flashing? (default: True) │
132
+ │ --repl, --no-repl After flashing/verify start REPL with mpremote to see the output of the device? (default: │
133
+ │ True) │
134
+ │ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
135
+ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
136
+ ```
137
+ [comment]: <> (✂✂✂ auto generated flash end ✂✂✂)
138
+
139
+
140
+
72
141
  ## CLI - run-desktop
73
142
 
74
143
 
@@ -169,7 +238,11 @@ usage: ./dev-cli.py [-h] {coverage,install,lint,mypy,nox,pip-audit,publish,shell
169
238
 
170
239
  [comment]: <> (✂✂✂ auto generated history start ✂✂✂)
171
240
 
172
- * [**dev**](https://github.com/jedie/mposcli/compare/1695026...main)
241
+ * [v0.2.0](https://github.com/jedie/mposcli/compare/v0.1.0...v0.2.0)
242
+ * 2026-02-16 - New CLI command: "cp" with convenience features.
243
+ * 2026-02-16 - New command: "flash" with file selector
244
+ * 2026-02-16 - Update README.md
245
+ * [v0.1.0](https://github.com/jedie/mposcli/compare/1695026...v0.1.0)
173
246
  * 2026-02-16 - Add "update-submodules" command
174
247
  * 2026-02-16 - Add "build" command
175
248
  * 2026-02-16 - CLI command: "run-desktop"
@@ -10,11 +10,29 @@ Experimental CLI helper for MicroPythonOS: https://github.com/MicroPythonOS/Micr
10
10
 
11
11
  Main Idea: Install it via pipx (see below) and use `mposcli` command in MicroPythonOS repository path.
12
12
 
13
+ Install, e.g.:
14
+
15
+ ```
16
+ sudo apt install pipx
17
+
18
+ pipx install mposcli
19
+ ```
20
+
21
+ To upgrade an existing installation: Just call: `pipx upgrade PyHardLinkBackup`
22
+
23
+ Usage e.g.:
24
+
25
+ ```
26
+ cd ~/MicroPythonOS
27
+ ~/MicroPythonOS$ mposcli run-desktop
28
+ ```
29
+
30
+
13
31
  ## CLI
14
32
 
15
33
  [comment]: <> (✂✂✂ auto generated main help start ✂✂✂)
16
34
  ```
17
- usage: mposcli [-h] {build,run-desktop,update-submodules,version}
35
+ usage: mposcli [-h] {build,cp,flash,run-desktop,update-submodules,version}
18
36
 
19
37
 
20
38
 
@@ -25,6 +43,12 @@ usage: mposcli [-h] {build,run-desktop,update-submodules,version}
25
43
  │ (required) │
26
44
  │ • build Build MicroPythonOS by calling: ./scripts/build_mpos.sh <target> see: │
27
45
  │ https://docs.micropythonos.com/os-development/ │
46
+ │ • cp Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp". Display a │
47
+ │ file chooser to select which files to copy/update. But can also be used to copy/update all │
48
+ │ files. see: https://docs.micropythonos.com/os-development/installing-on-esp32/ │
49
+ │ • flash Flash MicroPythonOS to the device. Display a file chooser to select the image to flash. All │
50
+ │ lvgl_micropython/build/*.bin files will be shown in the file chooser. see: │
51
+ │ https://docs.micropythonos.com/os-development/installing-on-esp32/ │
28
52
  │ • run-desktop Run MicroPythonOS on desktop. see: │
29
53
  │ https://docs.micropythonos.com/getting-started/running/#running-on-desktop │
30
54
  │ • update-submodules Update MicroPythonOS repository and all submodules see: │
@@ -35,6 +59,7 @@ usage: mposcli [-h] {build,run-desktop,update-submodules,version}
35
59
  [comment]: <> (✂✂✂ auto generated main help end ✂✂✂)
36
60
 
37
61
 
62
+
38
63
  ## CLI - build
39
64
 
40
65
  [comment]: <> (✂✂✂ auto generated build start ✂✂✂)
@@ -54,6 +79,50 @@ Build MicroPythonOS by calling: ./scripts/build_mpos.sh <target> see: https://do
54
79
 
55
80
 
56
81
 
82
+ ## CLI - cp
83
+
84
+ [comment]: <> (✂✂✂ auto generated cp start ✂✂✂)
85
+ ```
86
+ usage: mposcli cp [-h] [--new-file-limit INT] [--reset | --no-reset] [--repl | --no-repl] [-v]
87
+
88
+ Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp". Display a file chooser to select which files to copy/update. But can also be used to copy/update all files. see: https://docs.micropythonos.com/os-development/installing-on-esp32/
89
+
90
+ ╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
91
+ │ -h, --help show this help message and exit │
92
+ │ --new-file-limit INT How many of the newest files to show in the file chooser? (default: 10) │
93
+ │ --reset, --no-reset Reset the device after copy/update? (default: True) │
94
+ │ --repl, --no-repl After flashing/verify start REPL with mpremote to see the output of the device? (default: │
95
+ │ True) │
96
+ │ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
97
+ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
98
+ ```
99
+ [comment]: <> (✂✂✂ auto generated cp end ✂✂✂)
100
+
101
+
102
+
103
+ ## CLI - flash
104
+
105
+ [comment]: <> (✂✂✂ auto generated flash start ✂✂✂)
106
+ ```
107
+ usage: mposcli flash [-h] [FLASH OPTIONS]
108
+
109
+ Flash MicroPythonOS to the device. Display a file chooser to select the image to flash. All lvgl_micropython/build/*.bin files will be shown in the file chooser. see: https://docs.micropythonos.com/os-development/installing-on-esp32/
110
+
111
+ ╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
112
+ │ -h, --help show this help message and exit │
113
+ │ --port STR Port used for esptool and mpremote (default: /dev/ttyUSB0) │
114
+ │ --address STR Address (default: 0x0) │
115
+ │ --flash-size STR Flash Size (default: detect) │
116
+ │ --verify, --no-verify Verify after flashing? (default: True) │
117
+ │ --repl, --no-repl After flashing/verify start REPL with mpremote to see the output of the device? (default: │
118
+ │ True) │
119
+ │ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
120
+ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
121
+ ```
122
+ [comment]: <> (✂✂✂ auto generated flash end ✂✂✂)
123
+
124
+
125
+
57
126
  ## CLI - run-desktop
58
127
 
59
128
 
@@ -154,7 +223,11 @@ usage: ./dev-cli.py [-h] {coverage,install,lint,mypy,nox,pip-audit,publish,shell
154
223
 
155
224
  [comment]: <> (✂✂✂ auto generated history start ✂✂✂)
156
225
 
157
- * [**dev**](https://github.com/jedie/mposcli/compare/1695026...main)
226
+ * [v0.2.0](https://github.com/jedie/mposcli/compare/v0.1.0...v0.2.0)
227
+ * 2026-02-16 - New CLI command: "cp" with convenience features.
228
+ * 2026-02-16 - New command: "flash" with file selector
229
+ * 2026-02-16 - Update README.md
230
+ * [v0.1.0](https://github.com/jedie/mposcli/compare/1695026...v0.1.0)
158
231
  * 2026-02-16 - Add "update-submodules" command
159
232
  * 2026-02-16 - Add "build" command
160
233
  * 2026-02-16 - CLI command: "run-desktop"
@@ -4,5 +4,5 @@
4
4
  """
5
5
 
6
6
  # See https://packaging.python.org/en/latest/specifications/version-specifiers/
7
- __version__ = '0.1.0'
7
+ __version__ = '0.2.0'
8
8
  __author__ = 'Jens Diemer <cookiecutter_templates@jensdiemer.de>'
@@ -0,0 +1,92 @@
1
+
2
+ import logging
3
+ from typing import Annotated
4
+
5
+ import tyro
6
+ from bx_py_utils.path import assert_is_dir
7
+ from cli_base.cli_tools.subprocess_utils import verbose_check_call
8
+ from cli_base.cli_tools.verbosity import setup_logging
9
+ from cli_base.tyro_commands import TyroVerbosityArgType
10
+ from rich import print # noqa
11
+
12
+ from mposcli.cli_app import app
13
+ from mposcli.mpos_utils import get_mpos_path
14
+ from mposcli.tools import get_mpremote_bin
15
+ from mposcli.user_input import get_newest_files
16
+
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @app.command
22
+ def cp(
23
+ new_file_limit: Annotated[
24
+ int,
25
+ tyro.conf.arg(help='How many of the newest files to show in the file chooser?'),
26
+ ] = 10,
27
+ reset: Annotated[
28
+ bool,
29
+ tyro.conf.arg(help='Reset the device after copy/update?'),
30
+ ] = True,
31
+ repl: Annotated[
32
+ bool,
33
+ tyro.conf.arg(help='After flashing/verify start REPL with mpremote to see the output of the device?'),
34
+ ] = True,
35
+ verbosity: TyroVerbosityArgType = 1,
36
+ ):
37
+ """
38
+ Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp".
39
+ Display a file chooser to select which files to copy/update.
40
+ But can also be used to copy/update all files.
41
+ see: https://docs.micropythonos.com/os-development/installing-on-esp32/
42
+ """
43
+ setup_logging(verbosity=verbosity)
44
+
45
+ mpos_path = get_mpos_path()
46
+
47
+ internal_fs = mpos_path / 'internal_filesystem'
48
+ lib_mpos = internal_fs / 'lib' / 'mpos'
49
+ assert_is_dir(lib_mpos)
50
+
51
+ mpremote_bin = get_mpremote_bin()
52
+
53
+ print('\n')
54
+
55
+ local_path = get_newest_files(lib_mpos, limit=new_file_limit)
56
+
57
+ popenargs = (mpremote_bin, 'fs', 'cp')
58
+
59
+ if not local_path:
60
+ print('Copy/update all files in lib/mpos to the device')
61
+ local_path = lib_mpos
62
+ popenargs += ('-r',)
63
+
64
+ local_rel_path = local_path.relative_to(mpos_path)
65
+ remote_path = f':/{local_path.relative_to(lib_mpos.parent)}'
66
+
67
+ print(f'Copying "[bold]{local_rel_path}[/bold]" to device at "[bold]{remote_path}[/bold]" ...')
68
+
69
+ popenargs += (local_rel_path, remote_path)
70
+ verbose_check_call(
71
+ *popenargs,
72
+ verbose=True,
73
+ cwd=mpos_path,
74
+ text=None,
75
+ )
76
+ if reset:
77
+ verbose_check_call(
78
+ mpremote_bin,
79
+ 'reset',
80
+ verbose=True,
81
+ cwd=mpos_path,
82
+ text=None,
83
+ )
84
+ if repl:
85
+ verbose_check_call(
86
+ mpremote_bin,
87
+ 'repl',
88
+ verbose=True,
89
+ cwd=mpos_path,
90
+ timeout=None,
91
+ text=None,
92
+ )
@@ -0,0 +1,87 @@
1
+ import logging
2
+ from typing import Annotated
3
+
4
+ import tyro
5
+ from cli_base.cli_tools.subprocess_utils import verbose_check_call
6
+ from cli_base.cli_tools.verbosity import setup_logging
7
+ from cli_base.tyro_commands import TyroVerbosityArgType
8
+ from rich import print # noqa
9
+
10
+ from mposcli.cli_app import app
11
+ from mposcli.mpos_utils import get_mpos_path
12
+ from mposcli.tools import get_esptool_bin, get_mpremote_bin
13
+ from mposcli.user_input import file_chooser
14
+
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ @app.command
20
+ def flash(
21
+ port: Annotated[str, tyro.conf.arg(help='Port used for esptool and mpremote')] = '/dev/ttyUSB0',
22
+ address: Annotated[str, tyro.conf.arg(help='Address')] = '0x0',
23
+ flash_size: Annotated[str, tyro.conf.arg(help='Flash Size')] = 'detect',
24
+ verify: Annotated[bool, tyro.conf.arg(help='Verify after flashing?')] = True,
25
+ repl: Annotated[
26
+ bool,
27
+ tyro.conf.arg(help='After flashing/verify start REPL with mpremote to see the output of the device?'),
28
+ ] = True,
29
+ verbosity: TyroVerbosityArgType = 1,
30
+ ):
31
+ """
32
+ Flash MicroPythonOS to the device. Display a file chooser to select the image to flash.
33
+ All lvgl_micropython/build/*.bin files will be shown in the file chooser.
34
+ see: https://docs.micropythonos.com/os-development/installing-on-esp32/
35
+ """
36
+ setup_logging(verbosity=verbosity)
37
+
38
+ mpos_path = get_mpos_path()
39
+
40
+ esptool_bin = get_esptool_bin()
41
+ mpremote_bin = get_mpremote_bin()
42
+
43
+ print('\n')
44
+
45
+ lvgl_micropython_build_path = mpos_path / 'lvgl_micropython' / 'build'
46
+ image_files = lvgl_micropython_build_path.glob('*.bin')
47
+ image_file = file_chooser(image_files)
48
+
49
+ verbose_check_call(
50
+ esptool_bin,
51
+ '--port',
52
+ port,
53
+ 'write-flash',
54
+ '--flash-size',
55
+ flash_size,
56
+ address,
57
+ image_file,
58
+ verbose=True,
59
+ cwd=mpos_path,
60
+ timeout=None,
61
+ text=None,
62
+ )
63
+
64
+ if verify:
65
+ verbose_check_call(
66
+ esptool_bin,
67
+ '--port',
68
+ port,
69
+ 'verify-flash',
70
+ address,
71
+ image_file,
72
+ verbose=True,
73
+ cwd=mpos_path,
74
+ timeout=None,
75
+ text=None,
76
+ )
77
+
78
+ if repl:
79
+ verbose_check_call(
80
+ mpremote_bin,
81
+ 'repl',
82
+ port,
83
+ verbose=True,
84
+ cwd=mpos_path,
85
+ timeout=None,
86
+ text=None,
87
+ )
@@ -71,7 +71,7 @@ class ReadmeTestCase(BaseTestCase):
71
71
 
72
72
  commands.discard('version') # version is pseudo command, because the version always printed on every CLI call
73
73
  commands = sorted(commands)
74
- self.assertEqual(commands, ['build', 'run-desktop', 'update-submodules'])
74
+ self.assertEqual(commands, ['build', 'cp', 'flash', 'run-desktop', 'update-submodules'])
75
75
 
76
76
  for command in commands:
77
77
  with self.subTest(command):
@@ -0,0 +1,27 @@
1
+ import shutil
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ from cli_base.cli_tools.subprocess_utils import verbose_check_call
6
+
7
+
8
+ def get_bin(name: str) -> Path:
9
+ bin_path = shutil.which(name)
10
+ if bin_path is None:
11
+ print(f'[red]Error: {name} is not installed or not found in PATH.[/red]')
12
+ print('Hint: Install via pipx, e.g.:')
13
+ print(f'\tpipx install {name}')
14
+ sys.exit(1)
15
+ return Path(bin_path)
16
+
17
+
18
+ def get_esptool_bin() -> Path:
19
+ esptool_bin = get_bin('esptool')
20
+ verbose_check_call(esptool_bin, 'version')
21
+ return esptool_bin
22
+
23
+
24
+ def get_mpremote_bin():
25
+ mpremote_bin = get_bin('mpremote')
26
+ verbose_check_call(mpremote_bin, '--version')
27
+ return mpremote_bin
@@ -0,0 +1,87 @@
1
+ import datetime
2
+ import os
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ from rich import print
7
+
8
+
9
+ def file_chooser(paths) -> Path | None:
10
+ """
11
+ Display a numbered list of files sorted by modification time (newest first).
12
+ Show mtime and file name. Input number, ENTER = 1. Return selected Path.
13
+ """
14
+ print()
15
+
16
+ files = [(p, p.stat().st_mtime) for p in paths if p.is_file()]
17
+ if not files:
18
+ print('[red]No files found.[/red]')
19
+ return None
20
+ files.sort(key=lambda x: x[1], reverse=True)
21
+
22
+ print('[bold]Choose a file:[/bold]\n')
23
+ for idx, (p, mtime) in enumerate(files):
24
+ dt = datetime.datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S')
25
+ print(f'[{idx}] {dt} - {p.name}')
26
+
27
+ print()
28
+
29
+ number = input('Enter number (ENTER = 0 - the newest file): ').strip() or 0
30
+ print('Selected:', number)
31
+ try:
32
+ number = int(number)
33
+ except Exception as err:
34
+ print(f'[red]Invalid input: {err}[/red]')
35
+ sys.exit(1)
36
+
37
+ try:
38
+ selection = files[number][0]
39
+ except IndexError:
40
+ print(f'[red]Invalid selection: {number}[/red]')
41
+ sys.exit(1)
42
+
43
+ print(f'Selected file: {selection}')
44
+ return selection
45
+
46
+
47
+ def get_newest_files(directory, limit=10) -> Path | None:
48
+ files = []
49
+
50
+ def scan(dir_path):
51
+ with os.scandir(dir_path) as it:
52
+ for entry in it:
53
+ if entry.is_file(follow_symlinks=False):
54
+ files.append((entry, entry.stat().st_mtime))
55
+ elif entry.is_dir(follow_symlinks=False):
56
+ scan(entry.path)
57
+
58
+ scan(directory)
59
+ files.sort(key=lambda x: x[1], reverse=True)
60
+
61
+ print(f'[bold]Choose a file[/bold] (only from the newest {limit}):\n')
62
+ for idx, (entry, mtime) in enumerate(files[:limit]):
63
+ dt = datetime.datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S')
64
+ rel_path = Path(entry.path).relative_to(directory)
65
+ print(f'[{idx}] {dt} - {rel_path}')
66
+
67
+ print()
68
+
69
+ number = input('Enter number (ENTER = 0 - the newest file, "a" for all files): ').strip() or '0'
70
+ print('Selected:', number)
71
+ if number.lower() == 'a':
72
+ return None
73
+
74
+ try:
75
+ number = int(number)
76
+ except Exception as err:
77
+ print(f'[red]Invalid input: {err}[/red]')
78
+ sys.exit(1)
79
+
80
+ try:
81
+ selection = files[number][0]
82
+ except IndexError:
83
+ print(f'[red]Invalid selection: {number}[/red]')
84
+ sys.exit(1)
85
+
86
+ print(f'Selected file: {selection}')
87
+ return Path(selection)
@@ -1,37 +0,0 @@
1
- import datetime
2
- import sys
3
-
4
- from rich import print
5
-
6
-
7
- def file_chooser(paths):
8
- """
9
- Display a numbered list of files sorted by modification time (newest first).
10
- Show mtime and file name. Input number, ENTER = 1. Return selected Path.
11
- """
12
-
13
- files = [(p, p.stat().st_mtime) for p in paths if p.is_file()]
14
- if not files:
15
- print('[red]No files found.[/red]')
16
- return None
17
- files.sort(key=lambda x: x[1], reverse=True)
18
-
19
- print('[bold]Choose a file:[/bold]')
20
- for idx, (p, mtime) in enumerate(files):
21
- dt = datetime.datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S')
22
- print(f'[{idx}] {dt} {p.name}')
23
-
24
- number = input('Enter number (ENTER = 0 - the newest file): ').strip() or 0
25
- try:
26
- number = int(number)
27
- except Exception as err:
28
- print(f'[red]Invalid input: {err}[/red]')
29
- sys.exit(1)
30
-
31
- try:
32
- selection = files[number][0]
33
- except IndexError:
34
- print(f'[red]Invalid selection: {number}[/red]')
35
- sys.exit(1)
36
-
37
- return selection
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