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, index, mailmap, odb, revision, tree, Args, Subcommands}, show_progress, }, 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) || args.strict; 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 ); let to_match_settings = |mut opts: git::open::Options| { opts.permissions.config.git_binary = git_installation; if config.is_empty() { opts } else { opts.cli_overrides(config.clone()) } }; mapping.full.modify(to_match_settings); mapping.reduced.modify(to_match_settings); let mut repo = git::ThreadSafeRepository::discover_opts(repository, Default::default(), mapping) .map(git::Repository::from)?; if !config.is_empty() { repo.config_snapshot_mut() .append_config(config.iter(), git::config::Source::Cli) .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 auto_verbose = !progress && !args.no_verbose; 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 { #[cfg(feature = "gitoxide-core-blocking-client")] Subcommands::Clone(crate::plumbing::options::clone::Platform { handshake_info, bare, no_tags, remote, directory, }) => { let opts = core::repository::clone::Options { format, bare, handshake_info, no_tags, }; prepare_and_run( "clone", auto_verbose, progress, progress_keep_open, core::repository::clone::PROGRESS_RANGE, move |progress, out, err| core::repository::clone(remote, directory, config, progress, out, err, opts), ) } #[cfg(feature = "gitoxide-core-blocking-client")] Subcommands::Fetch(crate::plumbing::options::fetch::Platform { dry_run, handshake_info, remote, ref_spec, }) => { let opts = core::repository::fetch::Options { format, dry_run, remote, handshake_info, ref_specs: ref_spec, }; prepare_and_run( "fetch", auto_verbose, progress, progress_keep_open, core::repository::fetch::PROGRESS_RANGE, move |progress, out, err| { core::repository::fetch(repository(Mode::LenientWithGitInstallConfig)?, progress, out, err, opts) }, ) } Subcommands::ConfigTree => show_progress(), 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(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))] Subcommands::Remote(crate::plumbing::options::remote::Platform { name, cmd, handshake_info, }) => { use crate::plumbing::options::remote; match cmd { remote::Subcommands::Refs | remote::Subcommands::RefMap { .. } => { let kind = match cmd { remote::Subcommands::Refs => core::repository::remote::refs::Kind::Remote, remote::Subcommands::RefMap { ref_spec, show_unmapped_remote_refs, } => core::repository::remote::refs::Kind::Tracking { ref_specs: ref_spec, show_unmapped_remote_refs, }, }; let context = core::repository::remote::refs::Options { name_or_url: name, format, handshake_info, }; #[cfg(feature = "gitoxide-core-blocking-client")] { prepare_and_run( "remote-refs", auto_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( auto_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", auto_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", auto_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", auto_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_some(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", auto_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,Lines 1–500 of 892. Load more
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, index, mailmap, odb, revision, tree, Args, Subcommands}, show_progress, }, 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) || args.strict; 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 ); let to_match_settings = |mut opts: git::open::Options| { opts.permissions.config.git_binary = git_installation; if config.is_empty() { opts } else { opts.cli_overrides(config.clone()) } }; mapping.full.modify(to_match_settings); mapping.reduced.modify(to_match_settings); let mut repo = git::ThreadSafeRepository::discover_opts(repository, Default::default(), mapping) .map(git::Repository::from)?; if !config.is_empty() { repo.config_snapshot_mut() .append_config(config.iter(), git::config::Source::Cli) .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 auto_verbose = !progress && !args.no_verbose; 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 { #[cfg(feature = "gitoxide-core-blocking-client")] Subcommands::Clone(crate::plumbing::options::clone::Platform { handshake_info, bare, no_tags, remote, directory, }) => { let opts = core::repository::clone::Options { format, bare, handshake_info, no_tags, }; prepare_and_run( "clone", auto_verbose, progress, progress_keep_open, core::repository::clone::PROGRESS_RANGE, move |progress, out, err| core::repository::clone(remote, directory, config, progress, out, err, opts), ) } #[cfg(feature = "gitoxide-core-blocking-client")] Subcommands::Fetch(crate::plumbing::options::fetch::Platform { dry_run, handshake_info, remote, ref_spec, }) => { let opts = core::repository::fetch::Options { format, dry_run, remote, handshake_info, ref_specs: ref_spec, }; prepare_and_run( "fetch", auto_verbose, progress, progress_keep_open, core::repository::fetch::PROGRESS_RANGE, move |progress, out, err| { core::repository::fetch(repository(Mode::LenientWithGitInstallConfig)?, progress, out, err, opts) }, ) } Subcommands::ConfigTree => show_progress(), 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(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))] Subcommands::Remote(crate::plumbing::options::remote::Platform { name, cmd, handshake_info, }) => { use crate::plumbing::options::remote; match cmd { remote::Subcommands::Refs | remote::Subcommands::RefMap { .. } => { let kind = match cmd { remote::Subcommands::Refs => core::repository::remote::refs::Kind::Remote, remote::Subcommands::RefMap { ref_spec, show_unmapped_remote_refs, } => core::repository::remote::refs::Kind::Tracking { ref_specs: ref_spec, show_unmapped_remote_refs, }, }; let context = core::repository::remote::refs::Options { name_or_url: name, format, handshake_info, }; #[cfg(feature = "gitoxide-core-blocking-client")] { prepare_and_run( "remote-refs", auto_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( auto_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", auto_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", auto_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", auto_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_some(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", auto_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,