Skip to content

Commit d0d07db

Browse files
committed
Implement RFC 3289: source replacement ambiguity
1 parent fee1c7f commit d0d07db

20 files changed

+212
-167
lines changed

crates/cargo-test-support/src/lib.rs

+14
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,20 @@ impl Execs {
818818
self
819819
}
820820

821+
/// Allows replacement of crates-io source without specifying --registry <NAME>
822+
///
823+
/// Can be used for testing crates-io specific items where alt registries
824+
/// cannot be used.
825+
pub fn allow_silent_crates_io_replacement(&mut self) -> &mut Self {
826+
if let Some(ref mut p) = self.process_builder {
827+
p.env(
828+
"__CARGO_TEST_ALLOW_CRATES_IO_REPLACEMENT_DO_NOT_USE",
829+
"true",
830+
);
831+
}
832+
self
833+
}
834+
821835
pub fn enable_mac_dsym(&mut self) -> &mut Self {
822836
if cfg!(target_os = "macos") {
823837
self.env("CARGO_PROFILE_DEV_SPLIT_DEBUGINFO", "packed")

crates/cargo-test-support/src/registry.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,8 @@ impl RegistryBuilder {
250250
[source.crates-io]
251251
replace-with = 'dummy-registry'
252252
253-
[source.dummy-registry]
254-
registry = '{}'",
253+
[registries.dummy-registry]
254+
index = '{}'",
255255
registry.index_url
256256
)
257257
.as_bytes(),
@@ -282,6 +282,9 @@ impl RegistryBuilder {
282282
r#"
283283
[registry]
284284
token = "{token}"
285+
286+
[registries.dummy-registry]
287+
token = "{token}"
285288
"#
286289
)
287290
.as_bytes(),

src/cargo/core/source/source_id.rs

+13
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ struct SourceIdInner {
3939
/// WARNING: this is not always set for alt-registries when the name is
4040
/// not known.
4141
name: Option<String>,
42+
/// Name of the alt registry in the [registries] table.
43+
/// WARNING: this is not always set for alt-registries when the name is
44+
/// not known.
45+
alt_registry_key: Option<String>,
4246
}
4347

4448
/// The possible kinds of code source. Along with `SourceIdInner`, this fully defines the
@@ -81,6 +85,7 @@ impl SourceId {
8185
url,
8286
precise: None,
8387
name: name.map(|n| n.into()),
88+
alt_registry_key: None,
8489
});
8590
Ok(source_id)
8691
}
@@ -228,6 +233,7 @@ impl SourceId {
228233
url,
229234
precise: None,
230235
name: Some(key.to_string()),
236+
alt_registry_key: Some(key.to_string()),
231237
}))
232238
}
233239

@@ -264,6 +270,13 @@ impl SourceId {
264270
}
265271
}
266272

273+
/// Gets the name of the remote registry as defined in the [registries] table.
274+
/// WARNING: alt registries that come from Cargo.lock, or --index will
275+
/// not have a name.
276+
pub fn alt_registry_key(&self) -> Option<&str> {
277+
self.inner.alt_registry_key.as_deref()
278+
}
279+
267280
/// Returns `true` if this source is from a filesystem path.
268281
pub fn is_path(self) -> bool {
269282
self.inner.kind == SourceKind::Path

src/cargo/ops/registry.rs

+44-61
Original file line numberDiff line numberDiff line change
@@ -444,11 +444,9 @@ pub fn registry_configuration(
444444
///
445445
/// * `token`: The token from the command-line. If not set, uses the token
446446
/// from the config.
447-
/// * `index`: The index URL from the command-line. This is ignored if
448-
/// `registry` is set.
447+
/// * `index`: The index URL from the command-line.
449448
/// * `registry`: The registry name from the command-line. If neither
450-
/// `registry`, or `index` are set, then uses `crates-io`, honoring
451-
/// `[source]` replacement if defined.
449+
/// `registry`, or `index` are set, then uses `crates-io`.
452450
/// * `force_update`: If `true`, forces the index to be updated.
453451
/// * `validate_token`: If `true`, the token must be set.
454452
fn registry(
@@ -459,24 +457,8 @@ fn registry(
459457
force_update: bool,
460458
validate_token: bool,
461459
) -> CargoResult<(Registry, RegistryConfig, SourceId)> {
462-
if index.is_some() && registry.is_some() {
463-
// Otherwise we would silently ignore one or the other.
464-
bail!("both `--index` and `--registry` should not be set at the same time");
465-
}
466-
// Parse all configuration options
460+
let (sid, sid_no_replacement) = get_source_id(config, index, registry)?;
467461
let reg_cfg = registry_configuration(config, registry)?;
468-
let opt_index = registry
469-
.map(|r| config.get_registry_index(r))
470-
.transpose()?
471-
.map(|u| u.to_string());
472-
let sid = get_source_id(config, opt_index.as_deref().or(index), registry)?;
473-
if !sid.is_remote_registry() {
474-
bail!(
475-
"{} does not support API commands.\n\
476-
Check for a source-replacement in .cargo/config.",
477-
sid
478-
);
479-
}
480462
let api_host = {
481463
let _lock = config.acquire_package_cache_lock()?;
482464
let mut src = RegistrySource::remote(sid, &HashSet::new(), config)?;
@@ -503,42 +485,18 @@ fn registry(
503485
}
504486
token
505487
} else {
506-
// Check `is_default_registry` so that the crates.io index can
507-
// change config.json's "api" value, and this won't affect most
508-
// people. It will affect those using source replacement, but
509-
// hopefully that's a relatively small set of users.
510-
if token.is_none()
511-
&& reg_cfg.is_token()
512-
&& registry.is_none()
513-
&& !sid.is_default_registry()
514-
&& !crates_io::is_url_crates_io(&api_host)
515-
{
516-
config.shell().warn(
517-
"using `registry.token` config value with source \
518-
replacement is deprecated\n\
519-
This may become a hard error in the future; \
520-
see <https://github.com/rust-lang/cargo/issues/xxx>.\n\
521-
Use the --token command-line flag to remove this warning.",
522-
)?;
523-
reg_cfg.as_token().map(|t| t.to_owned())
524-
} else {
525-
let token =
526-
auth::auth_token(config, token.as_deref(), &reg_cfg, registry, &api_host)?;
527-
Some(token)
528-
}
488+
let token = auth::auth_token(config, token.as_deref(), &reg_cfg, registry, &api_host)?;
489+
Some(token)
529490
}
530491
} else {
531492
None
532493
};
533494
let handle = http_handle(config)?;
534-
// Workaround for the sparse+https://index.crates.io replacement index. Use the non-replaced
535-
// source_id so that the original (github) url is used when publishing a crate.
536-
let sid = if sid.is_default_registry() {
537-
SourceId::crates_io(config)?
538-
} else {
539-
sid
540-
};
541-
Ok((Registry::new_handle(api_host, token, handle), reg_cfg, sid))
495+
Ok((
496+
Registry::new_handle(api_host, token, handle),
497+
reg_cfg,
498+
sid_no_replacement,
499+
))
542500
}
543501

544502
/// Creates a new HTTP handle with appropriate global configuration for cargo.
@@ -943,16 +901,41 @@ pub fn yank(
943901
/// Gets the SourceId for an index or registry setting.
944902
///
945903
/// The `index` and `reg` values are from the command-line or config settings.
946-
/// If both are None, returns the source for crates.io.
947-
fn get_source_id(config: &Config, index: Option<&str>, reg: Option<&str>) -> CargoResult<SourceId> {
948-
match (reg, index) {
949-
(Some(r), _) => SourceId::alt_registry(config, r),
950-
(_, Some(i)) => SourceId::for_registry(&i.into_url()?),
951-
_ => {
952-
let map = SourceConfigMap::new(config)?;
953-
let src = map.load(SourceId::crates_io(config)?, &HashSet::new())?;
954-
Ok(src.replaced_source_id())
904+
/// If both are None, and no source-replacement is configured, returns the source for crates.io.
905+
/// If both are None, and source replacement is configured, returns an error (except when testing Cargo).
906+
///
907+
/// If `reg` is set, source replacement is not followed.
908+
fn get_source_id(
909+
config: &Config,
910+
index: Option<&str>,
911+
reg: Option<&str>,
912+
) -> CargoResult<(SourceId, SourceId)> {
913+
let map = SourceConfigMap::new(config)?;
914+
let sid = match (reg, index) {
915+
(None, None) | (Some("crates-io"), None) => SourceId::crates_io(config)?,
916+
(Some(r), None) => SourceId::alt_registry(config, r)?,
917+
(None, Some(i)) => SourceId::for_registry(&i.into_url()?)?,
918+
(Some(_), Some(_)) => {
919+
bail!("both `--index` and `--registry` should not be set at the same time")
955920
}
921+
};
922+
let src = map.load(sid, &HashSet::new())?;
923+
if src.is_replaced() && reg.is_none() && index.is_none() {
924+
// Neither --registry nor --index was passed and source replacement is configured.
925+
let replacement_sid = src.replaced_source_id();
926+
if replacement_sid.is_default_registry()
927+
|| std::env::var("__CARGO_TEST_ALLOW_CRATES_IO_REPLACEMENT_DO_NOT_USE").is_ok()
928+
{
929+
// Allow replacement of crates.io for the sparse crates.io endpoint or for Cargo's
930+
// testing framework.
931+
Ok((replacement_sid, sid))
932+
} else if let Some(replacement_name) = replacement_sid.alt_registry_key() {
933+
bail!("crates-io is replaced with remote registry {replacement_name};\ninclude `--registry {replacement_name}` or `--registry crates-io`");
934+
} else {
935+
bail!("crates-io is replaced with non-remote-registry source {replacement_sid};\ninclude `--registry crates-io` to publish to crates.io");
936+
}
937+
} else {
938+
Ok((sid.clone(), sid))
956939
}
957940
}
958941

src/cargo/sources/config.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -121,18 +121,24 @@ impl<'cfg> SourceConfigMap<'cfg> {
121121
};
122122
let mut cfg_loc = "";
123123
let orig_name = name;
124-
let new_id;
125-
loop {
124+
let new_id = loop {
126125
let cfg = match self.cfgs.get(name) {
127126
Some(cfg) => cfg,
128-
None => bail!(
129-
"could not find a configured source with the \
127+
None => {
128+
// Attempt to interpret the source name as an alt registry name
129+
if let Ok(alt_id) = SourceId::alt_registry(self.config, name) {
130+
debug!("following pointer to registry {}", name);
131+
break alt_id.with_precise(id.precise().map(str::to_string));
132+
}
133+
bail!(
134+
"could not find a configured source with the \
130135
name `{}` when attempting to lookup `{}` \
131136
(configuration in `{}`)",
132-
name,
133-
orig_name,
134-
cfg_loc
135-
),
137+
name,
138+
orig_name,
139+
cfg_loc
140+
);
141+
}
136142
};
137143
match &cfg.replace_with {
138144
Some((s, c)) => {
@@ -141,8 +147,7 @@ impl<'cfg> SourceConfigMap<'cfg> {
141147
}
142148
None if id == cfg.id => return id.load(self.config, yanked_whitelist),
143149
None => {
144-
new_id = cfg.id.with_precise(id.precise().map(|s| s.to_string()));
145-
break;
150+
break cfg.id.with_precise(id.precise().map(|s| s.to_string()));
146151
}
147152
}
148153
debug!("following pointer to {}", name);
@@ -155,7 +160,7 @@ impl<'cfg> SourceConfigMap<'cfg> {
155160
cfg_loc
156161
)
157162
}
158-
}
163+
};
159164

160165
let new_src = new_id.load(
161166
self.config,

src/doc/src/reference/source-replacement.md

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ directory = "vendor"
5050
# The crates.io default source for crates is available under the name
5151
# "crates-io", and here we use the `replace-with` key to indicate that it's
5252
# replaced with our source above.
53+
#
54+
# The `replace-with` key can also reference an alternative registry name
55+
# defined in the `[registries]` table.
5356
[source.crates-io]
5457
replace-with = "my-vendor-source"
5558

tests/testsuite/artifact_dep.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1901,7 +1901,7 @@ fn publish_artifact_dep() {
19011901
.file("src/lib.rs", "")
19021902
.build();
19031903

1904-
p.cargo("publish -Z bindeps --no-verify --token sekrit")
1904+
p.cargo("publish --registry dummy-registry -Z bindeps --no-verify --token sekrit")
19051905
.masquerade_as_nightly_cargo(&["bindeps"])
19061906
.with_stderr(
19071907
"\

tests/testsuite/bad_config.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ fn bad3() {
7474
.build();
7575
Package::new("foo", "1.0.0").publish();
7676

77-
p.cargo("publish -v")
77+
p.cargo("publish --registry dummy-registry -v")
7878
.with_status(101)
7979
.with_stderr(
8080
"\
@@ -125,7 +125,7 @@ fn bad6() {
125125
.build();
126126
Package::new("foo", "1.0.0").publish();
127127

128-
p.cargo("publish -v")
128+
p.cargo("publish --registry dummy-registry -v")
129129
.with_status(101)
130130
.with_stderr(
131131
"\

tests/testsuite/cargo_features.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ fn publish_allowed() {
626626
)
627627
.file("src/lib.rs", "")
628628
.build();
629-
p.cargo("publish --token sekrit")
629+
p.cargo("publish --registry dummy-registry --token sekrit")
630630
.masquerade_as_nightly_cargo(&["test-dummy-unstable"])
631631
.run();
632632
}

0 commit comments

Comments
 (0)