use anyhow::Result;
use gitoxide_core::repository::fetch::{
Options as FetchOptions, PROGRESS_RANGE as FetchProgressRange,
};
use gix::{features::progress, progress::prodash};
use prodash::render::line;
use std::io::{stderr, stdout};
pub fn setup_line_renderer_range(
progress: &std::sync::Arc<prodash::tree::Root>,
levels: std::ops::RangeInclusive<prodash::progress::key::Level>,
) -> line::JoinHandle {
prodash::render::line(
std::io::stderr(),
std::sync::Arc::downgrade(progress),
prodash::render::line::Options {
level_filter: Some(levels),
frames_per_second: 6.0,
initial_delay: Some(std::time::Duration::from_millis(1000)),
timestamp: true,
throughput: true,
hide_cursor: true,
..prodash::render::line::Options::default()
}
.auto_configure(prodash::render::line::StreamKind::Stderr),
)
}
#[must_use] pub fn progress_tree(trace: bool) -> std::sync::Arc<prodash::tree::Root> {
prodash::tree::root::Options {
message_buffer_capacity: if trace { 10_000 } else { 200 },
..Default::default()
}
.into()
}
pub fn get_progress<T>(
func_name: &str,
range: Option<std::ops::RangeInclusive<u8>>,
run: impl FnOnce(
progress::DoOrDiscard<prodash::tree::Item>,
&mut dyn std::io::Write,
&mut dyn std::io::Write,
) -> T,
) -> Result<T> {
let standard_range = 2..=2;
let range = range.unwrap_or_else(|| standard_range.clone());
let progress = progress_tree(false);
let sub_progress = progress.add_child(func_name);
let handle = setup_line_renderer_range(&progress, range);
let mut out = Vec::<u8>::new();
let mut err = Vec::<u8>::new();
let result = gix::trace::coarse!("run").into_scope(|| {
run(
progress::DoOrDiscard::from(Some(sub_progress)),
&mut out,
&mut err,
)
});
handle.shutdown_and_wait();
std::io::Write::write_all(&mut stdout(), &out)?;
std::io::Write::write_all(&mut stderr(), &err)?;
Ok(result)
}
const fn fetch_options(remote: Option<String>, shallow: bool) -> FetchOptions {
let shallow = if shallow {
gix::remote::fetch::Shallow::DepthAtRemote(std::num::NonZeroU32::new(1).unwrap())
} else {
gix::remote::fetch::Shallow::NoChange
};
FetchOptions {
format: gitoxide_core::OutputFormat::Human,
dry_run: false,
remote,
ref_specs: Vec::new(),
shallow,
handshake_info: false,
negotiation_info: false,
open_negotiation_graph: None,
}
}
pub fn fetch_repo(repo: gix::Repository, remote: Option<String>, shallow: bool) -> Result<()> {
let inner_result = get_progress("fetch", Some(FetchProgressRange), |progress, out, err| {
gitoxide_core::repository::fetch(repo, progress, out, err, fetch_options(remote, shallow))
})?;
inner_result.map_err(|e| anyhow::anyhow!("Fetch failed: {e}"))
}