Add --dev flag to stay on the same filesystem#349
Add --dev flag to stay on the same filesystem#349KSXGitHub wants to merge 2 commits intoKSXGitHub:masterfrom
Conversation
Add a --dev flag (POSIX only) that prevents pdu from crossing mount points during directory traversal. When active, entries whose st_dev differs from the root directory's st_dev are skipped entirely. - Add `dev` field to Args with clap integration (hidden on non-unix) - Add DevArgConflict runtime error when --dev is used with >1 path - Add UnsupportedFeature::Dev for non-unix platforms - Add root_dev field to FsTreeBuilder and Sub for device filtering - Add dev dimension to the run! macro (24 branches on unix) - Regenerate shell completions and help exports https://claude.ai/code/session_011HRevtBX4rP4YfBdapPFam
There was a problem hiding this comment.
Pull request overview
Adds a new --dev CLI flag to restrict filesystem traversal to the same device (avoid crossing mount points), by computing a root device ID and filtering traversal based on MetadataExt::dev() on Unix.
Changes:
- Adds
--devto CLI args with Unix-only behavior (hidden and rejected on non-Unix). - Threads
root_dev: Option<u64>throughApp → Sub → FsTreeBuilderand uses it to stop traversal into other devices. - Updates runtime errors/exit codes and refreshes help text, completion scripts, usage docs, and tests.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/args.rs |
Adds the --dev flag to CLI parsing (hidden on non-Unix). |
src/app.rs |
Validates --dev, computes root_dev, and expands the run! macro matrix to include dev on/off variants. |
src/app/sub.rs |
Passes root_dev into FsTreeBuilder during traversal. |
src/fs_tree_builder.rs |
Implements device-ID filtering during metadata collection to prevent crossing filesystems. |
src/runtime_error.rs |
Adds DevArgConflict and UnsupportedFeature::Dev, updates exit code mapping. |
tests/usual_cli.rs |
Updates builder struct literals for the new root_dev field. |
tests/json.rs |
Updates builder struct literal for the new root_dev field. |
tests/cli_errors.rs |
Updates builder struct literal for the new root_dev field. |
tests/_utils.rs |
Updates helper builder struct literal for the new root_dev field. |
exports/short.help |
Documents --dev in short help export. |
exports/long.help |
Documents --dev in long help export. |
exports/completion.* |
Adds --dev to shell completion outputs. |
USAGE.md |
Adds --dev documentation entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pub reporter: &'a Report, | ||
| /// Deepest level of descendant display in the graph. The sizes beyond the max depth still count toward total. | ||
| pub max_depth: u64, | ||
| /// Device ID of the root directory. When `Some`, entries on different devices are skipped. |
There was a problem hiding this comment.
The root_dev field doc comment implies it works on all platforms, but the actual filtering logic is behind #[cfg(unix)] and is a no-op on non-Unix builds. Please clarify in the doc comment that this filtering is Unix-only (or gate the field/docs accordingly) to avoid misleading library users on Windows.
| /// Device ID of the root directory. When `Some`, entries on different devices are skipped. | |
| /// Device ID of the root directory. | |
| /// | |
| /// On Unix, when this is `Some`, entries on different devices are skipped. | |
| /// On non-Unix platforms this field is currently ignored and has no effect. |
| // When --dev is active, skip entries on different filesystems | ||
| #[cfg(unix)] | ||
| if let Some(root_dev) = root_dev { | ||
| use std::os::unix::fs::MetadataExt; | ||
| if stats.dev() != root_dev { | ||
| return Info { | ||
| size: Size::default(), | ||
| children: Vec::new(), | ||
| }; | ||
| } |
There was a problem hiding this comment.
This --dev path check returns an empty Info (size=0, no children), which stops traversal but still keeps the mountpoint entry in the resulting DataTree with a zero size. If the intended behavior is to truly skip the entry (omit it from output entirely), the filtering likely needs to happen at the parent read_dir stage (or TreeBuilder/Info needs an explicit “skip node” mechanism). If keeping the node is intended, consider adjusting the comment to say “do not traverse into” rather than “skip entries”.
| pub min_ratio: Fraction, | ||
| /// Preserve order of entries. | ||
| pub no_sort: bool, | ||
| /// Device ID of the root directory. When `Some`, entries on different devices are skipped. |
There was a problem hiding this comment.
root_dev is documented as skipping entries on different devices, but on non-Unix platforms the dev-based filtering is not compiled in (and --dev is rejected). Consider clarifying in this field doc comment that it’s only meaningful on Unix, to keep the public Sub API accurate.
| /// Device ID of the root directory. When `Some`, entries on different devices are skipped. | |
| /// Device ID of the root directory. On Unix, when `Some`, entries on different devices are | |
| /// skipped. On non-Unix platforms this field is ignored and has no effect. |
| if self.args.dev && self.args.files.len() > 1 { | ||
| return Err(RuntimeError::DevArgConflict); | ||
| } |
There was a problem hiding this comment.
New behavior is introduced here (--dev validation and the DevArgConflict error), but there doesn’t appear to be a corresponding CLI test ensuring the error triggers (and that --dev is wired through the run! matrix). Adding a small test case (e.g., pdu --dev path1 path2 expecting DevArgConflict) would help prevent regressions when the macro arm list changes.
root_dev is only used inside a #[cfg(unix)] block, so it triggers an unused variable warning on Windows builds. Add #[allow(unused_variables)] to the destructuring to fix CI. https://claude.ai/code/session_011HRevtBX4rP4YfBdapPFam
Summary
This PR adds a new
--devcommand-line flag that restricts directory traversal to a single filesystem, preventing the tool from crossing mount points. This is useful when analyzing disk usage on systems with multiple mounted filesystems.Key Changes
--devCLI argument: Added toArgsstruct with platform-specific visibility (POSIX only)get_root_dev()function to retrieve the device ID of the root path usingMetadataExt::dev()on Unix systemsFsTreeBuilderto skip entries on different filesystems whenroot_devis set--devis only used on Unix platforms and cannot be combined with multiple path argumentsDevArgConflicterror variant for invalid flag combinations andUnsupportedFeature::Devfor non-Unix platformsroot_dev: Noneparameter in builder initializationImplementation Details
run!pattern was extended to handle the newdevparameter across all size getter and progress combinationshttps://claude.ai/code/session_011HRevtBX4rP4YfBdapPFam