Skip to content

Commit bc0a8cb

Browse files
committed
fix: Add more context when 'missing feild'
1 parent 48742e0 commit bc0a8cb

File tree

4 files changed

+60
-14
lines changed

4 files changed

+60
-14
lines changed

src/cargo/util/context/de.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ macro_rules! deserialize_method {
3535
.ok_or_else(|| ConfigError::missing(&self.key))?;
3636
let Value { val, definition } = v;
3737
let res: Result<V::Value, ConfigError> = visitor.$visit(val);
38-
res.map_err(|e| e.with_key_context(&self.key, definition))
38+
res.map_err(|e| e.with_key_context(&self.key, Some(definition)))
3939
}
4040
};
4141
}
@@ -60,7 +60,7 @@ impl<'de, 'gctx> de::Deserializer<'de> for Deserializer<'gctx> {
6060
CV::Boolean(b, def) => (visitor.visit_bool(b), def),
6161
};
6262
let (res, def) = res;
63-
return res.map_err(|e| e.with_key_context(&self.key, def));
63+
return res.map_err(|e| e.with_key_context(&self.key, Some(def)));
6464
}
6565
Err(ConfigError::missing(&self.key))
6666
}
@@ -178,7 +178,7 @@ impl<'de, 'gctx> de::Deserializer<'de> for Deserializer<'gctx> {
178178
let Value { val, definition } = value;
179179
visitor
180180
.visit_enum(val.into_deserializer())
181-
.map_err(|e: ConfigError| e.with_key_context(&self.key, definition))
181+
.map_err(|e: ConfigError| e.with_key_context(&self.key, Some(definition)))
182182
}
183183

184184
// These aren't really supported, yet.
@@ -345,11 +345,26 @@ impl<'de, 'gctx> de::MapAccess<'de> for ConfigMapAccess<'gctx> {
345345
field.replace('-', "_").starts_with(&env_prefix)
346346
});
347347

348-
let result = seed.deserialize(Deserializer {
349-
gctx: self.de.gctx,
350-
key: self.de.key.clone(),
351-
env_prefix_ok,
352-
});
348+
let result = seed
349+
.deserialize(Deserializer {
350+
gctx: self.de.gctx,
351+
key: self.de.key.clone(),
352+
env_prefix_ok,
353+
})
354+
.map_err(|e| {
355+
if !e.is_missing_field() {
356+
return e;
357+
}
358+
e.with_key_context(
359+
&self.de.key,
360+
self.de
361+
.gctx
362+
.get_cv_with_env(&self.de.key)
363+
.map_or(None, |cv| {
364+
cv.map_or(None, |cv| Some(cv.get_definition().clone()))
365+
}),
366+
)
367+
});
353368
self.de.key.pop();
354369
result
355370
}
@@ -486,7 +501,7 @@ impl<'de, 'gctx> de::MapAccess<'de> for ValueDeserializer<'gctx> {
486501
if let Some(de) = &self.de {
487502
return seed
488503
.deserialize(de.clone())
489-
.map_err(|e| e.with_key_context(&de.key, self.definition.clone()));
504+
.map_err(|e| e.with_key_context(&de.key, Some(self.definition.clone())));
490505
} else {
491506
return seed
492507
.deserialize(self.str_value.as_ref().unwrap().clone().into_deserializer());

src/cargo/util/context/mod.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,18 +2030,22 @@ impl ConfigError {
20302030
}
20312031
}
20322032

2033+
fn is_missing_field(&self) -> bool {
2034+
self.error.to_string().contains("missing field")
2035+
}
2036+
20332037
fn missing(key: &ConfigKey) -> ConfigError {
20342038
ConfigError {
20352039
error: anyhow!("missing config key `{}`", key),
20362040
definition: None,
20372041
}
20382042
}
20392043

2040-
fn with_key_context(self, key: &ConfigKey, definition: Definition) -> ConfigError {
2044+
fn with_key_context(self, key: &ConfigKey, definition: Option<Definition>) -> ConfigError {
20412045
ConfigError {
20422046
error: anyhow::Error::from(self)
20432047
.context(format!("could not load config key `{}`", key)),
2044-
definition: Some(definition),
2048+
definition: definition,
20452049
}
20462050
}
20472051
}
@@ -2111,6 +2115,16 @@ impl fmt::Debug for ConfigValue {
21112115
}
21122116

21132117
impl ConfigValue {
2118+
fn get_definition(&self) -> &Definition {
2119+
match self {
2120+
CV::Boolean(_, def)
2121+
| CV::Integer(_, def)
2122+
| CV::String(_, def)
2123+
| CV::List(_, def)
2124+
| CV::Table(_, def) => def,
2125+
}
2126+
}
2127+
21142128
fn from_toml(def: Definition, toml: toml::Value) -> CargoResult<ConfigValue> {
21152129
match toml {
21162130
toml::Value::String(val) => Ok(CV::String(val, def)),

tests/testsuite/config.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,7 +1880,14 @@ fn missing_fields() {
18801880
let gctx = GlobalContextBuilder::new()
18811881
.env("CARGO_FOO_BAR_BAZ", "true")
18821882
.build();
1883-
assert_error(gctx.get::<Foo>("foo").unwrap_err(), "missing field `bax`");
1883+
assert_error(
1884+
gctx.get::<Foo>("foo").unwrap_err(),
1885+
"\
1886+
could not load config key `foo.bar`
1887+
1888+
Caused by:
1889+
missing field `bax`",
1890+
);
18841891
let gctx: GlobalContext = GlobalContextBuilder::new()
18851892
.env("CARGO_FOO_BAR_BAZ", "true")
18861893
.env("CARGO_FOO_BAR_BAX", "true")
@@ -1892,5 +1899,12 @@ fn missing_fields() {
18921899
let gctx: GlobalContext = GlobalContextBuilder::new()
18931900
.config_arg("foo.bar.baz=true")
18941901
.build();
1895-
assert_error(gctx.get::<Foo>("foo").unwrap_err(), "missing field `bax`");
1902+
assert_error(
1903+
gctx.get::<Foo>("foo").unwrap_err(),
1904+
"\
1905+
error in --config cli option: could not load config key `foo.bar`
1906+
1907+
Caused by:
1908+
missing field `bax`",
1909+
);
18961910
}

tests/testsuite/progress.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ fn bad_progress_config_missing_when() {
7070
.with_status(101)
7171
.with_stderr(
7272
"\
73-
error: missing field `when`
73+
error: error in [..]: could not load config key `term.progress`
74+
75+
Caused by:
76+
missing field `when`
7477
",
7578
)
7679
.run();

0 commit comments

Comments
 (0)