diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs
index bdc344b83a0..6848733116b 100644
--- a/src/cargo/util/config.rs
+++ b/src/cargo/util/config.rs
@@ -705,12 +705,25 @@ impl Config {
if fs::metadata(&possible).is_ok() {
if warn && fs::metadata(&possible_with_extension).is_ok() {
- self.shell().warn(format!(
- "Both `{}` and `{}` exist. Using `{}`",
- possible.display(),
- possible_with_extension.display(),
- possible.display()
- ))?;
+ // We don't want to print a warning if the version
+ // without the extension is just a symlink to the version
+ // WITH an extension, which people may want to do to
+ // support multiple Cargo versions at once and not
+ // get a warning.
+ let skip_warning = if let Ok(target_path) = fs::read_link(&possible) {
+ target_path == possible_with_extension
+ } else {
+ false
+ };
+
+ if !skip_warning {
+ self.shell().warn(format!(
+ "Both `{}` and `{}` exist. Using `{}`",
+ possible.display(),
+ possible_with_extension.display(),
+ possible.display()
+ ))?;
+ }
}
Ok(Some(possible))
diff --git a/tests/testsuite/config.rs b/tests/testsuite/config.rs
index 8f7549c4309..bd56e996e0a 100644
--- a/tests/testsuite/config.rs
+++ b/tests/testsuite/config.rs
@@ -1,6 +1,9 @@
use std::borrow::Borrow;
use std::collections;
use std::fs;
+use std::io;
+use std::os;
+use std::path::Path;
use crate::support::{paths, project};
use cargo::core::{enable_nightly_features, Shell};
@@ -54,6 +57,44 @@ fn write_config_toml(config: &str) {
fs::write(path, config).unwrap();
}
+// Several test fail on windows if the user does not have permission to
+// create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
+// disabling these test on Windows, use this function to test whether we
+// have permission, and return otherwise. This way, we still don't run these
+// tests most of the time, but at least we do if the user has the right
+// permissions.
+// This function is derived from libstd fs tests.
+pub fn got_symlink_permission() -> bool {
+ if cfg!(unix) {
+ return true;
+ }
+ let link = paths::root().join("some_hopefully_unique_link_name");
+ let target = paths::root().join("nonexisting_target");
+
+ match symlink_file(&target, &link) {
+ Ok(_) => true,
+ // ERROR_PRIVILEGE_NOT_HELD = 1314
+ Err(ref err) if err.raw_os_error() == Some(1314) => false,
+ Err(_) => true,
+ }
+}
+
+#[cfg(unix)]
+fn symlink_file(target: &Path, link: &Path) -> io::Result<()> {
+ os::unix::fs::symlink(target, link)
+}
+
+#[cfg(windows)]
+fn symlink_file(target: &Path, link: &Path) -> io::Result<()> {
+ os::windows::fs::symlink_file(target, link)
+}
+
+fn symlink_config_to_config_toml() {
+ let toml_path = paths::root().join(".cargo/config.toml");
+ let symlink_path = paths::root().join(".cargo/config");
+ t!(symlink_file(&toml_path, &symlink_path));
+}
+
fn new_config(env: &[(&str, &str)]) -> Config {
enable_nightly_features(); // -Z advanced-env
let output = Box::new(fs::File::create(paths::root().join("shell.out")).unwrap());
@@ -132,6 +173,42 @@ f1 = 1
assert_eq!(config.get::