Skip to content

Commit

Permalink
Merge pull request GitoxideLabs#1645 from dvtkrlbs/refloglookup-date
Browse files Browse the repository at this point in the history
feat: handle ReflogLookup::Date
  • Loading branch information
Byron authored Dec 21, 2024
2 parents ca54b8c + 9662bc1 commit cbdbb8a
Show file tree
Hide file tree
Showing 15 changed files with 1,305 additions and 64 deletions.
4 changes: 2 additions & 2 deletions gix-ref/src/store/file/log/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl Platform<'_, '_> {
/// Return a forward iterator over all log-lines, most recent to oldest.
pub fn rev(&mut self) -> std::io::Result<Option<log::iter::Reverse<'_, std::fs::File>>> {
self.buf.clear();
self.buf.resize(512, 0);
self.buf.resize(1024 * 4, 0);
self.store
.reflog_iter_rev(self.name, &mut self.buf)
.map_err(must_be_io_err)
Expand Down Expand Up @@ -219,7 +219,7 @@ where
if npos == last_read_pos {
return Some(Err(std::io::Error::new(
std::io::ErrorKind::Other,
"buffer too small for line size",
format!("buffer too small for line size, got until {:?}", self.buf.as_bstr()),
)
.into()));
}
Expand Down
Binary file not shown.
585 changes: 585 additions & 0 deletions gix-ref/tests/fixtures/make_repo_for_reflog.sh

Large diffs are not rendered by default.

24 changes: 21 additions & 3 deletions gix-ref/tests/refs/file/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ mod iter {
.source()
.expect("source")
.to_string(),
"buffer too small for line size"
"buffer too small for line size, got until \"0000000000000000 134385f6d781b7e97062102c6a483440bfda2a03 committer <[email protected]> 946771200 +0000\\tcommit (initial): c1\""
);
assert!(iter.next().is_none(), "iterator depleted");
}
Expand All @@ -90,9 +90,9 @@ mod iter {
}

mod with_buffer_big_enough_for_largest_line {
use gix_ref::log::Line;

use crate::file::log::iter::reflog;
use crate::hex_to_id;
use gix_ref::log::Line;

#[test]
fn single_line() -> crate::Result {
Expand Down Expand Up @@ -157,6 +157,24 @@ mod iter {
}
Ok(())
}

#[test]
fn realistic_logs_can_be_read_completely() -> crate::Result {
let log = reflog("refs/heads/old")?;
let mut buf = Vec::with_capacity(16 * 1024);
for size in [2048, 3000, 4096, 8192, 16384] {
buf.resize(size, 0);
let read = std::io::Cursor::new(&*log);
let count = gix_ref::file::log::iter::reverse(read, &mut buf)?
.filter_map(Result::ok)
.count();
assert_eq!(
count, 581,
"All entries must be readable as long as the buffer can fit a whole line"
);
}
Ok(())
}
}
}
mod forward {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
118 changes: 70 additions & 48 deletions gix/src/revision/spec/parse/delegate/revision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,59 +105,81 @@ impl delegate::Revision for Delegate<'_> {

fn reflog(&mut self, query: ReflogLookup) -> Option<()> {
self.unset_disambiguate_call();
match query {
ReflogLookup::Date(_date) => {
// TODO: actually do this - this should be possible now despite incomplete date parsing
self.err.push(Error::Planned {
dependency: "remote handling and ref-specs are fleshed out more",
});
None
}
ReflogLookup::Entry(no) => {
let r = match &mut self.refs[self.idx] {
Some(r) => r.clone().attach(self.repo),
val @ None => match self.repo.head().map(crate::Head::try_into_referent) {
Ok(Some(r)) => {
*val = Some(r.clone().detach());
r
}
Ok(None) => {
self.err.push(Error::UnbornHeadsHaveNoRefLog);
return None;
}
Err(err) => {
self.err.push(err.into());
return None;
}
},
};
let mut platform = r.log_iter();
match platform.rev().ok().flatten() {
Some(mut it) => match it.nth(no).and_then(Result::ok) {
Some(line) => {
self.objs[self.idx]
.get_or_insert_with(HashSet::default)
.insert(line.new_oid);
Some(())
}
None => {
let available = platform.rev().ok().flatten().map_or(0, Iterator::count);
self.err.push(Error::RefLogEntryOutOfRange {
reference: r.detach(),
desired: no,
available,
let r = match &mut self.refs[self.idx] {
Some(r) => r.clone().attach(self.repo),
val @ None => match self.repo.head().map(crate::Head::try_into_referent) {
Ok(Some(r)) => {
*val = Some(r.clone().detach());
r
}
Ok(None) => {
self.err.push(Error::UnbornHeadsHaveNoRefLog);
return None;
}
Err(err) => {
self.err.push(err.into());
return None;
}
},
};

let mut platform = r.log_iter();
match platform.rev().ok().flatten() {
Some(mut it) => match query {
ReflogLookup::Date(date) => {
let mut last = None;
let id_to_insert = match it
.filter_map(Result::ok)
.inspect(|d| {
last = Some(if d.previous_oid.is_null() {
d.new_oid
} else {
d.previous_oid
});
None
}
},
})
.find(|l| l.signature.time.seconds <= date.seconds)
{
Some(closest_line) => closest_line.new_oid,
None => match last {
None => {
self.err.push(Error::EmptyReflog);
return None;
}
Some(id) => id,
},
};
self.objs[self.idx]
.get_or_insert_with(HashSet::default)
.insert(id_to_insert);
Some(())
}
ReflogLookup::Entry(no) => match it.nth(no).and_then(Result::ok) {
Some(line) => {
self.objs[self.idx]
.get_or_insert_with(HashSet::default)
.insert(line.new_oid);
Some(())
}
None => {
self.err.push(Error::MissingRefLog {
reference: r.name().as_bstr().into(),
action: "lookup entry",
let available = platform.rev().ok().flatten().map_or(0, Iterator::count);
self.err.push(Error::RefLogEntryOutOfRange {
reference: r.detach(),
desired: no,
available,
});
None
}
}
},
},
None => {
self.err.push(Error::MissingRefLog {
reference: r.name().as_bstr().into(),
action: match query {
ReflogLookup::Entry(_) => "lookup reflog entry by index",
ReflogLookup::Date(_) => "lookup reflog entry by date",
},
});
None
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions gix/src/revision/spec/parse/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ pub enum Error {
direction: remote::Direction,
source: Box<dyn std::error::Error + Send + Sync + 'static>,
},
#[error("This feature will be implemented once {dependency}")]
Planned { dependency: &'static str },
#[error("Reference {reference:?} does not have a reference log, cannot {action}")]
MissingRefLog { reference: BString, action: &'static str },
#[error("HEAD has {available} prior checkouts and checkout number {desired} is out of range")]
Expand Down Expand Up @@ -194,4 +192,6 @@ pub enum Error {
Walk(#[from] crate::revision::walk::Error),
#[error("Spec does not contain a single object id")]
SingleNotFound,
#[error("Reflog does not contain any entries")]
EmptyReflog,
}
Binary file not shown.
Loading

0 comments on commit cbdbb8a

Please sign in to comment.