Skip to content

Commit 7fa189d

Browse files
authored
Merge pull request #160 from amgross/add_cli_options
Add more needed options to CLI
2 parents cb85400 + e98a2f2 commit 7fa189d

2 files changed

Lines changed: 89 additions & 7 deletions

File tree

src/littlefs/__main__.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@
1919

2020

2121
def _fs_from_args(args: argparse.Namespace, block_count=None, mount=True, context: UserContext = None) -> LittleFS:
22+
"""Build LittleFS from CLI args. Options name_max, attr_max, file_max are stored in the
23+
superblock and must match when mounting an existing image. inline_max is format-relevant
24+
(limiting it may improve flash usage)."""
2225
block_count = block_count if block_count is not None else getattr(args, "block_count", 0)
23-
return LittleFS(
24-
context=context,
25-
block_size=args.block_size,
26-
block_count=block_count,
27-
name_max=args.name_max,
28-
mount=mount,
29-
)
26+
kwargs = {
27+
"block_size": args.block_size,
28+
"block_count": block_count,
29+
"name_max": args.name_max,
30+
"inline_max": args.inline_max,
31+
"attr_max": args.attr_max,
32+
"file_max": args.file_max,
33+
}
34+
return LittleFS(context=context, mount=mount, **kwargs)
3035

3136

3237
def size_parser(size_str):
@@ -81,6 +86,12 @@ def create(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
8186
print(f" Image Size: {args.fs_size:9d} / 0x{args.fs_size:X}")
8287
print(f" Block Count: {args.block_count:9d}")
8388
print(f" Name Max: {args.name_max:9d}")
89+
if args.inline_max:
90+
print(f" Inline Max: {args.inline_max:9d} / 0x{args.inline_max:X}")
91+
if args.attr_max:
92+
print(f" Attr Max: {args.attr_max:9d}")
93+
if args.file_max:
94+
print(f" File Max: {args.file_max:9d}")
8495
print(f" Image: {args.destination}")
8596

8697
source = Path(args.source).absolute()
@@ -144,6 +155,12 @@ def _mount_from_context(parser: argparse.ArgumentParser, args: argparse.Namespac
144155
print(f" Image Size: {input_image_size:9d} / 0x{input_image_size:X}")
145156
print(f" Block Count: {fs.block_count:9d}")
146157
print(f" Name Max: {args.name_max:9d}")
158+
if args.inline_max:
159+
print(f" Inline Max: {args.inline_max:9d} / 0x{args.inline_max:X}")
160+
if args.attr_max:
161+
print(f" Attr Max: {args.attr_max:9d}")
162+
if args.file_max:
163+
print(f" File Max: {args.file_max:9d}")
147164
print(f" Image: {args.source}")
148165

149166
return fs
@@ -251,12 +268,32 @@ def get_parser():
251268

252269
common_parser = argparse.ArgumentParser(add_help=False)
253270
common_parser.add_argument("-v", "--verbose", action="count", default=0)
271+
# Stored in superblock; must match when mounting an existing image:
254272
common_parser.add_argument(
255273
"--name-max",
256274
type=size_parser,
257275
default=255,
258276
help="LittleFS max file path length. Defaults to LittleFS's default (255).",
259277
)
278+
common_parser.add_argument(
279+
"--attr-max",
280+
type=int,
281+
default=0,
282+
help="Max custom attribute size per file. Defaults to LittleFS's default (0 = use library default).",
283+
)
284+
common_parser.add_argument(
285+
"--file-max",
286+
type=int,
287+
default=0,
288+
help="Max number of open files. Defaults to LittleFS's default (0 = use library default).",
289+
)
290+
# Format option: limiting inline_max may improve flash usage.
291+
common_parser.add_argument(
292+
"--inline-max",
293+
type=size_parser,
294+
default=0,
295+
help="Max inline file size; 0 = use library default. Limiting can improve flash usage.",
296+
)
260297

261298
subparsers = parser.add_subparsers(required=True, title="Available Commands", dest="command")
262299

test/cli/test_create_and_extract.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,48 @@ def test_create_compact_roundtrip(tmp_path, num_files, file_size):
9999
extracted_file = extract_dir / f"file_{i}.txt"
100100
assert extracted_file.exists(), f"file_{i}.txt missing from compact image"
101101
assert extracted_file.read_text() == f"content_{i}_" + "x" * file_size
102+
103+
104+
def _make_small_source(tmp_path):
105+
"""Create a small source tree (one dir, two small files) for config option tests."""
106+
source_dir = tmp_path / "source"
107+
source_dir.mkdir()
108+
(source_dir / "a.txt").write_text("hello")
109+
(source_dir / "b.txt").write_text("world")
110+
return source_dir
111+
112+
113+
@pytest.mark.parametrize(
114+
"option_name, create_extra, extract_extra",
115+
[
116+
("inline_max", ["--inline-max", "64"], ["--inline-max", "64"]),
117+
("attr_max", ["--attr-max", "64"], ["--attr-max", "64"]),
118+
("file_max", ["--file-max", "32"], ["--file-max", "32"]),
119+
],
120+
)
121+
def test_create_extract_roundtrip_with_config_option(tmp_path, option_name, create_extra, extract_extra):
122+
"""Create image with a config option, extract with same option, compare to source."""
123+
source_dir = _make_small_source(tmp_path)
124+
image_file = tmp_path / "image.bin"
125+
extract_dir = tmp_path / "extracted"
126+
127+
create_argv = [
128+
"littlefs", "create", str(source_dir), str(image_file),
129+
"--block-size", "1024", "--fs-size", "64KB",
130+
] + create_extra
131+
assert main(create_argv) == 0
132+
assert image_file.exists()
133+
134+
extract_argv = [
135+
"littlefs", "extract", str(image_file), str(extract_dir),
136+
"--block-size", "1024",
137+
] + extract_extra
138+
assert main(extract_argv) == 0
139+
assert extract_dir.exists()
140+
141+
comparison = filecmp.dircmp(source_dir, extract_dir)
142+
assert not comparison.diff_files
143+
assert not comparison.left_only
144+
assert not comparison.right_only
145+
assert (extract_dir / "a.txt").read_text() == "hello"
146+
assert (extract_dir / "b.txt").read_text() == "world"

0 commit comments

Comments
 (0)