Skip to content

Commit abc1159

Browse files
committed
Auto merge of #12439 - arlosi:registry-multiple-warning, r=ehuss
Fix printing multiple warning messages for unused fields in [registries] table Cargo currently prints the same warning message multiple times for unexpected fields in the `[registries.<registry>]` or `[registry]` tables. This is because Cargo warns each time that the structure is deserialized from `Config`. Depending on which code path is taken I've seen the warning printed up to 6 times. * A cache of deserialized registry configurations is added to the `Config` struct. * Registry authentication is changed to directly read the config when searching for a registry name, rather than deserializing each registry configuration. A test is added to ensure both `[registries]` and `[registry]` only warn once for unexpected fields.
2 parents b644a40 + 65ec65f commit abc1159

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

src/cargo/util/auth/mod.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use cargo_credential::{
1212

1313
use core::fmt;
1414
use serde::Deserialize;
15-
use std::collections::HashMap;
1615
use std::error::Error;
1716
use time::{Duration, OffsetDateTime};
1817
use url::Url;
@@ -31,7 +30,7 @@ use super::{
3130
/// `[registries.NAME]` tables.
3231
///
3332
/// The values here should be kept in sync with `RegistryConfigExtended`
34-
#[derive(Deserialize)]
33+
#[derive(Deserialize, Clone, Debug)]
3534
#[serde(rename_all = "kebab-case")]
3635
pub struct RegistryConfig {
3736
pub index: Option<String>,
@@ -207,6 +206,19 @@ fn credential_provider(config: &Config, sid: &SourceId) -> CargoResult<Vec<Vec<S
207206
pub fn registry_credential_config_raw(
208207
config: &Config,
209208
sid: &SourceId,
209+
) -> CargoResult<Option<RegistryConfig>> {
210+
let mut cache = config.registry_config();
211+
if let Some(cfg) = cache.get(&sid) {
212+
return Ok(cfg.clone());
213+
}
214+
let cfg = registry_credential_config_raw_uncached(config, sid)?;
215+
cache.insert(*sid, cfg.clone());
216+
return Ok(cfg);
217+
}
218+
219+
fn registry_credential_config_raw_uncached(
220+
config: &Config,
221+
sid: &SourceId,
210222
) -> CargoResult<Option<RegistryConfig>> {
211223
log::trace!("loading credential config for {}", sid);
212224
config.load_credentials()?;
@@ -237,6 +249,7 @@ pub fn registry_credential_config_raw(
237249
// This also allows the authorization token for a registry to be set
238250
// without knowing the registry name by using the _INDEX and _TOKEN
239251
// environment variables.
252+
240253
let name = {
241254
// Discover names from environment variables.
242255
let index = sid.canonical_url();
@@ -256,14 +269,17 @@ pub fn registry_credential_config_raw(
256269

257270
// Discover names from the configuration only if none were found in the environment.
258271
if names.len() == 0 {
259-
names = config
260-
.get::<HashMap<String, RegistryConfig>>("registries")?
261-
.iter()
262-
.filter_map(|(k, v)| Some((k, v.index.as_deref()?)))
263-
.filter_map(|(k, v)| Some((k, CanonicalUrl::new(&v.into_url().ok()?).ok()?)))
264-
.filter(|(_, v)| v == index)
265-
.map(|(k, _)| k.to_string())
266-
.collect();
272+
if let Some(registries) = config.values()?.get("registries") {
273+
let (registries, _) = registries.table("registries")?;
274+
for (name, value) in registries {
275+
if let Some(v) = value.table(&format!("registries.{name}"))?.0.get("index") {
276+
let (v, _) = v.string(&format!("registries.{name}.index"))?;
277+
if index == &CanonicalUrl::new(&v.into_url()?)? {
278+
names.push(name.clone());
279+
}
280+
}
281+
}
282+
}
267283
}
268284
names.sort();
269285
match names.len() {

src/cargo/util/config/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ pub use target::{TargetCfgConfig, TargetConfig};
106106
mod environment;
107107
use environment::Env;
108108

109+
use super::auth::RegistryConfig;
110+
109111
// Helper macro for creating typed access methods.
110112
macro_rules! get_value_typed {
111113
($name:ident, $ty:ty, $variant:ident, $expected:expr) => {
@@ -208,6 +210,8 @@ pub struct Config {
208210
/// Cache of credentials from configuration or credential providers.
209211
/// Maps from url to credential value.
210212
credential_cache: LazyCell<RefCell<HashMap<CanonicalUrl, CredentialCacheValue>>>,
213+
/// Cache of registry config from from the `[registries]` table.
214+
registry_config: LazyCell<RefCell<HashMap<SourceId, Option<RegistryConfig>>>>,
211215
/// Lock, if held, of the global package cache along with the number of
212216
/// acquisitions so far.
213217
package_cache_lock: RefCell<Option<(Option<FileLock>, usize)>>,
@@ -299,6 +303,7 @@ impl Config {
299303
env,
300304
updated_sources: LazyCell::new(),
301305
credential_cache: LazyCell::new(),
306+
registry_config: LazyCell::new(),
302307
package_cache_lock: RefCell::new(None),
303308
http_config: LazyCell::new(),
304309
future_incompat_config: LazyCell::new(),
@@ -488,6 +493,13 @@ impl Config {
488493
.borrow_mut()
489494
}
490495

496+
/// Cache of already parsed registries from the `[registries]` table.
497+
pub(crate) fn registry_config(&self) -> RefMut<'_, HashMap<SourceId, Option<RegistryConfig>>> {
498+
self.registry_config
499+
.borrow_with(|| RefCell::new(HashMap::new()))
500+
.borrow_mut()
501+
}
502+
491503
/// Gets all config values from disk.
492504
///
493505
/// This will lazy-load the values as necessary. Callers are responsible

tests/testsuite/alt_registry.rs

+41
Original file line numberDiff line numberDiff line change
@@ -1506,3 +1506,44 @@ fn publish_with_transitive_dep() {
15061506
.build();
15071507
p2.cargo("publish").run();
15081508
}
1509+
1510+
#[cargo_test]
1511+
fn warn_for_unused_fields() {
1512+
let _ = RegistryBuilder::new()
1513+
.no_configure_token()
1514+
.alternative()
1515+
.build();
1516+
let p = project()
1517+
.file("src/lib.rs", "")
1518+
.file(
1519+
".cargo/config.toml",
1520+
"[registry]
1521+
unexpected-field = 'foo'
1522+
[registries.alternative]
1523+
unexpected-field = 'foo'
1524+
",
1525+
)
1526+
.build();
1527+
1528+
p.cargo("publish --registry alternative")
1529+
.with_status(101)
1530+
.with_stderr(
1531+
"\
1532+
[UPDATING] `alternative` index
1533+
[WARNING] unused config key `registries.alternative.unexpected-field` in `[..]config.toml`
1534+
[ERROR] no token found for `alternative`, please run `cargo login --registry alternative`
1535+
or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN",
1536+
)
1537+
.run();
1538+
1539+
p.cargo("publish --registry crates-io")
1540+
.with_status(101)
1541+
.with_stderr(
1542+
"\
1543+
[UPDATING] crates.io index
1544+
[WARNING] unused config key `registry.unexpected-field` in `[..]config.toml`
1545+
[ERROR] no token found, please run `cargo login`
1546+
or use environment variable CARGO_REGISTRY_TOKEN",
1547+
)
1548+
.run();
1549+
}

0 commit comments

Comments
 (0)