-
-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathsub.rs
More file actions
153 lines (142 loc) · 5.06 KB
/
sub.rs
File metadata and controls
153 lines (142 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use crate::{
args::Fraction,
data_tree::{DataTree, DataTreeReflection},
fs_tree_builder::FsTreeBuilder,
get_size::GetSize,
json_data::{BinaryVersion, JsonData, SchemaVersion, UnitAndTree},
os_string_display::OsStringDisplay,
reporter::ParallelReporter,
runtime_error::RuntimeError,
size,
status_board::GLOBAL_STATUS_BOARD,
visualizer::{BarAlignment, ColumnWidthDistribution, Direction, Visualizer},
};
use serde::Serialize;
use std::{io::stdout, iter::once, num::NonZeroU64, path::PathBuf};
/// The sub program of the main application.
pub struct Sub<Size, SizeGetter, Report>
where
Report: ParallelReporter<Size> + Sync,
Size: size::Size + Into<u64> + Serialize + Send + Sync,
SizeGetter: GetSize<Size = Size> + Copy + Sync,
DataTreeReflection<String, Size>: Into<UnitAndTree>,
{
/// List of files and/or directories.
pub files: Vec<PathBuf>,
/// Print JSON data instead of an ASCII chart.
pub json_output: bool,
/// Format to be used to [`display`](size::Size::display) the sizes returned by [`size_getter`](Self::size_getter).
pub bytes_format: Size::DisplayFormat,
/// The direction of the visualization.
pub direction: Direction,
/// The alignment of the bars.
pub bar_alignment: BarAlignment,
/// Distribution and number of characters/blocks can be placed in a line.
pub column_width_distribution: ColumnWidthDistribution,
/// Maximum number of levels that should be visualized.
pub max_depth: NonZeroU64,
/// [Get the size](GetSize) of files/directories.
pub size_getter: SizeGetter,
/// Reports measurement progress.
pub reporter: Report,
/// Minimal size proportion required to appear.
pub min_ratio: Fraction,
/// Preserve order of entries.
pub no_sort: bool,
}
impl<Size, SizeGetter, Report> Sub<Size, SizeGetter, Report>
where
Size: size::Size + Into<u64> + Serialize + Send + Sync,
Report: ParallelReporter<Size> + Sync,
SizeGetter: GetSize<Size = Size> + Copy + Sync,
DataTreeReflection<String, Size>: Into<UnitAndTree>,
{
/// Run the sub program.
pub fn run(self) -> Result<(), RuntimeError> {
let Sub {
files,
json_output,
bytes_format,
direction,
bar_alignment,
column_width_distribution,
max_depth,
size_getter,
reporter,
min_ratio,
no_sort,
} = self;
let mut iter = files
.into_iter()
.map(|root| -> DataTree<OsStringDisplay, Size> {
FsTreeBuilder {
reporter: &reporter,
root,
size_getter,
max_depth: max_depth.get(),
}
.into()
});
let data_tree = if let Some(data_tree) = iter.next() {
data_tree
} else {
return Sub {
files: vec![".".into()],
reporter,
..self
}
.run();
};
// ExactSizeIterator::is_empty is unstable
let data_tree = if iter.len() == 0 {
data_tree
} else {
let max_depth = max_depth.get();
let children: Vec<_> = once(data_tree).chain(iter).collect();
DataTree::dir(
OsStringDisplay::os_string_from("(total)"),
Size::default(),
children,
)
.into_par_retained(|_, depth| depth + 1 < max_depth)
};
if reporter.destroy().is_err() {
eprintln!("[warning] Failed to destroy the thread that reports progress");
}
let min_ratio: f32 = min_ratio.into();
let data_tree = {
let mut data_tree = data_tree;
if min_ratio > 0.0 {
data_tree.par_cull_insignificant_data(min_ratio);
}
if !no_sort {
data_tree.par_sort_by(|left, right| left.size().cmp(&right.size()).reverse());
}
data_tree
};
GLOBAL_STATUS_BOARD.clear_line(0);
if json_output {
let unit_and_tree: UnitAndTree = data_tree
.into_reflection() // I really want to use std::mem::transmute here but can't.
.par_convert_names_to_utf8() // TODO: allow non-UTF8 somehow.
.expect("convert all names from raw string to UTF-8")
.into();
let json_data = JsonData {
schema_version: SchemaVersion,
binary_version: Some(BinaryVersion::current()),
unit_and_tree,
};
return serde_json::to_writer(stdout(), &json_data)
.map_err(RuntimeError::SerializationFailure);
}
let visualizer = Visualizer {
data_tree: &data_tree,
bytes_format,
direction,
bar_alignment,
column_width_distribution,
};
print!("{visualizer}"); // visualizer already ends with "\n", println! isn't needed here.
Ok(())
}
}