littlefs-python 0.14.0__tar.gz → 0.16.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.14.0 → littlefs_python-0.16.0}/.github/workflows/deploy.yml +25 -15
  2. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/.github/workflows/run-tests.yml +3 -3
  3. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/PKG-INFO +16 -3
  4. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/README.rst +15 -2
  5. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/Makefile +1 -0
  6. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/README.md +6 -1
  7. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/lfs.c +8 -5
  8. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/__init__.py +2 -1
  9. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/__main__.py +57 -1
  10. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/context.py +55 -0
  11. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/lfs.c +8517 -8585
  12. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/lfs.pxd +3 -0
  13. littlefs_python-0.16.0/src/littlefs/repl.py +281 -0
  14. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs_python.egg-info/PKG-INFO +16 -3
  15. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs_python.egg-info/SOURCES.txt +2 -0
  16. littlefs_python-0.16.0/test/test_context.py +41 -0
  17. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/.gitattributes +0 -0
  18. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/.github/dependabot.yml +0 -0
  19. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/.gitignore +0 -0
  20. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/.gitmodules +0 -0
  21. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/.pre-commit-config.yaml +0 -0
  22. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/.readthedocs.yml +0 -0
  23. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/LICENSE +0 -0
  24. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/MANIFEST.in +0 -0
  25. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/ci/build-wheels.sh +0 -0
  26. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/ci/download_release_files.py +0 -0
  27. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/Makefile +0 -0
  28. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/api/index.rst +0 -0
  29. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/cli.rst +0 -0
  30. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/conf.py +0 -0
  31. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/doc8.ini +0 -0
  32. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/examples/index.rst +0 -0
  33. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/index.rst +0 -0
  34. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/make.bat +0 -0
  35. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/requirements.txt +0 -0
  36. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/docs/usage.rst +0 -0
  37. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/examples/mkfsimg.py +0 -0
  38. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/examples/walk.py +0 -0
  39. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/.git +0 -0
  40. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/.gitattributes +0 -0
  41. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/.github/workflows/post-release.yml +0 -0
  42. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/.github/workflows/release.yml +0 -0
  43. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/.github/workflows/status.yml +0 -0
  44. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/.github/workflows/test.yml +0 -0
  45. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/.gitignore +0 -0
  46. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/DESIGN.md +0 -0
  47. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/LICENSE.md +0 -0
  48. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/SPEC.md +0 -0
  49. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/bd/lfs_emubd.c +0 -0
  50. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/bd/lfs_emubd.h +0 -0
  51. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/bd/lfs_filebd.c +0 -0
  52. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/bd/lfs_filebd.h +0 -0
  53. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/bd/lfs_rambd.c +0 -0
  54. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/bd/lfs_rambd.h +0 -0
  55. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/benches/bench_dir.toml +0 -0
  56. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/benches/bench_file.toml +0 -0
  57. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/benches/bench_superblock.toml +0 -0
  58. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/lfs.h +0 -0
  59. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/lfs_util.c +0 -0
  60. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/lfs_util.h +0 -0
  61. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/runners/bench_runner.c +0 -0
  62. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/runners/bench_runner.h +0 -0
  63. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/runners/test_runner.c +0 -0
  64. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/runners/test_runner.h +0 -0
  65. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/bench.py +0 -0
  66. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/changeprefix.py +0 -0
  67. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/code.py +0 -0
  68. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/cov.py +0 -0
  69. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/data.py +0 -0
  70. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/perf.py +0 -0
  71. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/perfbd.py +0 -0
  72. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/plot.py +0 -0
  73. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/plotmpl.py +0 -0
  74. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/prettyasserts.py +0 -0
  75. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/readblock.py +0 -0
  76. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/readmdir.py +0 -0
  77. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/readtree.py +0 -0
  78. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/stack.py +0 -0
  79. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/structs.py +0 -0
  80. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/summary.py +0 -0
  81. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/tailpipe.py +0 -0
  82. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/teepipe.py +0 -0
  83. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/test.py +0 -0
  84. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/tracebd.py +0 -0
  85. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/scripts/watch.py +0 -0
  86. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_alloc.toml +0 -0
  87. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_attrs.toml +0 -0
  88. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_badblocks.toml +0 -0
  89. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_bd.toml +0 -0
  90. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_compat.toml +0 -0
  91. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_dirs.toml +0 -0
  92. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_entries.toml +0 -0
  93. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_evil.toml +0 -0
  94. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_exhaustion.toml +0 -0
  95. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_files.toml +0 -0
  96. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_interspersed.toml +0 -0
  97. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_move.toml +0 -0
  98. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_orphans.toml +0 -0
  99. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_paths.toml +0 -0
  100. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_powerloss.toml +0 -0
  101. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_relocations.toml +0 -0
  102. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_seek.toml +0 -0
  103. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_shrink.toml +0 -0
  104. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_superblocks.toml +0 -0
  105. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/littlefs/tests/test_truncate.toml +0 -0
  106. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/mypy.ini +0 -0
  107. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/pyproject.toml +0 -0
  108. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/requirements.txt +0 -0
  109. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/setup.cfg +0 -0
  110. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/setup.py +0 -0
  111. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/errors.py +0 -0
  112. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/lfs.pyi +0 -0
  113. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/lfs.pyx +0 -0
  114. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs/py.typed +0 -0
  115. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs_python.egg-info/dependency_links.txt +0 -0
  116. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs_python.egg-info/entry_points.txt +0 -0
  117. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs_python.egg-info/not-zip-safe +0 -0
  118. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs_python.egg-info/requires.txt +0 -0
  119. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/src/littlefs_python.egg-info/top_level.txt +0 -0
  120. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/lfs/conftest.py +0 -0
  121. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/lfs/test_dir_functions.py +0 -0
  122. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/lfs/test_file_functions.py +0 -0
  123. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/lfs/test_fs_functions.py +0 -0
  124. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_attr.py +0 -0
  125. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_block_count.py +0 -0
  126. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_directories.py +0 -0
  127. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_files.py +0 -0
  128. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_grow.py +0 -0
  129. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_multiversion.py +0 -0
  130. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_name_max.py +0 -0
  131. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_remove_rename.py +0 -0
  132. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_version.py +0 -0
  133. {littlefs_python-0.14.0 → littlefs_python-0.16.0}/test/test_walk.py +0 -0
@@ -1,6 +1,13 @@
1
1
  name: Build and Deploy Package
2
2
 
3
- on: workflow_dispatch
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ upload_to_pypi:
7
+ description: 'Upload to PyPI after building'
8
+ required: true
9
+ default: false
10
+ type: boolean
4
11
 
5
12
  jobs:
6
13
  build_wheels:
@@ -11,14 +18,15 @@ jobs:
11
18
  os: [ubuntu-22.04, macos-13, windows-latest]
12
19
 
13
20
  env:
14
- CIBW_BUILD: "cp37-* cp38-* cp39-* cp310-* cp311-* cp312-* cp313-* pp37-* pp38-* pp39-* pp310-*"
15
- CIBW_SKIP: "cp36-* pp* *-win_arm64 *-musllinux_aarch64"
21
+ CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-* cp314-*"
22
+ CIBW_SKIP: "*-win_arm64 *-musllinux_aarch64"
16
23
  CIBW_ARCHS_LINUX: "x86_64 i686 aarch64"
17
24
 
18
25
  steps:
19
- - uses: actions/checkout@v4
26
+ - uses: actions/checkout@v5
20
27
  with:
21
28
  submodules: "recursive"
29
+ fetch-depth: 0
22
30
 
23
31
  - name: Setup QEMU # Needed to build aarch64 wheels
24
32
  if: runner.os == 'Linux'
@@ -27,9 +35,9 @@ jobs:
27
35
  platforms: all
28
36
 
29
37
  - name: Build wheels
30
- uses: pypa/cibuildwheel@v2.23.3
38
+ uses: pypa/cibuildwheel@v3.2.1
31
39
 
32
- - uses: actions/upload-artifact@v4
40
+ - uses: actions/upload-artifact@v5
33
41
  with:
34
42
  name: wheels-${{ matrix.os }}
35
43
  path: ./wheelhouse/*.whl
@@ -43,15 +51,16 @@ jobs:
43
51
  cibw_archs: ["arm64"]
44
52
 
45
53
  steps:
46
- - uses: actions/checkout@v4
54
+ - uses: actions/checkout@v5
47
55
  with:
48
56
  submodules: "recursive"
57
+ fetch-depth: 0
49
58
 
50
59
  - name: Build wheels
51
- uses: pypa/cibuildwheel@v2.23.3
60
+ uses: pypa/cibuildwheel@v3.2.1
52
61
  env:
53
62
  CIBW_BUILD: ${{ matrix.cibw_build }}
54
- CIBW_SKIP: "cp36-* pp*"
63
+ CIBW_SKIP: "pp*"
55
64
  CIBW_ARCHS: ${{ matrix.cibw_archs }}
56
65
  CIBW_REPAIR_WHEEL_COMMAND: |
57
66
  echo "Target delocate archs: {delocate_archs}"
@@ -75,7 +84,7 @@ jobs:
75
84
  delocate-listdeps --all {dest_dir}/$WHEEL_SIMPLE_FILENAME
76
85
 
77
86
  echo "DONE."
78
- - uses: actions/upload-artifact@v4
87
+ - uses: actions/upload-artifact@v5
79
88
  with:
80
89
  name: wheels-macos-arm64
81
90
  path: ./wheelhouse/*.whl
@@ -84,16 +93,17 @@ jobs:
84
93
  name: Build source distribution
85
94
  runs-on: ubuntu-22.04
86
95
  steps:
87
- - uses: actions/checkout@v4
96
+ - uses: actions/checkout@v5
88
97
  with:
89
98
  submodules: "recursive"
99
+ fetch-depth: 0
90
100
 
91
101
  - name: Build sdist
92
102
  run: |
93
103
  pip install build
94
104
  python -m build . --sdist
95
105
 
96
- - uses: actions/upload-artifact@v4
106
+ - uses: actions/upload-artifact@v5
97
107
  with:
98
108
  name: wheels-sdist
99
109
  path: dist/*.tar.gz
@@ -101,15 +111,15 @@ jobs:
101
111
  upload_pypi:
102
112
  needs: [build_wheels, build_wheels_macos_arm64, build_sdist]
103
113
  runs-on: ubuntu-22.04
104
- # if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/')
114
+ if: ${{ inputs.upload_to_pypi }}
105
115
  steps:
106
- - uses: actions/download-artifact@v4
116
+ - uses: actions/download-artifact@v6
107
117
  with:
108
118
  path: dist
109
119
  pattern: wheels-*
110
120
  merge-multiple: true
111
121
 
112
- - uses: pypa/gh-action-pypi-publish@v1.12.4
122
+ - uses: pypa/gh-action-pypi-publish@v1.13.0
113
123
  with:
114
124
  user: __token__
115
125
  password: ${{ secrets.pypi_api_token }}
@@ -15,14 +15,14 @@ jobs:
15
15
  strategy:
16
16
  matrix:
17
17
  os: [ubuntu-22.04, macos-13, windows-latest]
18
- python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
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@v4
21
+ - uses: actions/checkout@v5
22
22
  with:
23
23
  submodules: "recursive"
24
24
  - name: Set up Python ${{ matrix.python-version }}
25
- uses: actions/setup-python@v5
25
+ uses: actions/setup-python@v6
26
26
  with:
27
27
  python-version: ${{ matrix.python-version }}
28
28
  - name: Install dependencies
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: littlefs-python
3
- Version: 0.14.0
3
+ Version: 0.16.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
@@ -103,6 +103,7 @@ from scratch the latest version is recommended.
103
103
  .. csv-table::
104
104
  :header: "LittleFS Version", "Package Version", "LittleFS File System Version"
105
105
 
106
+ 2.11.2, v0.15.X, 2.0 / 2.1 [#f1]_
106
107
  2.11.0, v0.14.X, 2.0 / 2.1 [#f1]_
107
108
  2.10.0, v0.13.X, 2.0 / 2.1 [#f1]_
108
109
  2.9.0, v0.12.X v0.11.X, 2.0 / 2.1 [#f1]_
@@ -135,7 +136,7 @@ littlefs-python comes bundled with a command-line tool, ``littlefs-python``, tha
135
136
  .. code:: console
136
137
 
137
138
  $ littlefs-python --help
138
- usage: littlefs-python [-h] [--version] {create,extract,list} ...
139
+ usage: littlefs-python [-h] [--version] {create,extract,list,repl} ...
139
140
 
140
141
  Create, extract and inspect LittleFS filesystem images. Use one of the
141
142
  commands listed below, the '-h' / '--help' option can be used on each command
@@ -146,10 +147,11 @@ littlefs-python comes bundled with a command-line tool, ``littlefs-python``, tha
146
147
  --version show program's version number and exit
147
148
 
148
149
  Available Commands:
149
- {create,extract,list}
150
+ {create,extract,list,repl}
150
151
  create Create LittleFS image from file/directory contents.
151
152
  extract Extract LittleFS image contents to a directory.
152
153
  list List LittleFS image contents.
154
+ repl Inspect an existing LittleFS image through an interactive shell.
153
155
 
154
156
  To create a littlefs binary image:
155
157
 
@@ -167,6 +169,17 @@ To extract the contents of a littlefs binary image:
167
169
 
168
170
  $ littlefs-python extract lfs.bin output/ --block-size=4096
169
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
+
170
183
  Development Setup
171
184
  =================
172
185
 
@@ -70,6 +70,7 @@ from scratch the latest version is recommended.
70
70
  .. csv-table::
71
71
  :header: "LittleFS Version", "Package Version", "LittleFS File System Version"
72
72
 
73
+ 2.11.2, v0.15.X, 2.0 / 2.1 [#f1]_
73
74
  2.11.0, v0.14.X, 2.0 / 2.1 [#f1]_
74
75
  2.10.0, v0.13.X, 2.0 / 2.1 [#f1]_
75
76
  2.9.0, v0.12.X v0.11.X, 2.0 / 2.1 [#f1]_
@@ -102,7 +103,7 @@ littlefs-python comes bundled with a command-line tool, ``littlefs-python``, tha
102
103
  .. code:: console
103
104
 
104
105
  $ littlefs-python --help
105
- usage: littlefs-python [-h] [--version] {create,extract,list} ...
106
+ usage: littlefs-python [-h] [--version] {create,extract,list,repl} ...
106
107
 
107
108
  Create, extract and inspect LittleFS filesystem images. Use one of the
108
109
  commands listed below, the '-h' / '--help' option can be used on each command
@@ -113,10 +114,11 @@ littlefs-python comes bundled with a command-line tool, ``littlefs-python``, tha
113
114
  --version show program's version number and exit
114
115
 
115
116
  Available Commands:
116
- {create,extract,list}
117
+ {create,extract,list,repl}
117
118
  create Create LittleFS image from file/directory contents.
118
119
  extract Extract LittleFS image contents to a directory.
119
120
  list List LittleFS image contents.
121
+ repl Inspect an existing LittleFS image through an interactive shell.
120
122
 
121
123
  To create a littlefs binary image:
122
124
 
@@ -134,6 +136,17 @@ To extract the contents of a littlefs binary image:
134
136
 
135
137
  $ littlefs-python extract lfs.bin output/ --block-size=4096
136
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
+
137
150
  Development Setup
138
151
  =================
139
152
 
@@ -475,6 +475,7 @@ benchmarks-diff: $(BENCH_CSV)
475
475
  # rules
476
476
  -include $(DEP)
477
477
  -include $(TEST_DEP)
478
+ -include $(BENCH_DEP)
478
479
  .SUFFIXES:
479
480
  .SECONDARY:
480
481
 
@@ -267,7 +267,11 @@ License Identifiers that are here available: http://spdx.org/licenses/
267
267
  to create images of the filesystem on your PC. Check if littlefs will fit
268
268
  your needs, create images for a later download to the target memory or
269
269
  inspect the content of a binary image of the target memory.
270
-
270
+
271
+ - [littlefs-toy] - A command-line tool for creating and working with littlefs
272
+ images. Uses syntax similar to tar command for ease of use. Supports working
273
+ on littlefs images embedded inside another file (firmware image, etc).
274
+
271
275
  - [littlefs2-rust] - A Rust wrapper for littlefs. This project allows you
272
276
  to use littlefs in a Rust-friendly API, reaping the benefits of Rust's memory
273
277
  safety and other guarantees.
@@ -321,6 +325,7 @@ License Identifiers that are here available: http://spdx.org/licenses/
321
325
  [littlefs-js]: https://github.com/geky/littlefs-js
322
326
  [littlefs-js-demo]:http://littlefs.geky.net/demo.html
323
327
  [littlefs-python]: https://pypi.org/project/littlefs-python/
328
+ [littlefs-toy]: https://github.com/tjko/littlefs-toy
324
329
  [littlefs2-rust]: https://crates.io/crates/littlefs2
325
330
  [nim-littlefs]: https://github.com/Graveflo/nim-littlefs
326
331
  [chamelon]: https://github.com/yomimono/chamelon
@@ -93,6 +93,7 @@ static int lfs_bd_read(lfs_t *lfs,
93
93
  // bypass cache?
94
94
  diff = lfs_aligndown(diff, lfs->cfg->read_size);
95
95
  int err = lfs->cfg->read(lfs->cfg, block, off, data, diff);
96
+ LFS_ASSERT(err <= 0);
96
97
  if (err) {
97
98
  return err;
98
99
  }
@@ -739,6 +740,7 @@ static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir,
739
740
  int err = lfs_bd_read(lfs,
740
741
  NULL, &lfs->rcache, sizeof(ntag),
741
742
  dir->pair[0], off, &ntag, sizeof(ntag));
743
+ LFS_ASSERT(err <= 0);
742
744
  if (err) {
743
745
  return err;
744
746
  }
@@ -767,6 +769,7 @@ static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir,
767
769
  err = lfs_bd_read(lfs,
768
770
  NULL, &lfs->rcache, diff,
769
771
  dir->pair[0], off+sizeof(tag)+goff, gbuffer, diff);
772
+ LFS_ASSERT(err <= 0);
770
773
  if (err) {
771
774
  return err;
772
775
  }
@@ -828,9 +831,6 @@ static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir,
828
831
  size -= diff;
829
832
  continue;
830
833
  }
831
-
832
- // rcache takes priority
833
- diff = lfs_min(diff, rcache->off-off);
834
834
  }
835
835
 
836
836
  // load to cache, first condition can no longer fail
@@ -1282,6 +1282,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
1282
1282
  if (err == LFS_ERR_CORRUPT) {
1283
1283
  break;
1284
1284
  }
1285
+ return err;
1285
1286
  }
1286
1287
 
1287
1288
  lfs_fcrc_fromle32(&fcrc);
@@ -2267,7 +2268,7 @@ static int lfs_dir_relocatingcommit(lfs_t *lfs, lfs_mdir_t *dir,
2267
2268
  }
2268
2269
  }
2269
2270
 
2270
- if (dir->erased) {
2271
+ if (dir->erased && dir->count < 0xff) {
2271
2272
  // try to commit
2272
2273
  struct lfs_commit commit = {
2273
2274
  .block = dir->pair[0],
@@ -5225,7 +5226,9 @@ static int lfs_fs_gc_(lfs_t *lfs) {
5225
5226
  }
5226
5227
 
5227
5228
  // try to populate the lookahead buffer, unless it's already full
5228
- if (lfs->lookahead.size < 8*lfs->cfg->lookahead_size) {
5229
+ if (lfs->lookahead.size < lfs_min(
5230
+ 8 * lfs->cfg->lookahead_size,
5231
+ lfs->block_count)) {
5229
5232
  err = lfs_alloc_scan(lfs);
5230
5233
  if (err) {
5231
5234
  return err;
@@ -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: