Skip to content

Commit

Permalink
first sketch of printing fetch results, but… (#450)
Browse files Browse the repository at this point in the history
…it still violates the protocol in dry-run mode as it actually has to
get the pack, apparently the server can't be told to stop otherwise.
Needs more experimentation as well.
  • Loading branch information
Byron committed Oct 2, 2022
1 parent 169a979 commit 13ac9ba
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 13 deletions.
98 changes: 87 additions & 11 deletions gitoxide-core/src/repository/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ pub struct Options {
pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=2;

pub(crate) mod function {
#![allow(unused_variables, unused_mut)]

use super::Options;
use crate::OutputFormat;
use anyhow::bail;
use git_repository as git;
use git_repository::prelude::ObjectIdExt;
use git_repository::refspec::match_group::validate::Fix;
use git_repository::remote::fetch::Status;

pub fn fetch(
repo: git::Repository,
mut progress: impl git::Progress,
progress: impl git::Progress,
mut out: impl std::io::Write,
err: impl std::io::Write,
Options {
Expand All @@ -36,23 +36,99 @@ pub(crate) mod function {
if format != OutputFormat::Human {
bail!("JSON output isn't yet supported for fetching.");
}
let mut remote = crate::repository::remote::by_name_or_url(&repo, remote.as_deref())?;

let mut remote = crate::repository::remote::by_name_or_url(&repo, remote.as_deref())?;
if !ref_specs.is_empty() {
remote.replace_refspecs(ref_specs.iter(), git::remote::Direction::Fetch)?;
}
let res: git::remote::fetch::Outcome<'_> = remote
.connect(git::remote::Direction::Fetch, progress)?
.prepare_fetch(Default::default())?
.with_dry_run(dry_run)
.receive(&git::interrupt::IS_INTERRUPTED)?;

let ref_specs = remote.refspecs(git::remote::Direction::Fetch);
match res.status {
Status::NoChange => crate::repository::remote::refs::print_refmap(
&repo,
remote.refspecs(git::remote::Direction::Fetch),
res.ref_map,
out,
Status::NoChange => {
crate::repository::remote::refs::print_refmap(&repo, ref_specs, res.ref_map, &mut out, err)
}
Status::Change { update_refs, .. } | Status::DryRun { update_refs } => {
print_updates(&repo, update_refs, ref_specs, res.ref_map, &mut out, err)
}
}?;
if dry_run {
writeln!(out, "DRY-RUN: No ref was updated and no pack was received.").ok();
}
Ok(())
}

pub(crate) fn print_updates(
repo: &git::Repository,
update_refs: git::remote::fetch::refs::update::Outcome,
refspecs: &[git::refspec::RefSpec],
mut map: git::remote::fetch::RefMap<'_>,
mut out: impl std::io::Write,
mut err: impl std::io::Write,
) -> anyhow::Result<()> {
let mut last_spec_index = usize::MAX;
let mut updates = update_refs
.iter_mapping_updates(&map.mappings, refspecs)
.collect::<Vec<_>>();
updates.sort_by_key(|t| t.2);
for (update, mapping, spec, edit) in updates {
if mapping.spec_index != last_spec_index {
last_spec_index = mapping.spec_index;
spec.to_ref().write_to(&mut out)?;
writeln!(out)?;
}

write!(out, "\t")?;
match &mapping.remote {
git::remote::fetch::Source::ObjectId(id) => {
write!(out, "{}", id.attach(repo).shorten_or_id())?;
}
git::remote::fetch::Source::Ref(r) => {
crate::repository::remote::refs::print_ref(&mut out, r)?;
}
};
match edit {
Some(edit) => {
writeln!(out, " -> {} [{}]", edit.name, update.mode)
}
None => writeln!(out, " (fetch only)"),
}?;
}
if !map.fixes.is_empty() {
writeln!(
err,
"The following destination refs were removed as they didn't start with 'ref/'"
)?;
map.fixes.sort_by_key(|f| match f {
Fix::MappingWithPartialDestinationRemoved { spec, .. } => *spec,
});
let mut prev_spec = None;
for fix in &map.fixes {
match fix {
Fix::MappingWithPartialDestinationRemoved { name, spec } => {
if prev_spec.map_or(true, |prev_spec| prev_spec != spec) {
prev_spec = spec.into();
spec.write_to(&mut err)?;
writeln!(err)?;
}
writeln!(err, "\t{name}")?;
}
}
}
}
if map.remote_refs.len() - map.mappings.len() != 0 {
writeln!(
err,
),
Status::Change { update_refs, .. } | Status::DryRun { update_refs } => todo!("change printing or dry-run"),
"server sent {} tips, {} were filtered due to {} refspec(s).",
map.remote_refs.len(),
map.remote_refs.len() - map.mappings.len(),
refspecs.len()
)?;
}
Ok(())
}
}
4 changes: 2 additions & 2 deletions gitoxide-core/src/repository/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ mod refs_impl {
pub handshake_info: bool,
}

pub(crate) use super::{print, print_refmap};
pub(crate) use super::{print, print_ref, print_refmap};
}

#[git::protocol::maybe_async::maybe_async]
Expand Down Expand Up @@ -222,7 +222,7 @@ mod refs_impl {
}
}

fn print_ref(mut out: impl std::io::Write, r: &fetch::Ref) -> std::io::Result<&git::hash::oid> {
pub(crate) fn print_ref(mut out: impl std::io::Write, r: &fetch::Ref) -> std::io::Result<&git::hash::oid> {
match r {
fetch::Ref::Direct {
full_ref_name: path,
Expand Down

0 comments on commit 13ac9ba

Please sign in to comment.