Skip to content

Commit 8b3728c

Browse files
committed
fix: non-mergeable list from config cli merge the same way
Before we iterated key values directly for config cli values, so top level table name of config key is never tracked. And that resulted in `registries.example.credential-provider` becoming `example.credential-provider`, making `is_nonmergable_list` return false. This fix replaces the manual traversal with a direct `ConfigValue::merge` call. Now we unify how config values merge, regardless theird sources.
1 parent 5d611fa commit 8b3728c

File tree

3 files changed

+30
-22
lines changed

3 files changed

+30
-22
lines changed

src/cargo/util/context/mod.rs

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,24 +1546,18 @@ impl GlobalContext {
15461546

15471547
/// Add config arguments passed on the command line.
15481548
fn merge_cli_args(&mut self) -> CargoResult<()> {
1549-
let CV::Table(loaded_map, _def) = self.cli_args_as_table()? else {
1550-
unreachable!()
1551-
};
1552-
let values = self.values_mut()?;
1553-
for (key, value) in loaded_map.into_iter() {
1554-
match values.entry(key) {
1555-
Vacant(entry) => {
1556-
entry.insert(value);
1557-
}
1558-
Occupied(mut entry) => entry.get_mut().merge(value, true).with_context(|| {
1559-
format!(
1560-
"failed to merge --config key `{}` into `{}`",
1561-
entry.key(),
1562-
entry.get().definition(),
1563-
)
1564-
})?,
1565-
};
1566-
}
1549+
let cv_from_cli = self.cli_args_as_table()?;
1550+
assert!(cv_from_cli.is_table(), "cv from CLI must be a table");
1551+
1552+
let root_cv = mem::take(self.values_mut()?);
1553+
// This definition path is ignored, this is just a temporary container
1554+
// representing the entire file.
1555+
let mut root_cv = CV::Table(root_cv, Definition::Path(PathBuf::from(".")));
1556+
root_cv.merge(cv_from_cli, true)?;
1557+
1558+
// Put it back to gctx
1559+
mem::swap(self.values_mut()?, root_cv.table_mut("<root>")?.0);
1560+
15671561
Ok(())
15681562
}
15691563

@@ -2299,6 +2293,20 @@ impl ConfigValue {
22992293
}
23002294
}
23012295

2296+
pub fn table_mut(
2297+
&mut self,
2298+
key: &str,
2299+
) -> CargoResult<(&mut HashMap<String, ConfigValue>, &mut Definition)> {
2300+
match self {
2301+
CV::Table(table, def) => Ok((table, def)),
2302+
_ => self.expected("table", key),
2303+
}
2304+
}
2305+
2306+
pub fn is_table(&self) -> bool {
2307+
matches!(self, CV::Table(_table, _def))
2308+
}
2309+
23022310
pub fn string_list(&self, key: &str) -> CargoResult<Vec<(String, Definition)>> {
23032311
match self {
23042312
CV::List(list, _) => list

tests/testsuite/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ Caused by:
652652
assert_error(
653653
gctx.unwrap_err(),
654654
str![[r#"
655-
failed to merge --config key `a` into `[ROOT]/.cargo/config.toml`
655+
failed to merge key `a` between [ROOT]/.cargo/config.toml and --config cli option
656656
657657
Caused by:
658658
failed to merge config value from `--config cli option` into `[ROOT]/.cargo/config.toml`: expected boolean, but found array
@@ -2222,8 +2222,8 @@ credential-provider = ['c', 'd']
22222222
.credential_provider
22232223
.unwrap();
22242224
// expect: no merge happens; config CLI takes precedence
2225-
assert_eq!(provider.path.raw_value(), "c");
2226-
assert_eq!(provider.args, ["d", "cli", "cli-arg"]);
2225+
assert_eq!(provider.path.raw_value(), "cli");
2226+
assert_eq!(provider.args, ["cli-arg"]);
22272227
}
22282228

22292229
#[cargo_test]

tests/testsuite/config_include.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ fn cli_merge_failed() {
459459
assert_error(
460460
gctx.unwrap_err(),
461461
str![[r#"
462-
failed to merge --config key `foo` into `[ROOT]/.cargo/config.toml`
462+
failed to merge key `foo` between [ROOT]/.cargo/config.toml and [ROOT]/.cargo/other.toml
463463
464464
Caused by:
465465
failed to merge config value from `[ROOT]/.cargo/other.toml` into `[ROOT]/.cargo/config.toml`: expected array, but found string

0 commit comments

Comments
 (0)