1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use std::io;
use gix_transport::{client, Protocol};
use crate::fetch::{
response,
response::{Acknowledgement, ShallowUpdate, WantedRef},
Response,
};
fn parse_v2_section<T>(
line: &mut String,
reader: &mut impl client::ExtendedBufRead,
res: &mut Vec<T>,
parse: impl Fn(&str) -> Result<T, response::Error>,
) -> Result<bool, response::Error> {
line.clear();
while reader.read_line(line)? != 0 {
res.push(parse(line)?);
line.clear();
}
Ok(if reader.stopped_at() == Some(client::MessageKind::Delimiter) {
reader.reset(Protocol::V2);
false
} else {
true
})
}
impl Response {
pub fn from_line_reader(
version: Protocol,
reader: &mut impl client::ExtendedBufRead,
) -> Result<Response, response::Error> {
match version {
Protocol::V1 => {
let mut line = String::new();
let mut acks = Vec::<Acknowledgement>::new();
let mut shallows = Vec::<ShallowUpdate>::new();
let has_pack = 'lines: loop {
line.clear();
let peeked_line = match reader.peek_data_line() {
Some(Ok(Ok(line))) => String::from_utf8_lossy(line),
Some(Err(err)) if err.kind() == io::ErrorKind::UnexpectedEof => break 'lines false,
Some(Err(err)) => return Err(err.into()),
Some(Ok(Err(err))) => return Err(err.into()),
None => {
debug_assert_eq!(
reader.stopped_at(),
Some(client::MessageKind::Flush),
"If this isn't a flush packet, we don't know what's going on"
);
reader.read_line(&mut line)?;
reader.reset(Protocol::V1);
match reader.peek_data_line() {
Some(Ok(Ok(line))) => String::from_utf8_lossy(line),
Some(Err(err)) => return Err(err.into()),
Some(Ok(Err(err))) => return Err(err.into()),
None => break 'lines false, }
}
};
if Response::parse_v1_ack_or_shallow_or_assume_pack(&mut acks, &mut shallows, &peeked_line) {
break 'lines true;
}
assert_ne!(reader.read_line(&mut line)?, 0, "consuming a peeked line works");
};
Ok(Response {
acks,
shallows,
wanted_refs: vec![],
has_pack,
})
}
Protocol::V2 => {
let mut line = String::new();
reader.reset(Protocol::V2);
let mut acks = Vec::<Acknowledgement>::new();
let mut shallows = Vec::<ShallowUpdate>::new();
let mut wanted_refs = Vec::<WantedRef>::new();
let has_pack = 'section: loop {
line.clear();
if reader.read_line(&mut line)? == 0 {
return Err(response::Error::Io(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Could not read message headline",
)));
};
match line.trim_end() {
"acknowledgments" => {
if parse_v2_section(&mut line, reader, &mut acks, Acknowledgement::from_line)? {
break 'section false;
}
}
"shallow-info" => {
if parse_v2_section(&mut line, reader, &mut shallows, ShallowUpdate::from_line)? {
break 'section false;
}
}
"wanted-refs" => {
if parse_v2_section(&mut line, reader, &mut wanted_refs, WantedRef::from_line)? {
break 'section false;
}
}
"packfile" => {
break 'section true;
}
_ => return Err(response::Error::UnknownSectionHeader { header: line }),
}
};
Ok(Response {
acks,
shallows,
wanted_refs,
has_pack,
})
}
}
}
}