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
|
use std::process::exit;
use butchunker::{
chunker::{
context::ButckContext,
entry::{entry, print_help, print_version},
rw::error::{ButckRWError, ButckRWErrorKind},
},
log::init_logger,
special_argument, special_flag,
};
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| renderer.update(name, state));
join!(
async {
handle_entry_result(entry(ctx, args).await);
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"),
},
}
}
|