diff --git a/Cargo.lock b/Cargo.lock index acc898ef086..981107b19fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + [[package]] name = "bstr" version = "0.2.17" @@ -239,6 +245,22 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "fnv" version = "1.0.7" @@ -265,6 +287,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "globset" version = "0.4.8" @@ -341,9 +375,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" @@ -381,9 +421,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -421,13 +461,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "redox_syscall" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -436,7 +482,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.6", "redox_syscall", "thiserror", ] @@ -496,6 +542,7 @@ dependencies = [ "semver", "serde", "serde_json", + "tempfile", "term", "thiserror", "toml", @@ -506,6 +553,19 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.60.2", +] + [[package]] name = "ryu" version = "1.0.9" @@ -602,6 +662,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.60.2", +] + [[package]] name = "term" version = "1.1.0" @@ -782,6 +855,15 @@ version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -964,3 +1046,9 @@ name = "winnow" version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo.toml b/Cargo.toml index 9aba9bfa64d..2b693b19c0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,9 @@ unicode-properties = { version = "0.1", default-features = false, features = ["g rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } semver = "1.0.21" +[dev-dependencies] +tempfile = "3.23.0" + # Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. [package.metadata.rust-analyzer] diff --git a/src/config/mod.rs b/src/config/mod.rs index 04a4e89dee7..008d296b6a8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -499,10 +499,12 @@ fn get_toml_path(dir: &Path) -> Result, Error> { // Only return if it's a file to handle the unlikely situation of a directory named // `rustfmt.toml`. Ok(ref md) if md.is_file() => return Ok(Some(config_file.canonicalize()?)), - // Return the error if it's something other than `NotFound`; otherwise we didn't - // find the project file yet, and continue searching. + // We didn't find the project file yet, and continue searching if: + // `NotFound` => file not found + // `NotADirectory` => rare case where expected directory is a file + // Otherwise, return the error Err(e) => { - if e.kind() != ErrorKind::NotFound { + if !matches!(e.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) { let ctx = format!("Failed to get metadata for config file {:?}", &config_file); let err = anyhow::Error::new(e).context(ctx); return Err(Error::new(ErrorKind::Other, err)); diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index a9f58b9328e..9580eb9436f 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -1,28 +1,38 @@ //! Integration tests for rustfmt. use std::env; -use std::fs::remove_file; +use std::fs::{File, remove_file}; use std::path::Path; use std::process::Command; use rustfmt_config_proc_macro::{nightly_only_test, rustfmt_only_ci_test}; -/// Run the rustfmt executable and return its output. -fn rustfmt(args: &[&str]) -> (String, String) { +/// Run the rustfmt executable with environment vars set and return its output. +fn rustfmt_with_extra( + args: &[&str], + working_dir: Option<&str>, + envs: &[(&str, &str)], +) -> (String, String) { let mut bin_dir = env::current_exe().unwrap(); bin_dir.pop(); // chop off test exe name if bin_dir.ends_with("deps") { bin_dir.pop(); } - let cmd = bin_dir.join(format!("rustfmt{}", env::consts::EXE_SUFFIX)); + let rustfmt_exe = bin_dir.join(format!("rustfmt{}", env::consts::EXE_SUFFIX)); // Ensure the rustfmt binary runs from the local target dir. let path = env::var_os("PATH").unwrap_or_default(); let mut paths = env::split_paths(&path).collect::>(); paths.insert(0, bin_dir); let new_path = env::join_paths(paths).unwrap(); - - match Command::new(&cmd).args(args).env("PATH", new_path).output() { + let mut cmd = Command::new(rustfmt_exe); + cmd.args(args) + .env("PATH", new_path) + .envs(envs.iter().copied()); + if let Some(working_dir) = working_dir { + cmd.current_dir(working_dir); + } + match cmd.output() { Ok(output) => ( String::from_utf8(output.stdout).expect("utf-8"), String::from_utf8(output.stderr).expect("utf-8"), @@ -31,6 +41,10 @@ fn rustfmt(args: &[&str]) -> (String, String) { } } +fn rustfmt(args: &[&str]) -> (String, String) { + rustfmt_with_extra(args, None, &[]) +} + macro_rules! assert_that { ($args:expr, $($check:ident $check_args:tt)&&+) => { let (stdout, stderr) = rustfmt($args); @@ -232,3 +246,34 @@ fn rustfmt_error_improvement_regarding_invalid_toml() { assert!(stderr.contains(&expected_error_message)); } + +#[test] +fn rustfmt_allow_not_a_dir_errors() { + // See also https://github.com/rust-lang/rustfmt/pull/6624 + + // To get a proper test, we need to make sure that neither the working dir + // nor the input file have a "rustfmt.toml" file in any ancestor dirs. Since + // this project has a "rustfmt.toml" in the root dir, we can't use a temp + // dir in the target/ dir, which includes the directory given by + // CARGO_TARGET_TMPDIR. Thus, we need the OS-specific temp dir which is + // closer to the "root" directory which is less likely to have a + // "rustfmt.toml". + let fake_home = tempfile::tempdir().unwrap(); + let fake_home_str = fake_home.path().to_str().unwrap(); + + // create .config file + let dot_config_file = fake_home.path().join(".config"); + let _ = File::create(dot_config_file).unwrap(); + + // create empty.rs + let empty_rs = fake_home.path().join("empty.rs"); + let _ = File::create(&empty_rs).unwrap(); + + let args = [empty_rs.to_str().unwrap()]; + let envs = &[("HOME", fake_home_str)]; + let (stdout, stderr) = rustfmt_with_extra(&args, Some(fake_home_str), envs); + + // Should pass without any errors + assert_eq!(stdout, ""); + assert_eq!(stderr, ""); +}