Repositories

grarr

(mirrored on github)

Modified src/handler/git_smart_http/refs.rs

@@ -17,7 +17,7 @@ fn format_refs(head: git2::Reference, refs: git2::References) -> Result<Vec<u8>,
try!(result.write_pkt_line("# service=git-upload-pack"));
try!(result.write_pkt_line_flush());
let head_id = try!(head.target().ok_or(Error::from("HEAD missing target")));
try!(result.write_pkt_line(format!("{} HEAD\0{}", head_id, "side-band side-band-64k")));
try!(result.write_pkt_line(format!("{} HEAD\0{}", head_id, "side-band side-band-64k multi_ack_detailed")));
// TODO: Sort refs by name in C locale
for reff in refs {
try!(result.write_pkt_line(try!(format_ref(try!(reff)))));

Modified src/handler/git_smart_http/upload_pack.rs

@@ -22,6 +22,8 @@ pub struct UploadPack;
enum Capability {
SideBand,
SideBand64K,
MultiAck,
MultiAckDetailed,
Unknown(String),
}
@@ -40,8 +42,13 @@ struct UploadPackContext<'a> {
}
enum UploadPackResponse<'a> {
Pack(Revwalk<'a>),
/* Continue( ... ), */
Pack {
revwalk: Revwalk<'a>,
common: Vec<Oid>,
},
Continue {
common: Vec<Oid>,
},
}
fn parse_request(req: &mut Request, context: RepositoryContext) -> Result<UploadPackRequest, Error> {
@@ -74,7 +81,7 @@ fn parse_request(req: &mut Request, context: RepositoryContext) -> Result<Upload
let line = line[5..].trim();
let (want, caps) = line.split_at(line.find(' ').unwrap_or(line.len()));
request.wants.push(try!(want.parse()));
request.capabilities.extend(caps.split(' ').map(Capability::from));
request.capabilities.extend(caps.split(' ').filter(|s| !s.is_empty()).map(Capability::from));
},
"have" => {
let end = line.find(|c| c == '\n' || c == '\0').unwrap_or(line.len());
@@ -87,6 +94,7 @@ fn parse_request(req: &mut Request, context: RepositoryContext) -> Result<Upload
_ => return Err(Error::from(format!("Unexpected pkt-line {}", line))),
}
}
println!("request: {:?}", request);
Ok(request)
}
@@ -136,6 +144,7 @@ fn graph_descendant_of_any<I: Iterator<Item=Oid>>(repository: &Repository, commi
fn is_closed<I1: Iterator<Item=Oid>, I2: Iterator<Item=Oid> + Clone>(repository: &Repository, descendants: I1, ancestors: I2) -> Result<bool, Error> {
for descendant in descendants {
if !try!(graph_descendant_of_any(repository, descendant, ancestors.clone())) {
println!("{:?} has no ancestors in {:?}", descendant, ancestors.clone().collect::<Vec<_>>());
return Ok(false);
}
}
@@ -144,7 +153,7 @@ fn is_closed<I1: Iterator<Item=Oid>, I2: Iterator<Item=Oid> + Clone>(repository:
#[allow(collapsible_if)]
fn compute_response<'a>(context: &'a UploadPackContext, request: &'a UploadPackRequest) -> Result<UploadPackResponse<'a>, Error> {
let mut common = HashSet::<Oid>::new();
let mut common = Vec::<Oid>::new();
// for each id given in have
for id in request.haves.iter().cloned() {
// if it is an ancestor of a ref
@@ -152,21 +161,24 @@ fn compute_response<'a>(context: &'a UploadPackContext, request: &'a UploadPackR
// and is not an ancestor of a common
if !try!(graph_ancestor_of_any(&context.repository, id, common.iter().cloned())) {
// add it to common
common.insert(id);
common.push(id);
}
}
}
println!("common: {:?}", common);
if request.done || try!(is_closed(&context.repository, request.wants.iter().cloned(), common.iter().cloned())) {
let mut walker = try!(context.repository.revwalk());
let mut revwalk = try!(context.repository.revwalk());
for id in request.wants.iter().cloned() {
try!(walker.push(id));
try!(revwalk.push(id));
}
for id in common.iter().cloned() {
try!(walker.hide(id));
try!(revwalk.hide(id));
}
Ok(UploadPackResponse::Pack(walker))
Ok(UploadPackResponse::Pack { revwalk: revwalk, common: common })
} else {
Err(Error::from("TODO: ......"))
Ok(UploadPackResponse::Continue { common: common })
}
}
@@ -224,26 +236,45 @@ fn build_pack<'a>(repository: &'a Repository, mut revwalk: Revwalk<'a>, output:
impl WriteBody for UploadPackRequest {
fn write_body(&mut self, mut res: &mut Write) -> io::Result<()> {
res.write_pkt_line("NAK")?;
let limit = if self.capabilities.contains(&Capability::SideBand64K) {
Some(65520)
} else if self.capabilities.contains(&Capability::SideBand) {
Some(1000)
} else {
None
};
let output = Multiplexer::new(res, limit);
println!( "Preparing context for {}", self.context.path);
let context2 = prepare_context(&self.context).unwrap();
println!( "Prepared context for {}", self.context.path);
validate_request(&context2, self).unwrap();
println!( "Validated request for {}", self.context.path);
let result = compute_response(&context2, self).unwrap();
println!( "Computed response for {}", self.context.path);
match result {
UploadPackResponse::Pack(revwalk) => {
UploadPackResponse::Pack { revwalk, common } => {
if self.capabilities.contains(&Capability::MultiAckDetailed) {
for id in &common {
let line = format!("ACK {} common", id);
println!("{}", line);
res.write_pkt_line(line)?;
}
let line = format!("ACK {}", common.iter().last().unwrap());
println!("{}", line);
res.write_pkt_line(line)?;
} else {
res.write_pkt_line("NAK")?;
}
let limit = if self.capabilities.contains(&Capability::SideBand64K) {
Some(65520)
} else if self.capabilities.contains(&Capability::SideBand) {
Some(1000)
} else {
None
};
let mut output = Multiplexer::new(res, limit);
build_pack(&self.context.repository, revwalk, output).unwrap();
},
UploadPackResponse::Continue { common } => {
if self.capabilities.contains(&Capability::MultiAckDetailed) {
for id in common {
let line = format!("ACK {} common", id);
println!("{}", line);
res.write_pkt_line(line)?;
}
} else {
// TODO
}
res.write_pkt_line("NAK")?;
},
}
Ok(())
}
@@ -285,6 +316,8 @@ impl<S: AsRef<str>> From<S> for Capability {
match s.as_ref() {
"side-band" => Capability::SideBand,
"side-band-64k" => Capability::SideBand64K,
"multi_ack" => Capability::MultiAck,
"multi_ack_detailed" => Capability::MultiAckDetailed,
s => Capability::Unknown(s.to_owned()),
}
}