Git does everything except an actual attempt to negotiate for fetching a pack in order to apply purge rules for references for instance, and we do the same.
Unified · Split
| @@ -170,6 +170,7 @@ unit-tests: ## run all unit tests · 169 unmodified lines | ||
| 170 | 170 | && cargo test --features blocking-network-client \ |
| 171 | 171 | && cargo test --features regex |
| 172 | 172 | cd gitoxide-core && cargo test --lib |
| 173 | +# cd gix && cargo test --features async-network-client-async-std \ not being run as it's flaky even locally | |
| 173 | 174 | |
| 174 | 175 | nextest: ## run tests with `cargo nextest` (all unit-tests, no doc-tests, faster) |
| 175 | 176 | cargo nextest run --all |
| @@ -1,3 +1,4 @@ | ||
| 1 | +use crate::remote::fetch; | |
| 1 | 2 | use gix_refspec::RefSpec; |
| 2 | 3 | |
| 3 | 4 | /// The way the negotiation is performed |
| @@ -27,12 +28,21 @@ pub(crate) fn one_round( · 23 unmodified lines | ||
| 27 | 28 | fetch_tags: crate::remote::fetch::Tags, |
| 28 | 29 | arguments: &mut gix_protocol::fetch::Arguments, |
| 29 | 30 | _previous_response: Option<&gix_protocol::fetch::Response>, |
| 30 | − wants_shallow_change: Option<&[RefSpec]>, | |
| 31 | + wants_shallow_change: Option<(&fetch::Shallow, &[RefSpec])>, | |
| 31 | 32 | ) -> Result<bool, Error> { |
| 32 | 33 | let tag_refspec_to_ignore = fetch_tags |
| 33 | 34 | .to_refspec() |
| 34 | 35 | .filter(|_| matches!(fetch_tags, crate::remote::fetch::Tags::Included)); |
| 35 | − let non_wildcard_specs_only = wants_shallow_change; | |
| 36 | + let (shallow, non_wildcard_specs_only) = wants_shallow_change | |
| 37 | + .map(|(a, b)| (Some(a), Some(b))) | |
| 38 | + .unwrap_or_default(); | |
| 39 | + | |
| 40 | + if let Some(shallow) = shallow { | |
| 41 | + if *shallow == fetch::Shallow::Deepen(0) { | |
| 42 | + return Ok(true); | |
| 43 | + } | |
| 44 | + } | |
| 45 | + | |
| 36 | 46 | match algo { |
| 37 | 47 | Algorithm::Naive => { |
| 38 | 48 | assert_eq!(round, 1, "Naive always finishes after the first round, it claims."); |
| @@ -118,7 +118,8 @@ where · 117 unmodified lines | ||
| 118 | 118 | con.remote.fetch_tags, |
| 119 | 119 | &mut arguments, |
| 120 | 120 | previous_response.as_ref(), |
| 121 | − (self.shallow != Shallow::NoChange).then(|| con.remote.refspecs(remote::Direction::Fetch)), | |
| 121 | + (self.shallow != Shallow::NoChange) | |
| 122 | + .then(|| (&self.shallow, con.remote.refspecs(remote::Direction::Fetch))), | |
| 122 | 123 | ) { |
| 123 | 124 | Ok(_) if arguments.is_empty() => { |
| 124 | 125 | gix_protocol::indicate_end_of_interaction(&mut con.transport).await.ok(); |
| @@ -107,17 +107,60 @@ mod blocking_and_async_io { · 106 unmodified lines | ||
| 107 | 107 | Ok(()) |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | + #[maybe_async::test( | |
| 111 | + feature = "blocking-network-client", | |
| 112 | + async(feature = "async-network-client-async-std", async_std::test) | |
| 113 | + )] | |
| 114 | + async fn fetch_shallow_deepen_zero_does_not_fail() -> crate::Result { | |
| 115 | + let (repo, tmp) = try_repo_rw_args("two-origins", ["--depth=2"], Mode::CloneWithShallowSupport)?; | |
| 116 | + let daemon = spawn_git_daemon_if_async(tmp.path().join("base"))?; | |
| 117 | + let remote = into_daemon_remote_if_async( | |
| 118 | + repo.head()? | |
| 119 | + .into_remote(Fetch) | |
| 120 | + .expect("present")? | |
| 121 | + .with_fetch_tags(fetch::Tags::Included), | |
| 122 | + daemon.as_ref(), | |
| 123 | + None, | |
| 124 | + ); | |
| 125 | + | |
| 126 | + let prev_commits = repo.head_id()?.ancestors().all()?.count(); | |
| 127 | + | |
| 128 | + let changes = remote | |
| 129 | + .connect(Fetch, gix::progress::Discard) | |
| 130 | + .await? | |
| 131 | + .prepare_fetch(Default::default()) | |
| 132 | + .await? | |
| 133 | + .with_shallow(fetch::Shallow::Deepen(0)) | |
| 134 | + .receive(&AtomicBool::default()) | |
| 135 | + .await?; | |
| 136 | + | |
| 137 | + assert!( | |
| 138 | + matches!(changes.status, Status::NoPackReceived { .. }), | |
| 139 | + "we didn't negotiate at all, but ran all other ref updates" | |
| 140 | + ); | |
| 141 | + assert_eq!( | |
| 142 | + repo.head_id()?.ancestors().all()?.count(), | |
| 143 | + prev_commits, | |
| 144 | + "no more commits are available - we didn't fetch anything and there would be nothing to fetch" | |
| 145 | + ); | |
| 146 | + Ok(()) | |
| 147 | + } | |
| 148 | + | |
| 110 | 149 | #[maybe_async::test( |
| 111 | 150 | feature = "blocking-network-client", |
| 112 | 151 | async(feature = "async-network-client-async-std", async_std::test) |
| 113 | 152 | )] |
| 114 | 153 | async fn fetch_shallow_deepen_not_possible() -> crate::Result { |
| 115 | − let (repo, _tmp) = try_repo_rw_args("two-origins", ["--depth=2"], Mode::CloneWithShallowSupport)?; | |
| 116 | − let remote = repo | |
| 117 | − .head()? | |
| 118 | − .into_remote(Fetch) | |
| 119 | − .expect("present")? | |
| 120 | − .with_fetch_tags(fetch::Tags::Included); | |
| 154 | + let (repo, tmp) = try_repo_rw_args("two-origins", ["--depth=2"], Mode::CloneWithShallowSupport)?; | |
| 155 | + let daemon = spawn_git_daemon_if_async(tmp.path().join("base"))?; | |
| 156 | + let remote = into_daemon_remote_if_async( | |
| 157 | + repo.head()? | |
| 158 | + .into_remote(Fetch) | |
| 159 | + .expect("present")? | |
| 160 | + .with_fetch_tags(fetch::Tags::Included), | |
| 161 | + daemon.as_ref(), | |
| 162 | + None, | |
| 163 | + ); | |
| 121 | 164 | |
| 122 | 165 | assert_eq!( |
| 123 | 166 | repo.shallow_commits()?.expect("shallow clone").as_slice(), |