Skip to content

Commit b41a16c

Browse files
authored
fix(config): combine key error context into one (#16004)
### What does this PR try to resolve? This is a cleanup of annoying multiple "failed to parse key". ``` Caused by: failed to parse key `alias` Caused by: failed to parse key `nested` ``` to ``` Caused by: failed to parse config at path `alias.nested` ``` This also open a door to using annotate-snippets to get the span of a key path. ### How to test and review this PR? This controversial part is we are using the invalid syntax to represent the key path. For example, `alias.nested[2]` refers to ```toml [alias] nested = ["a", "b", "c"] # ^^^ this one ``` r? Muscraft
2 parents 440828a + bd93d31 commit b41a16c

File tree

6 files changed

+50
-20
lines changed

6 files changed

+50
-20
lines changed

src/cargo/util/context/key.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl fmt::Display for ConfigKey {
112112
}
113113
}
114114

115-
fn escape_key_part<'a>(part: &'a str) -> Cow<'a, str> {
115+
pub(super) fn escape_key_part<'a>(part: &'a str) -> Cow<'a, str> {
116116
let ok = part.chars().all(|c| {
117117
matches!(c,
118118
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_')

src/cargo/util/context/mod.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2155,6 +2155,12 @@ impl From<anyhow::Error> for ConfigError {
21552155
}
21562156
}
21572157

2158+
#[derive(Debug)]
2159+
enum KeyOrIdx {
2160+
Key(String),
2161+
Idx(usize),
2162+
}
2163+
21582164
#[derive(Eq, PartialEq, Clone)]
21592165
pub enum ConfigValue {
21602166
Integer(i64, Definition),
@@ -2197,26 +2203,56 @@ impl ConfigValue {
21972203
}
21982204

21992205
fn from_toml(def: Definition, toml: toml::Value) -> CargoResult<ConfigValue> {
2206+
let mut error_path = Vec::new();
2207+
Self::from_toml_inner(def, toml, &mut error_path).with_context(|| {
2208+
let mut it = error_path.iter().rev().peekable();
2209+
let mut key_path = String::with_capacity(error_path.len() * 3);
2210+
while let Some(k) = it.next() {
2211+
match k {
2212+
KeyOrIdx::Key(s) => key_path.push_str(&key::escape_key_part(&s)),
2213+
KeyOrIdx::Idx(i) => key_path.push_str(&format!("[{i}]")),
2214+
}
2215+
if matches!(it.peek(), Some(KeyOrIdx::Key(_))) {
2216+
key_path.push('.');
2217+
}
2218+
}
2219+
format!("failed to parse config at `{key_path}`")
2220+
})
2221+
}
2222+
2223+
fn from_toml_inner(
2224+
def: Definition,
2225+
toml: toml::Value,
2226+
path: &mut Vec<KeyOrIdx>,
2227+
) -> CargoResult<ConfigValue> {
22002228
match toml {
22012229
toml::Value::String(val) => Ok(CV::String(val, def)),
22022230
toml::Value::Boolean(b) => Ok(CV::Boolean(b, def)),
22032231
toml::Value::Integer(i) => Ok(CV::Integer(i, def)),
22042232
toml::Value::Array(val) => Ok(CV::List(
22052233
val.into_iter()
2206-
.map(|toml| match toml {
2234+
.enumerate()
2235+
.map(|(i, toml)| match toml {
22072236
toml::Value::String(val) => Ok((val, def.clone())),
2208-
v => bail!("expected string but found {} in list", v.type_str()),
2237+
v => {
2238+
path.push(KeyOrIdx::Idx(i));
2239+
bail!("expected string but found {} at index {i}", v.type_str())
2240+
}
22092241
})
22102242
.collect::<CargoResult<_>>()?,
22112243
def,
22122244
)),
22132245
toml::Value::Table(val) => Ok(CV::Table(
22142246
val.into_iter()
2215-
.map(|(key, value)| {
2216-
let value = CV::from_toml(def.clone(), value)
2217-
.with_context(|| format!("failed to parse key `{}`", key))?;
2218-
Ok((key, value))
2219-
})
2247+
.map(
2248+
|(key, value)| match CV::from_toml_inner(def.clone(), value, path) {
2249+
Ok(value) => Ok((key, value)),
2250+
Err(e) => {
2251+
path.push(KeyOrIdx::Key(key));
2252+
Err(e)
2253+
}
2254+
},
2255+
)
22202256
.collect::<CargoResult<_>>()?,
22212257
def,
22222258
)),

tests/testsuite/bad_config.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@ Caused by:
4747
failed to load TOML configuration from `[ROOT]/foo/.cargo/config.toml`
4848
4949
Caused by:
50-
failed to parse key `http`
51-
52-
Caused by:
53-
failed to parse key `proxy`
50+
failed to parse config at `http.proxy`
5451
5552
Caused by:
5653
found TOML configuration value of unknown type `float`

tests/testsuite/cargo_alias_config.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,10 @@ Caused by:
8787
failed to load TOML configuration from `[ROOT]/foo/.cargo/config.toml`
8888
8989
Caused by:
90-
failed to parse key `alias`
90+
failed to parse config at `alias.b-cargo-test[0]`
9191
9292
Caused by:
93-
failed to parse key `b-cargo-test`
94-
95-
Caused by:
96-
expected string but found integer in list
93+
expected string but found integer at index 0
9794
9895
"#]])
9996
.run();

tests/testsuite/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,10 +1363,10 @@ Caused by:
13631363
failed to load TOML configuration from `[ROOT]/.cargo/config.toml`
13641364
13651365
Caused by:
1366-
failed to parse key `foo`
1366+
failed to parse config at `foo[0]`
13671367
13681368
Caused by:
1369-
expected string but found integer in list
1369+
expected string but found integer at index 0
13701370
"#]],
13711371
);
13721372
}

tests/testsuite/config_cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ fn bad_cv_convert() {
527527
failed to convert --config argument `a=2019-12-01`
528528
529529
Caused by:
530-
failed to parse key `a`
530+
failed to parse config at `a`
531531
532532
Caused by:
533533
found TOML configuration value of unknown type `datetime`

0 commit comments

Comments
 (0)