Repository: rust-lang/rust-analyzer
Pull request #12953 (2022-08-06 15:00:42)

Run stable `fmt` & `cargo` through `rustup`
`cargo test -p ide-assists` fails on Windows/x64/nightly:

```shell
> rustup self update
info: checking for self-updates
  rustup unchanged - 1.25.1

> rustup update
info: syncing channel updates for 'stable-x86_64-pc-windows-msvc'
info: syncing channel updates for 'nightly-x86_64-pc-windows-msvc'
info: checking for self-updates

   stable-x86_64-pc-windows-msvc unchanged - rustc 1.62.1 (e092d0b6b 2022-07-16)
  nightly-x86_64-pc-windows-msvc unchanged - rustc 1.64.0-nightly (affe0d3a0 2022-08-05)

info: cleaning up downloads & tmp directories

> rustup show
Default host: x86_64-pc-windows-msvc
rustup home:  C:\Users\stanc\.rustup

installed toolchains
--------------------

stable-x86_64-pc-windows-msvc
nightly-x86_64-pc-windows-msvc (default)

active toolchain
----------------

nightly-x86_64-pc-windows-msvc (default)
rustc 1.64.0-nightly (affe0d3a0 2022-08-05)

> cargo test -p ide-assists

test tests::sourcegen::sourcegen_assists_docs ... FAILED

failures:

---- tests::sourcegen::sourcegen_assists_docs stdout ----
thread 'tests::sourcegen::sourcegen_assists_docs' panicked at 'Failed to run rustfmt from toolchain 'stable'. Please run `rustup component add rustfmt --toolchain stable` to install it.', crates\sourcegen\src\lib.rs:141:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::sourcegen::sourcegen_assists_docs

test result: FAILED. 1576 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.82s

error: test failed, to rerun pass '-p ide-assists --lib'
```

After some investigation it seemed that [`cmd!`](https://github.com/rust-lang/rust-analyzer/blob/51705698bd66919435e4fcbc25d96bd7fc5583f4/crates/sourcegen/src/lib.rs#L139) didn't execute the expected (stable) rustfmt.

A simple `xshell` test failed too:

```rust
use xshell::{cmd, Shell};

fn main() {
    let sh = &Shell::new().unwrap();
    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
    let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default();
    println!("{version}");
}
```

Bypassing `xshell` and using `Command` directly failed too:

```rust
use std::process::{Command, Stdio};

fn main() {
    let child = Command::new("rustfmt")
        .arg("--version")
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .env("RUSTUP_TOOLCHAIN", "stable")
        .spawn()
        .expect("failed to start");
    let output = child.wait_with_output().unwrap();
    let version = String::from_utf8_lossy(&output.stdout);
    println!("{version}");
}
```

Spawning `cargo +stable fmt version` [failed too](https://github.com/rust-lang/rustup/issues/3036) with `error: no such subcommand: +stable`.

Only `rustup run stable` worked fine for both `cargo` and `fmt`.


Thanks to @lnicola for a live investigation session, hints and tips.


Patch:
diff --git a/crates/sourcegen/src/lib.rs b/crates/sourcegen/src/lib.rs
index ce0224ec74..4e0ee63f32 100644
--- a/crates/sourcegen/src/lib.rs
+++ b/crates/sourcegen/src/lib.rs
@@ -136,7 +136,7 @@ impl fmt::Display for Location {
 }
 
 fn ensure_rustfmt(sh: &Shell) {
-    let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default();
+    let version = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap_or_default();
     if !version.contains("stable") {
         panic!(
             "Failed to run rustfmt from toolchain 'stable'. \
@@ -147,13 +147,15 @@ fn ensure_rustfmt(sh: &Shell) {
 
 pub fn reformat(text: String) -> String {
     let sh = Shell::new().unwrap();
-    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
     ensure_rustfmt(&sh);
     let rustfmt_toml = project_root().join("rustfmt.toml");
-    let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
-        .stdin(text)
-        .read()
-        .unwrap();
+    let mut stdout = cmd!(
+        sh,
+        "rustup run stable rustfmt --config-path {rustfmt_toml} --config fn_single_line=true"
+    )
+    .stdin(text)
+    .read()
+    .unwrap();
     if !stdout.ends_with('\n') {
         stdout.push('\n');
     }


Test patch:
diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 18f95925d9..58099a58de 100644
--- a/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -13,9 +13,8 @@ use xshell::cmd;
 fn check_code_formatting() {
     let sh = &Shell::new().unwrap();
     sh.change_dir(sourcegen::project_root());
-    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
 
-    let out = cmd!(sh, "rustfmt --version").read().unwrap();
+    let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap();
     if !out.contains("stable") {
         panic!(
             "Failed to run rustfmt from toolchain 'stable'. \
@@ -23,9 +22,9 @@ fn check_code_formatting() {
         )
     }
 
-    let res = cmd!(sh, "cargo fmt -- --check").run();
+    let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run();
     if res.is_err() {
-        let _ = cmd!(sh, "cargo fmt").run();
+        let _ = cmd!(sh, "rustup run stable cargo fmt").run();
     }
     res.unwrap()
 }