Skip to content

Commit 64b2cba

Browse files
authored
fix glob matching of alternatives (#6839)
### Description The unicode refactoring introduced some bugs in matching of alternatives Closes PACK-2172
1 parent bcf22ad commit 64b2cba

File tree

1 file changed

+56
-47
lines changed

1 file changed

+56
-47
lines changed

crates/turbo-tasks-fs/src/glob.rs

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ impl GlobPart {
159159
match_partial,
160160
previous_part_is_path_separator_equivalent,
161161
cursor: GraphemeCursor::new(0, path.len(), true),
162+
index: 0,
162163
glob_iterator: None,
163164
}
164165
}
@@ -257,6 +258,7 @@ struct GlobPartMatchesIterator<'a> {
257258
match_partial: bool,
258259
previous_part_is_path_separator_equivalent: bool,
259260
cursor: GraphemeCursor,
261+
index: usize,
260262
glob_iterator: Option<Box<GlobMatchesIterator<'a>>>,
261263
}
262264

@@ -267,12 +269,9 @@ impl<'a> Iterator for GlobPartMatchesIterator<'a> {
267269
match self.part {
268270
GlobPart::AnyDirectories => {
269271
if self.cursor.cur_cursor() == 0 {
270-
let end = self.cursor.next_boundary(self.path, 0);
271-
match end {
272-
Ok(Some(_)) => {}
273-
Ok(None) => return None,
274-
Err(..) => return None,
275-
}
272+
let Ok(Some(_)) = self.cursor.next_boundary(self.path, 0) else {
273+
return None;
274+
};
276275
return Some((self.path, true));
277276
}
278277

@@ -304,22 +303,19 @@ impl<'a> Iterator for GlobPartMatchesIterator<'a> {
304303
}
305304
}
306305
GlobPart::AnyFile => {
307-
let end = self.cursor.next_boundary(self.path, 0);
308-
match end {
309-
Ok(Some(_)) => {}
310-
Ok(None) => return None,
311-
Err(..) => return None,
312-
}
306+
let Ok(Some(c)) = self.cursor.next_boundary(self.path, 0) else {
307+
return None;
308+
};
313309

314-
let idx = self.path[0..self.cursor.cur_cursor()].len();
310+
let idx = self.path[0..c].len();
315311

316312
// TODO verify if `*` does match zero chars?
317-
if let Some(slice) = self.path.get(0..self.cursor.cur_cursor()) {
313+
if let Some(slice) = self.path.get(0..c) {
318314
if slice.ends_with('/') {
319315
None
320316
} else {
321317
Some((
322-
&self.path[self.cursor.cur_cursor()..],
318+
&self.path[c..],
323319
self.previous_part_is_path_separator_equivalent && idx == 1,
324320
))
325321
}
@@ -330,14 +326,11 @@ impl<'a> Iterator for GlobPartMatchesIterator<'a> {
330326
GlobPart::AnyFileChar => todo!(),
331327
GlobPart::PathSeparator => {
332328
if self.cursor.cur_cursor() == 0 {
333-
let end = self.cursor.next_boundary(self.path, 0);
334-
match end {
335-
Ok(Some(_)) => {}
336-
Ok(None) => return None,
337-
Err(..) => return None,
338-
}
329+
let Ok(Some(b)) = self.cursor.next_boundary(self.path, 0) else {
330+
return None;
331+
};
339332
if self.path.starts_with('/') {
340-
Some((&self.path[1..], true))
333+
Some((&self.path[b..], true))
341334
} else if self.previous_part_is_path_separator_equivalent {
342335
Some((self.path, true))
343336
} else {
@@ -347,28 +340,25 @@ impl<'a> Iterator for GlobPartMatchesIterator<'a> {
347340
None
348341
}
349342
}
350-
GlobPart::FileChar(chars) => loop {
351-
let end = match self.cursor.next_boundary(self.path, 0) {
352-
Ok(Some(end)) => end,
353-
_ => return None,
343+
GlobPart::FileChar(chars) => {
344+
let start = self.cursor.cur_cursor();
345+
let Ok(Some(end)) = self.cursor.next_boundary(self.path, 0) else {
346+
return None;
354347
};
355-
356-
let c = &chars[self.cursor.cur_cursor()..end]
357-
.iter()
358-
.cloned()
359-
.collect::<String>();
360-
if self.path.starts_with(c) {
361-
return Some((&self.path[c.len()..], false));
348+
let mut chars_in_path = self.path[start..end].chars();
349+
let Some(c) = chars_in_path.next() else {
350+
return None;
351+
};
352+
if chars_in_path.next().is_some() {
353+
return None;
362354
}
363-
},
355+
chars.contains(&c).then(|| (&self.path[end..], false))
356+
}
364357
GlobPart::File(name) => {
365358
if self.cursor.cur_cursor() == 0 && self.path.starts_with(name) {
366-
let end = self.cursor.next_boundary(self.path, 0);
367-
match end {
368-
Ok(Some(_)) => {}
369-
Ok(None) => return None,
370-
Err(..) => return None,
371-
}
359+
let Ok(Some(_)) = self.cursor.next_boundary(self.path, 0) else {
360+
return None;
361+
};
372362
Some((&self.path[name.len()..], false))
373363
} else {
374364
None
@@ -379,15 +369,10 @@ impl<'a> Iterator for GlobPartMatchesIterator<'a> {
379369
if let Some((path, is_path_separator_equivalent)) = glob_iterator.next() {
380370
return Some((path, is_path_separator_equivalent));
381371
} else {
382-
let end = self.cursor.next_boundary(self.path, 0);
372+
self.index += 1;
383373
self.glob_iterator = None;
384-
match end {
385-
Ok(Some(_)) => {}
386-
Ok(None) => return None,
387-
Err(..) => return None,
388-
}
389374
}
390-
} else if let Some(alternative) = alternatives.get(self.cursor.cur_cursor()) {
375+
} else if let Some(alternative) = alternatives.get(self.index) {
391376
self.glob_iterator = Some(Box::new(alternative.iter_matches(
392377
self.path,
393378
self.previous_part_is_path_separator_equivalent,
@@ -457,19 +442,43 @@ mod tests {
457442
"node_modules/next/dist/server/next.js"
458443
)]
459444
#[case::node_modules_root("**/node_modules/**", "node_modules/next/dist/server/next.js")]
445+
#[case::node_modules_root_package(
446+
"**/node_modules/next/**",
447+
"node_modules/next/dist/server/next.js"
448+
)]
460449
#[case::node_modules_nested(
461450
"**/node_modules/**",
462451
"apps/some-app/node_modules/regenerate-unicode-properties/Script_Extensions/Osage.js"
463452
)]
453+
#[case::node_modules_nested_package(
454+
"**/node_modules/regenerate-unicode-properties/**",
455+
"apps/some-app/node_modules/regenerate-unicode-properties/Script_Extensions/Osage.js"
456+
)]
464457
#[case::node_modules_pnpm(
465458
"**/node_modules/**",
466459
"node_modules/.pnpm/[email protected]/node_modules/\
467460
regenerate-unicode-properties/Script_Extensions/Osage.js"
468461
)]
462+
#[case::node_modules_pnpm_package(
463+
"**/node_modules/{regenerate,regenerate-unicode-properties}/**",
464+
"node_modules/.pnpm/[email protected]/node_modules/\
465+
regenerate-unicode-properties/Script_Extensions/Osage.js"
466+
)]
467+
#[case::node_modules_pnpm_prefixed_package(
468+
"**/node_modules/{@blockfrost/blockfrost-js,@highlight-run/node,@libsql/client,@jpg-store/\
469+
lucid-cardano,@mikro-orm/core,@mikro-orm/knex,@prisma/client,@sentry/nextjs,@sentry/node,\
470+
@swc/core,argon2,autoprefixer,bcrypt,better-sqlite3,canvas,cpu-features,cypress,eslint,\
471+
express,next-seo,node-pty,payload,pg,playwright,postcss,prettier,prisma,puppeteer,rimraf,\
472+
sharp,shiki,sqlite3,tailwindcss,ts-node,typescript,vscode-oniguruma,webpack,websocket,@\
473+
aws-sdk/client-dynamodb,@aws-sdk/lib-dynamodb}/**",
474+
"node_modules/.pnpm/@[email protected]_@[email protected]/\
475+
node_modules/@aws-sdk/lib-dynamodb/dist-es/index.js"
476+
)]
469477
#[case::alternatives_nested1("{a,b/c,d/e/{f,g/h}}", "a")]
470478
#[case::alternatives_nested2("{a,b/c,d/e/{f,g/h}}", "b/c")]
471479
#[case::alternatives_nested3("{a,b/c,d/e/{f,g/h}}", "d/e/f")]
472480
#[case::alternatives_nested4("{a,b/c,d/e/{f,g/h}}", "d/e/g/h")]
481+
// #[case::alternatives_chars("[abc]", "b")]
473482
fn glob_match(#[case] glob: &str, #[case] path: &str) {
474483
let glob = Glob::parse(glob).unwrap();
475484

0 commit comments

Comments
 (0)