Skip to content

Commit

Permalink
Merge branch 'shallow-protocol'
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Mar 11, 2023
2 parents 01277a6 + 9723e1a commit 531dd19
Show file tree
Hide file tree
Showing 36 changed files with 959 additions and 67 deletions.
6 changes: 5 additions & 1 deletion crate-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -637,10 +637,14 @@ See its [README.md](https://github.com/Byron/gitoxide/blob/main/gix-lock/README.
* [x] find remote itself
- [ ] respect `branch.<name>.merge` in the returned remote.
* **remotes**
* [ ] clone
* [x] clone
* [ ] shallow
* [ ] include-tags when shallow is used (needs separate fetch)
* [ ] prune non-existing shallow commits
* [ ] [bundles](https://git-scm.com/docs/git-bundle)
* [x] fetch
* [ ] 'ref-in-want'
* [ ] standard negotiation algorithms (right now we only have a 'naive' one)
* [ ] push
* [x] ls-refs
* [x] ls-refs with ref-spec filter
Expand Down
7 changes: 5 additions & 2 deletions gitoxide-core/src/repository/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub struct Options {
pub bare: bool,
pub handshake_info: bool,
pub no_tags: bool,
pub shallow: gix::remote::fetch::Shallow,
}

pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3;
Expand All @@ -30,6 +31,7 @@ pub(crate) mod function {
handshake_info,
bare,
no_tags,
shallow,
}: Options,
) -> anyhow::Result<()>
where
Expand Down Expand Up @@ -66,8 +68,9 @@ pub(crate) mod function {
if no_tags {
prepare = prepare.configure_remote(|r| Ok(r.with_fetch_tags(gix::remote::fetch::Tags::None)));
}
let (mut checkout, fetch_outcome) =
prepare.fetch_then_checkout(&mut progress, &gix::interrupt::IS_INTERRUPTED)?;
let (mut checkout, fetch_outcome) = prepare
.with_shallow(shallow)
.fetch_then_checkout(&mut progress, &gix::interrupt::IS_INTERRUPTED)?;

let (repo, outcome) = if bare {
(checkout.persist(), None)
Expand Down
3 changes: 3 additions & 0 deletions gitoxide-core/src/repository/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub struct Options {
pub remote: Option<String>,
/// If non-empty, override all ref-specs otherwise configured in the remote
pub ref_specs: Vec<BString>,
pub shallow: gix::remote::fetch::Shallow,
pub handshake_info: bool,
}

Expand All @@ -30,6 +31,7 @@ pub(crate) mod function {
dry_run,
remote,
handshake_info,
shallow,
ref_specs,
}: Options,
) -> anyhow::Result<()>
Expand All @@ -50,6 +52,7 @@ pub(crate) mod function {
.connect(gix::remote::Direction::Fetch, progress)?
.prepare_fetch(Default::default())?
.with_dry_run(dry_run)
.with_shallow(shallow)
.receive(&gix::interrupt::IS_INTERRUPTED)?;

if handshake_info {
Expand Down
2 changes: 1 addition & 1 deletion gix-packetline/src/read/sidebands/async_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ where
}

/// Read a packet line as string line.
pub fn read_line<'b>(&'b mut self, buf: &'b mut String) -> ReadLineFuture<'a, 'b, T, F> {
pub fn read_line_to_string<'b>(&'b mut self, buf: &'b mut String) -> ReadLineFuture<'a, 'b, T, F> {
ReadLineFuture { parent: self, buf }
}

Expand Down
28 changes: 16 additions & 12 deletions gix-packetline/src/read/sidebands/blocking_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ where
);
self.parent.read_line()
}

/// Like `BufRead::read_line()`, but will only read one packetline at a time.
///
/// It will also be easier to call as sometimes it's unclear which implementation we get on a type like this with
/// plenty of generic parameters.
pub fn read_line_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
assert_eq!(
self.cap, 0,
"we don't support partial buffers right now - read-line must be used consistently"
);
let line = std::str::from_utf8(self.fill_buf()?).map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
buf.push_str(line);
let bytes = line.len();
self.cap = 0;
Ok(bytes)
}
}

impl<'a, T, F> BufRead for WithSidebands<'a, T, F>
Expand Down Expand Up @@ -168,18 +184,6 @@ where
fn consume(&mut self, amt: usize) {
self.pos = std::cmp::min(self.pos + amt, self.cap);
}

fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
assert_eq!(
self.cap, 0,
"we don't support partial buffers right now - read-line must be used consistently"
);
let line = std::str::from_utf8(self.fill_buf()?).map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
buf.push_str(line);
let bytes = line.len();
self.cap = 0;
Ok(bytes)
}
}

impl<'a, T, F> io::Read for WithSidebands<'a, T, F>
Expand Down
20 changes: 10 additions & 10 deletions gix-packetline/tests/read/sideband.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[cfg(feature = "blocking-io")]
use std::io::{BufRead, Read};
use std::io::Read;

use bstr::{BString, ByteSlice};
#[cfg(all(not(feature = "blocking-io"), feature = "async-io"))]
Expand Down Expand Up @@ -106,16 +106,16 @@ async fn read_line_trait_method_reads_one_packet_line_at_a_time() -> crate::Resu

let mut out = String::new();
let mut r = rd.as_read();
r.read_line(&mut out).await?;
r.read_line_to_string(&mut out).await?;
assert_eq!(out, "808e50d724f604f69ab93c6da2919c014667bedb HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag multi_ack_detailed symref=HEAD:refs/heads/master object-format=sha1 agent=git/2.28.0\n");
out.clear();
r.read_line(&mut out).await?;
r.read_line_to_string(&mut out).await?;
assert_eq!(out, "808e50d724f604f69ab93c6da2919c014667bedb refs/heads/master\n");
out.clear();
r.read_line(&mut out).await?;
r.read_line_to_string(&mut out).await?;
assert_eq!(out, "", "flush means empty lines…");
out.clear();
r.read_line(&mut out).await?;
r.read_line_to_string(&mut out).await?;
assert_eq!(out, "", "…which can't be overcome unless the reader is reset");
assert_eq!(
r.stopped_at(),
Expand All @@ -127,18 +127,18 @@ async fn read_line_trait_method_reads_one_packet_line_at_a_time() -> crate::Resu
rd.reset();

let mut r = rd.as_read();
r.read_line(&mut out).await?;
r.read_line_to_string(&mut out).await?;
assert_eq!(out, "NAK\n");

drop(r);

let mut r = rd.as_read_with_sidebands(|_, _| ());
out.clear();
r.read_line(&mut out).await?;
r.read_line_to_string(&mut out).await?;
assert_eq!(out, "&");

out.clear();
r.read_line(&mut out).await?;
r.read_line_to_string(&mut out).await?;
assert_eq!(out, "");

Ok(())
Expand Down Expand Up @@ -199,7 +199,7 @@ async fn peek_past_an_actual_eof_is_an_error() -> crate::Result {
assert_eq!(res.expect("one line")??, b"ERR e");

let mut buf = String::new();
reader.read_line(&mut buf).await?;
reader.read_line_to_string(&mut buf).await?;
assert_eq!(
buf, "ERR e",
"by default ERR lines won't propagate as failure but are merely text"
Expand All @@ -223,7 +223,7 @@ async fn peek_past_a_delimiter_is_no_error() -> crate::Result {
assert_eq!(res.expect("one line")??, b"hello");

let mut buf = String::new();
reader.read_line(&mut buf).await?;
reader.read_line_to_string(&mut buf).await?;
assert_eq!(buf, "hello");

let res = reader.peek_data_line().await;
Expand Down
13 changes: 8 additions & 5 deletions gix-protocol/src/fetch/response/async_io.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::io;

use futures_lite::AsyncBufReadExt;
use gix_transport::{client, Protocol};

use crate::fetch::{
Expand All @@ -16,7 +15,7 @@ async fn parse_v2_section<T>(
parse: impl Fn(&str) -> Result<T, response::Error>,
) -> Result<bool, response::Error> {
line.clear();
while reader.read_line(line).await? != 0 {
while reader.readline_str(line).await? != 0 {
res.push(parse(line)?);
line.clear();
}
Expand Down Expand Up @@ -62,7 +61,7 @@ impl Response {
Some(client::MessageKind::Flush),
"If this isn't a flush packet, we don't know what's going on"
);
reader.read_line(&mut line).await?;
reader.readline_str(&mut line).await?;
reader.reset(Protocol::V1);
match reader.peek_data_line().await {
Some(Ok(Ok(line))) => String::from_utf8_lossy(line),
Expand All @@ -76,7 +75,11 @@ impl Response {
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).await?, 0, "consuming a peeked line works");
assert_ne!(
reader.readline_str(&mut line).await?,
0,
"consuming a peeked line works"
);
};
Ok(Response {
acks,
Expand All @@ -94,7 +97,7 @@ impl Response {
let mut wanted_refs = Vec::<WantedRef>::new();
let has_pack = 'section: loop {
line.clear();
if reader.read_line(&mut line).await? == 0 {
if reader.readline_str(&mut line).await? == 0 {
return Err(response::Error::Io(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Could not read message headline",
Expand Down
8 changes: 4 additions & 4 deletions gix-protocol/src/fetch/response/blocking_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn parse_v2_section<T>(
parse: impl Fn(&str) -> Result<T, response::Error>,
) -> Result<bool, response::Error> {
line.clear();
while reader.read_line(line)? != 0 {
while reader.readline_str(line)? != 0 {
res.push(parse(line)?);
line.clear();
}
Expand Down Expand Up @@ -61,7 +61,7 @@ impl Response {
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.readline_str(&mut line)?;
reader.reset(Protocol::V1);
match reader.peek_data_line() {
Some(Ok(Ok(line))) => String::from_utf8_lossy(line),
Expand All @@ -75,7 +75,7 @@ impl Response {
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");
assert_ne!(reader.readline_str(&mut line)?, 0, "consuming a peeked line works");
};
Ok(Response {
acks,
Expand All @@ -93,7 +93,7 @@ impl Response {
let mut wanted_refs = Vec::<WantedRef>::new();
let has_pack = 'section: loop {
line.clear();
if reader.read_line(&mut line)? == 0 {
if reader.readline_str(&mut line)? == 0 {
return Err(response::Error::Io(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Could not read message headline",
Expand Down
27 changes: 27 additions & 0 deletions gix-protocol/src/handshake/refs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,20 @@ impl<'a> gix_transport::client::ReadlineBufRead for Fixture<'a> {
self.0 = lines.as_bytes();
Some(Ok(Ok(gix_packetline::PacketLineRef::Data(res))))
}

fn readline_str(&mut self, line: &mut String) -> std::io::Result<usize> {
use bstr::{BStr, ByteSlice};
let bytes: &BStr = self.0.into();
let mut lines = bytes.lines();
let res = match lines.next() {
None => return Ok(0),
Some(line) => line,
};
self.0 = lines.as_bytes();
let len = res.len();
line.push_str(res.to_str().expect("valid UTF8 in fixture"));
Ok(len)
}
}

#[cfg(feature = "async-client")]
Expand Down Expand Up @@ -220,4 +234,17 @@ impl<'a> gix_transport::client::ReadlineBufRead for Fixture<'a> {
self.0 = lines.as_bytes();
Some(Ok(Ok(gix_packetline::PacketLineRef::Data(res))))
}
async fn readline_str(&mut self, line: &mut String) -> std::io::Result<usize> {
use bstr::{BStr, ByteSlice};
let bytes: &BStr = self.0.into();
let mut lines = bytes.lines();
let res = match lines.next() {
None => return Ok(0),
Some(line) => line,
};
self.0 = lines.as_bytes();
let len = res.len();
line.push_str(res.to_str().expect("valid UTF8 in fixture"));
Ok(len)
}
}
Loading

0 comments on commit 531dd19

Please sign in to comment.