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 | && cargo test --features blocking-network-client \ | 170 | && cargo test --features blocking-network-client \ |
| 171 | && cargo test --features regex | 171 | && cargo test --features regex |
| 172 | cd gitoxide-core && cargo test --lib | 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 | nextest: ## run tests with `cargo nextest` (all unit-tests, no doc-tests, faster) | 175 | nextest: ## run tests with `cargo nextest` (all unit-tests, no doc-tests, faster) |
| 175 | cargo nextest run --all | 176 | cargo nextest run --all |
| @@ -1,3 +1,4 @@ | |||
| 1 | use crate::remote::fetch; | ||
| 1 | use gix_refspec::RefSpec; | 2 | use gix_refspec::RefSpec; |
| 2 | 3 | ||
| 3 | /// The way the negotiation is performed | 4 | /// The way the negotiation is performed |
| @@ -27,12 +28,21 @@ pub(crate) fn one_round( · 23 unmodified lines | |||
| 27 | fetch_tags: crate::remote::fetch::Tags, | 28 | fetch_tags: crate::remote::fetch::Tags, |
| 28 | arguments: &mut gix_protocol::fetch::Arguments, | 29 | arguments: &mut gix_protocol::fetch::Arguments, |
| 29 | _previous_response: Option<&gix_protocol::fetch::Response>, | 30 | _previous_response: Option<&gix_protocol::fetch::Response>, |
| 30 | wants_shallow_change: Option<&[RefSpec]>, | 31 | wants_shallow_change: Option<(&fetch::Shallow, &[RefSpec])>, |
| 31 | ) -> Result<bool, Error> { | 32 | ) -> Result<bool, Error> { |
| 32 | let tag_refspec_to_ignore = fetch_tags | 33 | let tag_refspec_to_ignore = fetch_tags |
| 33 | .to_refspec() | 34 | .to_refspec() |
| 34 | .filter(|_| matches!(fetch_tags, crate::remote::fetch::Tags::Included)); | 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 | match algo { | 46 | match algo { |
| 37 | Algorithm::Naive => { | 47 | Algorithm::Naive => { |
| 38 | assert_eq!(round, 1, "Naive always finishes after the first round, it claims."); | 48 | assert_eq!(round, 1, "Naive always finishes after the first round, it claims."); |
| @@ -118,7 +118,8 @@ where · 117 unmodified lines | |||
| 118 | con.remote.fetch_tags, | 118 | con.remote.fetch_tags, |
| 119 | &mut arguments, | 119 | &mut arguments, |
| 120 | previous_response.as_ref(), | 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 | Ok(_) if arguments.is_empty() => { | 124 | Ok(_) if arguments.is_empty() => { |
| 124 | gix_protocol::indicate_end_of_interaction(&mut con.transport).await.ok(); | 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 | Ok(()) | 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 | #[maybe_async::test( | 149 | #[maybe_async::test( |
| 111 | feature = "blocking-network-client", | 150 | feature = "blocking-network-client", |
| 112 | async(feature = "async-network-client-async-std", async_std::test) | 151 | async(feature = "async-network-client-async-std", async_std::test) |
| 113 | )] | 152 | )] |
| 114 | async fn fetch_shallow_deepen_not_possible() -> crate::Result { | 153 | async fn fetch_shallow_deepen_not_possible() -> crate::Result { |
| 115 | let (repo, _tmp) = try_repo_rw_args("two-origins", ["--depth=2"], Mode::CloneWithShallowSupport)?; | 154 | let (repo, tmp) = try_repo_rw_args("two-origins", ["--depth=2"], Mode::CloneWithShallowSupport)?; |
| 116 | let remote = repo | 155 | let daemon = spawn_git_daemon_if_async(tmp.path().join("base"))?; |
| 117 | .head()? | 156 | let remote = into_daemon_remote_if_async( |
| 118 | .into_remote(Fetch) | 157 | repo.head()? |
| 119 | .expect("present")? | 158 | .into_remote(Fetch) |
| 120 | .with_fetch_tags(fetch::Tags::Included); | 159 | .expect("present")? |
| 160 | .with_fetch_tags(fetch::Tags::Included), | ||
| 161 | daemon.as_ref(), | ||
| 162 | None, | ||
| 163 | ); | ||
| 121 | 164 | ||
| 122 | assert_eq!( | 165 | assert_eq!( |
| 123 | repo.shallow_commits()?.expect("shallow clone").as_slice(), | 166 | repo.shallow_commits()?.expect("shallow clone").as_slice(), |