fix(config): combine key error context into one

This commit is contained in:
Weihang Lo 2025-09-23 22:09:41 -04:00
parent 440828ae07
commit 22f2745066
No known key found for this signature in database
GPG Key ID: D7DBF189825E82E7
6 changed files with 48 additions and 18 deletions

View File

@ -112,7 +112,7 @@ impl fmt::Display for ConfigKey {
} }
} }
fn escape_key_part<'a>(part: &'a str) -> Cow<'a, str> { pub(super) fn escape_key_part<'a>(part: &'a str) -> Cow<'a, str> {
let ok = part.chars().all(|c| { let ok = part.chars().all(|c| {
matches!(c, matches!(c,
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_') 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_')

View File

@ -2155,6 +2155,12 @@ impl From<anyhow::Error> for ConfigError {
} }
} }
#[derive(Debug)]
enum KeyOrIdx {
Key(String),
Idx(usize),
}
#[derive(Eq, PartialEq, Clone)] #[derive(Eq, PartialEq, Clone)]
pub enum ConfigValue { pub enum ConfigValue {
Integer(i64, Definition), Integer(i64, Definition),
@ -2197,26 +2203,56 @@ impl ConfigValue {
} }
fn from_toml(def: Definition, toml: toml::Value) -> CargoResult<ConfigValue> { fn from_toml(def: Definition, toml: toml::Value) -> CargoResult<ConfigValue> {
let mut error_path = Vec::new();
Self::from_toml_inner(def, toml, &mut error_path).with_context(|| {
let mut it = error_path.iter().rev().peekable();
let mut key_path = String::with_capacity(error_path.len() * 3);
while let Some(k) = it.next() {
match k {
KeyOrIdx::Key(s) => key_path.push_str(&key::escape_key_part(&s)),
KeyOrIdx::Idx(i) => key_path.push_str(&format!("[{i}]")),
}
if matches!(it.peek(), Some(KeyOrIdx::Key(_))) {
key_path.push('.');
}
}
format!("failed to parse config at `{key_path}`")
})
}
fn from_toml_inner(
def: Definition,
toml: toml::Value,
path: &mut Vec<KeyOrIdx>,
) -> CargoResult<ConfigValue> {
match toml { match toml {
toml::Value::String(val) => Ok(CV::String(val, def)), toml::Value::String(val) => Ok(CV::String(val, def)),
toml::Value::Boolean(b) => Ok(CV::Boolean(b, def)), toml::Value::Boolean(b) => Ok(CV::Boolean(b, def)),
toml::Value::Integer(i) => Ok(CV::Integer(i, def)), toml::Value::Integer(i) => Ok(CV::Integer(i, def)),
toml::Value::Array(val) => Ok(CV::List( toml::Value::Array(val) => Ok(CV::List(
val.into_iter() val.into_iter()
.map(|toml| match toml { .enumerate()
.map(|(i, toml)| match toml {
toml::Value::String(val) => Ok((val, def.clone())), toml::Value::String(val) => Ok((val, def.clone())),
v => bail!("expected string but found {} in list", v.type_str()), v => {
path.push(KeyOrIdx::Idx(i));
bail!("expected string but found {} in list", v.type_str())
}
}) })
.collect::<CargoResult<_>>()?, .collect::<CargoResult<_>>()?,
def, def,
)), )),
toml::Value::Table(val) => Ok(CV::Table( toml::Value::Table(val) => Ok(CV::Table(
val.into_iter() val.into_iter()
.map(|(key, value)| { .map(
let value = CV::from_toml(def.clone(), value) |(key, value)| match CV::from_toml_inner(def.clone(), value, path) {
.with_context(|| format!("failed to parse key `{}`", key))?; Ok(value) => Ok((key, value)),
Ok((key, value)) Err(e) => {
}) path.push(KeyOrIdx::Key(key));
Err(e)
}
},
)
.collect::<CargoResult<_>>()?, .collect::<CargoResult<_>>()?,
def, def,
)), )),

View File

@ -47,10 +47,7 @@ Caused by:
failed to load TOML configuration from `[ROOT]/foo/.cargo/config.toml` failed to load TOML configuration from `[ROOT]/foo/.cargo/config.toml`
Caused by: Caused by:
failed to parse key `http` failed to parse config at `http.proxy`
Caused by:
failed to parse key `proxy`
Caused by: Caused by:
found TOML configuration value of unknown type `float` found TOML configuration value of unknown type `float`

View File

@ -87,10 +87,7 @@ Caused by:
failed to load TOML configuration from `[ROOT]/foo/.cargo/config.toml` failed to load TOML configuration from `[ROOT]/foo/.cargo/config.toml`
Caused by: Caused by:
failed to parse key `alias` failed to parse config at `alias.b-cargo-test[0]`
Caused by:
failed to parse key `b-cargo-test`
Caused by: Caused by:
expected string but found integer in list expected string but found integer in list

View File

@ -1363,7 +1363,7 @@ Caused by:
failed to load TOML configuration from `[ROOT]/.cargo/config.toml` failed to load TOML configuration from `[ROOT]/.cargo/config.toml`
Caused by: Caused by:
failed to parse key `foo` failed to parse config at `foo[0]`
Caused by: Caused by:
expected string but found integer in list expected string but found integer in list

View File

@ -527,7 +527,7 @@ fn bad_cv_convert() {
failed to convert --config argument `a=2019-12-01` failed to convert --config argument `a=2019-12-01`
Caused by: Caused by:
failed to parse key `a` failed to parse config at `a`
Caused by: Caused by:
found TOML configuration value of unknown type `datetime` found TOML configuration value of unknown type `datetime`