littlefs-python 0.16.0__tar.gz → 0.17.1__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.
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/.github/workflows/deploy.yml +11 -10
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/.github/workflows/run-tests.yml +2 -2
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/PKG-INFO +1 -1
- littlefs_python-0.17.1/requirements.txt +3 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/__main__.py +63 -61
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/context.py +12 -4
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/lfs.c +1667 -1441
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/lfs.pxd +1 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/lfs.pyi +5 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/lfs.pyx +8 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/repl.py +5 -1
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs_python.egg-info/PKG-INFO +1 -1
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs_python.egg-info/SOURCES.txt +4 -0
- littlefs_python-0.17.1/test/cli/test_create_and_extract.py +101 -0
- littlefs_python-0.17.1/test/cli/test_create_and_repl.py +99 -0
- littlefs_python-0.17.1/test/cli/test_walk_all.py +60 -0
- littlefs_python-0.17.1/test/test_windisk_context.py +60 -0
- littlefs_python-0.16.0/requirements.txt +0 -2
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/.gitattributes +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/.github/dependabot.yml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/.gitignore +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/.gitmodules +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/.pre-commit-config.yaml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/.readthedocs.yml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/LICENSE +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/MANIFEST.in +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/README.rst +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/ci/build-wheels.sh +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/ci/download_release_files.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/Makefile +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/api/index.rst +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/cli.rst +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/conf.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/doc8.ini +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/examples/index.rst +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/index.rst +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/make.bat +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/requirements.txt +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/docs/usage.rst +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/examples/mkfsimg.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/examples/walk.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/.git +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/.gitattributes +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/.github/workflows/post-release.yml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/.github/workflows/release.yml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/.github/workflows/status.yml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/.github/workflows/test.yml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/.gitignore +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/DESIGN.md +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/LICENSE.md +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/Makefile +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/README.md +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/SPEC.md +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/bd/lfs_emubd.c +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/bd/lfs_emubd.h +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/bd/lfs_filebd.c +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/bd/lfs_filebd.h +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/bd/lfs_rambd.c +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/bd/lfs_rambd.h +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/benches/bench_dir.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/benches/bench_file.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/benches/bench_superblock.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/lfs.c +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/lfs.h +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/lfs_util.c +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/lfs_util.h +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/runners/bench_runner.c +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/runners/bench_runner.h +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/runners/test_runner.c +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/runners/test_runner.h +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/bench.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/changeprefix.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/code.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/cov.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/data.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/perf.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/perfbd.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/plot.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/plotmpl.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/prettyasserts.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/readblock.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/readmdir.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/readtree.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/stack.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/structs.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/summary.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/tailpipe.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/teepipe.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/test.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/tracebd.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/scripts/watch.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_alloc.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_attrs.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_badblocks.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_bd.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_compat.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_dirs.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_entries.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_evil.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_exhaustion.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_files.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_interspersed.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_move.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_orphans.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_paths.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_powerloss.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_relocations.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_seek.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_shrink.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_superblocks.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/littlefs/tests/test_truncate.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/mypy.ini +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/pyproject.toml +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/setup.cfg +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/setup.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/__init__.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/errors.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs/py.typed +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs_python.egg-info/dependency_links.txt +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs_python.egg-info/entry_points.txt +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs_python.egg-info/not-zip-safe +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs_python.egg-info/requires.txt +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/src/littlefs_python.egg-info/top_level.txt +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/lfs/conftest.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/lfs/test_dir_functions.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/lfs/test_file_functions.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/lfs/test_fs_functions.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_attr.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_block_count.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_context.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_directories.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_files.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_grow.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_multiversion.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_name_max.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_remove_rename.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/test/test_version.py +0 -0
- {littlefs_python-0.16.0 → littlefs_python-0.17.1}/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-
|
|
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@
|
|
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.
|
|
38
|
+
uses: pypa/cibuildwheel@v3.3.1
|
|
39
39
|
|
|
40
|
-
- uses: actions/upload-artifact@
|
|
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@
|
|
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.
|
|
60
|
+
uses: pypa/cibuildwheel@v3.3.1
|
|
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@
|
|
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@
|
|
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@
|
|
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@
|
|
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-
|
|
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@
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
22
|
with:
|
|
23
23
|
submodules: "recursive"
|
|
24
24
|
- name: Set up Python ${{ matrix.python-version }}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
from contextlib import suppress
|
|
3
|
+
import os
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
import sys
|
|
5
6
|
import textwrap
|
|
@@ -7,7 +8,7 @@ import textwrap
|
|
|
7
8
|
from littlefs import LittleFS, __version__
|
|
8
9
|
from littlefs.errors import LittleFSError
|
|
9
10
|
from littlefs.repl import LittleFSRepl
|
|
10
|
-
from littlefs.context import UserContextFile
|
|
11
|
+
from littlefs.context import UserContextFile, UserContext
|
|
11
12
|
|
|
12
13
|
# Dictionary mapping suffixes to their size in bytes
|
|
13
14
|
_suffix_map = {
|
|
@@ -17,10 +18,12 @@ _suffix_map = {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
def _fs_from_args(args: argparse.Namespace, mount=True) -> LittleFS:
|
|
21
|
+
def _fs_from_args(args: argparse.Namespace, block_count=None, mount=True, context: UserContext = None) -> LittleFS:
|
|
22
|
+
block_count = block_count if block_count is not None else getattr(args, "block_count", 0)
|
|
21
23
|
return LittleFS(
|
|
24
|
+
context=context,
|
|
22
25
|
block_size=args.block_size,
|
|
23
|
-
block_count=
|
|
26
|
+
block_count=block_count,
|
|
24
27
|
name_max=args.name_max,
|
|
25
28
|
mount=mount,
|
|
26
29
|
)
|
|
@@ -51,6 +54,16 @@ def size_parser(size_str):
|
|
|
51
54
|
return int(size_str, base)
|
|
52
55
|
|
|
53
56
|
|
|
57
|
+
def _walk_all(root):
|
|
58
|
+
"""Recursively yield all paths under root, following symlinks."""
|
|
59
|
+
for dirpath, dirnames, filenames in os.walk(root, followlinks=True):
|
|
60
|
+
dirpath = Path(dirpath)
|
|
61
|
+
for dirname in dirnames:
|
|
62
|
+
yield dirpath / dirname
|
|
63
|
+
for filename in filenames:
|
|
64
|
+
yield dirpath / filename
|
|
65
|
+
|
|
66
|
+
|
|
54
67
|
def create(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
55
68
|
"""Create LittleFS image from file/directory contents."""
|
|
56
69
|
# fs_size OR block_count may be populated; make them consistent.
|
|
@@ -72,7 +85,7 @@ def create(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
|
72
85
|
|
|
73
86
|
source = Path(args.source).absolute()
|
|
74
87
|
if source.is_dir():
|
|
75
|
-
sources = source
|
|
88
|
+
sources = list(_walk_all(source))
|
|
76
89
|
root = source
|
|
77
90
|
else:
|
|
78
91
|
sources = [source]
|
|
@@ -94,21 +107,14 @@ def create(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
|
94
107
|
if args.compact:
|
|
95
108
|
if args.verbose:
|
|
96
109
|
print(f"Compacting... {fs.used_block_count} / {args.block_count}")
|
|
97
|
-
compact_fs =
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
for _dir in dirs:
|
|
106
|
-
compact_fs.makedirs(root + _dir, exist_ok=True)
|
|
107
|
-
for file in files:
|
|
108
|
-
path = root + file
|
|
109
|
-
print(path)
|
|
110
|
-
with fs.open(path, "rb") as src, compact_fs.open(path, "wb") as dest:
|
|
111
|
-
dest.write(src.read())
|
|
110
|
+
compact_fs = _fs_from_args(args, block_count=fs.used_block_count)
|
|
111
|
+
for path in sources:
|
|
112
|
+
rel_path = path.relative_to(root)
|
|
113
|
+
if path.is_dir():
|
|
114
|
+
compact_fs.mkdir(rel_path.as_posix())
|
|
115
|
+
else:
|
|
116
|
+
with compact_fs.open(rel_path.as_posix(), "wb") as dest:
|
|
117
|
+
dest.write(path.read_bytes())
|
|
112
118
|
compact_fs.fs_grow(args.block_count)
|
|
113
119
|
data = compact_fs.context.buffer
|
|
114
120
|
if not args.no_pad:
|
|
@@ -121,21 +127,37 @@ def create(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
|
121
127
|
return 0
|
|
122
128
|
|
|
123
129
|
|
|
124
|
-
def
|
|
125
|
-
|
|
126
|
-
fs = _fs_from_args(args, mount=False)
|
|
127
|
-
fs.context.buffer = bytearray(args.source.read_bytes())
|
|
130
|
+
def _mount_from_context(parser: argparse.ArgumentParser, args: argparse.Namespace, context: UserContext) -> LittleFS:
|
|
131
|
+
# Block count is 0 because we don't know the size of the real image yet, the source file may be compacted (with the create --compact option).
|
|
132
|
+
fs = _fs_from_args(args, block_count=0, mount=False, context=context)
|
|
128
133
|
fs.mount()
|
|
129
134
|
|
|
130
135
|
if args.verbose:
|
|
131
|
-
|
|
136
|
+
input_image_size = context.in_size
|
|
137
|
+
actual_image_size = fs.block_count * args.block_size
|
|
132
138
|
print("LittleFS Configuration:")
|
|
133
139
|
print(f" Block Size: {args.block_size:9d} / 0x{args.block_size:X}")
|
|
134
|
-
|
|
140
|
+
if input_image_size != actual_image_size:
|
|
141
|
+
print(f" Image Size: {actual_image_size:9d} / 0x{actual_image_size:X}")
|
|
142
|
+
print(f" Input Image Size (compacted): {input_image_size:9d} / 0x{input_image_size:X}")
|
|
143
|
+
else:
|
|
144
|
+
print(f" Image Size: {input_image_size:9d} / 0x{input_image_size:X}")
|
|
135
145
|
print(f" Block Count: {fs.block_count:9d}")
|
|
136
146
|
print(f" Name Max: {args.name_max:9d}")
|
|
137
147
|
print(f" Image: {args.source}")
|
|
138
148
|
|
|
149
|
+
return fs
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _list(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
153
|
+
"""List LittleFS image contents."""
|
|
154
|
+
source: Path = args.source
|
|
155
|
+
if not source.is_file():
|
|
156
|
+
parser.error(f"Source image '{source}' does not exist.")
|
|
157
|
+
context = UserContext(buffer=bytearray(source.read_bytes()))
|
|
158
|
+
|
|
159
|
+
fs = _mount_from_context(parser, args, context)
|
|
160
|
+
|
|
139
161
|
for root, dirs, files in fs.walk("/"):
|
|
140
162
|
if not root.endswith("/"):
|
|
141
163
|
root += "/"
|
|
@@ -148,18 +170,12 @@ def _list(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
|
148
170
|
|
|
149
171
|
def extract(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
150
172
|
"""Extract LittleFS image contents to a directory."""
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
173
|
+
source: Path = args.source
|
|
174
|
+
if not source.is_file():
|
|
175
|
+
parser.error(f"Source image '{source}' does not exist.")
|
|
176
|
+
context = UserContext(buffer=bytearray(source.read_bytes()))
|
|
154
177
|
|
|
155
|
-
|
|
156
|
-
fs_size = len(fs.context.buffer)
|
|
157
|
-
print("LittleFS Configuration:")
|
|
158
|
-
print(f" Block Size: {args.block_size:9d} / 0x{args.block_size:X}")
|
|
159
|
-
print(f" Image Size: {fs_size:9d} / 0x{fs_size:X}")
|
|
160
|
-
print(f" Block Count: {fs.block_count:9d}")
|
|
161
|
-
print(f" Name Max: {args.name_max:9d}")
|
|
162
|
-
print(f" Image: {args.source}")
|
|
178
|
+
fs = _mount_from_context(parser, args, context)
|
|
163
179
|
|
|
164
180
|
root_dest = args.destination.absolute()
|
|
165
181
|
if not root_dest.exists():
|
|
@@ -192,36 +208,19 @@ def extract(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
|
192
208
|
|
|
193
209
|
def repl(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
|
|
194
210
|
"""Inspect an existing LittleFS image through an interactive shell."""
|
|
195
|
-
|
|
196
211
|
source: Path = args.source
|
|
197
212
|
if not source.is_file():
|
|
198
213
|
parser.error(f"Source image '{source}' does not exist.")
|
|
214
|
+
context = UserContextFile(str(source)) # In repl we want context to be the file itself, so commands will change it
|
|
199
215
|
|
|
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
216
|
try:
|
|
221
217
|
try:
|
|
222
|
-
|
|
218
|
+
fs = _mount_from_context(parser, args, context)
|
|
223
219
|
except LittleFSError as exc:
|
|
224
220
|
parser.error(f"Failed to mount '{source}': {exc}")
|
|
221
|
+
|
|
222
|
+
shell = LittleFSRepl(fs)
|
|
223
|
+
|
|
225
224
|
shell.cmdloop()
|
|
226
225
|
finally:
|
|
227
226
|
if shell._mounted:
|
|
@@ -358,10 +357,13 @@ def get_parser():
|
|
|
358
357
|
return parser
|
|
359
358
|
|
|
360
359
|
|
|
361
|
-
|
|
360
|
+
# Getting argv optionally from the caller to enable call from python (generally for testing, but could be used for other purposes)
|
|
361
|
+
def main(argv=None):
|
|
362
|
+
if argv is None:
|
|
363
|
+
argv = sys.argv
|
|
362
364
|
parser = get_parser()
|
|
363
|
-
parser.parse_known_args(
|
|
364
|
-
args = parser.parse_args(
|
|
365
|
+
parser.parse_known_args(argv[1:]) # Allows for ``littlefs-python --version``
|
|
366
|
+
args = parser.parse_args(argv[1:])
|
|
365
367
|
return args.func(parser, args)
|
|
366
368
|
|
|
367
369
|
|
|
@@ -10,8 +10,14 @@ if typing.TYPE_CHECKING:
|
|
|
10
10
|
class UserContext:
|
|
11
11
|
"""Basic User Context Implementation"""
|
|
12
12
|
|
|
13
|
-
def __init__(self, buffsize: int) -> None:
|
|
14
|
-
|
|
13
|
+
def __init__(self, buffsize: int = None, buffer: bytearray = None) -> None:
|
|
14
|
+
if buffer is not None:
|
|
15
|
+
self.buffer = buffer
|
|
16
|
+
elif buffsize is not None:
|
|
17
|
+
self.buffer = bytearray([0xFF] * buffsize)
|
|
18
|
+
else:
|
|
19
|
+
raise ValueError("Either buffsize or buffer must be provided")
|
|
20
|
+
self.in_size = len(self.buffer)
|
|
15
21
|
|
|
16
22
|
def read(self, cfg: "LFSConfig", block: int, off: int, size: int) -> bytearray:
|
|
17
23
|
"""read data
|
|
@@ -91,6 +97,7 @@ class UserContextFile(UserContext):
|
|
|
91
97
|
|
|
92
98
|
self._path = file_path
|
|
93
99
|
self._fh = open(file_path, mode)
|
|
100
|
+
self.in_size = os.path.getsize(file_path)
|
|
94
101
|
|
|
95
102
|
def read(self, cfg: "LFSConfig", block: int, off: int, size: int) -> bytearray:
|
|
96
103
|
logging.getLogger(__name__).debug("LFS Read : Block: %d, Offset: %d, Size=%d" % (block, off, size))
|
|
@@ -150,10 +157,11 @@ class UserContextWinDisk(UserContext):
|
|
|
150
157
|
"Unable to import 'win32file'. This module is required for Windows-specific functionality. Please ensure you are running on a Windows platform or install 'pywin32' using: 'pip install pywin32'."
|
|
151
158
|
)
|
|
152
159
|
self.device = win32file.CreateFile(
|
|
153
|
-
disk_path, win32file.GENERIC_READ, win32file.FILE_SHARE_READ, None, win32file.OPEN_EXISTING, 0, None
|
|
160
|
+
disk_path, win32file.GENERIC_READ | win32file.GENERIC_WRITE, win32file.FILE_SHARE_READ, None, win32file.OPEN_EXISTING, 0, None
|
|
154
161
|
)
|
|
155
162
|
if self.device == win32file.INVALID_HANDLE_VALUE:
|
|
156
163
|
raise IOError("Could not open disk %s" % disk_path)
|
|
164
|
+
self.in_size = win32file.GetFileSize(self.device)
|
|
157
165
|
|
|
158
166
|
def read(self, cfg: "LFSConfig", block: int, off: int, size: int) -> bytearray:
|
|
159
167
|
"""read data
|
|
@@ -214,7 +222,7 @@ class UserContextWinDisk(UserContext):
|
|
|
214
222
|
start = block * cfg.block_size
|
|
215
223
|
|
|
216
224
|
win32file.SetFilePointer(self.device, start, win32file.FILE_BEGIN)
|
|
217
|
-
win32file.WriteFile(self.device,
|
|
225
|
+
win32file.WriteFile(self.device, b'\xff' * cfg.block_size)
|
|
218
226
|
return 0
|
|
219
227
|
|
|
220
228
|
def sync(self, cfg: "LFSConfig") -> int:
|