Skip to content

Commit b3c4b7e

Browse files
committed
support reading the fetch algorithm from configuration
1 parent 4f879bf commit b3c4b7e

File tree

8 files changed

+141
-25
lines changed

8 files changed

+141
-25
lines changed

gix/src/config/tree/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ pub(crate) mod root {
3434
pub const DIFF: sections::Diff = sections::Diff;
3535
/// The `extensions` section.
3636
pub const EXTENSIONS: sections::Extensions = sections::Extensions;
37+
/// The `fetch` section.
38+
pub const FETCH: sections::Fetch = sections::Fetch;
3739
/// The `gitoxide` section.
3840
pub const GITOXIDE: sections::Gitoxide = sections::Gitoxide;
3941
/// The `http` section.
@@ -69,6 +71,7 @@ pub(crate) mod root {
6971
&Self::CREDENTIAL,
7072
&Self::DIFF,
7173
&Self::EXTENSIONS,
74+
&Self::FETCH,
7275
&Self::GITOXIDE,
7376
&Self::HTTP,
7477
&Self::INDEX,
@@ -87,9 +90,9 @@ pub(crate) mod root {
8790

8891
mod sections;
8992
pub use sections::{
90-
branch, checkout, core, credential, diff, extensions, gitoxide, http, index, protocol, remote, ssh, Author, Branch,
91-
Checkout, Clone, Committer, Core, Credential, Diff, Extensions, Gitoxide, Http, Index, Init, Pack, Protocol,
92-
Remote, Safe, Ssh, Url, User,
93+
branch, checkout, core, credential, diff, extensions, fetch, gitoxide, http, index, protocol, remote, ssh, Author,
94+
Branch, Checkout, Clone, Committer, Core, Credential, Diff, Extensions, Fetch, Gitoxide, Http, Index, Init, Pack,
95+
Protocol, Remote, Safe, Ssh, Url, User,
9396
};
9497

9598
/// Generic value implementations for static instantiation.

gix/src/config/tree/sections/fetch.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use crate::{
2+
config,
3+
config::tree::{keys, Fetch, Key, Section},
4+
};
5+
6+
impl Fetch {
7+
/// The `fetch.negotiationAlgorithm` key.
8+
pub const NEGOTIATION_ALGORITHM: NegotiationAlgorithm = NegotiationAlgorithm::new_with_validate(
9+
"negotiationAlgorithm",
10+
&config::Tree::FETCH,
11+
validate::NegotiationAlgorithm,
12+
);
13+
}
14+
15+
impl Section for Fetch {
16+
fn name(&self) -> &str {
17+
"fetch"
18+
}
19+
20+
fn keys(&self) -> &[&dyn Key] {
21+
&[&Self::NEGOTIATION_ALGORITHM]
22+
}
23+
}
24+
25+
/// The `fetch.negotiationAlgorithm` key.
26+
pub type NegotiationAlgorithm = keys::Any<validate::NegotiationAlgorithm>;
27+
28+
mod algorithm {
29+
use gix_object::bstr::ByteSlice;
30+
use std::borrow::Cow;
31+
32+
use crate::remote::fetch::negotiate;
33+
use crate::{
34+
bstr::BStr,
35+
config::{key::GenericErrorWithValue, tree::sections::fetch::NegotiationAlgorithm},
36+
};
37+
38+
impl NegotiationAlgorithm {
39+
/// Derive the negotiation algorithm identified by `name`, case-sensitively.
40+
pub fn try_into_negotiation_algorithm(
41+
&'static self,
42+
name: Cow<'_, BStr>,
43+
) -> Result<negotiate::Algorithm, GenericErrorWithValue> {
44+
Ok(match name.as_ref().as_bytes() {
45+
b"noop" => negotiate::Algorithm::Noop,
46+
b"consecutive" | b"default" => negotiate::Algorithm::Consecutive,
47+
b"skipping" => negotiate::Algorithm::Skipping,
48+
_ => return Err(GenericErrorWithValue::from_value(self, name.into_owned())),
49+
})
50+
}
51+
}
52+
}
53+
54+
mod validate {
55+
use crate::{
56+
bstr::BStr,
57+
config::tree::{keys, Fetch},
58+
};
59+
60+
pub struct NegotiationAlgorithm;
61+
impl keys::Validate for NegotiationAlgorithm {
62+
fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
63+
Fetch::NEGOTIATION_ALGORITHM.try_into_negotiation_algorithm(value.into())?;
64+
Ok(())
65+
}
66+
}
67+
}

gix/src/config/tree/sections/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ pub mod diff;
4545
pub struct Extensions;
4646
pub mod extensions;
4747

48+
/// The `fetch` top-level section.
49+
#[derive(Copy, Clone, Default)]
50+
pub struct Fetch;
51+
pub mod fetch;
52+
4853
/// The `gitoxide` top-level section.
4954
#[derive(Copy, Clone, Default)]
5055
pub struct Gitoxide;

gix/src/remote/connection/fetch/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ impl From<ProgressId> for gix_features::progress::Id {
9191
}
9292
}
9393

94-
///
95-
pub mod negotiate;
94+
pub(crate) mod negotiate;
9695

9796
///
9897
pub mod prepare {

gix/src/remote/connection/fetch/negotiate.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
use crate::remote::fetch;
2-
3-
/// The way the negotiation is performed
4-
#[derive(Copy, Clone)]
5-
pub(crate) enum Algorithm {
6-
/// Our very own implementation that probably should be replaced by one of the known algorithms soon.
7-
Naive,
8-
}
2+
use crate::remote::fetch::negotiate::Algorithm;
93

104
/// The error returned during negotiation.
115
#[derive(Debug, thiserror::Error)]
@@ -23,8 +17,8 @@ pub(crate) fn one_round(
2317
algo: Algorithm,
2418
round: usize,
2519
repo: &crate::Repository,
26-
ref_map: &crate::remote::fetch::RefMap,
27-
fetch_tags: crate::remote::fetch::Tags,
20+
ref_map: &fetch::RefMap,
21+
fetch_tags: fetch::Tags,
2822
arguments: &mut gix_protocol::fetch::Arguments,
2923
_previous_response: Option<&gix_protocol::fetch::Response>,
3024
shallow: Option<&fetch::Shallow>,
@@ -39,6 +33,9 @@ pub(crate) fn one_round(
3933
}
4034

4135
match algo {
36+
Algorithm::Noop | Algorithm::Skipping | Algorithm::Consecutive => {
37+
todo!()
38+
}
4239
Algorithm::Naive => {
4340
assert_eq!(round, 1, "Naive always finishes after the first round, it claims.");
4441
let mut has_missing_tracking_branch = false;

gix/src/remote/fetch.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
///
2+
pub mod negotiate {
3+
/// The way the negotiation is performed.
4+
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
5+
pub enum Algorithm {
6+
/// Do not send any information at all, likely at cost of larger-than-necessary packs.
7+
Noop,
8+
/// Walk over consecutive commits and check each one. This can be costly be assures packs are exactly the size they need to be.
9+
#[default]
10+
Consecutive,
11+
/// Like `Consecutive`, but skips commits to converge faster, at the cost of receiving packs that are larger than they have to be.
12+
Skipping,
13+
/// Our very own implementation that probably should be replaced by one of the known algorithms soon.
14+
Naive,
15+
}
16+
17+
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
18+
pub use super::super::connection::fetch::negotiate::Error;
19+
20+
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
21+
pub(crate) use super::super::connection::fetch::negotiate::one_round;
22+
}
23+
24+
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
25+
pub use super::connection::fetch::{prepare, refs, Error, Outcome, Prepare, ProgressId, RefLogMessage, Status};
26+
127
/// If `Yes`, don't really make changes but do as much as possible to get an idea of what would be done.
228
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
329
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
@@ -197,8 +223,3 @@ pub struct Mapping {
197223
/// The index into the fetch ref-specs used to produce the mapping, allowing it to be recovered.
198224
pub spec_index: SpecIndex,
199225
}
200-
201-
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
202-
pub use super::connection::fetch::{
203-
negotiate, prepare, refs, Error, Outcome, Prepare, ProgressId, RefLogMessage, Status,
204-
};

gix/tests/config/tree.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,36 @@ mod ssh {
117117
}
118118
}
119119

120+
mod fetch {
121+
use crate::config::tree::bcow;
122+
use gix::config::tree::{Fetch, Key};
123+
use gix::remote::fetch::negotiate::Algorithm;
124+
125+
#[test]
126+
fn algorithm() -> crate::Result {
127+
for (actual, expected) in [
128+
("noop", Algorithm::Noop),
129+
("consecutive", Algorithm::Consecutive),
130+
("skipping", Algorithm::Skipping),
131+
("default", Algorithm::Consecutive), // actually, default can be Skipping of `feature.experimental` is true, but we don't deal with that yet until we implement `skipping`
132+
] {
133+
assert_eq!(
134+
Fetch::NEGOTIATION_ALGORITHM.try_into_negotiation_algorithm(bcow(actual))?,
135+
expected
136+
);
137+
assert!(Fetch::NEGOTIATION_ALGORITHM.validate(actual.into()).is_ok());
138+
}
139+
assert_eq!(
140+
Fetch::NEGOTIATION_ALGORITHM
141+
.try_into_negotiation_algorithm(bcow("foo"))
142+
.unwrap_err()
143+
.to_string(),
144+
"The key \"fetch.negotiationAlgorithm=foo\" was invalid"
145+
);
146+
Ok(())
147+
}
148+
}
149+
120150
mod diff {
121151
use gix::{
122152
config::tree::{Diff, Key},

src/plumbing/progress.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,6 @@ static GIT_CONFIG: &[Record] = &[
294294
config: "fetch.output",
295295
usage: NotPlanned {reason: "'gix' might support it, but there is no intention on copying the 'git' CLI"},
296296
},
297-
Record {
298-
config: "fetch.negotiationAlgorithm",
299-
usage: Planned {
300-
note: Some("Implements our own 'naive' algorithm, only"),
301-
},
302-
},
303297
Record {
304298
config: "remotes.<group>",
305299
usage: Planned {

0 commit comments

Comments
 (0)