diff --git a/gix/src/revision/spec/parse/delegate/revision.rs b/gix/src/revision/spec/parse/delegate/revision.rs index d92a51ac225..445b5d80dc2 100644 --- a/gix/src/revision/spec/parse/delegate/revision.rs +++ b/gix/src/revision/spec/parse/delegate/revision.rs @@ -106,12 +106,51 @@ 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::Date(date) => { + 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(it) => match it + .filter_map(Result::ok) + .min_by_key(|l| (date - l.signature.time).abs()) + { + Some(closest_line) => { + self.objs[self.idx] + .get_or_insert_with(HashSet::default) + .insert(closest_line.new_oid); + Some(()) + } + None => { + // do we need an another error variant? + self.err.push(Error::SingleNotFound); + None + } + }, + None => { + self.err.push(Error::MissingRefLog { + reference: r.name().as_bstr().into(), + action: "lookup entry", + }); + None + } + } } ReflogLookup::Entry(no) => { let r = match &mut self.refs[self.idx] { diff --git a/gix/src/revision/spec/parse/types.rs b/gix/src/revision/spec/parse/types.rs index 11bf7317add..a3f5c55939f 100644 --- a/gix/src/revision/spec/parse/types.rs +++ b/gix/src/revision/spec/parse/types.rs @@ -77,8 +77,6 @@ pub enum Error { direction: remote::Direction, source: Box, }, - #[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")] @@ -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 } diff --git a/gix/tests/gix/revision/spec/from_bytes/reflog.rs b/gix/tests/gix/revision/spec/from_bytes/reflog.rs index 69fa218464e..3c2f1f7d0e9 100644 --- a/gix/tests/gix/revision/spec/from_bytes/reflog.rs +++ b/gix/tests/gix/revision/spec/from_bytes/reflog.rs @@ -1,7 +1,4 @@ -use gix::{ - prelude::ObjectIdExt, - revision::{spec::parse::Error, Spec}, -}; +use gix::{prelude::ObjectIdExt, revision::Spec}; use crate::{ revision::spec::from_bytes::{parse_spec, parse_spec_no_baseline, repo}, @@ -78,10 +75,13 @@ fn by_index() { } #[test] -fn by_date_is_planned_until_git_date_crate_is_implements_parsing() { +fn by_date() { let repo = repo("complex_graph").unwrap(); - assert!(matches!( - parse_spec_no_baseline("main@{1979-02-26 18:30:00}", &repo).unwrap_err(), - Error::Planned { .. } - )); + + let spec = parse_spec_no_baseline("main@{1979-02-26 18:30:00}", &repo).unwrap(); + + assert_eq!( + spec, + Spec::from_id(hex_to_id("9f9eac6bd1cd4b4cc6a494f044b28c985a22972b").attach(&repo)) + ); }