Skip to content

Commit abb56d8

Browse files
committed
[ref-ls] A step towards getting the negotiation right, really need tests
1 parent 22c3640 commit abb56d8

File tree

3 files changed

+42
-21
lines changed

3 files changed

+42
-21
lines changed

git-protocol/src/fetch/arguments.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use std::fmt;
77
use std::io::Write;
88

99
pub struct Arguments {
10-
base_features: Vec<String>,
1110
base_args: Vec<BString>,
1211

1312
args: Vec<BString>,
13+
haves: Vec<BString>,
1414

1515
filter: bool,
1616
shallow: bool,
@@ -48,7 +48,7 @@ impl Arguments {
4848
}
4949
}
5050
pub fn have(&mut self, id: borrowed::Id) {
51-
self.prefixed("have ", id);
51+
self.haves.push(format!("have {}", id).into());
5252
}
5353
pub fn deepen(&mut self, depth: usize) {
5454
assert!(self.shallow, "'shallow' feature required for deepen");
@@ -78,7 +78,7 @@ impl Arguments {
7878
let mut deepen_since = shallow;
7979
let mut deepen_not = shallow;
8080
let mut deepen_relative = shallow;
81-
let (initial_arguments, base_features, features_for_first_want) = match version {
81+
let (initial_arguments, features_for_first_want) = match version {
8282
Protocol::V1 => {
8383
deepen_since = has("deepen-since");
8484
deepen_not = has("deepen-not");
@@ -90,15 +90,15 @@ impl Arguments {
9090
None => n.to_string(),
9191
})
9292
.collect::<Vec<_>>();
93-
(Vec::new(), baked_features.clone(), Some(baked_features))
93+
(Vec::new(), Some(baked_features))
9494
}
95-
Protocol::V2 => (Command::Fetch.initial_arguments(&features), Vec::new(), None),
95+
Protocol::V2 => (Command::Fetch.initial_arguments(&features), None),
9696
};
9797

9898
Arguments {
99-
base_features,
10099
base_args: initial_arguments.clone(),
101100
args: initial_arguments,
101+
haves: Vec::new(),
102102
filter,
103103
shallow,
104104
deepen_not,
@@ -121,17 +121,24 @@ impl Arguments {
121121
}
122122
match version {
123123
git_transport::Protocol::V1 => {
124-
let mut on_drop = vec![client::MessageKind::Flush];
125-
if add_done_argument {
126-
on_drop.push(client::MessageKind::Text(&b"done"[..]));
127-
}
124+
let mut on_drop = if add_done_argument {
125+
vec![client::MessageKind::Text(&b"done"[..])]
126+
} else {
127+
vec![client::MessageKind::Flush]
128+
};
129+
let is_stateful = transport.is_stateful();
130+
let retained_state = if is_stateful { None } else { Some(self.args.clone()) };
128131
let mut line_writer = transport.request(client::WriteMode::OneLFTerminatedLinePerWriteCall, on_drop)?;
132+
129133
for arg in self.args.drain(..) {
130134
line_writer.write_all(&arg)?;
131135
}
132-
if !is_done {
133-
// re-install features for the next round
134-
self.features_for_first_want = Some(self.base_features.clone());
136+
line_writer.write_message(client::MessageKind::Flush)?;
137+
for line in self.haves.drain(..) {
138+
line_writer.write_all(&line)?;
139+
}
140+
if let Some(next_args) = retained_state {
141+
self.args = next_args;
135142
}
136143
Ok(line_writer.into_read())
137144
}

git-protocol/src/fetch/delegate.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,23 @@ pub trait Delegate {
4646
Action::Continue
4747
}
4848

49-
/// Given a list of `arguments` to populate to be send to the remote to start negotiating wants and haves.
50-
/// `refs` are passed in each round, unchanged.
51-
/// `previous_result` will be populated after the first server response has been received and can be used to figure
52-
/// out whether to continue negotiating, or be done by returning `Action::Close`. The latter will be used to cause the
53-
/// server to send a pack, if possible.
54-
fn negotiate(&mut self, refs: &[Ref], arguments: &mut Arguments, previous_result: Option<&Response>) -> Action;
49+
/// ### `previous` is None
50+
/// Given a list of `arguments` to populate to be send to the remote to start negotiation with wants, shallows, filters and
51+
/// other contextual information. This method is called once.
52+
/// Send the objects you `have` have afterwards based on your tips, in preparation to walk down their parents with each call
53+
/// to `negotiate` in find the common base.
54+
/// Note that you should not `want` and object that you already have.
55+
/// `refs` are the the tips of on the server side, effectively the latest objects they have.
56+
///
57+
/// Return `Action::Close` if you know that there are no `haves` on your end to allow the server to send all of its objects,
58+
/// as done during clone.
59+
///
60+
/// ### `previous` is Some
61+
/// Populate `arguments` with the objects you `have` starting from the tips, taking into consideration the `previous` response of the server to see
62+
/// which objects they acknowledged to have. You have to maintain enough state to be able to walk down from your tips on each call,
63+
/// if they are not in common, and keep setting `have` for those which are in common if that helps teaching the server about our state.
64+
/// This method is called until the other side signals they are ready to send a pack.
65+
/// Return `Action::Close` if you want to give up before finding a common base. This can happen if the remote repository has radically changed
66+
/// so there are no bases, or they are very far in the past.
67+
fn negotiate(&mut self, refs: &[Ref], arguments: &mut Arguments, previous: Option<&Response>) -> Action;
5568
}

git-protocol/src/fetch/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ pub fn fetch<F: FnMut(credentials::Action) -> credentials::Result>(
156156
}
157157
let mut arguments = Arguments::new(protocol_version, &fetch_features);
158158
let previous_response = None::<Response>;
159-
// 16? Git does it that way, limiting the amount of lines sent at a time
159+
// 16? Git does it that way, limiting the amount of iterations we take.
160+
// TODO: Make this a loop and abort after having exchanged a certain amount of objects instead
160161
for round in 1..=16 {
161162
progress.step();
162163
progress.set_name(format!("negotiate (round {})", round));
@@ -167,7 +168,7 @@ pub fn fetch<F: FnMut(credentials::Action) -> credentials::Result>(
167168
&fetch_features,
168169
action == Action::Close,
169170
)?;
170-
// TODO: read result in a protocol independent way
171+
// TODO: read server response in a protocol independent way
171172
// match action {
172173
// Action::Close {
173174
//

0 commit comments

Comments
 (0)