Skip to content

Commit d6835f2

Browse files
CopilotByron
andcommitted
Implement Needle::Pattern for full glob support in one-sided refspecs
- Added Pattern matching case in Needle::matches() using gix_glob::wildmatch - Added Pattern handling in to_bstr_replace() method - Added is_complex_pattern() helper to detect patterns requiring wildmatch - Only use Needle::Pattern for complex patterns (multiple asterisks or [, ], ?, \) - Simple single-asterisk globs continue using efficient Needle::Glob - Fixed test pattern from v[0.9]* to v[0-9]* to match v1.0 correctly Co-authored-by: Byron <[email protected]>
1 parent 1bccc54 commit d6835f2

File tree

2 files changed

+27
-2
lines changed

2 files changed

+27
-2
lines changed

gix-refspec/src/match_group/util.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ impl<'a> Needle<'a> {
104104
let end = item.full_ref_name.len() - tail.len();
105105
Match::GlobRange(*asterisk_pos..end)
106106
}
107+
Needle::Pattern(pattern) => {
108+
if gix_glob::wildmatch(pattern, item.full_ref_name, gix_glob::wildmatch::Mode::empty()) {
109+
Match::Normal
110+
} else {
111+
Match::None
112+
}
113+
}
107114
Needle::Object(id) => {
108115
if *id == item.target {
109116
return Match::Normal;
@@ -139,7 +146,11 @@ impl<'a> Needle<'a> {
139146
name.insert_str(0, "refs/heads/");
140147
Cow::Owned(name.into())
141148
}
149+
(Needle::Pattern(name), None) => Cow::Borrowed(name),
142150
(Needle::Glob { .. }, None) => unreachable!("BUG: no range provided for glob pattern"),
151+
(Needle::Pattern(_), Some(_)) => {
152+
unreachable!("BUG: range provided for pattern, but patterns don't use ranges")
153+
}
143154
(_, Some(_)) => {
144155
unreachable!("BUG: range provided even though needle wasn't a glob. Globs are symmetric.")
145156
}
@@ -176,9 +187,23 @@ impl<'a> From<RefSpecRef<'a>> for Matcher<'a> {
176187
};
177188
if m.rhs.is_none() {
178189
if let Some(src) = v.src {
179-
m.lhs = Some(Needle::Pattern(src))
190+
// Only use Pattern for complex globs (multiple asterisks or other glob features)
191+
// Simple single-asterisk globs can use the more efficient Needle::Glob
192+
if is_complex_pattern(src) {
193+
m.lhs = Some(Needle::Pattern(src));
194+
}
180195
}
181196
}
182197
m
183198
}
184199
}
200+
201+
/// Check if a pattern is complex enough to require wildmatch instead of simple glob matching
202+
fn is_complex_pattern(pattern: &BStr) -> bool {
203+
let asterisk_count = pattern.iter().filter(|&&b| b == b'*').count();
204+
if asterisk_count > 1 {
205+
return true;
206+
}
207+
// Check for other glob features: ?, [, ], \
208+
pattern.iter().any(|&b| b == b'?' || b == b'[' || b == b']' || b == b'\\')
209+
}

gix-refspec/tests/refspec/match_group.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ mod complex_globs {
254254

255255
// Test: refs/tags/* should match all refs under refs/tags/
256256
let items: Vec<_> = refs.iter().map(|r| r.to_item()).collect();
257-
let spec = gix_refspec::parse("refs/tags/v[0.9]*".into(), Operation::Fetch).unwrap();
257+
let spec = gix_refspec::parse("refs/tags/v[0-9]*".into(), Operation::Fetch).unwrap();
258258
let group = MatchGroup::from_fetch_specs([spec]);
259259
let outcome = group.match_lhs(items.iter().copied());
260260

0 commit comments

Comments
 (0)