From 250e410016cd2e31b8c4629c573b051d5a0c52ab Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 24 May 2022 13:45:43 +0800 Subject: [PATCH] A basis for 'pure' parsing of rev-specs (#427) --- git-revision/src/lib.rs | 3 +++ git-revision/src/spec.rs | 34 +++++++++++++++++++++++ git-revision/tests/revision.rs | 1 + git-revision/tests/spec/mod.rs | 49 ++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 git-revision/src/spec.rs create mode 100644 git-revision/tests/spec/mod.rs diff --git a/git-revision/src/lib.rs b/git-revision/src/lib.rs index 59eaf4a113..82c56a0795 100644 --- a/git-revision/src/lib.rs +++ b/git-revision/src/lib.rs @@ -10,3 +10,6 @@ pub use hash_hasher; /// pub mod describe; pub use describe::function::describe; + +/// +pub mod spec; diff --git a/git-revision/src/spec.rs b/git-revision/src/spec.rs new file mode 100644 index 0000000000..67645ce61c --- /dev/null +++ b/git-revision/src/spec.rs @@ -0,0 +1,34 @@ +pub mod parse { + #![allow(missing_docs)] + use git_object::bstr::BStr; + + #[derive(Debug, thiserror::Error)] + pub enum Error { + #[error("The delegate didn't indicate success - check delegate for more information")] + Delegate, + } + + pub trait Delegate { + fn resolve_ref(&mut self, input: &BStr) -> Option<()>; + fn find_by_prefix(&mut self, input: &BStr) -> Option<()>; + + fn nth_ancestor(&mut self, n: usize) -> Option<()>; + fn nth_parent(&mut self, n: usize) -> Option<()>; + } + + pub(crate) mod function { + use crate::spec::parse::{Delegate, Error}; + use git_object::bstr::BStr; + + pub fn parse(input: &BStr, delegate: &mut impl Delegate) -> Result<(), Error> { + // TODO: don't hardcode these cases, see how git does it. This remains + // just an example. + if input == "@" || input == "HEAD" { + return delegate.resolve_ref("HEAD".into()).ok_or(Error::Delegate); + } + + todo!("") + } + } +} +pub use parse::function::parse; diff --git a/git-revision/tests/revision.rs b/git-revision/tests/revision.rs index 14367453bc..d1317fcef0 100644 --- a/git-revision/tests/revision.rs +++ b/git-revision/tests/revision.rs @@ -1,3 +1,4 @@ mod describe; +mod spec; pub type Result = std::result::Result>; diff --git a/git-revision/tests/spec/mod.rs b/git-revision/tests/spec/mod.rs new file mode 100644 index 0000000000..9685a4c980 --- /dev/null +++ b/git-revision/tests/spec/mod.rs @@ -0,0 +1,49 @@ +mod parse { + use git_object::bstr::{BStr, BString}; + use git_revision::spec; + #[derive(Default, Debug)] + struct Recorder { + resolve_ref_input: Option, + } + impl spec::parse::Delegate for Recorder { + fn resolve_ref(&mut self, input: &BStr) -> Option<()> { + assert!( + self.resolve_ref_input.is_none(), + "called resolve_ref twice with '{}'", + input + ); + self.resolve_ref_input = input.to_owned().into(); + Some(()) + } + + fn find_by_prefix(&mut self, _input: &BStr) -> Option<()> { + todo!() + } + + fn nth_ancestor(&mut self, _n: usize) -> Option<()> { + todo!() + } + + fn nth_parent(&mut self, _n: usize) -> Option<()> { + todo!() + } + } + + fn b(s: &str) -> &BStr { + s.into() + } + + #[test] + fn at_alone_is_shortcut_for_head() { + let mut rec = Recorder::default(); + spec::parse(b("@"), &mut rec).unwrap(); + assert_eq!(rec.resolve_ref_input.unwrap(), "HEAD"); + } + + #[test] + fn refname() { + let mut rec = Recorder::default(); + spec::parse(b("HEAD"), &mut rec).unwrap(); + assert_eq!(rec.resolve_ref_input.unwrap(), "HEAD"); + } +}