Skip to content

Commit 495d02c

Browse files
committed
Auto merge of #14340 - tweag:infer-registry, r=epage
Infer registry While working on `cargo publish` for workspaces, I noticed a few ways in which the registry inference for `cargo package` seemed wrong. (This only affects the unstable `-Zpackage-workspace` feature.) This is all about the interaction between `--index`/`--registry`, and the `package.publish` fields. - Previously, if multiple crates were packaged and they had different `package.publish` settings, we would ignore those setting and fall back to "crates-io". After this PR, we will bail out with an error instead (unless they've specified `--registry` or `--index`). - Previously, we would validate the inferred registry against the `package.publish` settings, even if the `--index` argument would have taken precedence. After this PR, we will skip registry validation in this case. - Previously, we were just ignoring the registry value inferred from `package.publish`: we'd validate that it was ok, but then just not use it.
2 parents 94977cb + 275d3b6 commit 495d02c

File tree

2 files changed

+416
-20
lines changed

2 files changed

+416
-20
lines changed

src/cargo/ops/cargo_package.rs

+52-20
Original file line numberDiff line numberDiff line change
@@ -185,44 +185,76 @@ fn infer_registry(
185185
pkgs: &[&Package],
186186
reg_or_index: Option<RegistryOrIndex>,
187187
) -> CargoResult<SourceId> {
188-
let publish_registry = if let Some(RegistryOrIndex::Registry(registry)) = reg_or_index.as_ref()
189-
{
190-
Some(registry.clone())
191-
} else if let Some([first_pkg_reg]) = pkgs[0].publish().as_deref() {
192-
// If no registry is specified in the command, but all of the packages
193-
// to publish have the same, unique allowed registry, push to that one.
194-
if pkgs[1..].iter().all(|p| p.publish() == pkgs[0].publish()) {
195-
Some(first_pkg_reg.clone())
196-
} else {
197-
None
188+
let reg_or_index = match reg_or_index {
189+
Some(r) => r,
190+
None => {
191+
if pkgs[1..].iter().all(|p| p.publish() == pkgs[0].publish()) {
192+
// If all packages have the same publish settings, we take that as the default.
193+
match pkgs[0].publish().as_deref() {
194+
Some([unique_pkg_reg]) => RegistryOrIndex::Registry(unique_pkg_reg.to_owned()),
195+
None | Some([]) => RegistryOrIndex::Registry(CRATES_IO_REGISTRY.to_owned()),
196+
Some([reg, ..]) if pkgs.len() == 1 => {
197+
// For backwards compatibility, avoid erroring if there's only one package.
198+
// The registry doesn't affect packaging in this case.
199+
RegistryOrIndex::Registry(reg.to_owned())
200+
}
201+
Some(regs) => {
202+
let mut regs: Vec<_> = regs.iter().map(|s| format!("\"{}\"", s)).collect();
203+
regs.sort();
204+
regs.dedup();
205+
// unwrap: the match block ensures that there's more than one reg.
206+
let (last_reg, regs) = regs.split_last().unwrap();
207+
bail!(
208+
"--registry is required to disambiguate between {} or {} registries",
209+
regs.join(", "),
210+
last_reg
211+
)
212+
}
213+
}
214+
} else {
215+
let common_regs = pkgs
216+
.iter()
217+
// `None` means "all registries", so drop them instead of including them
218+
// in the intersection.
219+
.filter_map(|p| p.publish().as_deref())
220+
.map(|p| p.iter().collect::<HashSet<_>>())
221+
.reduce(|xs, ys| xs.intersection(&ys).cloned().collect())
222+
.unwrap_or_default();
223+
if common_regs.is_empty() {
224+
bail!("conflicts between `package.publish` fields in the selected packages");
225+
} else {
226+
bail!(
227+
"--registry is required because not all `package.publish` settings agree",
228+
);
229+
}
230+
}
198231
}
199-
} else {
200-
None
201232
};
202233

203234
// Validate the registry against the packages' allow-lists. For backwards compatibility, we
204235
// skip this if only a single package is being published (because in that case the registry
205236
// doesn't affect the packaging step).
206237
if pkgs.len() > 1 {
207-
let reg_name = publish_registry.as_deref().unwrap_or(CRATES_IO_REGISTRY);
208-
for pkg in pkgs {
209-
if let Some(allowed) = pkg.publish().as_ref() {
210-
if !allowed.iter().any(|a| a == reg_name) {
211-
bail!(
238+
if let RegistryOrIndex::Registry(reg_name) = &reg_or_index {
239+
for pkg in pkgs {
240+
if let Some(allowed) = pkg.publish().as_ref() {
241+
if !allowed.iter().any(|a| a == reg_name) {
242+
bail!(
212243
"`{}` cannot be packaged.\n\
213244
The registry `{}` is not listed in the `package.publish` value in Cargo.toml.",
214245
pkg.name(),
215246
reg_name
216247
);
248+
}
217249
}
218250
}
219251
}
220252
}
221253

222254
let sid = match reg_or_index {
223-
None => SourceId::crates_io(gctx)?,
224-
Some(RegistryOrIndex::Registry(r)) => SourceId::alt_registry(gctx, &r)?,
225-
Some(RegistryOrIndex::Index(url)) => SourceId::for_registry(&url)?,
255+
RegistryOrIndex::Index(url) => SourceId::for_registry(&url)?,
256+
RegistryOrIndex::Registry(reg) if reg == CRATES_IO_REGISTRY => SourceId::crates_io(gctx)?,
257+
RegistryOrIndex::Registry(reg) => SourceId::alt_registry(gctx, &reg)?,
226258
};
227259

228260
// Load source replacements that are built-in to Cargo.

0 commit comments

Comments
 (0)