Skip to content
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

Ptw/do not skeleton patches #70

Closed
28 changes: 27 additions & 1 deletion src/skeleton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@ const CONST_VERSION: &str = "0.0.1";
impl Skeleton {
/// Find all Cargo.toml files in `base_path` by traversing sub-directories recursively.
pub fn derive<P: AsRef<Path>>(base_path: P) -> Result<Self, anyhow::Error> {
let walker = GlobWalkerBuilder::new(&base_path, "/**/Cargo.toml")
let cargo_regex = "/**/Cargo.toml";
let builder = if let Some(patches) = get_top_level_patches(&base_path) {
let regex_patterns = std::iter::once(cargo_regex.to_string())
.chain(patches.into_iter().map(|s| String::from("!") + &s))
.collect::<Vec<_>>();
GlobWalkerBuilder::from_patterns(&base_path, &regex_patterns)
} else {
GlobWalkerBuilder::new(&base_path, cargo_regex)
};
let walker = builder
.build()
.context("Failed to scan the files in the current directory.")?;
let mut manifests = vec![];
Expand Down Expand Up @@ -320,6 +329,23 @@ enum ErrorStrategy {
Crash(WalkError),
}

/// Try to read the top-level `Cargo.toml`. Returns all of the paths of its `patch`es.
fn get_top_level_patches<P: AsRef<Path>>(base_path: P) -> Option<impl Iterator<Item = String>> {
let base_cargo_toml = base_path.as_ref().join("Cargo.toml");
let contents = fs::read_to_string(&base_cargo_toml).ok()?;

let parsed = cargo_manifest::Manifest::from_str(&contents).ok()?;
parsed.patch.map(|patches| {
{
patches.into_iter().flat_map(|(_entry_title, values)| {
values.into_iter().flat_map(|(_key, dependency)| {
dependency.detail().and_then(|detail| detail.path.clone())
})
})
}
})
}

/// Ignore directory/files for which we don't have enough permissions to perform our scan.
#[must_use]
fn handle_walk_error(e: WalkError) -> ErrorStrategy {
Expand Down
39 changes: 38 additions & 1 deletion tests/skeletons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ pub fn config_toml() {
name = "test-dummy"
version = "0.1.0"
edition = "2018"

[dependencies]
"#;

Expand Down Expand Up @@ -360,3 +360,40 @@ pub fn config_toml() {
.path()
.exists());
}

#[test]
pub fn test_ignoring_patches() {
let content = r#"
[package]
name = "test-dummy"
version = "0.1.0"
edition = "2018"

[patch.crates-io]
yaml-rust = { package = "yaml-rust", path = 'rust-patches/yaml-rust' }
"#;
let recipe_directory = TempDir::new().unwrap();
let manifest = recipe_directory.child("Cargo.toml");
manifest.write_str(content).unwrap();
let src_dir = recipe_directory.child("src");
src_dir.create_dir_all().unwrap();
src_dir.child("main.rs").touch().unwrap();

// Make rust-patch directory
let patch_dir = recipe_directory.child("rust-patches");
patch_dir.create_dir_all().unwrap();
let yaml_dir = patch_dir.child("yaml-rust");
yaml_dir.create_dir_all().unwrap();
let yaml_toml = yaml_dir.child("Cargo.toml");
let yaml_cargo_content = r#"
[package]
name="yaml-rust"
version = "0.1.0"
edition = "2018"
"#;
yaml_toml.write_str(yaml_cargo_content).unwrap();

// Test that we ignore rust-patches---we should only find `test-dummy`'s Cargo.toml.
let skeleton = Skeleton::derive(recipe_directory.path()).unwrap();
assert_eq!(1, skeleton.manifests.len());
}