Skip to content

Commit c530720

Browse files
committed
Allow using 'config.toml' instead of just 'config' files.
Note that this change only makes 'config.toml' optional to use instead of 'config'. If both exist, we will print a warning and prefer 'config', since that would be the existing behavior if both existed. We should also consider a separate change to make config.toml the default and update docs, etc.
1 parent 475a23e commit c530720

File tree

2 files changed

+113
-26
lines changed

2 files changed

+113
-26
lines changed

src/cargo/util/config.rs

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ impl Config {
662662
let mut cfg = CV::Table(HashMap::new(), PathBuf::from("."));
663663
let home = self.home_path.clone().into_path_unlocked();
664664

665-
walk_tree(path, &home, |path| {
665+
self.walk_tree(path, &home, |path| {
666666
let mut contents = String::new();
667667
let mut file = File::open(&path)?;
668668
file.read_to_string(&mut contents)
@@ -689,6 +689,61 @@ impl Config {
689689
}
690690
}
691691

692+
fn walk_tree<F>(&self, pwd: &Path, home: &Path, mut walk: F) -> CargoResult<()>
693+
where
694+
F: FnMut(&Path) -> CargoResult<()>,
695+
{
696+
let mut stash: HashSet<PathBuf> = HashSet::new();
697+
698+
for current in paths::ancestors(pwd) {
699+
let possible = current.join(".cargo").join("config");
700+
let possible_with_extension = current.join(".cargo").join("config.toml");
701+
702+
// If both 'config' and 'config.toml' exist, we should use 'config'
703+
// for backward compatibility, but we should warn the user.
704+
if fs::metadata(&possible).is_ok() {
705+
if fs::metadata(&possible_with_extension).is_ok() {
706+
self.shell().warn(format!(
707+
"Both `{}` and `{}` exist. Using `{}`",
708+
possible.display(),
709+
possible_with_extension.display(),
710+
possible.display()
711+
))?;
712+
}
713+
714+
walk(&possible)?;
715+
stash.insert(possible);
716+
} else if fs::metadata(&possible_with_extension).is_ok() {
717+
walk(&possible_with_extension)?;
718+
stash.insert(possible);
719+
}
720+
}
721+
722+
// Once we're done, also be sure to walk the home directory even if it's not
723+
// in our history to be sure we pick up that standard location for
724+
// information.
725+
let config = home.join("config");
726+
let config_with_extension = home.join("config.toml");
727+
if !stash.contains(&config) && fs::metadata(&config).is_ok() {
728+
if fs::metadata(&config_with_extension).is_ok() {
729+
self.shell().warn(format!(
730+
"Both `{}` and `{}` exist. Using `{}`",
731+
config.display(),
732+
config_with_extension.display(),
733+
config.display()
734+
))?;
735+
}
736+
737+
walk(&config)?;
738+
} else if !stash.contains(&config_with_extension)
739+
&& fs::metadata(&config_with_extension).is_ok()
740+
{
741+
walk(&config_with_extension)?;
742+
}
743+
744+
Ok(())
745+
}
746+
692747
/// Gets the index for a registry.
693748
pub fn get_registry_index(&self, registry: &str) -> CargoResult<Url> {
694749
validate_package_name(registry, "registry name", "")?;
@@ -1673,31 +1728,6 @@ pub fn homedir(cwd: &Path) -> Option<PathBuf> {
16731728
::home::cargo_home_with_cwd(cwd).ok()
16741729
}
16751730

1676-
fn walk_tree<F>(pwd: &Path, home: &Path, mut walk: F) -> CargoResult<()>
1677-
where
1678-
F: FnMut(&Path) -> CargoResult<()>,
1679-
{
1680-
let mut stash: HashSet<PathBuf> = HashSet::new();
1681-
1682-
for current in paths::ancestors(pwd) {
1683-
let possible = current.join(".cargo").join("config");
1684-
if fs::metadata(&possible).is_ok() {
1685-
walk(&possible)?;
1686-
stash.insert(possible);
1687-
}
1688-
}
1689-
1690-
// Once we're done, also be sure to walk the home directory even if it's not
1691-
// in our history to be sure we pick up that standard location for
1692-
// information.
1693-
let config = home.join("config");
1694-
if !stash.contains(&config) && fs::metadata(&config).is_ok() {
1695-
walk(&config)?;
1696-
}
1697-
1698-
Ok(())
1699-
}
1700-
17011731
pub fn save_credentials(cfg: &Config, token: String, registry: Option<String>) -> CargoResult<()> {
17021732
let mut file = {
17031733
cfg.home_path.create_dir()?;

tests/testsuite/config.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ fn write_config(config: &str) {
4848
fs::write(path, config).unwrap();
4949
}
5050

51+
fn write_config_toml(config: &str) {
52+
let path = paths::root().join(".cargo/config.toml");
53+
fs::create_dir_all(path.parent().unwrap()).unwrap();
54+
fs::write(path, config).unwrap();
55+
}
56+
5157
fn new_config(env: &[(&str, &str)]) -> Config {
5258
enable_nightly_features(); // -Z advanced-env
5359
let output = Box::new(fs::File::create(paths::root().join("shell.out")).unwrap());
@@ -112,6 +118,57 @@ f1 = 123
112118
assert_eq!(s, S { f1: Some(456) });
113119
}
114120

121+
#[cargo_test]
122+
fn config_works_with_extension() {
123+
write_config_toml(
124+
"\
125+
[foo]
126+
f1 = 1
127+
",
128+
);
129+
130+
let config = new_config(&[]);
131+
132+
assert_eq!(config.get::<Option<i32>>("foo.f1").unwrap(), Some(1));
133+
}
134+
135+
#[cargo_test]
136+
fn config_ambiguous_filename() {
137+
write_config(
138+
"\
139+
[foo]
140+
f1 = 1
141+
",
142+
);
143+
144+
write_config_toml(
145+
"\
146+
[foo]
147+
f1 = 2
148+
",
149+
);
150+
151+
let config = new_config(&[]);
152+
153+
// It should use the value from the one without the extension for
154+
// backwards compatibility.
155+
assert_eq!(config.get::<Option<i32>>("foo.f1").unwrap(), Some(1));
156+
157+
// But it also should have warned.
158+
drop(config); // Paranoid about flushing the file.
159+
let path = paths::root().join("shell.out");
160+
let output = fs::read_to_string(path).unwrap();
161+
let expected = "\
162+
warning: Both `[..]/.cargo/config` and `[..]/.cargo/config.toml` exist. Using `[..]/.cargo/config`
163+
";
164+
if !lines_match(expected, &output) {
165+
panic!(
166+
"Did not find expected:\n{}\nActual error:\n{}\n",
167+
expected, output
168+
);
169+
}
170+
}
171+
115172
#[cargo_test]
116173
fn config_unused_fields() {
117174
write_config(

0 commit comments

Comments
 (0)