summaryrefslogtreecommitdiff
path: root/src/bin/butck.rs
blob: 6a81fbbe750af56d35bc51e8b4a712b5002093c4 (plain)
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"),
        },
    }
}