parallel_disk_usage/
args.rs1pub mod fraction;
2pub mod quantity;
3pub mod threads;
4
5pub use fraction::Fraction;
6pub use quantity::Quantity;
7pub use threads::Threads;
8
9use crate::{bytes_format::BytesFormat, visualizer::ColumnWidthDistribution};
10use clap::{ColorChoice, Parser};
11use derive_setters::Setters;
12use smart_default::SmartDefault;
13use std::{num::NonZeroU64, path::PathBuf};
14use terminal_size::{terminal_size, Width};
15use text_block_macros::text_block;
16
17#[derive(Debug, SmartDefault, Setters, Clone, Parser)]
19#[clap(
20 name = "pdu",
21
22 version,
23
24 about = "Summarize disk usage of the set of files, recursively for directories.",
25
26 long_about = text_block! {
27 "Summarize disk usage of the set of files, recursively for directories."
28 ""
29 "Copyright: Apache-2.0 © 2021 Hoàng Văn Khải <https://github.com/KSXGitHub/>"
30 "Sponsor: https://github.com/sponsors/KSXGitHub"
31 },
32
33 after_help = text_block! {
34 "Examples:"
35 " $ pdu"
36 " $ pdu path/to/file/or/directory"
37 " $ pdu file.txt dir/"
38 " $ pdu --quantity=apparent-size"
39 " $ pdu --deduplicate-hardlinks"
40 " $ pdu --bytes-format=plain"
41 " $ pdu --bytes-format=binary"
42 " $ pdu --min-ratio=0"
43 " $ pdu --min-ratio=0.05"
44 " $ pdu --min-ratio=0 --json-output | jq"
45 " $ pdu --min-ratio=0 < disk-usage.json"
46 },
47
48 after_long_help = text_block! {
49 "Examples:"
50 " Show disk usage chart of current working directory"
51 " $ pdu"
52 ""
53 " Show disk usage chart of a single file or directory"
54 " $ pdu path/to/file/or/directory"
55 ""
56 " Compare disk usages of multiple files and/or directories"
57 " $ pdu file.txt dir/"
58 ""
59 " Show chart in apparent sizes instead of block sizes"
60 " $ pdu --quantity=apparent-size"
61 ""
62 " Detect and subtract the sizes of hardlinks from their parent nodes"
63 " $ pdu --deduplicate-hardlinks"
64 ""
65 " Show sizes in plain numbers instead of metric units"
66 " $ pdu --bytes-format=plain"
67 ""
68 " Show sizes in base 2¹⁰ units (binary) instead of base 10³ units (metric)"
69 " $ pdu --bytes-format=binary"
70 ""
71 " Show disk usage chart of all entries regardless of size"
72 " $ pdu --min-ratio=0"
73 ""
74 " Only show disk usage chart of entries whose size is at least 5% of total"
75 " $ pdu --min-ratio=0.05"
76 ""
77 " Show disk usage data as JSON instead of chart"
78 " $ pdu --min-ratio=0 --json-output | jq"
79 ""
80 " Visualize existing JSON representation of disk usage data"
81 " $ pdu --min-ratio=0 < disk-usage.json"
82 },
83
84 color = ColorChoice::Never,
85)]
86#[setters(prefix = "with_")]
87#[non_exhaustive]
88pub struct Args {
89 pub files: Vec<PathBuf>,
91
92 #[clap(
94 long,
95 conflicts_with_all = ["quantity", "deduplicate_hardlinks"]
96 )]
97 pub json_input: bool,
98
99 #[clap(long)]
101 pub json_output: bool,
102
103 #[clap(long, value_enum, default_value_t = BytesFormat::MetricUnits)]
105 #[default(BytesFormat::MetricUnits)]
106 pub bytes_format: BytesFormat,
107
108 #[clap(long, visible_aliases = ["detect-links", "dedupe-links"])]
110 #[cfg_attr(not(unix), clap(hide = true))]
111 pub deduplicate_hardlinks: bool,
112
113 #[clap(long)]
115 pub top_down: bool,
116
117 #[clap(long)]
119 pub align_right: bool,
120
121 #[clap(long, value_enum, default_value_t = Quantity::DEFAULT)]
123 #[default(Quantity::DEFAULT)]
124 pub quantity: Quantity,
125
126 #[clap(long, default_value = "10", visible_alias = "depth")]
128 #[default(_code = "10.try_into().unwrap()")]
129 pub max_depth: NonZeroU64,
130
131 #[clap(long, conflicts_with = "column_width", visible_alias = "width")]
133 pub total_width: Option<usize>,
134
135 #[clap(long, number_of_values = 2, value_names = &["TREE_WIDTH", "BAR_WIDTH"])]
137 pub column_width: Option<Vec<usize>>,
138
139 #[clap(long, default_value = "0.01")]
141 pub min_ratio: Fraction,
142
143 #[clap(long)]
145 pub no_sort: bool,
146
147 #[clap(long, visible_alias = "no-errors")]
149 pub silent_errors: bool,
150
151 #[clap(long)]
153 pub progress: bool,
154
155 #[clap(long, default_value_t = Threads::Auto)]
157 pub threads: Threads,
158
159 #[clap(long, requires = "json_output", requires = "deduplicate_hardlinks")]
161 pub omit_json_shared_details: bool,
162
163 #[clap(long, requires = "json_output", requires = "deduplicate_hardlinks")]
165 pub omit_json_shared_summary: bool,
166}
167
168impl Args {
169 pub(crate) fn column_width_distribution(&self) -> ColumnWidthDistribution {
171 match (self.total_width, self.column_width.as_deref()) {
172 (None, None) => {
173 ColumnWidthDistribution::total(if let Some((Width(width), _)) = terminal_size() {
174 width as usize
175 } else {
176 150
177 })
178 }
179 (Some(total_width), None) => ColumnWidthDistribution::total(total_width),
180 (None, Some([tree_width, bar_width])) => {
181 ColumnWidthDistribution::components(*tree_width, *bar_width)
182 }
183 (total_width, column_width) => {
184 dbg!(total_width, column_width);
185 panic!("Something goes wrong")
186 }
187 }
188 }
189}