mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Auto merge of #11242 - cassaundra:remove-workspace, r=epage
Clean up workspace dependencies after cargo remove ### What does this PR try to resolve? After successful removal of an inherited dependency from a workspace member, clean up the root workspace manifest. This PR is part of the continued working on cargo remove (#11099, see deferred work). ### How should we test and review this PR? Make sure the tests cover all possible use cases. After posting this PR, I will post a short self-review regarding some design concerns. ### Additional information #11194 is currently blocked on this feature.
This commit is contained in:
commit
65b2149770
@ -1,9 +1,12 @@
|
|||||||
use cargo::core::dependency::DepKind;
|
use cargo::core::dependency::DepKind;
|
||||||
|
use cargo::core::Workspace;
|
||||||
use cargo::ops::cargo_remove::remove;
|
use cargo::ops::cargo_remove::remove;
|
||||||
use cargo::ops::cargo_remove::RemoveOptions;
|
use cargo::ops::cargo_remove::RemoveOptions;
|
||||||
use cargo::ops::resolve_ws;
|
use cargo::ops::resolve_ws;
|
||||||
use cargo::util::command_prelude::*;
|
use cargo::util::command_prelude::*;
|
||||||
use cargo::util::toml_mut::manifest::DepTable;
|
use cargo::util::toml_mut::manifest::DepTable;
|
||||||
|
use cargo::util::toml_mut::manifest::LocalManifest;
|
||||||
|
use cargo::CargoResult;
|
||||||
|
|
||||||
pub fn cli() -> clap::Command {
|
pub fn cli() -> clap::Command {
|
||||||
clap::Command::new("remove")
|
clap::Command::new("remove")
|
||||||
@ -85,6 +88,9 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
|
|||||||
remove(&options)?;
|
remove(&options)?;
|
||||||
|
|
||||||
if !dry_run {
|
if !dry_run {
|
||||||
|
// Clean up workspace dependencies
|
||||||
|
gc_workspace(&workspace, &options.dependencies)?;
|
||||||
|
|
||||||
// Reload the workspace since we've changed dependencies
|
// Reload the workspace since we've changed dependencies
|
||||||
let ws = args.workspace(config)?;
|
let ws = args.workspace(config)?;
|
||||||
resolve_ws(&ws)?;
|
resolve_ws(&ws)?;
|
||||||
@ -114,3 +120,50 @@ fn parse_section(args: &ArgMatches) -> DepTable {
|
|||||||
|
|
||||||
table
|
table
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clean up workspace dependencies which no longer have a reference to them.
|
||||||
|
fn gc_workspace(workspace: &Workspace<'_>, dependencies: &[String]) -> CargoResult<()> {
|
||||||
|
let mut manifest: toml_edit::Document =
|
||||||
|
cargo_util::paths::read(workspace.root_manifest())?.parse()?;
|
||||||
|
|
||||||
|
let members = workspace
|
||||||
|
.members()
|
||||||
|
.map(|p| LocalManifest::try_new(p.manifest_path()))
|
||||||
|
.collect::<CargoResult<Vec<_>>>()?;
|
||||||
|
|
||||||
|
for dep in dependencies {
|
||||||
|
if !dep_in_workspace(dep, &members) {
|
||||||
|
remove_workspace_dep(dep, &mut manifest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cargo_util::paths::write(workspace.root_manifest(), manifest.to_string().as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get whether or not a dependency is depended upon in a workspace.
|
||||||
|
fn dep_in_workspace(dep: &str, members: &[LocalManifest]) -> bool {
|
||||||
|
members.iter().any(|manifest| {
|
||||||
|
manifest.get_sections().iter().any(|(_, table)| {
|
||||||
|
table
|
||||||
|
.as_table_like()
|
||||||
|
.unwrap()
|
||||||
|
.get(dep)
|
||||||
|
.and_then(|t| t.get("workspace"))
|
||||||
|
.and_then(|v| v.as_bool())
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a dependency from a workspace manifest.
|
||||||
|
fn remove_workspace_dep(dep: &str, ws_manifest: &mut toml_edit::Document) {
|
||||||
|
if let Some(toml_edit::Item::Table(table)) = ws_manifest
|
||||||
|
.get_mut("workspace")
|
||||||
|
.and_then(|t| t.get_mut("dependencies"))
|
||||||
|
{
|
||||||
|
table.set_implicit(true);
|
||||||
|
table.remove(dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -246,7 +246,7 @@ impl std::fmt::Display for Manifest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An editable Cargo manifest that is available locally.
|
/// An editable Cargo manifest that is available locally.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LocalManifest {
|
pub struct LocalManifest {
|
||||||
/// Path to the manifest.
|
/// Path to the manifest.
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
|
@ -22,6 +22,9 @@ mod target;
|
|||||||
mod target_build;
|
mod target_build;
|
||||||
mod target_dev;
|
mod target_dev;
|
||||||
mod update_lock_file;
|
mod update_lock_file;
|
||||||
|
mod workspace;
|
||||||
|
mod workspace_non_virtual;
|
||||||
|
mod workspace_preserved;
|
||||||
|
|
||||||
fn init_registry() {
|
fn init_registry() {
|
||||||
cargo_test_support::registry::init();
|
cargo_test_support::registry::init();
|
||||||
|
5
tests/testsuite/cargo_remove/workspace/in/Cargo.toml
Normal file
5
tests/testsuite/cargo_remove/workspace/in/Cargo.toml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [ "my-package" ]
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
semver = "0.1.0"
|
@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "my-package"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
semver = { workspace = true }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
docopt = "0.6"
|
||||||
|
rustc-serialize = "0.4"
|
||||||
|
semver = "0.1"
|
||||||
|
toml = "0.1"
|
||||||
|
clippy = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
regex = "0.1.1"
|
||||||
|
serde = "1.0.90"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde/std", "semver/std"]
|
@ -0,0 +1 @@
|
|||||||
|
|
25
tests/testsuite/cargo_remove/workspace/mod.rs
Normal file
25
tests/testsuite/cargo_remove/workspace/mod.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use cargo_test_support::compare::assert_ui;
|
||||||
|
use cargo_test_support::curr_dir;
|
||||||
|
use cargo_test_support::CargoCommand;
|
||||||
|
use cargo_test_support::Project;
|
||||||
|
|
||||||
|
use crate::cargo_remove::init_registry;
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn case() {
|
||||||
|
init_registry();
|
||||||
|
let project = Project::from_template(curr_dir!().join("in"));
|
||||||
|
let project_root = project.root();
|
||||||
|
let cwd = &project_root;
|
||||||
|
|
||||||
|
snapbox::cmd::Command::cargo_ui()
|
||||||
|
.arg("remove")
|
||||||
|
.args(["--package", "my-package", "--build", "semver"])
|
||||||
|
.current_dir(cwd)
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout_matches_path(curr_dir!().join("stdout.log"))
|
||||||
|
.stderr_matches_path(curr_dir!().join("stderr.log"));
|
||||||
|
|
||||||
|
assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
|
||||||
|
}
|
2
tests/testsuite/cargo_remove/workspace/out/Cargo.toml
Normal file
2
tests/testsuite/cargo_remove/workspace/out/Cargo.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [ "my-package" ]
|
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "my-package"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
docopt = "0.6"
|
||||||
|
rustc-serialize = "0.4"
|
||||||
|
semver = "0.1"
|
||||||
|
toml = "0.1"
|
||||||
|
clippy = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
regex = "0.1.1"
|
||||||
|
serde = "1.0.90"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde/std", "semver/std"]
|
@ -0,0 +1 @@
|
|||||||
|
|
2
tests/testsuite/cargo_remove/workspace/stderr.log
Normal file
2
tests/testsuite/cargo_remove/workspace/stderr.log
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Removing semver from build-dependencies
|
||||||
|
Updating `dummy-registry` index
|
0
tests/testsuite/cargo_remove/workspace/stdout.log
Normal file
0
tests/testsuite/cargo_remove/workspace/stdout.log
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [ "my-member" ]
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
semver = "0.1.0"
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "my-package"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
semver = { workspace = true }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
docopt = "0.6"
|
||||||
|
rustc-serialize = "0.4"
|
||||||
|
semver = "0.1"
|
||||||
|
toml = "0.1"
|
||||||
|
clippy = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
regex = "0.1.1"
|
||||||
|
serde = "1.0.90"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde/std", "semver/std"]
|
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "my-member"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
25
tests/testsuite/cargo_remove/workspace_non_virtual/mod.rs
Normal file
25
tests/testsuite/cargo_remove/workspace_non_virtual/mod.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use cargo_test_support::compare::assert_ui;
|
||||||
|
use cargo_test_support::curr_dir;
|
||||||
|
use cargo_test_support::CargoCommand;
|
||||||
|
use cargo_test_support::Project;
|
||||||
|
|
||||||
|
use crate::cargo_remove::init_registry;
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn case() {
|
||||||
|
init_registry();
|
||||||
|
let project = Project::from_template(curr_dir!().join("in"));
|
||||||
|
let project_root = project.root();
|
||||||
|
let cwd = &project_root;
|
||||||
|
|
||||||
|
snapbox::cmd::Command::cargo_ui()
|
||||||
|
.arg("remove")
|
||||||
|
.args(["--package", "my-package", "--build", "semver"])
|
||||||
|
.current_dir(cwd)
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout_matches_path(curr_dir!().join("stdout.log"))
|
||||||
|
.stderr_matches_path(curr_dir!().join("stderr.log"));
|
||||||
|
|
||||||
|
assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [ "my-member" ]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "my-package"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
docopt = "0.6"
|
||||||
|
rustc-serialize = "0.4"
|
||||||
|
semver = "0.1"
|
||||||
|
toml = "0.1"
|
||||||
|
clippy = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
regex = "0.1.1"
|
||||||
|
serde = "1.0.90"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde/std", "semver/std"]
|
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "my-member"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
@ -0,0 +1,2 @@
|
|||||||
|
Removing semver from build-dependencies
|
||||||
|
Updating `dummy-registry` index
|
@ -0,0 +1,5 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [ "my-package", "my-other-package" ]
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
semver = "0.1.0"
|
@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
name = "my-other-package"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
docopt = "0.6"
|
||||||
|
rustc-serialize = "0.4"
|
||||||
|
semver = "0.1"
|
||||||
|
toml = "0.1"
|
||||||
|
clippy = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
regex = "0.1.1"
|
||||||
|
semver = { workspace = true }
|
||||||
|
serde = "1.0.90"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde/std", "semver/std"]
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "my-package"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
semver = { workspace = true }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
docopt = "0.6"
|
||||||
|
rustc-serialize = "0.4"
|
||||||
|
semver = "0.1"
|
||||||
|
toml = "0.1"
|
||||||
|
clippy = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
regex = "0.1.1"
|
||||||
|
serde = "1.0.90"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde/std", "semver/std"]
|
@ -0,0 +1 @@
|
|||||||
|
|
25
tests/testsuite/cargo_remove/workspace_preserved/mod.rs
Normal file
25
tests/testsuite/cargo_remove/workspace_preserved/mod.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use cargo_test_support::compare::assert_ui;
|
||||||
|
use cargo_test_support::curr_dir;
|
||||||
|
use cargo_test_support::CargoCommand;
|
||||||
|
use cargo_test_support::Project;
|
||||||
|
|
||||||
|
use crate::cargo_remove::init_registry;
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn case() {
|
||||||
|
init_registry();
|
||||||
|
let project = Project::from_template(curr_dir!().join("in"));
|
||||||
|
let project_root = project.root();
|
||||||
|
let cwd = &project_root;
|
||||||
|
|
||||||
|
snapbox::cmd::Command::cargo_ui()
|
||||||
|
.arg("remove")
|
||||||
|
.args(["--package", "my-package", "--build", "semver"])
|
||||||
|
.current_dir(cwd)
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout_matches_path(curr_dir!().join("stdout.log"))
|
||||||
|
.stderr_matches_path(curr_dir!().join("stderr.log"));
|
||||||
|
|
||||||
|
assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [ "my-package", "my-other-package" ]
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
semver = "0.1.0"
|
@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
name = "my-other-package"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
docopt = "0.6"
|
||||||
|
rustc-serialize = "0.4"
|
||||||
|
semver = "0.1"
|
||||||
|
toml = "0.1"
|
||||||
|
clippy = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
regex = "0.1.1"
|
||||||
|
semver = { workspace = true }
|
||||||
|
serde = "1.0.90"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde/std", "semver/std"]
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "my-package"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
docopt = "0.6"
|
||||||
|
rustc-serialize = "0.4"
|
||||||
|
semver = "0.1"
|
||||||
|
toml = "0.1"
|
||||||
|
clippy = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
regex = "0.1.1"
|
||||||
|
serde = "1.0.90"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde/std", "semver/std"]
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,2 @@
|
|||||||
|
Removing semver from build-dependencies
|
||||||
|
Updating `dummy-registry` index
|
Loading…
x
Reference in New Issue
Block a user