-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(turborepo): avoid globbing directories due to ancestor truncation #5273
Changes from 13 commits
0027122
55e5e97
25c7995
ef596c3
b8a47ed
271ea3b
501df33
aecf7e1
4355840
c354c1e
687bc8e
ef71312
9ac8098
d9abec8
5fdf477
ed98399
5947864
d57fe76
93cb112
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -143,9 +143,17 @@ macro_rules! walk { | |
.strip_prefix(&$state.prefix) | ||
.expect("path is not in tree"); | ||
let depth = entry.depth().saturating_sub(1); | ||
// Globs don't include the root token, but absolute paths on unix do. | ||
// If we have an absolute path and are on unix, skip that token so that | ||
// matching up components will work below. | ||
let to_skip_in_path = if cfg!(unix) && path.is_absolute() { | ||
depth + 1 | ||
} else { | ||
depth | ||
}; | ||
for candidate in path | ||
.components() | ||
.skip(depth) | ||
.skip(to_skip_in_path) | ||
.filter_map(|component| match component { | ||
Component::Normal(component) => Some(CandidatePath::from(component)), | ||
_ => None, | ||
|
@@ -570,9 +578,22 @@ pub struct Walk<'g> { | |
root: PathBuf, | ||
prefix: PathBuf, | ||
walk: walkdir::IntoIter, | ||
// This is a hack to express an empty iterator | ||
is_empty: bool, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't blocking, but I feel like we could either make this into an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, this is definitely not the optimal way of doing this. |
||
} | ||
|
||
impl<'g> Walk<'g> { | ||
fn empty() -> Self { | ||
Self { | ||
pattern: Cow::Owned(Regex::new("").unwrap()), | ||
components: vec![], | ||
root: PathBuf::new(), | ||
prefix: PathBuf::new(), | ||
walk: walkdir::WalkDir::new(PathBuf::new()).into_iter(), | ||
is_empty: true, | ||
} | ||
} | ||
|
||
fn compile<'t, I>(tokens: I) -> Result<Vec<Regex>, CompileError> | ||
where | ||
I: IntoIterator<Item = &'t Token<'t>>, | ||
|
@@ -602,13 +623,15 @@ impl<'g> Walk<'g> { | |
root, | ||
prefix, | ||
walk, | ||
is_empty, | ||
} = self; | ||
Walk { | ||
pattern: Cow::Owned(pattern.into_owned()), | ||
components, | ||
root, | ||
prefix, | ||
walk, | ||
is_empty, | ||
} | ||
} | ||
|
||
|
@@ -704,6 +727,9 @@ impl Iterator for Walk<'_> { | |
type Item = WalkItem<'static>; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
if self.is_empty { | ||
return None; | ||
} | ||
walk!(self => |entry| { | ||
return Some(entry.map(WalkEntry::into_owned)); | ||
}); | ||
|
@@ -907,6 +933,24 @@ pub fn walk<'g>( | |
} | ||
}, | ||
); | ||
if matches!(link, LinkBehavior::ReadFile) { | ||
if let Ok(tail) = root.strip_prefix(directory) { | ||
let found = tail | ||
.components() | ||
.try_fold(directory.to_path_buf(), |accum, c| { | ||
let candidate = accum.join(c); | ||
if candidate.is_symlink() { | ||
None | ||
} else { | ||
Some(candidate) | ||
} | ||
}) | ||
.is_none(); | ||
if found { | ||
return Walk::empty(); | ||
} | ||
} | ||
} | ||
let components = | ||
Walk::compile(glob.tree.as_ref().tokens()).expect("failed to compile glob sub-expressions"); | ||
Walk { | ||
|
@@ -921,6 +965,7 @@ pub fn walk<'g>( | |
}) | ||
.max_depth(depth) | ||
.into_iter(), | ||
is_empty: false, | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is sadly irrelevant in the latest revision, we can't rely on globs being rooted, as they don't count as rooted on windows.