History

[git-protocol] move everything into `blocking_io` for later translation…

…into async-io, as usual.

Sebastian Thiel committed 5 years ago

Commit fa033741 parent 0d39b5d12 files · +295 −254Browse files

Showing the changes to git-protocol/src/fetch/refs.rs (1 of 12 files). Show all

Unified · Split

git-protocol/src/fetch/refs.rs+0−271
@@ -1,271 +0,0 @@
1−use bstr::{BString, ByteSlice};
2−use quick_error::quick_error;
3−use std::io;
4−
5−quick_error! {
6− #[derive(Debug)]
7− pub enum Error {
8− Io(err: io::Error) {
9− display("An IO error occurred while reading refs from the server")
10− from()
11− source(err)
12− }
13− Id(err: git_hash::decode::Error) {
14− display("Failed to hex-decode object hash")
15− from()
16− source(err)
17− }
18− MalformedSymref(symref: BString) {
19− display("'{}' could not be parsed. A symref is expected to look like <NAME>:<target>.", symref)
20− }
21− MalformedV1RefLine(line: String) {
22− display("'{}' could not be parsed. A V1 ref line should be '<hex-hash> <path>'.", line)
23− }
24− MalformedV2RefLine(line: String) {
25− display("'{}' could not be parsed. A V2 ref line should be '<hex-hash> <path>[ (peeled|symref-target):<value>'.", line)
26− }
27− UnkownAttribute(attribute: String, line: String) {
28− display("The ref attribute '{}' is unknown. Found in line '{}'", attribute, line)
29− }
30− InvariantViolation(message: &'static str) {
31− display("{}", message)
32− }
33− }
34−}
35−
36−/// A git reference, commonly referred to as 'ref', as returned by a git server before sending a pack.
37−#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
38−#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
39−pub enum Ref {
40− /// A ref pointing to a `tag` object, which in turns points to an `object`, usually a commit
41− Peeled {
42− /// The path at which the ref is located, like `/refs/heads/main`.
43− path: BString,
44− /// The hash of the tag the ref points to.
45− tag: git_hash::ObjectId,
46− /// The hash of the object the `tag` points to.
47− object: git_hash::ObjectId,
48− },
49− /// A ref pointing to a commit object
50− Direct {
51− /// The path at which the ref is located, like `/refs/heads/main`.
52− path: BString,
53− /// The hash of the object the ref points to.
54− object: git_hash::ObjectId,
55− },
56− /// A symbolic ref pointing to `target` ref, which in turn points to an `object`
57− Symbolic {
58− /// The path at which the symbolic ref is located, like `/refs/heads/main`.
59− path: BString,
60− /// The path of the ref the symbolic ref points to.
61− target: BString,
62− /// The hash of the object the `target` ref points to.
63− object: git_hash::ObjectId,
64− },
65−}
66−
67−impl Ref {
68− /// Provide shared fields referring to the ref itself, namely `(path, object id)`.
69− /// In case of peeled refs, the tag object itself is returned as it is what the path refers to.
70− pub fn unpack(&self) -> (&BString, &git_hash::ObjectId) {
71− match self {
72− Ref::Direct { path, object, .. }
73− | Ref::Peeled { path, tag: object, .. } // the tag acts as reference
74− | Ref::Symbolic { path, object, .. } => (path, object),
75− }
76− }
77−}
78−
79−impl From<InternalRef> for Ref {
80− fn from(v: InternalRef) -> Self {
81− match v {
82− InternalRef::Symbolic { path, target, object } => Ref::Symbolic { path, target, object },
83− InternalRef::Peeled { path, tag, object } => Ref::Peeled { path, tag, object },
84− InternalRef::Direct { path, object } => Ref::Direct { path, object },
85− InternalRef::SymbolicForLookup { .. } => {
86− unreachable!("this case should have been removed during processing")
87− }
88− }
89− }
90−}
91−
92−#[cfg_attr(test, derive(PartialEq, Eq, Debug, Clone))]
93−pub(crate) enum InternalRef {
94− /// A ref pointing to a `tag` object, which in turns points to an `object`, usually a commit
95− Peeled {
96− path: BString,
97− tag: git_hash::ObjectId,
98− object: git_hash::ObjectId,
99− },
100− /// A ref pointing to a commit object
101− Direct { path: BString, object: git_hash::ObjectId },
102− /// A symbolic ref pointing to `target` ref, which in turn points to an `object`
103− Symbolic {
104− path: BString,
105− target: BString,
106− object: git_hash::ObjectId,
107− },
108− /// extracted from V1 capabilities, which contain some important symbolic refs along with their targets
109− /// These don't contain the Id
110− SymbolicForLookup { path: BString, target: BString },
111−}
112−
113−impl InternalRef {
114− fn unpack_direct(self) -> Option<(BString, git_hash::ObjectId)> {
115− match self {
116− InternalRef::Direct { path, object } => Some((path, object)),
117− _ => None,
118− }
119− }
120− fn lookup_symbol_has_path(&self, predicate_path: &str) -> bool {
121− matches!(self, InternalRef::SymbolicForLookup { path, .. } if path == predicate_path)
122− }
123−}
124−
125−pub(crate) fn from_capabilities<'a>(
126− out_refs: &mut Vec<InternalRef>,
127− capabilities: impl Iterator<Item = git_transport::client::capabilities::Capability<'a>>,
128−) -> Result<(), Error> {
129− let symref_values = capabilities.filter_map(|c| {
130− if c.name() == b"symref".as_bstr() {
131− c.value().map(ToOwned::to_owned)
132− } else {
133− None
134− }
135− });
136− for symref in symref_values {
137− let (left, right) = symref.split_at(
138− symref
139− .find_byte(b':')
140− .ok_or_else(|| Error::MalformedSymref(symref.to_owned()))?,
141− );
142− if left.is_empty() || right.is_empty() {
143− return Err(Error::MalformedSymref(symref.to_owned()));
144− }
145− out_refs.push(InternalRef::SymbolicForLookup {
146− path: left.into(),
147− target: right[1..].into(),
148− })
149− }
150− Ok(())
151−}
152−
153−pub(crate) fn from_v2_refs(out_refs: &mut Vec<Ref>, in_refs: &mut dyn io::BufRead) -> Result<(), Error> {
154− let mut line = String::new();
155− loop {
156− line.clear();
157− let bytes_read = in_refs.read_line(&mut line)?;
158− if bytes_read == 0 {
159− break;
160− }
161− let trimmed = line.trim_end();
162− let mut tokens = trimmed.splitn(3, ' ');
163− match (tokens.next(), tokens.next()) {
164− (Some(hex_hash), Some(path)) => {
165− let id = git_hash::ObjectId::from_hex(hex_hash.as_bytes())?;
166− if path.is_empty() {
167− return Err(Error::MalformedV2RefLine(trimmed.to_owned()));
168− }
169− out_refs.push(if let Some(attribute) = tokens.next() {
170− let mut tokens = attribute.splitn(2, ':');
171− match (tokens.next(), tokens.next()) {
172− (Some(attribute), Some(value)) => {
173− if value.is_empty() {
174− return Err(Error::MalformedV2RefLine(trimmed.to_owned()));
175− }
176− match attribute {
177− "peeled" => Ref::Peeled {
178− path: path.into(),
179− object: git_hash::ObjectId::from_hex(value.as_bytes())?,
180− tag: id,
181− },
182− "symref-target" => Ref::Symbolic {
183− path: path.into(),
184− object: id,
185− target: value.into(),
186− },
187− _ => return Err(Error::UnkownAttribute(attribute.to_owned(), trimmed.to_owned())),
188− }
189− }
190− _ => return Err(Error::MalformedV2RefLine(trimmed.to_owned())),
191− }
192− } else {
193− Ref::Direct {
194− object: id,
195− path: path.into(),
196− }
197− });
198− }
199− _ => return Err(Error::MalformedV2RefLine(trimmed.to_owned())),
200− }
201− }
202− Ok(())
203−}
204−
205−pub(crate) fn from_v1_refs_received_as_part_of_handshake(
206− out_refs: &mut Vec<InternalRef>,
207− in_refs: &mut dyn io::BufRead,
208−) -> Result<(), Error> {
209− let number_of_possible_symbolic_refs_for_lookup = out_refs.len();
210− let mut line = String::new();
211− loop {
212− line.clear();
213− let bytes_read = in_refs.read_line(&mut line)?;
214− if bytes_read == 0 {
215− break;
216− }
217− let trimmed = line.trim_end();
218− let (hex_hash, path) = trimmed.split_at(
219− trimmed
220− .find(' ')
221− .ok_or_else(|| Error::MalformedV1RefLine(trimmed.to_owned()))?,
222− );
223− let path = &path[1..];
224− if path.is_empty() {
225− return Err(Error::MalformedV1RefLine(trimmed.to_owned()));
226− }
227− match path.strip_suffix("^{}") {
228− Some(stripped) => {
229− let (previous_path, tag) =
230− out_refs
231− .pop()
232− .and_then(InternalRef::unpack_direct)
233− .ok_or(Error::InvariantViolation(
234− "Expecting peeled refs to be preceded by direct refs",
235− ))?;
236− if previous_path != stripped {
237− return Err(Error::InvariantViolation(
238− "Expecting peeled refs to have the same base path as the previous, unpeeled one",
239− ));
240− }
241− out_refs.push(InternalRef::Peeled {
242− path: previous_path,
243− tag,
244− object: git_hash::ObjectId::from_hex(hex_hash.as_bytes())?,
245− });
246− }
247− None => {
248− let object = git_hash::ObjectId::from_hex(hex_hash.as_bytes())?;
249− match out_refs
250− .iter()
251− .take(number_of_possible_symbolic_refs_for_lookup)
252− .position(|r| r.lookup_symbol_has_path(path))
253− {
254− Some(position) => match out_refs.swap_remove(position) {
255− InternalRef::SymbolicForLookup { path: _, target } => out_refs.push(InternalRef::Symbolic {
256− path: path.into(),
257− object,
258− target,
259− }),
260− _ => unreachable!("Bug in lookup_symbol_has_path - must return lookup symbols"),
261− },
262− None => out_refs.push(InternalRef::Direct {
263− object,
264− path: path.into(),
265− }),
266− };
267− }
268− }
269− }
270− Ok(())
271−}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t