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
146146 mut delegate: impl Delegate,
147147 mut authenticate: F,
148148 ) -> Result<(), Error> {
149− let (actual_protocol, _refs, capabilities, call_ls_refs) = {
149+ let (actual_protocol, mut parsed_refs, capabilities, call_ls_refs) = {
150150 let result = transport.handshake(Service::UploadPack);
151151 let SetServiceResponse {
152152 actual_protocol,
@@ -216,11 +216,12 @@ pub fn fetch<F: FnMut(credentials::Action) -> credentials::Result>( · 63 unmodified lines
216216 let _next = delegate.prepare_command(ls_refs, &capabilities, &mut ls_args, &mut ls_features);
217217 ls_refs.validate_prefixes_or_panic(&capabilities, &ls_args, &ls_features);
218218
219− let _refs = transport.invoke(
219+ let mut refs = transport.invoke(
220220 ls_refs.as_str(),
221221 ls_features.iter().map(|f| (*f, None)).chain(Some(agent)),
222222 if ls_args.is_empty() { None } else { Some(ls_args) },
223223 )?;
224+ refs::from_v2_refs(&mut parsed_refs, &mut refs)?;
224225 }
225226
226227 transport.close()?;
git-protocol/src/fetch/refs.rs+58−0
@@ -22,6 +22,12 @@ quick_error! { · 21 unmodified lines
2222 MalformedV1RefLine(line: String) {
2323 display("'{}' could not be parsed. A V1 ref line should be '<hex-hash> <path>'.", line)
2424 }
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+ }
2531 InvariantViolation(message: &'static str) {
2632 display("{}", message)
2733 }
@@ -83,6 +89,58 @@ pub(crate) fn from_capabilities(out_refs: &mut Vec<Ref>, symrefs: Vec<BString>) · 55 unmodified lines
8389 Ok(())
8490 }
8591
92+pub(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+
86144 pub(crate) fn from_v1_refs_received_as_part_of_handshake(
87145 out_refs: &mut Vec<Ref>,
88146 in_refs: &mut dyn io::BufRead,
git-protocol/src/fetch/tests.rs+37−0
@@ -8,6 +8,43 @@ mod refs { · 7 unmodified lines
88 owned::Id::from_40_bytes_in_hex(hex_sha.as_bytes()).expect("valid input")
99 }
1010
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
15+808e50d724f604f69ab93c6da2919c014667bedb refs/heads/main
16+7fe1b98b39423b71e14217aa299a03b7c937d656 refs/tags/foo peeled:808e50d724f604f69ab93c6da2919c014667bedb
17+7fe1b98b39423b71e14217aa299a03b7c937d6ff 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+
1148 #[test]
1249 fn extract_references_from_v1_refs() {
1350 let input: &mut dyn io::BufRead = &mut "73a6868963993a3328e7d8fe94e5a6ac5078a944 HEAD