Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 235 additions & 0 deletions docs/CLI-Usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
# CLI Usage

```sh
pdu [OPTIONS] [FILES]...
```

## Arguments

* `[FILES]...`: List of files and/or directories.

## Options

<a id="json-input" name="json-input"></a>

### `--json-input`

Read JSON data from stdin.

<a id="json-output" name="json-output"></a>

### `--json-output`

Print JSON data instead of an ASCII chart.

<a id="option-b" name="option-b"></a><a id="bytes-format" name="bytes-format"></a>

### `--bytes-format`

* _Aliases:_ `-b`.
* _Default:_ `metric`.
* _Choices:_
- `plain`: Display plain number of bytes without units
- `metric`: Use metric scale, i.e. 1K = 1000B, 1M = 1000K, and so on
- `binary`: Use binary scale, i.e. 1K = 1024B, 1M = 1024K, and so on

How to display the numbers of bytes.

<a id="option-H" name="option-H"></a><a id="deduplicate-hardlinks" name="deduplicate-hardlinks"></a><a id="detect-links" name="detect-links"></a><a id="dedupe-links" name="dedupe-links"></a>

### `--deduplicate-hardlinks`

* _Aliases:_ `-H`, `--detect-links`, `--dedupe-links`.

Detect and subtract the sizes of hardlinks from their parent directory totals.

<a id="option-x" name="option-x"></a><a id="one-file-system" name="one-file-system"></a>

### `--one-file-system`

* _Aliases:_ `-x`.

Skip directories on different filesystems.

<a id="top-down" name="top-down"></a>

### `--top-down`

Print the tree top-down instead of bottom-up.

<a id="align-right" name="align-right"></a>

### `--align-right`

Set the root of the bars to the right.

<a id="option-q" name="option-q"></a><a id="quantity" name="quantity"></a>

### `--quantity`

* _Aliases:_ `-q`.
* _Default:_ `block-size`.
* _Choices:_
- `apparent-size`: Measure apparent sizes
- `block-size`: Measure block sizes (block-count * 512B)
- `block-count`: Count numbers of blocks

Aspect of the files/directories to be measured.

<a id="option-d" name="option-d"></a><a id="max-depth" name="max-depth"></a><a id="depth" name="depth"></a>

### `--max-depth`

* _Aliases:_ `-d`, `--depth`.
* _Default:_ `10`.

Maximum depth to display the data. Could be either "inf" or a positive integer.

<a id="option-w" name="option-w"></a><a id="total-width" name="total-width"></a><a id="width" name="width"></a>

### `--total-width`

* _Aliases:_ `-w`, `--width`.

Width of the visualization.

<a id="column-width" name="column-width"></a>

### `--column-width`

Maximum widths of the tree column and width of the bar column.

<a id="option-m" name="option-m"></a><a id="min-ratio" name="min-ratio"></a>

### `--min-ratio`

* _Aliases:_ `-m`.
* _Default:_ `0.01`.

Minimal size proportion required to appear.

<a id="no-sort" name="no-sort"></a>

### `--no-sort`

Do not sort the branches in the tree.

<a id="option-s" name="option-s"></a><a id="silent-errors" name="silent-errors"></a><a id="no-errors" name="no-errors"></a>

### `--silent-errors`

* _Aliases:_ `-s`, `--no-errors`.

Prevent filesystem error messages from appearing in stderr.

<a id="option-p" name="option-p"></a><a id="progress" name="progress"></a>

### `--progress`

* _Aliases:_ `-p`.

Report progress being made at the expense of performance.

<a id="threads" name="threads"></a>

### `--threads`

* _Default:_ `auto`.

Set the maximum number of threads to spawn. Could be either "auto", "max", or a positive integer.

<a id="omit-json-shared-details" name="omit-json-shared-details"></a>

### `--omit-json-shared-details`

Do not output `.shared.details` in the JSON output.

<a id="omit-json-shared-summary" name="omit-json-shared-summary"></a>

### `--omit-json-shared-summary`

Do not output `.shared.summary` in the JSON output.

<a id="option-h" name="option-h"></a><a id="help" name="help"></a>

### `--help`

* _Aliases:_ `-h`.

Print help.

<a id="option-V" name="option-V"></a><a id="version" name="version"></a>

### `--version`

* _Aliases:_ `-V`.

Print version.

## Examples

### Show disk usage chart of current working directory

```sh
pdu
```

### Show disk usage chart of a single file or directory

```sh
pdu path/to/file/or/directory
```

### Compare disk usages of multiple files and/or directories

```sh
pdu file.txt dir/
```

### Show chart in apparent sizes instead of block sizes

```sh
pdu --quantity=apparent-size
```

### Detect and subtract the sizes of hardlinks from their parent nodes

```sh
pdu --deduplicate-hardlinks
```

### Show sizes in plain numbers instead of metric units

```sh
pdu --bytes-format=plain
```

### Show sizes in base 2¹⁰ units (binary) instead of base 10³ units (metric)

```sh
pdu --bytes-format=binary
```

### Show disk usage chart of all entries regardless of size

```sh
pdu --min-ratio=0
```

### Only show disk usage chart of entries whose size is at least 5% of total

```sh
pdu --min-ratio=0.05
```

### Show disk usage data as JSON instead of chart

```sh
pdu --min-ratio=0 --max-depth=inf --json-output | jq
```

### Visualize existing JSON representation of disk usage data

```sh
pdu --json-input < disk-usage.json
```
121 changes: 121 additions & 0 deletions docs/Library-Building-Trees.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Building Trees

A [`DataTree`](Library-DataTree.md) comes from one of three places: `FsTreeBuilder` for the real filesystem, `TreeBuilder` for any other hierarchy, or a
[`Reflection`](Library-DataTree.md#reflection). This page covers the first two.

## `FsTreeBuilder`

`fs_tree_builder::FsTreeBuilder` walks a real directory tree. It is a struct of parameters, and the traversal is performed by its `From` implementation, so measurement starts at `.into()`.

```rust
use parallel_disk_usage::data_tree::DataTree;
use parallel_disk_usage::device::DeviceBoundary;
use parallel_disk_usage::fs_tree_builder::FsTreeBuilder;
use parallel_disk_usage::get_size::GetApparentSize;
use parallel_disk_usage::hardlink::HardlinkIgnorant;
use parallel_disk_usage::os_string_display::OsStringDisplay;
use parallel_disk_usage::reporter::{ErrorOnlyReporter, ErrorReport};
use parallel_disk_usage::size::Bytes;

let builder = FsTreeBuilder {
root: "/usr/share".into(),
size_getter: GetApparentSize,
hardlinks_recorder: & HardlinkIgnorant,
reporter: & ErrorOnlyReporter::new(ErrorReport::SILENT),
device_boundary: DeviceBoundary::Cross,
max_depth: 10,
};

let data_tree: DataTree<OsStringDisplay, Bytes> = builder.into();
```

### Fields

| Field | Type | Meaning |
|----------------------|---------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|
| `root` | `PathBuf` | The directory or file at the top of the walk. Becomes the name of the root node. |
| `size_getter` | `impl GetSize<Size = Size> + Sync` | Decides what a file's size is. See [Sizes and Formatting](Library-Sizes-And-Formatting.md#getsize). |
| `hardlinks_recorder` | `&impl RecordHardlinks<Size, Report>` | Detects and records hardlinks during the walk. Use `&HardlinkIgnorant` to skip detection. See [Hardlinks](Library-Hardlinks.md). |
| `reporter` | `&impl Reporter<Size> + Sync` | Receives progress and error events. See [Reporters](Library-Reporters.md). |
| `device_boundary` | `DeviceBoundary` | `Cross` descends into other filesystems, `Stay` does not. |
| `max_depth` | `u64` | Deepest level retained as nodes. |

`From<FsTreeBuilder<..>>` is implemented for `DataTree<OsStringDisplay, Size>`, where `Size` comes from the `size_getter`. The name type is always `OsStringDisplay`. Annotate the destination binding explicitly to pin both down.

### `max_depth`

`max_depth` limits the depth of the *stored* tree, not the depth of the *walk*. Everything below the cutoff is measured and contributes to its ancestors' totals, but is not kept as a separate node. A
`max_depth` of `1` yields a childless root whose size is the total of the whole tree. Use
`u64::MAX` for no limit.

Lowering `max_depth` therefore reduces memory usage but not traversal time.

### `device_boundary`

`DeviceBoundary::Stay` reproduces `--one-file-system`. It reads the device ID of `root` once, then skips any directory whose device ID differs. If `root` cannot be stated, the builder reports a
`SymlinkMetadata` error and returns a single zero-sized file node.

`DeviceBoundary::Cross` performs no device check.

### Errors

`FsTreeBuilder` never fails as a whole. Every I/O problem becomes an `Event::EncounterError` handed to the reporter, and the affected subtree is recorded with a size of zero and no children. The three failing operations are `SymlinkMetadata`, `ReadDirectory`, and `AccessEntry`. See
[Reporters](Library-Reporters.md#error-reports).

The walk uses `symlink_metadata`, so symbolic links are measured as links and never followed.

## `TreeBuilder`

`tree_builder::TreeBuilder` is the generic engine underneath `FsTreeBuilder`. It knows nothing about the filesystem: supply two closures and it performs the parallel recursion. Use it for a hierarchy that is not a directory tree, such as an archive index, an object store listing, or a test fixture.

```rust
use parallel_disk_usage::data_tree::DataTree;
use parallel_disk_usage::size::Bytes;
use parallel_disk_usage::tree_builder::{Info, TreeBuilder};

let builder = TreeBuilder::<String, String, Bytes, _, _ > {
path: "root".to_string(),
name: "root".to_string(),
get_info: | path| Info {
size: Bytes::new(path.len() as u64),
children: Vec::new(),
},
join_path: | prefix, name | format !("{prefix}/{name}"),
max_depth: 10,
};

let data_tree: DataTree<String, Bytes> = builder.into();
```

### Fields

| Field | Meaning |
|-------------|---------------------------------------------------------------------------------------------|
| `path` | The address of the root in whatever address space you are walking. |
| `name` | The label of the root node. `Path` and `Name` may be different types. |
| `get_info` | `Fn(&Path) -> Info<Name, Size>`. Returns the node's own size and the names of its children. |
| `join_path` | `Fn(&Path, &Name) -> Path`. Combines a parent path with a child name. |
| `max_depth` | Same meaning as in `FsTreeBuilder`. |

### `Info`

```rust
pub struct Info<Name, Size> {
pub size: Size,
pub children: Vec<Name>,
}
```

`size` is the node's own size, excluding children. `TreeBuilder` recurses into each child and
`DataTree::dir` adds their totals on top.

### Closure requirements

Both closures are `Copy + Send + Sync`, since they are cloned into every Rayon task. That rules out closures capturing by mutable reference or owning non-`Sync` state. For shared mutable state, capture a shared reference to something internally synchronized, as `FsTreeBuilder` does with its reporter and hardlink recorder.

`get_info` has no error channel and must not panic. Report failures out of band and return
`Info { size: default, children: vec![] }`, again following `FsTreeBuilder`.

## Choosing between the two

Use `FsTreeBuilder` for real directories. Reach for `TreeBuilder` when the source is not a filesystem, or when you need name and path types that `FsTreeBuilder` fixes for you.
Loading