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
154
155
156
157
158
159
160
161
162
|
use std::process::exit;
use butchunker::{
ctx::ButckContext,
special_argument, special_flag,
storage::{ButckRWError, ButckRWErrorKind, build, write},
utils::log::init_logger,
};
use just_progress::{progress, renderer};
use log::error;
use tokio::join;
#[tokio::main]
async fn main() {
// Collect arguments
let mut args: Vec<String> = std::env::args().skip(1).collect();
let version = special_flag!(args, "-v", "--version");
let help = special_flag!(args, "-h", "--help");
if version {
print_version();
exit(0)
}
// Special arguments, early return
if help || args.is_empty() {
print_help();
exit(0)
}
// Init colored
#[cfg(windows)]
colored::control::set_virtual_terminal(true).unwrap();
// Output control flags
let quiet = special_flag!(args, "-q", "--quiet");
let no_progress = special_flag!(args, "-np", "--no-progress");
// Logger
if !quiet {
let logger_level = match special_argument!(args, "-l", "--log-level") {
Some(level) => match level.trim().to_lowercase().as_str() {
"trace" => log::LevelFilter::Trace,
"debug" => log::LevelFilter::Debug,
"info" => log::LevelFilter::Info,
"warn" => log::LevelFilter::Warn,
"error" => log::LevelFilter::Error,
_ => log::LevelFilter::Info,
},
None => log::LevelFilter::Info,
};
init_logger(Some(logger_level));
}
let ctx = ButckContext::from_args(args.clone());
// When `--no-progress` or `--quiet` is enabled,
// the progress system will not be initialized
if no_progress || quiet {
handle_entry_result(entry(ctx, args).await);
} else {
let progress = progress::init();
let renderer = renderer::ProgressSimpleRenderer::new().with_subprogress(true);
let bind = progress::bind(progress, move |name, state| {
if state.progress() > 0. {
renderer.update(name, state)
}
});
join!(
async {
handle_entry_result(entry(ctx, args).await);
progress::clear_all();
progress::close();
},
bind
);
}
}
fn handle_entry_result(r: Result<(), ButckRWError>) {
match r {
Ok(_) => {}
Err(e) => match e.kind() {
ButckRWErrorKind::NoButckStorageFound => {
error!("No butck storage found");
error!("Use `--storage <PATH>` to specify or init butck storage");
}
ButckRWErrorKind::ChunkingPolicyNotSpecified => {
error!("Chunking policy not specified");
error!("Use `--policy <policy_name>` to specify chunking policy");
error!("or use `butck policies` to output the available policies");
}
ButckRWErrorKind::ReadingMethodAmbiguous => error!("Reading method ambiguous"),
ButckRWErrorKind::OutputCountMismatch => {
error!("Output count mismatch");
error!("When processing a single file, use `--output-file` to specify output path");
error!(
"When processing multiple files, use `--output-dir` to specify output directory"
);
}
ButckRWErrorKind::ChunkNotFound(chunk_id) => {
error!("Chunk not found in storage: {}", chunk_id)
}
ButckRWErrorKind::RebuildFailed(reason) => error!("Failed to rebuild file: {}", reason),
ButckRWErrorKind::ChunkFailed(_chunk_failed) => error!("Chunk failed"),
ButckRWErrorKind::IOError(error) => error!("IO error: {}", error),
ButckRWErrorKind::InvalidBidxFormat => error!("Invalid bidx format"),
ButckRWErrorKind::ChunkingFailed(reason) => error!("Chunking failed: {}", reason),
ButckRWErrorKind::IndexFileWriteFailed(reason) => {
error!("Failed to write index file: {}", reason)
}
},
}
}
pub async fn entry(ctx: ButckContext, args: Vec<String>) -> Result<(), ButckRWError> {
if let Some(subcommand) = args.first() {
return match subcommand.as_str() {
"write" => write(ctx).await,
"build" => build(ctx).await,
"lspolicy" => {
if ctx.stream_read.is_some() {
butck_policies::stream_policies()
.iter()
.for_each(|p| println!("{}", p));
} else {
butck_policies::policies()
.iter()
.for_each(|p| println!("{}", p));
}
return Ok(());
}
"lspolicy-all" => {
let policies = butck_policies::policies();
let stream_policies = butck_policies::stream_policies();
let mut all_policies: Vec<_> =
policies.iter().chain(stream_policies.iter()).collect();
all_policies.sort();
all_policies.dedup();
all_policies.iter().for_each(|p| println!("{}", p));
return Ok(());
}
_ => {
print_help();
exit(1)
}
};
}
Ok(())
}
pub fn print_help() {
println!("{}", include_str!("../../resources/helps/butck.txt").trim());
}
pub fn print_version() {
println!(
"{}",
include_str!("../../resources/version_info.txt").trim()
);
}
|