207 lines · 7.2 KB · Rust
RawDownload
mod options {    use argh::FromArgs;    use gitoxide_core as core;    use std::path::PathBuf;     #[derive(FromArgs)]    #[argh(name = "gix-plumbing")]    /// The lean git underworld    pub struct Args {        #[argh(switch)]        /// print the program version.        pub version: bool,         #[argh(option, short = 't')]        /// the amount of threads to use for some operations.        ///        /// If unset, or the value is 0, there is no limit and all logical cores can be used.        pub threads: Option<usize>,         #[argh(subcommand)]        pub subcommand: SubCommands,    }     #[derive(FromArgs, PartialEq, Debug)]    #[argh(subcommand)]    pub enum SubCommands {        PackVerify(PackVerify),        PackExplode(PackExplode),    }    /// Explode a pack into loose objects.    ///    /// This can be useful in case of partially invalidated packs to extract as much information as possible,    /// or because working with loose objects is easier with custom tooling.    #[derive(FromArgs, PartialEq, Debug)]    #[argh(subcommand, name = "pack-explode")]    pub struct PackExplode {        #[argh(switch)]        /// read written objects back and assert they match their source. Fail the operation otherwise.        ///        /// Only relevant if an object directory is set.        pub verify: bool,         /// delete the pack and index file after the operation is successful        #[argh(switch)]        pub delete_pack: bool,         /// display verbose messages and progress information        #[argh(switch, short = 'v')]        pub verbose: bool,         /// compress bytes even when using the sink, i.e. no object directory is specified        ///        /// This helps to determine overhead related to compression. If unset, the sink will        /// only create hashes from bytes, which is usually limited by the speed at which input        /// can be obtained.        #[argh(switch)]        pub sink_compress: bool,         /// the amount of checks to run. Defaults to 'all'.        ///        /// Allowed values:        /// all        /// skip-file-checksum        /// skip-file-and-object-checksum        /// skip-file-and-object-checksum-and-no-abort-on-decode        #[argh(option, short = 'c')]        pub check: Option<core::pack::explode::SafetyCheck>,         /// the '.pack' or '.idx' file to explode into loose objects        #[argh(positional)]        pub pack_path: PathBuf,         /// the path into which all objects should be written. Commonly '.git/objects'        #[argh(positional)]        pub object_path: Option<PathBuf>,    }     /// Verify a pack    #[derive(FromArgs, PartialEq, Debug)]    #[argh(subcommand, name = "pack-verify")]    pub struct PackVerify {        #[argh(switch)]        /// decode and parse tags, commits and trees to validate their correctness beyond hashing correctly.        ///        /// Malformed objects should not usually occur, but could be injected on purpose or accident.        /// This will reduce overall performance.        pub decode: bool,         #[argh(switch)]        /// decode and parse tags, commits and trees to validate their correctness, and re-encode them.        ///        /// This flag is primarily to test the implementation of encoding, and requires to decode the object first.        /// Encoding an object after decoding it should yield exactly the same bytes.        /// This will reduce overall performance even more, as re-encoding requires to transform zero-copy objects into        /// owned objects, causing plenty of allocation to occour.        pub re_encode: bool,         #[argh(option)]        /// the algorithm used to verify the pack. They differ in costs.        ///        /// Possible values are "less-time" and "less-memory". Default is "less-memory".        pub algorithm: Option<core::pack::verify::Algorithm>,         /// output statistical information about the pack        #[argh(switch, short = 's')]        pub statistics: bool,        /// display verbose messages and progress information        #[argh(switch, short = 'v')]        pub verbose: bool,        /// the '.pack' or '.idx' file whose checksum to validate.        #[argh(positional)]        pub path: PathBuf,    }} use anyhow::Result;use gitoxide_core as core;use std::io::{stderr, stdout}; #[cfg(not(any(    feature = "prodash-line-renderer-crossterm",    feature = "prodash-line-renderer-termion")))]fn prepare(verbose: bool, name: &str) -> ((), Option<git_features::progress::Log>) {    super::init_env_logger(verbose);    ((), Some(git_features::progress::Log::new(name, Some(1))))} #[cfg(any(    feature = "prodash-line-renderer-crossterm",    feature = "prodash-line-renderer-termion"))]fn prepare(verbose: bool, name: &str) -> (Option<prodash::line::JoinHandle>, Option<prodash::tree::Item>) {    super::init_env_logger(false);     if verbose {        let progress = prodash::Tree::new();        let sub_progress = progress.add_child(name);        let handle = crate::shared::setup_line_renderer(progress, 2, false);        (Some(handle), Some(sub_progress))    } else {        (None, None)    }} pub fn main() -> Result<()> {    pub use options::*;    let cli: Args = crate::shared::from_env();    let thread_limit = cli.threads;    match cli.subcommand {        SubCommands::PackExplode(PackExplode {            pack_path,            sink_compress,            object_path,            verbose,            verify,            check,            delete_pack,        }) => {            let (_handle, progress) = prepare(verbose, "pack-explode");            core::pack::explode::pack_or_pack_index(                pack_path,                object_path,                check.unwrap_or(core::pack::explode::SafetyCheck::All),                progress,                core::pack::explode::Context {                    thread_limit,                    delete_pack,                    sink_compress,                    verify,                },            )        }        SubCommands::PackVerify(PackVerify {            path,            verbose,            statistics,            algorithm,            decode,            re_encode,        }) => {            use self::core::pack::verify;            let (_handle, progress) = prepare(verbose, "pack-verify");            core::pack::verify::pack_or_pack_index(                path,                progress,                core::pack::verify::Context {                    output_statistics: if statistics {                        Some(core::OutputFormat::Human)                    } else {                        None                    },                    algorithm: algorithm.unwrap_or(verify::Algorithm::LessTime),                    thread_limit,                    mode: match (decode, re_encode) {                        (true, false) => verify::Mode::Sha1CRC32Decode,                        (true, true) | (false, true) => verify::Mode::Sha1CRC32DecodeEncode,                        (false, false) => verify::Mode::Sha1CRC32,                    },                    out: stdout(),                    err: stderr(),                },            )            .map(|_| ())        }    }}