diff --git a/Cargo.lock b/Cargo.lock index b01b163..4e16dbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,9 +101,8 @@ dependencies = [ [[package]] name = "cargo-manifest" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db7ad32d2729eca70d1669bae38b6a29dabc30a16f1892cc00977873f450d0a" +version = "0.15.2" +source = "git+https://github.com/hdoordt/cargo-manifest.git#7fd5e7a28410971d323251fed6399ca701ec4050" dependencies = [ "serde", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 0979ebf..5de43ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ anyhow = "1.0.80" clap = { version = "4", features = ["derive"] } guppy = "0.17.5" fs-err = "2.11.0" -cargo-manifest = "0.14.0" +cargo-manifest = "0.15.2" toml = "0.8.10" semver = "1.0.22" toml_edit = "0.22.6" @@ -37,3 +37,7 @@ installers = [] targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] # Publish jobs to run in CI pr-run-mode = "plan" + +[patch.crates-io] +# TODO remove me once https://github.com/LukeMathWalker/cargo-manifest/pull/57 is released +cargo-manifest = { git = "https://github.com/hdoordt/cargo-manifest.git" } \ No newline at end of file diff --git a/README.md b/README.md index 5016a9b..fb52e74 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,33 @@ It collects all the dependencies in your workspace, determines which ones can be the `[workspace.dependencies]` section of the root `Cargo.toml`. It also takes care of updating the members' `Cargo.toml` files, setting the correct `features` field for each package. +To exclude workspace members from the autoinherit process, you can either pass their packgage names as an +option like so: + +```bash +cargo autoinherit -e cargo-inherit-test-web +``` + +or you can define the exclusion in the workspace metadata: + +```toml +# Cargo.toml +[workspace] +members = [ + "cli", + "config", + "db", + "web", + "macros" +] + +[workspace.metadata.cargo-autoinherit] +# Skip cargo-autoinherit for these packages +exclude-members = [ + "cargo-autoinherit-test-web" # <= This member will be excluded +] +``` + ## Installation You can find prebuilt binaries on the [Releases page](https://github.com/mainmatter/cargo-autoinherit/releases). diff --git a/src/lib.rs b/src/lib.rs index ca253b8..5325c1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ use crate::dedup::MinimalVersionSet; -use anyhow::Context; -use cargo_manifest::{Dependency, DependencyDetail, DepsSet, Manifest}; +use anyhow::{anyhow, Context}; +use cargo_manifest::{Dependency, DependencyDetail, DepsSet, Manifest, Workspace}; use guppy::VersionReq; use std::collections::{BTreeMap, BTreeSet}; use std::fmt::Formatter; @@ -20,6 +20,41 @@ pub struct AutoInheritConf { exclude: Vec, } +#[derive(Debug, Default)] +struct AutoInheritMetadata { + exclude: Vec, +} + +impl AutoInheritMetadata { + fn from_workspace(workspace: &Workspace) -> Result { + fn error() -> anyhow::Error { + anyhow!("Excpected value of `exclude` in `workspace.metadata.cargo-autoinherit` to be an array of strings") + } + + let Some(exclude) = workspace + .metadata + .as_ref() + .and_then(|m| m.get("cargo-autoinherit")) + .and_then(|v| v.as_table()) + .and_then(|t| t.get("exclude-members").or(t.get("exclude_members"))) + else { + return Ok(Self::default()); + }; + + let exclude: Vec = match exclude { + toml::Value::Array(excluded) => excluded + .iter() + .map(|v| v.as_str().ok_or_else(error).map(|s| s.to_string())) + .try_fold(Vec::with_capacity(excluded.len()), |mut res, item| { + res.push(item?); + Ok::<_, anyhow::Error>(res) + })?, + _ => return Err(error()), + }; + Ok(Self { exclude }) + } +} + /// Rewrites a `path` dependency as being absolute, based on a given path fn rewrite_dep_paths_as_absolute<'a, P: AsRef>( deps: impl Iterator, @@ -87,7 +122,7 @@ pub fn auto_inherit(conf: AutoInheritConf) -> Result<(), anyhow::Error> { .build_graph() .context("Failed to build package graph")?; let workspace_root = graph.workspace().root(); - let mut root_manifest: Manifest = { + let mut root_manifest: Manifest = { let contents = fs_err::read_to_string(workspace_root.join("Cargo.toml").as_std_path()) .context("Failed to read root manifest")?; toml::from_str(&contents).context("Failed to parse root manifest")? @@ -99,7 +134,10 @@ pub fn auto_inherit(conf: AutoInheritConf) -> Result<(), anyhow::Error> { workspace_root ) }; - let excluded = BTreeSet::from_iter(conf.exclude); + + let autoinherit_metadata = AutoInheritMetadata::from_workspace(workspace)?; + let excluded = + BTreeSet::from_iter(conf.exclude.into_iter().chain(autoinherit_metadata.exclude)); let mut package_name2specs: BTreeMap = BTreeMap::new(); if let Some(deps) = &mut workspace.dependencies { @@ -113,7 +151,7 @@ pub fn auto_inherit(conf: AutoInheritConf) -> Result<(), anyhow::Error> { let mut manifest: Manifest = { if excluded.contains(package.name()) { - println!("Excluded package `{}`", package.name()); + println!("Excluded workspace member `{}`", package.name()); continue; } let contents = fs_err::read_to_string(package.manifest_path().as_std_path())