-
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: clean paths and use package path instead of package.json path #6649
Changes from all commits
3e9abff
fcb0f7b
4b4362c
665bdcf
07edae0
5b10a64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,7 +38,7 @@ impl PackageInference { | |
); | ||
let full_inference_path = turbo_root.resolve(pkg_inference_path); | ||
for (workspace_name, workspace_entry) in pkg_graph.workspaces() { | ||
let pkg_path = turbo_root.resolve(workspace_entry.package_json_path()); | ||
let pkg_path = turbo_root.resolve(workspace_entry.package_path()); | ||
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. Previously we would be checking if |
||
let inferred_path_is_below = pkg_path.contains(&full_inference_path); | ||
// We skip over the root package as the inferred path will always be below it | ||
if inferred_path_is_below && (&pkg_path as &AbsoluteSystemPath) != turbo_root { | ||
|
@@ -47,7 +47,7 @@ impl PackageInference { | |
// do so in a consistent manner | ||
return Self { | ||
package_name: Some(workspace_name.to_string()), | ||
directory_root: workspace_entry.package_json_path().to_owned(), | ||
directory_root: workspace_entry.package_path().to_owned(), | ||
}; | ||
} | ||
let inferred_path_is_between_root_and_pkg = full_inference_path.contains(&pkg_path); | ||
|
@@ -75,7 +75,14 @@ impl PackageInference { | |
} | ||
|
||
if selector.parent_dir != turbopath::AnchoredSystemPathBuf::default() { | ||
selector.parent_dir = self.directory_root.join(&selector.parent_dir); | ||
let repo_relative_parent_dir = self.directory_root.join(&selector.parent_dir); | ||
let clean_parent_dir = | ||
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. Definitely not blocking, but we ought to think about how to work this into the path library properly |
||
path_clean::clean(std::path::Path::new(repo_relative_parent_dir.as_path())) | ||
.into_os_string() | ||
.into_string() | ||
.expect("path was valid utf8 before cleaning"); | ||
selector.parent_dir = AnchoredSystemPathBuf::try_from(clean_parent_dir.as_str()) | ||
.expect("path wasn't absolute before cleaning"); | ||
} else if self.package_name.is_none() { | ||
// fallback: the user didn't set a parent directory and we didn't find a single | ||
// package, so use the directory we inferred and select all subdirectories | ||
|
@@ -343,7 +350,7 @@ impl<'a, T: PackageChangeDetector> FilterResolver<'a, T> { | |
} else { | ||
let path = selector.parent_dir.to_unix(); | ||
let parent_dir_matcher = wax::Glob::new(path.as_str())?; | ||
let matches = parent_dir_matcher.is_match(info.package_json_path.as_path()); | ||
let matches = parent_dir_matcher.is_match(info.package_path().as_path()); | ||
|
||
if matches { | ||
entry_packages.insert(name.to_owned()); | ||
|
@@ -413,7 +420,7 @@ impl<'a, T: PackageChangeDetector> FilterResolver<'a, T> { | |
let package_path_lookup = self | ||
.pkg_graph | ||
.workspaces() | ||
.map(|(name, entry)| (name, entry.package_json_path())) | ||
.map(|(name, entry)| (name, entry.package_path())) | ||
.collect::<HashMap<_, _>>(); | ||
|
||
for package in changed_packages { | ||
|
@@ -446,7 +453,7 @@ impl<'a, T: PackageChangeDetector> FilterResolver<'a, T> { | |
} else { | ||
let packages = self.pkg_graph.workspaces(); | ||
for (name, _) in packages.filter(|(_name, info)| { | ||
let path = info.package_json_path.as_path(); | ||
let path = info.package_path().as_path(); | ||
parent_dir_globber.is_match(path) | ||
}) { | ||
entry_packages.insert(name.to_owned()); | ||
|
@@ -625,7 +632,7 @@ mod test { | |
AbsoluteSystemPathBuf::new(temp_folder.path().as_os_str().to_str().unwrap()).unwrap(), | ||
)); | ||
|
||
let packages = dependencies | ||
let package_dirs = dependencies | ||
.iter() | ||
.flat_map(|(a, b)| vec![a, b]) | ||
.chain(extras.iter()) | ||
|
@@ -641,13 +648,16 @@ mod test { | |
acc | ||
}); | ||
|
||
let package_jsons = packages | ||
let package_jsons = package_dirs | ||
.iter() | ||
.map(|package_path| { | ||
let (_, name) = get_name(package_path); | ||
( | ||
turbo_root | ||
.join_unix_path(RelativeUnixPathBuf::new(**package_path).unwrap()) | ||
.join_unix_path( | ||
RelativeUnixPathBuf::new(format!("{package_path}/package.json")) | ||
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. The keys to the package json map for the package graph builder should be paths to This caused the test fixture to cover up the logic errors in the implementation. |
||
.unwrap(), | ||
) | ||
.unwrap(), | ||
PackageJson { | ||
name: Some(name.to_string()), | ||
|
@@ -808,6 +818,18 @@ mod test { | |
&["project-0", "project-1"] ; | ||
"select by parentDir using glob" | ||
)] | ||
#[test_case( | ||
vec![TargetSelector { | ||
parent_dir: AnchoredSystemPathBuf::try_from(if cfg!(windows) { "..\\packages\\*" } else { "../packages/*" }).unwrap(), | ||
..Default::default() | ||
}], | ||
Some(PackageInference{ | ||
package_name: None, | ||
directory_root: AnchoredSystemPathBuf::try_from("project-5").unwrap(), | ||
}), | ||
&["project-0", "project-1"] ; | ||
"select sibling directory" | ||
)] | ||
#[test_case( | ||
vec![ | ||
TargetSelector { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -120,7 +120,11 @@ impl FromStr for TargetSelector { | |
if directory.is_empty() { | ||
return Err(InvalidSelectorError::EmptyPathSpecification); | ||
} else { | ||
parent_dir = AnchoredSystemPathBuf::try_from(directory.as_str()) | ||
let clean_directory = path_clean::clean(std::path::Path::new(directory.as_str())) | ||
.into_os_string() | ||
.into_string() | ||
.expect("directory was valid utf8 before cleaning"); | ||
parent_dir = AnchoredSystemPathBuf::try_from(clean_directory.as_str()) | ||
.map_err(|_| InvalidSelectorError::InvalidAnchoredPath(directory))?; | ||
} | ||
} | ||
|
@@ -195,8 +199,12 @@ pub fn is_selector_by_location( | |
.iter() | ||
.any(|prefix| raw_selector.starts_with(prefix)) | ||
{ | ||
let cleaned_selector = path_clean::clean(std::path::Path::new(raw_selector)) | ||
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. We do this to match the Go behavior where 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. Maybe we should clean all AnchoredSystemPathBuf and RelativeUnixPaths such that there are as few ways to represent the same path as possible. |
||
.into_os_string() | ||
.into_string() | ||
Comment on lines
+203
to
+204
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. We could use |
||
.expect("raw selector was valid utf8"); | ||
Some( | ||
AnchoredSystemPathBuf::try_from(raw_selector) | ||
AnchoredSystemPathBuf::try_from(cleaned_selector.as_str()) | ||
.map_err(|_| InvalidSelectorError::InvalidAnchoredPath(raw_selector.to_string())), | ||
) | ||
} else { | ||
|
@@ -219,9 +227,10 @@ mod test { | |
#[test_case("...foo...", TargetSelector { name_pattern: "foo".to_string(), raw: "...foo...".to_string(), include_dependents: true, include_dependencies: true, ..Default::default() }; "dot dot dot foo dot dot dot")] | ||
#[test_case("foo^...", TargetSelector { name_pattern: "foo".to_string(), raw: "foo^...".to_string(), include_dependencies: true, exclude_self: true, ..Default::default() }; "foo caret dot dot dot")] | ||
#[test_case("...^foo", TargetSelector { name_pattern: "foo".to_string(), raw: "...^foo".to_string(), include_dependents: true, exclude_self: true, ..Default::default() }; "dot dot dot caret foo")] | ||
#[test_case("./foo", TargetSelector { raw: "./foo".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("./foo").unwrap(), ..Default::default() }; "dot slash foo")] | ||
#[test_case("../foo", TargetSelector { raw: "../foo".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("../foo").unwrap(), ..Default::default() }; "dot dot slash foo")] | ||
#[test_case("...{./foo}", TargetSelector { raw: "...{./foo}".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("./foo").unwrap(), include_dependents: true, ..Default::default() }; "dot dot dot curly bracket foo")] | ||
#[test_case("../foo", TargetSelector { raw: "../foo".to_string(), parent_dir: AnchoredSystemPathBuf::try_from(if cfg!(windows) { "..\\foo" } else { "../foo" }).unwrap(), ..Default::default() }; "dot dot slash foo")] | ||
#[test_case("./foo", TargetSelector { raw: "./foo".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("foo").unwrap(), ..Default::default() }; "dot slash foo")] | ||
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.
|
||
#[test_case("./foo/*", TargetSelector { raw: "./foo/*".to_string(), parent_dir: AnchoredSystemPathBuf::try_from(if cfg!(windows) { "foo\\*" } else { "foo/*" }).unwrap(), ..Default::default() }; "dot slash foo star")] | ||
#[test_case("...{./foo}", TargetSelector { raw: "...{./foo}".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("foo").unwrap(), include_dependents: true, ..Default::default() }; "dot dot dot curly bracket foo")] | ||
#[test_case(".", TargetSelector { raw: ".".to_string(), parent_dir: AnchoredSystemPathBuf::try_from(".").unwrap(), ..Default::default() }; "parent dir dot")] | ||
#[test_case("..", TargetSelector { raw: "..".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("..").unwrap(), ..Default::default() }; "parent dir dot dot")] | ||
#[test_case("[master]", TargetSelector { raw: "[master]".to_string(), from_ref: "master".to_string(), ..Default::default() }; "square brackets master")] | ||
|
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 library was intentionally written to match the behavior of Go's
filepath.Clean
. I did a spot check and it does seem to be a true to form port, but more eyes are always welcome.filepath.Clean
path_clean::clean
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.
Yeah, we already use it in turbopath. Might be worth making a root dependency?