summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/remote/connection/fetch/receive_pack.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix/src/remote/connection/fetch/receive_pack.rs')
-rw-r--r--vendor/gix/src/remote/connection/fetch/receive_pack.rs129
1 files changed, 74 insertions, 55 deletions
diff --git a/vendor/gix/src/remote/connection/fetch/receive_pack.rs b/vendor/gix/src/remote/connection/fetch/receive_pack.rs
index 7837a9d3a..18e5ac159 100644
--- a/vendor/gix/src/remote/connection/fetch/receive_pack.rs
+++ b/vendor/gix/src/remote/connection/fetch/receive_pack.rs
@@ -19,17 +19,18 @@ use crate::{
connection::fetch::config,
fetch,
fetch::{
- negotiate, negotiate::Algorithm, refs, Error, Outcome, Prepare, ProgressId, RefLogMessage, Shallow, Status,
+ negotiate, negotiate::Algorithm, outcome, refs, Error, Outcome, Prepare, ProgressId, RefLogMessage,
+ Shallow, Status,
},
},
- Progress, Repository,
+ Repository,
};
impl<'remote, 'repo, T> Prepare<'remote, 'repo, T>
where
T: Transport,
{
- /// Receive the pack and perform the operation as configured by git via `gix-config` or overridden by various builder methods.
+ /// Receive the pack and perform the operation as configured by git via `git-config` or overridden by various builder methods.
/// Return `Ok(None)` if there was nothing to do because all remote refs are at the same state as they are locally, or `Ok(Some(outcome))`
/// to inform about all the changes that were made.
///
@@ -72,18 +73,28 @@ where
/// - `gitoxide.userAgent` is read to obtain the application user agent for git servers and for HTTP servers as well.
///
#[gix_protocol::maybe_async::maybe_async]
- pub async fn receive<P>(mut self, mut progress: P, should_interrupt: &AtomicBool) -> Result<Outcome, Error>
+ pub async fn receive<P>(self, mut progress: P, should_interrupt: &AtomicBool) -> Result<Outcome, Error>
where
- P: Progress,
+ P: gix_features::progress::NestedProgress,
P::SubProgress: 'static,
{
+ self.receive_inner(&mut progress, should_interrupt).await
+ }
+
+ #[gix_protocol::maybe_async::maybe_async]
+ #[allow(clippy::drop_non_drop)]
+ pub(crate) async fn receive_inner(
+ mut self,
+ progress: &mut dyn crate::DynNestedProgress,
+ should_interrupt: &AtomicBool,
+ ) -> Result<Outcome, Error> {
+ let _span = gix_trace::coarse!("fetch::Prepare::receive()");
let mut con = self.con.take().expect("receive() can only be called once");
let handshake = &self.ref_map.handshake;
let protocol_version = handshake.server_protocol_version;
let fetch = gix_protocol::Command::Fetch;
- let progress = &mut progress;
let repo = con.remote.repo;
let fetch_features = {
let mut f = fetch.default_features(protocol_version, &handshake.capabilities);
@@ -114,6 +125,7 @@ where
});
}
+ let negotiate_span = gix_trace::detail!("negotiate");
let mut negotiator = repo
.config
.resolved
@@ -131,20 +143,20 @@ where
r.objects.unset_object_cache();
r
};
- let mut graph = graph_repo.commit_graph();
+ let mut graph = graph_repo.revision_graph();
let action = negotiate::mark_complete_and_common_ref(
&graph_repo,
negotiator.deref_mut(),
&mut graph,
&self.ref_map,
&self.shallow,
+ negotiate::make_refmapping_ignore_predicate(con.remote.fetch_tags, &self.ref_map),
)?;
let mut previous_response = None::<gix_protocol::fetch::Response>;
- let mut round = 1;
- let mut write_pack_bundle = match &action {
+ let (mut write_pack_bundle, negotiate) = match &action {
negotiate::Action::NoChange | negotiate::Action::SkipToRefUpdate => {
gix_protocol::indicate_end_of_interaction(&mut con.transport).await.ok();
- None
+ (None, None)
}
negotiate::Action::MustNegotiate {
remote_ref_target_known,
@@ -155,17 +167,19 @@ where
&self.ref_map,
remote_ref_target_known,
&self.shallow,
- con.remote.fetch_tags,
+ negotiate::make_refmapping_ignore_predicate(con.remote.fetch_tags, &self.ref_map),
);
+ let mut rounds = Vec::new();
let is_stateless =
arguments.is_stateless(!con.transport.connection_persists_across_multiple_requests());
let mut haves_to_send = gix_negotiate::window_size(is_stateless, None);
let mut seen_ack = false;
let mut in_vain = 0;
let mut common = is_stateless.then(Vec::new);
- let reader = 'negotiation: loop {
+ let mut reader = 'negotiation: loop {
+ let _round = gix_trace::detail!("negotiate round", round = rounds.len() + 1);
progress.step();
- progress.set_name(format!("negotiate (round {round})"));
+ progress.set_name(format!("negotiate (round {})", rounds.len() + 1));
let is_done = match negotiate::one_round(
negotiator.deref_mut(),
@@ -181,8 +195,14 @@ where
}
seen_ack |= ack_seen;
in_vain += haves_sent;
+ rounds.push(outcome::negotiate::Round {
+ haves_sent,
+ in_vain,
+ haves_to_send,
+ previous_response_had_at_least_one_in_common: ack_seen,
+ });
let is_done = haves_sent != haves_to_send || (seen_ack && in_vain >= 256);
- haves_to_send = gix_negotiate::window_size(is_stateless, haves_to_send);
+ haves_to_send = gix_negotiate::window_size(is_stateless, Some(haves_to_send));
is_done
}
Err(err) => {
@@ -200,17 +220,17 @@ where
previous_response = Some(response);
if has_pack {
progress.step();
- progress.set_name("receiving pack");
+ progress.set_name("receiving pack".into());
if !sideband_all {
setup_remote_progress(progress, &mut reader, should_interrupt);
}
break 'negotiation reader;
- } else {
- round += 1;
}
};
- drop(graph);
+ let graph = graph.detach();
drop(graph_repo);
+ drop(negotiate_span);
+
let previous_response = previous_response.expect("knowledge of a pack means a response was received");
if !previous_response.shallow_updates().is_empty() && shallow_lock.is_none() {
let reject_shallow_remote = repo
@@ -234,28 +254,34 @@ where
};
let write_pack_bundle = if matches!(self.dry_run, fetch::DryRun::No) {
- Some(gix_pack::Bundle::write_to_directory(
- #[cfg(feature = "async-network-client")]
- {
- gix_protocol::futures_lite::io::BlockOn::new(reader)
- },
- #[cfg(not(feature = "async-network-client"))]
- {
- reader
- },
- Some(repo.objects.store_ref().path().join("pack")),
+ #[cfg(not(feature = "async-network-client"))]
+ let mut rd = reader;
+ #[cfg(feature = "async-network-client")]
+ let mut rd = gix_protocol::futures_lite::io::BlockOn::new(reader);
+ let res = gix_pack::Bundle::write_to_directory(
+ &mut rd,
+ Some(&repo.objects.store_ref().path().join("pack")),
progress,
should_interrupt,
Some(Box::new({
let repo = repo.clone();
- move |oid, buf| repo.objects.find(oid, buf).ok()
+ move |oid, buf| repo.objects.find(&oid, buf).ok()
})),
options,
- )?)
+ )?;
+ #[cfg(feature = "async-network-client")]
+ {
+ reader = rd.into_inner();
+ }
+ #[cfg(not(feature = "async-network-client"))]
+ {
+ reader = rd;
+ }
+ Some(res)
} else {
- drop(reader);
None
};
+ drop(reader);
if matches!(protocol_version, gix_protocol::transport::Protocol::V2) {
gix_protocol::indicate_end_of_interaction(&mut con.transport).await.ok();
@@ -266,7 +292,7 @@ where
crate::shallow::write(shallow_lock, shallow_commits, previous_response.shallow_updates())?;
}
}
- write_pack_bundle
+ (write_pack_bundle, Some(outcome::Negotiate { graph, rounds }))
}
};
@@ -293,21 +319,17 @@ where
let out = Outcome {
ref_map: std::mem::take(&mut self.ref_map),
- status: if matches!(self.dry_run, fetch::DryRun::Yes) {
- assert!(write_pack_bundle.is_none(), "in dry run we never read a bundle");
- Status::DryRun {
+ status: match write_pack_bundle {
+ Some(write_pack_bundle) => Status::Change {
+ write_pack_bundle,
update_refs,
- negotiation_rounds: round,
- }
- } else {
- match write_pack_bundle {
- Some(write_pack_bundle) => Status::Change {
- write_pack_bundle,
- update_refs,
- negotiation_rounds: round,
- },
- None => Status::NoPackReceived { update_refs },
- }
+ negotiate: negotiate.expect("if we have a pack, we always negotiated it"),
+ },
+ None => Status::NoPackReceived {
+ dry_run: matches!(self.dry_run, fetch::DryRun::Yes),
+ negotiate,
+ update_refs,
+ },
},
};
Ok(out)
@@ -348,14 +370,14 @@ fn add_shallow_args(
args.deepen_relative();
}
Shallow::Since { cutoff } => {
- args.deepen_since(cutoff.seconds_since_unix_epoch as usize);
+ args.deepen_since(cutoff.seconds);
}
Shallow::Exclude {
remote_refs,
since_cutoff,
} => {
if let Some(cutoff) = since_cutoff {
- args.deepen_since(cutoff.seconds_since_unix_epoch as usize);
+ args.deepen_since(cutoff.seconds);
}
for ref_ in remote_refs {
args.deepen_not(ref_.as_ref().as_bstr());
@@ -365,17 +387,14 @@ fn add_shallow_args(
Ok((shallow_commits, shallow_lock))
}
-fn setup_remote_progress<P>(
- progress: &mut P,
+fn setup_remote_progress(
+ progress: &mut dyn crate::DynNestedProgress,
reader: &mut Box<dyn gix_protocol::transport::client::ExtendedBufRead + Unpin + '_>,
should_interrupt: &AtomicBool,
-) where
- P: Progress,
- P::SubProgress: 'static,
-{
+) {
use gix_protocol::transport::client::ExtendedBufRead;
reader.set_progress_handler(Some(Box::new({
- let mut remote_progress = progress.add_child_with_id("remote", ProgressId::RemoteProgress.into());
+ let mut remote_progress = progress.add_child_with_id("remote".to_string(), ProgressId::RemoteProgress.into());
// SAFETY: Ugh, so, with current Rust I can't declare lifetimes in the involved traits the way they need to
// be and I also can't use scoped threads to pump from local scopes to an Arc version that could be
// used here due to the this being called from sync AND async code (and the async version doesn't work