Skip to content

Commit

Permalink
feat: emit error if package not found within workspace (#15071)
Browse files Browse the repository at this point in the history
### What does this PR try to resolve?

Fixes #12978

currently, if `--package `and `--workspace` passe in the same time, the
`--package` will be ignore even the package doesnt exist in the
workspace, this PR regards this behavior as an error

### How should we test and review this PR?

one commit add test, one commit fixes the issue.

### Additional information
  • Loading branch information
epage authored Feb 6, 2025
2 parents 1687f74 + 23ab2af commit 027b415
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 10 deletions.
50 changes: 41 additions & 9 deletions src/cargo/ops/cargo_compile/packages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ pub enum Packages {
/// Opt in all packages.
///
/// As of the time of this writing, it only works on opting in all workspace members.
All,
/// Keeps the packages passed in to verify that they exist in the workspace.
All(Vec<String>),
/// Opt out of packages passed in.
///
/// As of the time of this writing, it only works on opting out workspace members.
Expand All @@ -36,19 +37,21 @@ impl Packages {
(false, 0, 0) => Packages::Default,
(false, 0, _) => Packages::Packages(package),
(false, _, _) => anyhow::bail!("--exclude can only be used together with --workspace"),
(true, 0, _) => Packages::All,
(true, 0, _) => Packages::All(package),
(true, _, _) => Packages::OptOut(exclude),
})
}

/// Converts selected packages to [`PackageIdSpec`]s.
pub fn to_package_id_specs(&self, ws: &Workspace<'_>) -> CargoResult<Vec<PackageIdSpec>> {
let specs = match self {
Packages::All => ws
.members()
.map(Package::package_id)
.map(|id| id.to_spec())
.collect(),
Packages::All(packages) => {
emit_packages_not_found_within_workspace(ws, packages)?;
ws.members()
.map(Package::package_id)
.map(|id| id.to_spec())
.collect()
}
Packages::OptOut(opt_out) => {
let (mut patterns, mut ids) = opt_patterns_and_ids(opt_out)?;
let specs = ws
Expand Down Expand Up @@ -111,7 +114,10 @@ impl Packages {
pub fn get_packages<'ws>(&self, ws: &'ws Workspace<'_>) -> CargoResult<Vec<&'ws Package>> {
let packages: Vec<_> = match self {
Packages::Default => ws.default_members().collect(),
Packages::All => ws.members().collect(),
Packages::All(packages) => {
emit_packages_not_found_within_workspace(ws, packages)?;
ws.members().collect()
}
Packages::OptOut(opt_out) => {
let (mut patterns, mut ids) = opt_patterns_and_ids(opt_out)?;
let packages = ws
Expand Down Expand Up @@ -161,7 +167,7 @@ impl Packages {
pub fn needs_spec_flag(&self, ws: &Workspace<'_>) -> bool {
match self {
Packages::Default => ws.default_members().count() > 1,
Packages::All => ws.members().count() > 1,
Packages::All(_) => ws.members().count() > 1,
Packages::Packages(_) => true,
Packages::OptOut(_) => true,
}
Expand Down Expand Up @@ -207,6 +213,32 @@ fn emit_pattern_not_found(
Ok(())
}

fn emit_packages_not_found_within_workspace(
ws: &Workspace<'_>,
packages: &[String],
) -> CargoResult<()> {
let (mut patterns, mut ids) = opt_patterns_and_ids(packages)?;
let _: Vec<_> = ws
.members()
.filter(|pkg| {
let id = ids.iter().find(|id| id.matches(pkg.package_id())).cloned();
if let Some(id) = &id {
ids.remove(id);
}
!id.is_some() && !match_patterns(pkg, &mut patterns)
})
.map(Package::package_id)
.map(|id| id.to_spec())
.collect();
let names = ids
.into_iter()
.map(|id| id.to_string())
.collect::<BTreeSet<_>>();
emit_package_not_found(ws, names, false)?;
emit_pattern_not_found(ws, patterns, false)?;
Ok(())
}

/// Given a list opt-in or opt-out package selection strings, generates two
/// collections that represent glob patterns and package id specs respectively.
fn opt_patterns_and_ids(
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/cargo_output_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ fn build_resolve_graph(
CompileKind::from_requested_targets(ws.gctx(), &metadata_opts.filter_platforms)?;
let mut target_data = RustcTargetData::new(ws, &requested_kinds)?;
// Resolve entire workspace.
let specs = Packages::All.to_package_id_specs(ws)?;
let specs = Packages::All(Vec::new()).to_package_id_specs(ws)?;
let force_all = if metadata_opts.filter_platforms.is_empty() {
crate::core::resolver::features::ForceAllTargets::Yes
} else {
Expand Down
92 changes: 92 additions & 0 deletions tests/testsuite/workspaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2624,3 +2624,95 @@ foo v0.1.0 ([ROOT]/foo/sub/foo)
"#]])
.run();
}

#[cargo_test]
fn nonexistence_package_togother_with_workspace() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
edition = "2021"
[workspace]
members = ["baz"]
"#,
)
.file("src/lib.rs", "")
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "");

let p = p.build();

p.cargo("check --package nonexistence --workspace")
.with_status(101)
.with_stderr_data(
str![[r#"
[ERROR] package(s) `nonexistence` not found in workspace `[ROOT]/foo`
"#]]
.unordered(),
)
.run();
// With pattern *
p.cargo("check --package nonpattern* --workspace")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] package pattern(s) `nonpattern*` not found in workspace `[ROOT]/foo`
"#]])
.run();

p.cargo("package --package nonexistence --workspace")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] package(s) `nonexistence` not found in workspace `[ROOT]/foo`
"#]])
.run();
// With pattern *
p.cargo("package --package nonpattern* --workspace")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] package pattern(s) `nonpattern*` not found in workspace `[ROOT]/foo`
"#]])
.run();

p.cargo("publish --dry-run --package nonexistence -Zpackage-workspace --workspace")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] package(s) `nonexistence` not found in workspace `[ROOT]/foo`
"#]])
.masquerade_as_nightly_cargo(&["package-workspace"])
.run();
// With pattern *
p.cargo("publish --dry-run --package nonpattern* -Zpackage-workspace --workspace")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] package pattern(s) `nonpattern*` not found in workspace `[ROOT]/foo`
"#]])
.masquerade_as_nightly_cargo(&["package-workspace"])
.run();

p.cargo("tree --package nonexistence --workspace")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] package(s) `nonexistence` not found in workspace `[ROOT]/foo`
"#]])
.run();
// With pattern *
p.cargo("tree --package nonpattern* --workspace")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] package pattern(s) `nonpattern*` not found in workspace `[ROOT]/foo`
"#]])
.run();
}

0 comments on commit 027b415

Please sign in to comment.