summaryrefslogtreecommitdiff
path: root/src/bin/butck.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/butck.rs')
-rw-r--r--src/bin/butck.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/bin/butck.rs b/src/bin/butck.rs
new file mode 100644
index 0000000..6a81fbb
--- /dev/null
+++ b/src/bin/butck.rs
@@ -0,0 +1,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"),
+ },
+ }
+}