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