diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index e96b6e93cca3..323807563c0f 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -198,7 +198,10 @@ fn get_registry( if let RegistryOrIndex::Registry(reg_name) = reg { for pkg in pkgs { if let Some(allowed) = pkg.publish().as_ref() { - if !allowed.iter().any(|a| a == ®_name) { + // If allowed is empty (i.e. package.publish is false), we let it slide. + // This allows packaging unpublishable packages (although packaging might + // fail later if the unpublishable package is a dependency of something else). + if !allowed.is_empty() && !allowed.iter().any(|a| a == ®_name) { bail!( "`{}` cannot be packaged.\n\ The registry `{}` is not listed in the `package.publish` value in Cargo.toml.", @@ -282,7 +285,9 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult CargoResult> { - if pkgs[1..].iter().all(|p| p.publish() == pkgs[0].publish()) { + // Ignore "publish = false" packages while inferring the registry. + let publishable_pkgs: Vec<_> = pkgs + .iter() + .filter(|p| p.publish() != &Some(Vec::new())) + .collect(); + + if let Some((first, rest)) = publishable_pkgs.split_first() { // If all packages have the same publish settings, we take that as the default. - match pkgs[0].publish().as_deref() { - Some([unique_pkg_reg]) => { - Ok(Some(RegistryOrIndex::Registry(unique_pkg_reg.to_owned()))) + if rest.iter().all(|p| p.publish() == first.publish()) { + match publishable_pkgs[0].publish().as_deref() { + Some([unique_pkg_reg]) => { + Ok(Some(RegistryOrIndex::Registry(unique_pkg_reg.to_owned()))) + } + None | Some([]) => Ok(None), + Some(regs) => { + let mut regs: Vec<_> = regs.iter().map(|s| format!("\"{}\"", s)).collect(); + regs.sort(); + regs.dedup(); + // unwrap: the match block ensures that there's more than one reg. + let (last_reg, regs) = regs.split_last().unwrap(); + bail!( + "--registry is required to disambiguate between {} or {} registries", + regs.join(", "), + last_reg + ) + } } - None | Some([]) => Ok(None), - Some(regs) => { - let mut regs: Vec<_> = regs.iter().map(|s| format!("\"{}\"", s)).collect(); - regs.sort(); - regs.dedup(); - // unwrap: the match block ensures that there's more than one reg. - let (last_reg, regs) = regs.split_last().unwrap(); - bail!( - "--registry is required to disambiguate between {} or {} registries", - regs.join(", "), - last_reg - ) + } else { + let common_regs = publishable_pkgs + .iter() + // `None` means "all registries", so drop them instead of including them + // in the intersection. + .filter_map(|p| p.publish().as_deref()) + .map(|p| p.iter().collect::>()) + .reduce(|xs, ys| xs.intersection(&ys).cloned().collect()) + .unwrap_or_default(); + if common_regs.is_empty() { + bail!("conflicts between `package.publish` fields in the selected packages"); + } else { + bail!("--registry is required because not all `package.publish` settings agree",); } } } else { - let common_regs = pkgs - .iter() - // `None` means "all registries", so drop them instead of including them - // in the intersection. - .filter_map(|p| p.publish().as_deref()) - .map(|p| p.iter().collect::>()) - .reduce(|xs, ys| xs.intersection(&ys).cloned().collect()) - .unwrap_or_default(); - if common_regs.is_empty() { - bail!("conflicts between `package.publish` fields in the selected packages"); - } else { - bail!("--registry is required because not all `package.publish` settings agree",); - } + Ok(None) } } diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs index 6e79ca250a34..7b937ca53b95 100644 --- a/tests/testsuite/package.rs +++ b/tests/testsuite/package.rs @@ -6227,19 +6227,41 @@ fn registry_inference_ignores_unpublishable() { p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) - .with_status(101) .with_stderr_data(str![[r#" -[ERROR] conflicts between `package.publish` fields in the selected packages +[PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) +[PACKAGED] 3 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) +[PACKAGING] main v0.0.1 ([ROOT]/foo/main) +[UPDATING] `alternative` index +[PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) +[VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) +[COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[VERIFYING] main v0.0.1 ([ROOT]/foo/main) +[UPDATING] `alternative` index +[UNPACKING] dep v0.1.0 (registry `[ROOT]/foo/target/package/tmp-registry`) +[COMPILING] dep v0.1.0 (registry `alternative`) +[COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("package -Zpackage-workspace --registry=alternative") .masquerade_as_nightly_cargo(&["package-workspace"]) - .with_status(101) .with_stderr_data(str![[r#" -[ERROR] `main` cannot be packaged. -The registry `alternative` is not listed in the `package.publish` value in Cargo.toml. +[PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) +[PACKAGED] 3 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) +[PACKAGING] main v0.0.1 ([ROOT]/foo/main) +[UPDATING] `alternative` index +[PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) +[VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) +[COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[VERIFYING] main v0.0.1 ([ROOT]/foo/main) +[UPDATING] `alternative` index +[COMPILING] dep v0.1.0 (registry `alternative`) +[COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); @@ -6464,7 +6486,16 @@ fn unpublishable_dependency() { .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" -[ERROR] conflicts between `package.publish` fields in the selected packages +[PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) +[PACKAGED] 3 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) +[PACKAGING] main v0.0.1 ([ROOT]/foo/main) +[UPDATING] `alternative` index +[ERROR] failed to prepare local package for uploading + +Caused by: + no matching package named `dep` found + location searched: registry `alternative` + required by package `main v0.0.1 ([ROOT]/foo/main)` "#]]) .run();