From 6e5bd5c152403d76ba1cf3da2b984689cb6fe8c5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 6 Aug 2022 13:20:27 +0800 Subject: [PATCH] first successful test for returning a refspec. (#450) It's the simplest possible one, but it shows the test framework is up to the task now so it can be test-driven. We should be able to construct a test for each possible instruction and eventually pass all tests, including the baseline ones. --- git-refspec/src/lib.rs | 4 +-- git-refspec/src/parse.rs | 28 +++++++++++++++---- git-refspec/src/spec.rs | 14 +++++----- git-refspec/src/types.rs | 13 ++++++--- git-refspec/tests/parse/mod.rs | 7 ++++- .../src/repository/revision/resolve.rs | 4 +-- 6 files changed, 49 insertions(+), 21 deletions(-) diff --git a/git-refspec/src/lib.rs b/git-refspec/src/lib.rs index 2d38f3931b..3da9be64f1 100644 --- a/git-refspec/src/lib.rs +++ b/git-refspec/src/lib.rs @@ -11,7 +11,7 @@ pub struct RefSpecRef<'a> { mode: Mode, op: Operation, src: Option<&'a bstr::BStr>, - dest: Option<&'a bstr::BStr>, + dst: Option<&'a bstr::BStr>, } /// An owned refspec. @@ -20,7 +20,7 @@ pub struct RefSpec { mode: Mode, op: Operation, src: Option, - dest: Option, + dst: Option, } mod spec; diff --git a/git-refspec/src/parse.rs b/git-refspec/src/parse.rs index a437246d30..b736abfa2d 100644 --- a/git-refspec/src/parse.rs +++ b/git-refspec/src/parse.rs @@ -12,25 +12,43 @@ pub(crate) mod function { use bstr::{BStr, ByteSlice}; /// Parse `spec` for use in `operation` and return it if it is valid. - pub fn parse(mut spec: &BStr, _operation: Operation) -> Result, Error> { + pub fn parse(mut spec: &BStr, operation: Operation) -> Result, Error> { let mode = match spec.get(0) { Some(&b'^') => { spec = &spec[1..]; Mode::Negative } + Some(&b'+') => { + spec = &spec[1..]; + Mode::Force + } Some(_) => Mode::Normal, None => return Err(Error::Empty), }; - match spec.find_byte(b':') { + let (src, dst) = match spec.find_byte(b':') { Some(pos) => { - let (_src, _dst) = spec.split_at(pos); + let (src, dst) = spec.split_at(pos); + let dst = &dst[1..]; if mode == Mode::Negative { return Err(Error::NegativeWithDestination); } - todo!("with colon") + let src = (!src.is_empty()).then(|| src.as_bstr()); + let dst = (!dst.is_empty()).then(|| dst.as_bstr()); + match (src, dst) { + (None, None) => {} + _ => todo!("src or dst handling"), + }; + (src, dst) } None => todo!("no colon"), - } + }; + + Ok(RefSpecRef { + op: operation, + mode, + src, + dst, + }) } } diff --git a/git-refspec/src/spec.rs b/git-refspec/src/spec.rs index d9488d2b68..161f0fd919 100644 --- a/git-refspec/src/spec.rs +++ b/git-refspec/src/spec.rs @@ -14,25 +14,25 @@ impl RefSpecRef<'_> { fn has_pattern(item: &BStr) -> bool { item.contains(&b'*') } - match (self.op, self.mode, self.src, self.dest) { + match (self.op, self.mode, self.src, self.dst) { (Operation::Push, Mode::Normal | Mode::Force, Some(src), None) => Instruction::Push(Push::Single { src, - dest: src, + dst: src, allow_non_fast_forward: matches!(self.mode, Mode::Force), }), (Operation::Push, Mode::Normal | Mode::Force, None, None) => Instruction::Push(Push::AllMatchingBranches { allow_non_fast_forward: matches!(self.mode, Mode::Force), }), - (Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dest)) if has_pattern(src) => { + (Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dst)) if has_pattern(src) => { Instruction::Push(Push::MultipleWithGlob { src, - dest, + dst, allow_non_fast_forward: matches!(self.mode, Mode::Force), }) } - (Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dest)) => Instruction::Push(Push::Single { + (Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dst)) => Instruction::Push(Push::Single { src, - dest, + dst, allow_non_fast_forward: matches!(self.mode, Mode::Force), }), (Operation::Push, Mode::Negative, Some(src), None) if has_pattern(src) => { @@ -57,7 +57,7 @@ impl RefSpecRef<'_> { mode: self.mode, op: self.op, src: self.src.map(ToOwned::to_owned), - dest: self.dest.map(ToOwned::to_owned), + dst: self.dst.map(ToOwned::to_owned), } } } diff --git a/git-refspec/src/types.rs b/git-refspec/src/types.rs index ac129f75cf..6ca621aacf 100644 --- a/git-refspec/src/types.rs +++ b/git-refspec/src/types.rs @@ -33,6 +33,11 @@ pub enum Push<'a> { /// If true, allow non-fast-forward updates of the matched destination branch. allow_non_fast_forward: bool, }, + /// Delete the destination ref or glob pattern, with only a single `*` allowed. + Delete { + /// The reference or pattern to delete on the remote. + ref_or_pattern: &'a BStr, + }, /// Exclude a single ref. ExcludeSingle { /// A single full ref name to exclude. @@ -48,7 +53,7 @@ pub enum Push<'a> { /// The source ref or refspec to push. src: &'a BStr, /// The ref to update with the object from `src`. - dest: &'a BStr, + dst: &'a BStr, /// If true, allow non-fast-forward updates of `dest`. allow_non_fast_forward: bool, }, @@ -57,7 +62,7 @@ pub enum Push<'a> { /// The source ref to match against all refs for pushing. src: &'a BStr, /// The ref to update with object obtained from `src`, filling in the `*` with the portion that matched in `src`. - dest: &'a BStr, + dst: &'a BStr, /// If true, allow non-fast-forward updates of `dest`. allow_non_fast_forward: bool, }, @@ -83,7 +88,7 @@ pub enum Fetch<'a> { /// The ref name to fetch on the remote side. src: &'a BStr, /// The local destination to update with what was fetched. - dest: &'a BStr, + dst: &'a BStr, /// If true, allow non-fast-forward updates of `dest`. allow_non_fast_forward: bool, }, @@ -92,7 +97,7 @@ pub enum Fetch<'a> { /// The ref glob to match against all refs on the remote side for fetching. src: &'a BStr, /// The local destination to update with what was fetched by replacing the single `*` with the matching portion from `src`. - dest: &'a BStr, + dst: &'a BStr, /// If true, allow non-fast-forward updates of `dest`. allow_non_fast_forward: bool, }, diff --git a/git-refspec/tests/parse/mod.rs b/git-refspec/tests/parse/mod.rs index 4948708e33..35ae4b3d54 100644 --- a/git-refspec/tests/parse/mod.rs +++ b/git-refspec/tests/parse/mod.rs @@ -75,7 +75,6 @@ mod invalid { use git_refspec::{Instruction, Push}; #[test] - #[ignore] fn colon_alone_is_for_pushing_matching_refs() { assert_parse( ":", @@ -83,6 +82,12 @@ mod invalid { allow_non_fast_forward: false, }), ); + assert_parse( + "+:", + Instruction::Push(Push::AllMatchingBranches { + allow_non_fast_forward: true, + }), + ); } } } diff --git a/gitoxide-core/src/repository/revision/resolve.rs b/gitoxide-core/src/repository/revision/resolve.rs index d58851715c..e20097f7e7 100644 --- a/gitoxide-core/src/repository/revision/resolve.rs +++ b/gitoxide-core/src/repository/revision/resolve.rs @@ -7,7 +7,7 @@ pub struct Options { } pub(crate) mod function { - use anyhow::{bail, Context}; + use anyhow::Context; use std::ffi::OsString; use git_repository as git; @@ -45,7 +45,7 @@ pub(crate) mod function { #[cfg(feature = "serde1")] OutputFormat::Json => { if explain { - bail!("Explanations are only for human consumption") + anyhow::bail!("Explanations are only for human consumption") } serde_json::to_writer_pretty( &mut out,