Browse Source

[git-transport] simplify parsing capabilities from lines

pull/86/head
Sebastian Thiel 1 month ago
parent
commit
401af09747
No known key found for this signature in database GPG Key ID: 9CB5EE7895E8268B
  1. 2
      git-protocol/src/fetch/tests/command.rs
  2. 74
      git-transport/src/client/capabilities.rs

2
git-protocol/src/fetch/tests/command.rs

@ -55,7 +55,7 @@ mod v2 {
use git_transport::client::Capabilities;
fn capabilities(command: &str, input: &str) -> Capabilities {
Capabilities::from_lines(format!("version 2\n{}={}", command, input).as_bytes())
Capabilities::from_lines(Some(Ok("version 2".into())), format!("{}={}", command, input))
.expect("valid input for V2 capabilities")
}

74
git-transport/src/client/capabilities.rs

@ -84,32 +84,17 @@ impl Capabilities {
))
}
/// Returns true of the given `feature` is mentioned in this list of capabilities.
pub fn contains(&self, feature: &str) -> bool {
self.capability(feature).is_some()
}
/// Returns the capability with `name`.
pub fn capability(&self, name: &str) -> Option<Capability<'_>> {
self.iter().find(|c| c.name() == name.as_bytes().as_bstr())
}
/// Returns an iterator over all capabilities.
pub fn iter(&self) -> impl Iterator<Item = Capability<'_>> {
self.data
.split(move |b| *b == self.value_sep)
.map(|c| Capability(c.as_bstr()))
}
}
#[cfg(feature = "blocking-client")]
impl Capabilities {
/// Parse capabilities from the given `read`.
/// Parse capabilities from the given a `first_line` and the rest of the lines as single newline
/// separated string via `remaining_lines`.
///
/// Useful for parsing capabilities from a data sent from a server.
pub fn from_lines(read: impl io::BufRead) -> Result<Capabilities, Error> {
let mut lines = read.lines();
let version_line = lines.next().ok_or(Error::MissingVersionLine)??;
/// Useful for parsing capabilities from a data sent from a server, and to avoid having to deal with
/// blocking and async traits for as long as possible. There is no value in parsing a few bytes
/// in a non-blocking fashion.
pub fn from_lines(
first_line: Option<impl Into<std::io::Result<String>>>,
remaining_lines: impl Into<String>,
) -> Result<Capabilities, Error> {
let version_line = first_line.map(Into::into).ok_or(Error::MissingVersionLine)??;
let (name, value) = version_line.split_at(
version_line
.find(' ')
@ -123,28 +108,33 @@ impl Capabilities {
}
Ok(Capabilities {
value_sep: b'\n',
data: lines
.inspect(|l| {
if let Ok(l) = l {
assert!(
!l.contains('\n'),
"newlines are not expected in keys or values, got '{}'",
l
)
}
})
.collect::<Result<Vec<_>, _>>()?
.join("\n")
.into(),
data: remaining_lines.into().into(),
})
}
/// Returns true of the given `feature` is mentioned in this list of capabilities.
pub fn contains(&self, feature: &str) -> bool {
self.capability(feature).is_some()
}
/// Returns the capability with `name`.
pub fn capability(&self, name: &str) -> Option<Capability<'_>> {
self.iter().find(|c| c.name() == name.as_bytes().as_bstr())
}
/// Returns an iterator over all capabilities.
pub fn iter(&self) -> impl Iterator<Item = Capability<'_>> {
self.data
.split(move |b| *b == self.value_sep)
.map(|c| Capability(c.as_bstr()))
}
}
#[cfg(feature = "blocking-client")]
pub(crate) mod recv {
use crate::{client, client::Capabilities, Protocol};
use bstr::ByteSlice;
use std::io;
use std::{io, io::BufRead};
pub struct Outcome<'a> {
pub capabilities: Capabilities,
@ -189,7 +179,11 @@ pub(crate) mod recv {
})
}
Protocol::V2 => Ok(Outcome {
capabilities: Capabilities::from_lines(rd.as_read())?,
capabilities: {
let rd = rd.as_read();
let mut lines = rd.lines();
Capabilities::from_lines(lines.next(), lines.collect::<Result<Vec<_>, _>>()?.join("\n"))?
},
refs: None,
protocol: Protocol::V2,
}),

Loading…
Cancel
Save