diff --git a/gix-date/src/lib.rs b/gix-date/src/lib.rs index 20893a7cab8..1570a596eac 100644 --- a/gix-date/src/lib.rs +++ b/gix-date/src/lib.rs @@ -15,7 +15,10 @@ pub mod time; /// pub mod parse; + +use crate::time::Sign; pub use parse::function::parse; +use std::ops::Sub; /// A timestamp with timezone. #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] @@ -29,6 +32,24 @@ pub struct Time { pub sign: time::Sign, } +impl Sub for Time { + type Output = i64; + + fn sub(self, rhs: Self) -> Self::Output { + self.total() - rhs.total() + } +} + +impl Time { + fn total(&self) -> i64 { + if self.sign == Sign::Minus { + self.seconds - self.offset as i64 + } else { + self.seconds + self.offset as i64 + } + } +} + /// The amount of seconds since unix epoch. /// /// Note that negative dates represent times before the unix epoch. 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/tests/gix/revision/spec/from_bytes/reflog.rs b/gix/tests/gix/revision/spec/from_bytes/reflog.rs index 69fa218464e..eab30bba979 100644 --- a/gix/tests/gix/revision/spec/from_bytes/reflog.rs +++ b/gix/tests/gix/revision/spec/from_bytes/reflog.rs @@ -1,6 +1,6 @@ use gix::{ prelude::ObjectIdExt, - revision::{spec::parse::Error, Spec}, + revision::Spec, }; use crate::{ @@ -78,10 +78,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)) + ); }