littlefs-python 0.15.0__tar.gz → 0.17.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 (133) hide show
  1. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/.github/workflows/deploy.yml +11 -10
  2. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/.github/workflows/run-tests.yml +2 -2
  3. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/PKG-INFO +15 -3
  4. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/README.rst +14 -2
  5. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/__init__.py +2 -1
  6. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/__main__.py +57 -1
  7. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/context.py +55 -0
  8. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/lfs.c +9402 -9403
  9. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/lfs.pxd +1 -0
  10. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/lfs.pyi +5 -0
  11. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/lfs.pyx +8 -0
  12. littlefs_python-0.17.0/src/littlefs/repl.py +281 -0
  13. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs_python.egg-info/PKG-INFO +15 -3
  14. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs_python.egg-info/SOURCES.txt +2 -0
  15. littlefs_python-0.17.0/test/test_context.py +41 -0
  16. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/.gitattributes +0 -0
  17. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/.github/dependabot.yml +0 -0
  18. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/.gitignore +0 -0
  19. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/.gitmodules +0 -0
  20. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/.pre-commit-config.yaml +0 -0
  21. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/.readthedocs.yml +0 -0
  22. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/LICENSE +0 -0
  23. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/MANIFEST.in +0 -0
  24. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/ci/build-wheels.sh +0 -0
  25. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/ci/download_release_files.py +0 -0
  26. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/Makefile +0 -0
  27. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/api/index.rst +0 -0
  28. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/cli.rst +0 -0
  29. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/conf.py +0 -0
  30. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/doc8.ini +0 -0
  31. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/examples/index.rst +0 -0
  32. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/index.rst +0 -0
  33. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/make.bat +0 -0
  34. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/requirements.txt +0 -0
  35. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/docs/usage.rst +0 -0
  36. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/examples/mkfsimg.py +0 -0
  37. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/examples/walk.py +0 -0
  38. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/.git +0 -0
  39. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/.gitattributes +0 -0
  40. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/.github/workflows/post-release.yml +0 -0
  41. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/.github/workflows/release.yml +0 -0
  42. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/.github/workflows/status.yml +0 -0
  43. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/.github/workflows/test.yml +0 -0
  44. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/.gitignore +0 -0
  45. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/DESIGN.md +0 -0
  46. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/LICENSE.md +0 -0
  47. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/Makefile +0 -0
  48. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/README.md +0 -0
  49. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/SPEC.md +0 -0
  50. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/bd/lfs_emubd.c +0 -0
  51. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/bd/lfs_emubd.h +0 -0
  52. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/bd/lfs_filebd.c +0 -0
  53. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/bd/lfs_filebd.h +0 -0
  54. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/bd/lfs_rambd.c +0 -0
  55. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/bd/lfs_rambd.h +0 -0
  56. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/benches/bench_dir.toml +0 -0
  57. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/benches/bench_file.toml +0 -0
  58. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/benches/bench_superblock.toml +0 -0
  59. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/lfs.c +0 -0
  60. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/lfs.h +0 -0
  61. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/lfs_util.c +0 -0
  62. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/lfs_util.h +0 -0
  63. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/runners/bench_runner.c +0 -0
  64. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/runners/bench_runner.h +0 -0
  65. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/runners/test_runner.c +0 -0
  66. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/runners/test_runner.h +0 -0
  67. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/bench.py +0 -0
  68. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/changeprefix.py +0 -0
  69. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/code.py +0 -0
  70. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/cov.py +0 -0
  71. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/data.py +0 -0
  72. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/perf.py +0 -0
  73. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/perfbd.py +0 -0
  74. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/plot.py +0 -0
  75. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/plotmpl.py +0 -0
  76. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/prettyasserts.py +0 -0
  77. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/readblock.py +0 -0
  78. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/readmdir.py +0 -0
  79. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/readtree.py +0 -0
  80. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/stack.py +0 -0
  81. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/structs.py +0 -0
  82. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/summary.py +0 -0
  83. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/tailpipe.py +0 -0
  84. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/teepipe.py +0 -0
  85. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/test.py +0 -0
  86. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/tracebd.py +0 -0
  87. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/scripts/watch.py +0 -0
  88. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_alloc.toml +0 -0
  89. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_attrs.toml +0 -0
  90. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_badblocks.toml +0 -0
  91. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_bd.toml +0 -0
  92. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_compat.toml +0 -0
  93. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_dirs.toml +0 -0
  94. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_entries.toml +0 -0
  95. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_evil.toml +0 -0
  96. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_exhaustion.toml +0 -0
  97. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_files.toml +0 -0
  98. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_interspersed.toml +0 -0
  99. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_move.toml +0 -0
  100. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_orphans.toml +0 -0
  101. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_paths.toml +0 -0
  102. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_powerloss.toml +0 -0
  103. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_relocations.toml +0 -0
  104. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_seek.toml +0 -0
  105. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_shrink.toml +0 -0
  106. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_superblocks.toml +0 -0
  107. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/littlefs/tests/test_truncate.toml +0 -0
  108. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/mypy.ini +0 -0
  109. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/pyproject.toml +0 -0
  110. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/requirements.txt +0 -0
  111. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/setup.cfg +0 -0
  112. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/setup.py +0 -0
  113. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/errors.py +0 -0
  114. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs/py.typed +0 -0
  115. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs_python.egg-info/dependency_links.txt +0 -0
  116. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs_python.egg-info/entry_points.txt +0 -0
  117. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs_python.egg-info/not-zip-safe +0 -0
  118. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs_python.egg-info/requires.txt +0 -0
  119. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/src/littlefs_python.egg-info/top_level.txt +0 -0
  120. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/lfs/conftest.py +0 -0
  121. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/lfs/test_dir_functions.py +0 -0
  122. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/lfs/test_file_functions.py +0 -0
  123. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/lfs/test_fs_functions.py +0 -0
  124. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_attr.py +0 -0
  125. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_block_count.py +0 -0
  126. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_directories.py +0 -0
  127. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_files.py +0 -0
  128. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_grow.py +0 -0
  129. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_multiversion.py +0 -0
  130. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_name_max.py +0 -0
  131. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_remove_rename.py +0 -0
  132. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_version.py +0 -0
  133. {littlefs_python-0.15.0 → littlefs_python-0.17.0}/test/test_walk.py +0 -0
@@ -15,7 +15,7 @@ jobs:
15
15
  runs-on: ${{ matrix.os }}
16
16
  strategy:
17
17
  matrix:
18
- os: [ubuntu-22.04, macos-13, windows-latest]
18
+ os: [ubuntu-22.04, macos-15-intel, windows-latest]
19
19
 
20
20
  env:
21
21
  CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-* cp314-*"
@@ -23,7 +23,7 @@ jobs:
23
23
  CIBW_ARCHS_LINUX: "x86_64 i686 aarch64"
24
24
 
25
25
  steps:
26
- - uses: actions/checkout@v5
26
+ - uses: actions/checkout@v6
27
27
  with:
28
28
  submodules: "recursive"
29
29
  fetch-depth: 0
@@ -35,9 +35,9 @@ jobs:
35
35
  platforms: all
36
36
 
37
37
  - name: Build wheels
38
- uses: pypa/cibuildwheel@v3.2.1
38
+ uses: pypa/cibuildwheel@v3.3.0
39
39
 
40
- - uses: actions/upload-artifact@v5
40
+ - uses: actions/upload-artifact@v6
41
41
  with:
42
42
  name: wheels-${{ matrix.os }}
43
43
  path: ./wheelhouse/*.whl
@@ -51,13 +51,13 @@ jobs:
51
51
  cibw_archs: ["arm64"]
52
52
 
53
53
  steps:
54
- - uses: actions/checkout@v5
54
+ - uses: actions/checkout@v6
55
55
  with:
56
56
  submodules: "recursive"
57
57
  fetch-depth: 0
58
58
 
59
59
  - name: Build wheels
60
- uses: pypa/cibuildwheel@v3.2.1
60
+ uses: pypa/cibuildwheel@v3.3.0
61
61
  env:
62
62
  CIBW_BUILD: ${{ matrix.cibw_build }}
63
63
  CIBW_SKIP: "pp*"
@@ -84,7 +84,7 @@ jobs:
84
84
  delocate-listdeps --all {dest_dir}/$WHEEL_SIMPLE_FILENAME
85
85
 
86
86
  echo "DONE."
87
- - uses: actions/upload-artifact@v5
87
+ - uses: actions/upload-artifact@v6
88
88
  with:
89
89
  name: wheels-macos-arm64
90
90
  path: ./wheelhouse/*.whl
@@ -93,7 +93,7 @@ jobs:
93
93
  name: Build source distribution
94
94
  runs-on: ubuntu-22.04
95
95
  steps:
96
- - uses: actions/checkout@v5
96
+ - uses: actions/checkout@v6
97
97
  with:
98
98
  submodules: "recursive"
99
99
  fetch-depth: 0
@@ -103,7 +103,7 @@ jobs:
103
103
  pip install build
104
104
  python -m build . --sdist
105
105
 
106
- - uses: actions/upload-artifact@v5
106
+ - uses: actions/upload-artifact@v6
107
107
  with:
108
108
  name: wheels-sdist
109
109
  path: dist/*.tar.gz
@@ -113,7 +113,7 @@ jobs:
113
113
  runs-on: ubuntu-22.04
114
114
  if: ${{ inputs.upload_to_pypi }}
115
115
  steps:
116
- - uses: actions/download-artifact@v6
116
+ - uses: actions/download-artifact@v7
117
117
  with:
118
118
  path: dist
119
119
  pattern: wheels-*
@@ -123,3 +123,4 @@ jobs:
123
123
  with:
124
124
  user: __token__
125
125
  password: ${{ secrets.pypi_api_token }}
126
+ skip-existing: true
@@ -14,11 +14,11 @@ jobs:
14
14
  runs-on: ${{ matrix.os }}
15
15
  strategy:
16
16
  matrix:
17
- os: [ubuntu-22.04, macos-13, windows-latest]
17
+ os: [ubuntu-22.04, macos-15, windows-latest]
18
18
  python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "3.14"]
19
19
 
20
20
  steps:
21
- - uses: actions/checkout@v5
21
+ - uses: actions/checkout@v6
22
22
  with:
23
23
  submodules: "recursive"
24
24
  - name: Set up Python ${{ matrix.python-version }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: littlefs-python
3
- Version: 0.15.0
3
+ Version: 0.17.0
4
4
  Summary: A python wrapper for littlefs
5
5
  Home-page: https://github.com/jrast/littlefs-python
6
6
  Author: Jürg Rast
@@ -136,7 +136,7 @@ littlefs-python comes bundled with a command-line tool, ``littlefs-python``, tha
136
136
  .. code:: console
137
137
 
138
138
  $ littlefs-python --help
139
- usage: littlefs-python [-h] [--version] {create,extract,list} ...
139
+ usage: littlefs-python [-h] [--version] {create,extract,list,repl} ...
140
140
 
141
141
  Create, extract and inspect LittleFS filesystem images. Use one of the
142
142
  commands listed below, the '-h' / '--help' option can be used on each command
@@ -147,10 +147,11 @@ littlefs-python comes bundled with a command-line tool, ``littlefs-python``, tha
147
147
  --version show program's version number and exit
148
148
 
149
149
  Available Commands:
150
- {create,extract,list}
150
+ {create,extract,list,repl}
151
151
  create Create LittleFS image from file/directory contents.
152
152
  extract Extract LittleFS image contents to a directory.
153
153
  list List LittleFS image contents.
154
+ repl Inspect an existing LittleFS image through an interactive shell.
154
155
 
155
156
  To create a littlefs binary image:
156
157
 
@@ -168,6 +169,17 @@ To extract the contents of a littlefs binary image:
168
169
 
169
170
  $ littlefs-python extract lfs.bin output/ --block-size=4096
170
171
 
172
+ To inspect or debug an existing image without extracting it first you can start a
173
+ simple REPL. It provides shell-like commands such as ``ls``, ``tree``, ``put``, ``get``
174
+ and ``rm`` that operate directly on the image data:
175
+
176
+ .. code:: console
177
+
178
+ $ littlefs-python repl lfs.bin --block-size=4096
179
+ Mounted remote littlefs.
180
+ littlefs> ls
181
+ README.rst
182
+
171
183
  Development Setup
172
184
  =================
173
185
 
@@ -103,7 +103,7 @@ littlefs-python comes bundled with a command-line tool, ``littlefs-python``, tha
103
103
  .. code:: console
104
104
 
105
105
  $ littlefs-python --help
106
- usage: littlefs-python [-h] [--version] {create,extract,list} ...
106
+ usage: littlefs-python [-h] [--version] {create,extract,list,repl} ...
107
107
 
108
108
  Create, extract and inspect LittleFS filesystem images. Use one of the
109
109
  commands listed below, the '-h' / '--help' option can be used on each command
@@ -114,10 +114,11 @@ littlefs-python comes bundled with a command-line tool, ``littlefs-python``, tha
114
114
  --version show program's version number and exit
115
115
 
116
116
  Available Commands:
117
- {create,extract,list}
117
+ {create,extract,list,repl}
118
118
  create Create LittleFS image from file/directory contents.
119
119
  extract Extract LittleFS image contents to a directory.
120
120
  list List LittleFS image contents.
121
+ repl Inspect an existing LittleFS image through an interactive shell.
121
122
 
122
123
  To create a littlefs binary image:
123
124
 
@@ -135,6 +136,17 @@ To extract the contents of a littlefs binary image:
135
136
 
136
137
  $ littlefs-python extract lfs.bin output/ --block-size=4096
137
138
 
139
+ To inspect or debug an existing image without extracting it first you can start a
140
+ simple REPL. It provides shell-like commands such as ``ls``, ``tree``, ``put``, ``get``
141
+ and ``rm`` that operate directly on the image data:
142
+
143
+ .. code:: console
144
+
145
+ $ littlefs-python repl lfs.bin --block-size=4096
146
+ Mounted remote littlefs.
147
+ littlefs> ls
148
+ README.rst
149
+
138
150
  Development Setup
139
151
  =================
140
152
 
@@ -34,6 +34,7 @@ __all__ = [
34
34
  "LittleFS",
35
35
  "LittleFSError",
36
36
  "UserContext",
37
+ "UserContextFile",
37
38
  "UserContextWinDisk",
38
39
  "__LFS_DISK_VERSION__",
39
40
  "__LFS_VERSION__",
@@ -48,7 +49,7 @@ except PackageNotFoundError:
48
49
  # Package not installed
49
50
  pass
50
51
 
51
- from .context import UserContext, UserContextWinDisk
52
+ from .context import UserContext, UserContextFile, UserContextWinDisk
52
53
 
53
54
  if TYPE_CHECKING:
54
55
  from .lfs import LFSStat
@@ -6,6 +6,8 @@ import textwrap
6
6
 
7
7
  from littlefs import LittleFS, __version__
8
8
  from littlefs.errors import LittleFSError
9
+ from littlefs.repl import LittleFSRepl
10
+ from littlefs.context import UserContextFile
9
11
 
10
12
  # Dictionary mapping suffixes to their size in bytes
11
13
  _suffix_map = {
@@ -110,7 +112,7 @@ def create(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
110
112
  compact_fs.fs_grow(args.block_count)
111
113
  data = compact_fs.context.buffer
112
114
  if not args.no_pad:
113
- data = data.ljust(args.fs_size, b"\xFF")
115
+ data = data.ljust(args.fs_size, b"\xff")
114
116
  else:
115
117
  data = fs.context.buffer
116
118
 
@@ -188,6 +190,47 @@ def extract(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
188
190
  return 0
189
191
 
190
192
 
193
+ def repl(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
194
+ """Inspect an existing LittleFS image through an interactive shell."""
195
+
196
+ source: Path = args.source
197
+ if not source.is_file():
198
+ parser.error(f"Source image '{source}' does not exist.")
199
+
200
+ image_size = source.stat().st_size
201
+ if not image_size or image_size % args.block_size:
202
+ parser.error(
203
+ f"Image size ({image_size} bytes) is not a multiple of the supplied block size ({args.block_size})."
204
+ )
205
+
206
+ block_count = image_size // args.block_size
207
+ if block_count == 0:
208
+ parser.error("Image is smaller than a single block; cannot mount.")
209
+
210
+ context = UserContextFile(str(source))
211
+ fs = LittleFS(
212
+ context=context,
213
+ block_size=args.block_size,
214
+ block_count=block_count,
215
+ name_max=args.name_max,
216
+ mount=False,
217
+ )
218
+
219
+ shell = LittleFSRepl(fs)
220
+ try:
221
+ try:
222
+ shell.do_mount()
223
+ except LittleFSError as exc:
224
+ parser.error(f"Failed to mount '{source}': {exc}")
225
+ shell.cmdloop()
226
+ finally:
227
+ if shell._mounted:
228
+ with suppress(LittleFSError):
229
+ fs.unmount()
230
+
231
+ return 0
232
+
233
+
191
234
  def get_parser():
192
235
  if sys.argv[0].endswith("__main__.py"):
193
236
  prog = f"python -m littlefs"
@@ -299,6 +342,19 @@ def get_parser():
299
342
  help="LittleFS block size.",
300
343
  )
301
344
 
345
+ parser_repl = add_command(repl)
346
+ parser_repl.add_argument(
347
+ "source",
348
+ type=Path,
349
+ help="Source LittleFS filesystem binary.",
350
+ )
351
+ parser_repl.add_argument(
352
+ "--block-size",
353
+ type=size_parser,
354
+ required=True,
355
+ help="LittleFS block size.",
356
+ )
357
+
302
358
  return parser
303
359
 
304
360
 
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import typing
3
3
  import ctypes
4
+ import os
4
5
 
5
6
  if typing.TYPE_CHECKING:
6
7
  from .lfs import LFSConfig
@@ -78,6 +79,60 @@ class UserContext:
78
79
  return 0
79
80
 
80
81
 
82
+ class UserContextFile(UserContext):
83
+ """File-backed context using the standard library"""
84
+
85
+ def __init__(self, file_path: str, *, create: bool = False) -> None:
86
+ mode = "r+b"
87
+ if not os.path.exists(file_path):
88
+ if not create:
89
+ raise FileNotFoundError(f"Context file '{file_path}' does not exist")
90
+ mode = "w+b"
91
+
92
+ self._path = file_path
93
+ self._fh = open(file_path, mode)
94
+
95
+ def read(self, cfg: "LFSConfig", block: int, off: int, size: int) -> bytearray:
96
+ logging.getLogger(__name__).debug("LFS Read : Block: %d, Offset: %d, Size=%d" % (block, off, size))
97
+ start = block * cfg.block_size + off
98
+ self._fh.seek(start)
99
+ data = self._fh.read(size)
100
+
101
+ if len(data) < size:
102
+ data += b"\xff" * (size - len(data))
103
+
104
+ return bytearray(data)
105
+
106
+ def prog(self, cfg: "LFSConfig", block: int, off: int, data: bytes) -> int:
107
+ logging.getLogger(__name__).debug("LFS Prog : Block: %d, Offset: %d, Data=%r" % (block, off, data))
108
+ start = block * cfg.block_size + off
109
+ self._fh.seek(start)
110
+ self._fh.write(data)
111
+ return 0
112
+
113
+ def erase(self, cfg: "LFSConfig", block: int) -> int:
114
+ logging.getLogger(__name__).debug("LFS Erase: Block: %d" % block)
115
+ start = block * cfg.block_size
116
+ self._fh.seek(start)
117
+ self._fh.write(b"\xff" * cfg.block_size)
118
+ return 0
119
+
120
+ def sync(self, cfg: "LFSConfig") -> int:
121
+ self._fh.flush()
122
+ os.fsync(self._fh.fileno())
123
+ return 0
124
+
125
+ def close(self) -> None:
126
+ if not self._fh.closed:
127
+ self._fh.close()
128
+
129
+ def __del__(self):
130
+ try:
131
+ self.close()
132
+ except Exception:
133
+ pass
134
+
135
+
81
136
  try:
82
137
  import win32file
83
138
  except ImportError: