History

[clone] V2 ref parsing

Sebastian Thiel committed 6 years ago

Commit 455fa0f1 parent 325d3a25 files · +101 −5Browse files

Showing the changes to git-protocol/src (3 of 5 files). Show all

Unified · Split

3 files
  1. git-protocol/src/fetch/mod.rs +3 −2
  2. git-protocol/src/fetch/refs.rs +58 −0
  3. git-protocol/src/fetch/tests.rs +37 −0
git-protocol/src/fetch/mod.rs+3−2
@@ -146,7 +146,7 @@ pub fn fetch<F: FnMut(credentials::Action) -> credentials::Result>( · 145 unmodified lines
146 mut delegate: impl Delegate,146 mut delegate: impl Delegate,
147 mut authenticate: F,147 mut authenticate: F,
148) -> Result<(), Error> {148) -> Result<(), Error> {
149 let (actual_protocol, _refs, capabilities, call_ls_refs) = {149 let (actual_protocol, mut parsed_refs, capabilities, call_ls_refs) = {
150 let result = transport.handshake(Service::UploadPack);150 let result = transport.handshake(Service::UploadPack);
151 let SetServiceResponse {151 let SetServiceResponse {
152 actual_protocol,152 actual_protocol,
@@ -216,11 +216,12 @@ pub fn fetch<F: FnMut(credentials::Action) -> credentials::Result>( · 63 unmodified lines
216 let _next = delegate.prepare_command(ls_refs, &capabilities, &mut ls_args, &mut ls_features);216 let _next = delegate.prepare_command(ls_refs, &capabilities, &mut ls_args, &mut ls_features);
217 ls_refs.validate_prefixes_or_panic(&capabilities, &ls_args, &ls_features);217 ls_refs.validate_prefixes_or_panic(&capabilities, &ls_args, &ls_features);
218 218
219 let _refs = transport.invoke(219 let mut refs = transport.invoke(
220 ls_refs.as_str(),220 ls_refs.as_str(),
221 ls_features.iter().map(|f| (*f, None)).chain(Some(agent)),221 ls_features.iter().map(|f| (*f, None)).chain(Some(agent)),
222 if ls_args.is_empty() { None } else { Some(ls_args) },222 if ls_args.is_empty() { None } else { Some(ls_args) },
223 )?;223 )?;
224 refs::from_v2_refs(&mut parsed_refs, &mut refs)?;
224 }225 }
225 226
226 transport.close()?;227 transport.close()?;
git-protocol/src/fetch/refs.rs+58−0
@@ -22,6 +22,12 @@ quick_error! { · 21 unmodified lines
22 MalformedV1RefLine(line: String) {22 MalformedV1RefLine(line: String) {
23 display("'{}' could not be parsed. A V1 ref line should be '<hex-hash> <path>'.", line)23 display("'{}' could not be parsed. A V1 ref line should be '<hex-hash> <path>'.", line)
24 }24 }
25 MalformedV2RefLine(line: String) {
26 display("'{}' could not be parsed. A V2 ref line should be '<hex-hash> <path>[ (peeled|symref-target):<value>'.", line)
27 }
28 UnkownAttribute(attribute: String, line: String) {
29 display("The ref attribute '{}' is unknown. Found in line '{}'", attribute, line)
30 }
25 InvariantViolation(message: &'static str) {31 InvariantViolation(message: &'static str) {
26 display("{}", message)32 display("{}", message)
27 }33 }
@@ -83,6 +89,58 @@ pub(crate) fn from_capabilities(out_refs: &mut Vec<Ref>, symrefs: Vec<BString>) · 55 unmodified lines
83 Ok(())89 Ok(())
84}90}
85 91
92pub(crate) fn from_v2_refs(out_refs: &mut Vec<Ref>, in_refs: &mut dyn io::BufRead) -> Result<(), Error> {
93 let mut line = String::new();
94 loop {
95 line.clear();
96 let bytes_read = in_refs.read_line(&mut line)?;
97 if bytes_read == 0 {
98 break;
99 }
100 let trimmed = line.trim_end();
101 let mut tokens = trimmed.splitn(3, ' ');
102 match (tokens.next(), tokens.next()) {
103 (Some(hex_hash), Some(path)) => {
104 let id = owned::Id::from_40_bytes_in_hex(hex_hash.as_bytes())?;
105 if path.is_empty() {
106 return Err(Error::MalformedV2RefLine(trimmed.to_owned()));
107 }
108 out_refs.push(if let Some(attribute) = tokens.next() {
109 let mut tokens = attribute.splitn(2, ':');
110 match (tokens.next(), tokens.next()) {
111 (Some(attribute), Some(value)) => {
112 if value.is_empty() {
113 return Err(Error::MalformedV2RefLine(trimmed.to_owned()));
114 }
115 match attribute {
116 "peeled" => Ref::Peeled {
117 path: path.into(),
118 object: owned::Id::from_40_bytes_in_hex(value.as_bytes())?,
119 tag: id,
120 },
121 "symref-target" => Ref::Symbolic {
122 path: path.into(),
123 object: id,
124 target: value.into(),
125 },
126 _ => return Err(Error::UnkownAttribute(attribute.to_owned(), trimmed.to_owned())),
127 }
128 }
129 _ => return Err(Error::MalformedV2RefLine(trimmed.to_owned())),
130 }
131 } else {
132 Ref::Direct {
133 object: id,
134 path: path.into(),
135 }
136 });
137 }
138 _ => return Err(Error::MalformedV2RefLine(trimmed.to_owned())),
139 }
140 }
141 Ok(())
142}
143
86pub(crate) fn from_v1_refs_received_as_part_of_handshake(144pub(crate) fn from_v1_refs_received_as_part_of_handshake(
87 out_refs: &mut Vec<Ref>,145 out_refs: &mut Vec<Ref>,
88 in_refs: &mut dyn io::BufRead,146 in_refs: &mut dyn io::BufRead,
git-protocol/src/fetch/tests.rs+37−0
@@ -8,6 +8,43 @@ mod refs { · 7 unmodified lines
8 owned::Id::from_40_bytes_in_hex(hex_sha.as_bytes()).expect("valid input")8 owned::Id::from_40_bytes_in_hex(hex_sha.as_bytes()).expect("valid input")
9 }9 }
10 10
11 #[test]
12 fn extract_references_from_v2_refs() {
13 let input: &mut dyn io::BufRead =
14 &mut "808e50d724f604f69ab93c6da2919c014667bedb HEAD symref-target:refs/heads/main
15808e50d724f604f69ab93c6da2919c014667bedb refs/heads/main
167fe1b98b39423b71e14217aa299a03b7c937d656 refs/tags/foo peeled:808e50d724f604f69ab93c6da2919c014667bedb
177fe1b98b39423b71e14217aa299a03b7c937d6ff refs/tags/blaz
18"
19 .as_bytes();
20 let mut out = Vec::new();
21 refs::from_v2_refs(&mut out, input).expect("no failure on valid input");
22
23 assert_eq!(
24 out,
25 vec![
26 Ref::Symbolic {
27 path: "HEAD".into(),
28 target: "refs/heads/main".into(),
29 object: oid("808e50d724f604f69ab93c6da2919c014667bedb")
30 },
31 Ref::Direct {
32 path: "refs/heads/main".into(),
33 object: oid("808e50d724f604f69ab93c6da2919c014667bedb")
34 },
35 Ref::Peeled {
36 path: "refs/tags/foo".into(),
37 tag: oid("7fe1b98b39423b71e14217aa299a03b7c937d656"),
38 object: oid("808e50d724f604f69ab93c6da2919c014667bedb")
39 },
40 Ref::Direct {
41 path: "refs/tags/blaz".into(),
42 object: oid("7fe1b98b39423b71e14217aa299a03b7c937d6ff")
43 },
44 ]
45 )
46 }
47
11 #[test]48 #[test]
12 fn extract_references_from_v1_refs() {49 fn extract_references_from_v1_refs() {
13 let input: &mut dyn io::BufRead = &mut "73a6868963993a3328e7d8fe94e5a6ac5078a944 HEAD50 let input: &mut dyn io::BufRead = &mut "73a6868963993a3328e7d8fe94e5a6ac5078a944 HEAD