Skip to content

Commit e4227d6

Browse files
committed
basic validation and detection of patterns (#450)
1 parent 7afebb7 commit e4227d6

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

git-refspec/src/parse.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ pub enum Error {
66
NegativeWithDestination,
77
#[error("Cannot push into an empty destination")]
88
PushToEmpty,
9+
#[error("glob patterns may only involved a single '*' character, found {pattern:?}")]
10+
PatternUnsupported { pattern: bstr::BString },
11+
#[error("Both sides of the specification need a pattern, like 'a/*:b/*'")]
12+
PatternUnbalanced,
913
}
1014

1115
pub(crate) mod function {
@@ -48,17 +52,35 @@ pub(crate) mod function {
4852
Operation::Push => return Err(Error::PushToEmpty),
4953
Operation::Fetch => (Some(src), None),
5054
},
51-
_ => todo!("src or dst handling"),
55+
(Some(src), Some(dst)) => (Some(src), Some(dst)),
5256
}
5357
}
54-
None => todo!("no colon"),
58+
None => (Some(spec), None),
5559
};
5660

61+
let (src, src_had_pattern) = validated(src)?;
62+
let (dst, dst_had_pattern) = validated(dst)?;
63+
if src_had_pattern != dst_had_pattern {
64+
return Err(Error::PatternUnbalanced);
65+
}
5766
Ok(RefSpecRef {
5867
op: operation,
5968
mode,
6069
src,
6170
dst,
6271
})
6372
}
73+
74+
fn validated(spec: Option<&BStr>) -> Result<(Option<&BStr>, bool), Error> {
75+
match spec {
76+
Some(spec) => {
77+
let glob_count = spec.iter().filter(|b| **b == b'*').take(2).count();
78+
if glob_count == 2 {
79+
return Err(Error::PatternUnsupported { pattern: spec.into() });
80+
}
81+
Ok((Some(spec), glob_count == 1))
82+
}
83+
None => Ok((None, false)),
84+
}
85+
}
6486
}

git-refspec/tests/parse/mod.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fn baseline() {
1515
while let Some(kind_spec) = lines.next() {
1616
count += 1;
1717
let (kind, spec) = kind_spec.split_at(kind_spec.find_byte(b' ').expect("space between kind and spec"));
18+
let spec = &spec[1..];
1819
let err_code: usize = lines
1920
.next()
2021
.expect("err code")
@@ -32,7 +33,7 @@ fn baseline() {
3233
Ok(res) => match (res.is_ok(), err_code == 0) {
3334
(true, true) | (false, false) => {}
3435
_ => {
35-
eprintln!("{res:?} {err_code}");
36+
eprintln!("{res:?} {err_code} {} {:?}", kind.as_bstr(), spec.as_bstr());
3637
mismatch += 1;
3738
}
3839
},
@@ -74,6 +75,27 @@ mod invalid {
7475
}
7576
}
7677

78+
#[test]
79+
fn complex_patterns_with_more_than_one_asterisk() {
80+
for op in [Operation::Fetch, Operation::Push] {
81+
for spec in ["^*/*", "a/*/c/*", "a**:**b", "+:**/"] {
82+
assert!(matches!(
83+
try_parse(spec, op).unwrap_err(),
84+
Error::PatternUnsupported { .. }
85+
));
86+
}
87+
}
88+
}
89+
90+
#[test]
91+
fn both_sides_need_pattern_if_one_uses_it() {
92+
for op in [Operation::Fetch, Operation::Push] {
93+
for spec in ["/*/a", ":a/*", "+:a/*", "a*:b/c", "a:b/*"] {
94+
assert!(matches!(try_parse(spec, op).unwrap_err(), Error::PatternUnbalanced));
95+
}
96+
}
97+
}
98+
7799
#[test]
78100
fn push_to_empty() {
79101
assert!(matches!(

0 commit comments

Comments
 (0)