Sebastian Thielrefactor (#450)11851f34 years agoHistory
796 lines · 31.1 KB · Rust
RawDownload
use std::{    io::{stdin, BufReader},    path::PathBuf,    sync::{        atomic::{AtomicBool, Ordering},        Arc,    },}; use anyhow::{Context, Result};use clap::Parser;use git_repository::bstr::io::BufReadExt;use gitoxide_core as core;use gitoxide_core::pack::verify; use crate::{    plumbing::options::{        commit, config, credential, exclude, free, mailmap, odb, remote, revision, tree, Args, Subcommands,    },    shared::pretty::prepare_and_run,}; #[cfg(feature = "gitoxide-core-async-client")]pub mod async_util {    use crate::shared::ProgressRange;     #[cfg(not(feature = "prodash-render-line"))]    compile_error!("BUG: Need at least a line renderer in async mode");     pub fn prepare(        verbose: bool,        name: &str,        range: impl Into<Option<ProgressRange>>,    ) -> (        Option<prodash::render::line::JoinHandle>,        git_features::progress::DoOrDiscard<prodash::tree::Item>,    ) {        use crate::shared::{self, STANDARD_RANGE};        shared::init_env_logger();         if verbose {            let progress = shared::progress_tree();            let sub_progress = progress.add_child(name);            let ui_handle = shared::setup_line_renderer_range(&progress, range.into().unwrap_or(STANDARD_RANGE));            (Some(ui_handle), Some(sub_progress).into())        } else {            (None, None.into())        }    }} pub fn main() -> Result<()> {    let args: Args = Args::parse_from(git_repository::env::args_os());    let thread_limit = args.threads;    let verbose = args.verbose;    let format = args.format;    let cmd = args.cmd;    let object_hash = args.object_hash;    let config = args.config;    use git_repository as git;    let repository = args.repository;    enum Mode {        Strict,        StrictWithGitInstallConfig,        Lenient,        LenientWithGitInstallConfig,    }     let repository = {        let config = config.clone();        move |mode: Mode| -> Result<git::Repository> {            let mut mapping: git::sec::trust::Mapping<git::open::Options> = Default::default();            let strict_toggle = matches!(mode, Mode::Strict | Mode::StrictWithGitInstallConfig);            mapping.full = mapping.full.strict_config(strict_toggle);            mapping.reduced = mapping.reduced.strict_config(strict_toggle);            let git_installation = matches!(                mode,                Mode::StrictWithGitInstallConfig | Mode::LenientWithGitInstallConfig            );            mapping.full.permissions.config.git_binary = git_installation;            mapping.reduced.permissions.config.git_binary = git_installation;            let mut repo = git::ThreadSafeRepository::discover_opts(repository, Default::default(), mapping)                .map(git::Repository::from)                .map(|r| r.apply_environment())?;            if !config.is_empty() {                repo.config_snapshot_mut()                    .apply_cli_overrides(config.iter())                    .context("Unable to parse command-line configuration")?;            }            Ok(repo)        }    };     let progress;    let progress_keep_open;    #[cfg(feature = "prodash-render-tui")]    {        progress = args.progress;        progress_keep_open = args.progress_keep_open;    }    #[cfg(not(feature = "prodash-render-tui"))]    {        progress = false;        progress_keep_open = false;    }     let should_interrupt = Arc::new(AtomicBool::new(false));    git_repository::interrupt::init_handler({        let should_interrupt = Arc::clone(&should_interrupt);        move || should_interrupt.store(true, Ordering::SeqCst)    })?;     match cmd {        Subcommands::Credential(cmd) => core::repository::credential(            repository(Mode::StrictWithGitInstallConfig)?,            match cmd {                credential::Subcommands::Fill => git::credentials::program::main::Action::Get,                credential::Subcommands::Approve => git::credentials::program::main::Action::Store,                credential::Subcommands::Reject => git::credentials::program::main::Action::Erase,            },        ),        #[cfg_attr(feature = "small", allow(unused_variables))]        Subcommands::Remote(remote::Platform {            name,            url,            cmd,            handshake_info,        }) => match cmd {            #[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]            remote::Subcommands::Refs | remote::Subcommands::RefMap { .. } => {                let kind = match cmd {                    remote::Subcommands::Refs => core::repository::remote::refs::Kind::Remote,                    remote::Subcommands::RefMap { ref_spec } => {                        core::repository::remote::refs::Kind::Tracking { ref_specs: ref_spec }                    }                };                let context = core::repository::remote::refs::Context {                    name,                    url,                    format,                    handshake_info,                };                #[cfg(feature = "gitoxide-core-blocking-client")]                {                    prepare_and_run(                        "remote-refs",                        verbose,                        progress,                        progress_keep_open,                        core::repository::remote::refs::PROGRESS_RANGE,                        move |progress, out, err| {                            core::repository::remote::refs(                                repository(Mode::LenientWithGitInstallConfig)?,                                kind,                                progress,                                out,                                err,                                context,                            )                        },                    )                }                #[cfg(feature = "gitoxide-core-async-client")]                {                    let (_handle, progress) = async_util::prepare(                        verbose,                        "remote-refs",                        Some(core::repository::remote::refs::PROGRESS_RANGE),                    );                    futures_lite::future::block_on(core::repository::remote::refs(                        repository(Mode::LenientWithGitInstallConfig)?,                        kind,                        progress,                        std::io::stdout(),                        std::io::stderr(),                        context,                    ))                }            }        },        Subcommands::Config(config::Platform { filter }) => prepare_and_run(            "config-list",            verbose,            progress,            progress_keep_open,            None,            move |_progress, out, _err| {                core::repository::config::list(                    repository(Mode::LenientWithGitInstallConfig)?,                    filter,                    config,                    format,                    out,                )            },        )        .map(|_| ()),        Subcommands::Free(subcommands) => match subcommands {            free::Subcommands::CommitGraph(subcommands) => match subcommands {                free::commitgraph::Subcommands::Verify { path, statistics } => prepare_and_run(                    "commitgraph-verify",                    verbose,                    progress,                    progress_keep_open,                    None,                    move |_progress, out, err| {                        let output_statistics = if statistics { Some(format) } else { None };                        core::commitgraph::verify::graph_or_file(                            path,                            core::commitgraph::verify::Context {                                err,                                out,                                output_statistics,                            },                        )                    },                )                .map(|_| ()),            },            free::Subcommands::Index(free::index::Platform {                object_hash,                index_path,                cmd,            }) => match cmd {                free::index::Subcommands::CheckoutExclusive {                    directory,                    empty_files,                    repository,                    keep_going,                } => prepare_and_run(                    "index-checkout",                    verbose,                    progress,                    progress_keep_open,                    None,                    move |progress, _out, err| {                        core::index::checkout_exclusive(                            index_path,                            directory,                            repository,                            err,                            progress,                            &should_interrupt,                            core::index::checkout_exclusive::Options {                                index: core::index::Options { object_hash, format },                                empty_files,                                keep_going,                                thread_limit,                            },                        )                    },                ),                free::index::Subcommands::Info { no_details } => prepare_and_run(                    "index-entries",                    verbose,                    progress,                    progress_keep_open,                    None,                    move |_progress, out, err| {                        core::index::information(                            index_path,                            out,                            err,                            core::index::information::Options {                                index: core::index::Options { object_hash, format },                                extension_details: !no_details,                            },                        )                    },                ),                free::index::Subcommands::Entries => prepare_and_run(                    "index-entries",                    verbose,                    progress,                    progress_keep_open,                    None,                    move |_progress, out, _err| {                        core::index::entries(index_path, out, core::index::Options { object_hash, format })                    },                ),                free::index::Subcommands::Verify => prepare_and_run(                    "index-verify",                    verbose,                    progress,                    progress_keep_open,                    None,                    move |_progress, out, _err| {                        core::index::verify(index_path, out, core::index::Options { object_hash, format })                    },                ),            },            free::Subcommands::Mailmap {                cmd: free::mailmap::Platform { path, cmd },            } => match cmd {                free::mailmap::Subcommands::Verify => prepare_and_run(                    "mailmap-verify",                    verbose,                    progress,                    progress_keep_open,                    core::mailmap::PROGRESS_RANGE,                    move |_progress, out, _err| core::mailmap::verify(path, format, out),                ),            },            free::Subcommands::Pack(subcommands) => match subcommands {                free::pack::Subcommands::Create {                    repository,                    expansion,                    thin,                    statistics,                    nondeterministic_count,                    tips,                    pack_cache_size_mb,                    counting_threads,                    object_cache_size_mb,                    output_directory,                } => {                    let has_tips = !tips.is_empty();                    prepare_and_run(                        "pack-create",                        verbose,                        progress,                        progress_keep_open,                        core::pack::create::PROGRESS_RANGE,                        move |progress, out, _err| {                            let input = if has_tips { None } else { stdin_or_bail()?.into() };                            let repository = repository.unwrap_or_else(|| PathBuf::from("."));                            let context = core::pack::create::Context {                                thread_limit,                                thin,                                nondeterministic_thread_count: nondeterministic_count.then(|| counting_threads),                                pack_cache_size_in_bytes: pack_cache_size_mb.unwrap_or(0) * 1_000_000,                                object_cache_size_in_bytes: object_cache_size_mb.unwrap_or(0) * 1_000_000,                                statistics: if statistics { Some(format) } else { None },                                out,                                expansion: expansion.unwrap_or(if has_tips {                                    core::pack::create::ObjectExpansion::TreeTraversal                                } else {                                    core::pack::create::ObjectExpansion::None                                }),                            };                            core::pack::create(repository, tips, input, output_directory, progress, context)                        },                    )                }                #[cfg(feature = "gitoxide-core-async-client")]                free::pack::Subcommands::Receive {                    protocol,                    url,                    directory,                    refs,                    refs_directory,                } => {                    let (_handle, progress) =                        async_util::prepare(verbose, "pack-receive", core::pack::receive::PROGRESS_RANGE);                    let fut = core::pack::receive(                        protocol,                        &url,                        directory,                        refs_directory,                        refs.into_iter().map(|s| s.into()).collect(),                        progress,                        core::pack::receive::Context {                            thread_limit,                            format,                            out: std::io::stdout(),                            should_interrupt,                            object_hash,                        },                    );                    return futures_lite::future::block_on(fut);                }                #[cfg(feature = "gitoxide-core-blocking-client")]                free::pack::Subcommands::Receive {                    protocol,                    url,                    directory,                    refs,                    refs_directory,                } => prepare_and_run(                    "pack-receive",                    verbose,                    progress,                    progress_keep_open,                    core::pack::receive::PROGRESS_RANGE,                    move |progress, out, _err| {                        core::pack::receive(                            protocol,                            &url,                            directory,                            refs_directory,                            refs.into_iter().map(|r| r.into()).collect(),                            progress,                            core::pack::receive::Context {                                thread_limit,                                format,                                should_interrupt,                                out,                                object_hash,                            },                        )                    },                ),                free::pack::Subcommands::Explode {                    check,                    sink_compress,                    delete_pack,                    pack_path,                    object_path,                    verify,                } => prepare_and_run(                    "pack-explode",                    verbose,                    progress,                    progress_keep_open,                    None,                    move |progress, _out, _err| {                        core::pack::explode::pack_or_pack_index(                            pack_path,                            object_path,                            check,                            progress,                            core::pack::explode::Context {                                thread_limit,                                delete_pack,                                sink_compress,                                verify,                                should_interrupt,                                object_hash,                            },                        )                    },                ),                free::pack::Subcommands::Verify {                    args:                        free::pack::VerifyOptions {                            algorithm,                            decode,                            re_encode,                            statistics,                        },                    path,                } => prepare_and_run(                    "pack-verify",                    verbose,                    progress,                    progress_keep_open,                    verify::PROGRESS_RANGE,                    move |progress, out, err| {                        let mode = verify_mode(decode, re_encode);                        let output_statistics = if statistics { Some(format) } else { None };                        verify::pack_or_pack_index(                            path,                            progress,                            verify::Context {                                output_statistics,                                out,                                err,                                thread_limit,                                mode,                                algorithm,                                should_interrupt: &should_interrupt,                                object_hash,                            },                        )                    },                )                .map(|_| ()),                free::pack::Subcommands::MultiIndex(free::pack::multi_index::Platform { multi_index_path, cmd }) => {                    match cmd {                        free::pack::multi_index::Subcommands::Entries => prepare_and_run(                            "pack-multi-index-entries",                            verbose,                            progress,                            progress_keep_open,                            core::pack::multi_index::PROGRESS_RANGE,                            move |_progress, out, _err| core::pack::multi_index::entries(multi_index_path, format, out),                        ),                        free::pack::multi_index::Subcommands::Info => prepare_and_run(                            "pack-multi-index-info",                            verbose,                            progress,                            progress_keep_open,                            core::pack::multi_index::PROGRESS_RANGE,                            move |_progress, out, err| {                                core::pack::multi_index::info(multi_index_path, format, out, err)                            },                        ),                        free::pack::multi_index::Subcommands::Verify => prepare_and_run(                            "pack-multi-index-verify",                            verbose,                            progress,                            progress_keep_open,                            core::pack::multi_index::PROGRESS_RANGE,                            move |progress, _out, _err| {                                core::pack::multi_index::verify(multi_index_path, progress, &should_interrupt)                            },                        ),                        free::pack::multi_index::Subcommands::Create { index_paths } => prepare_and_run(                            "pack-multi-index-create",                            verbose,

Lines 1–500 of 796.