dtolnay / request-for-implementation

Crates that don't exist, but should

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Find rustup components installed under a different toolchain

dtolnay opened this issue · comments

In dtolnay/cargo-expand#39 I need to look for any rustfmt that may be installed on the system.

Currently what happens is that if the user has rustup component add rustfmt --toolchain stable but is running cargo +nightly expand, then somehow Cargo sets up the subcommand environment such that simply running Command::new("rustfmt") will end up running a shim that only tells you there is no rustfmt installed for the nightly toolchain. The thing is, I don't care whether the rustfmt I run is from the same toolchain as the cargo-expand binary. I would happily run the stable toolchain's rustfmt from the nightly toolchain's cargo-expand if I knew the path to the right binary.

pub fn find_installed_component(name: &str) -> Option<PathBuf>;

Intended usage:

use std::process::Command;

let which_rustfmt = find_installed_component("rustfmt");
match which_rustfmt {
    None => {
        /* there is no rustfmt on any toolchain */
    }
    Some(rustfmt) => {
        Command::new(rustfmt).args(...).spawn();
    }
}

This will be relevant to other Cargo subcommands too, so the implementation should go in a crate rather than directly in cargo-expand.

I think I can give this a spin but I wanted to ask a question. If the user has more than two toolchains installed and runs expand under nightly which does not have rustfmt but the other two toolchains do, does it matter which toolchain gets picked?

I would go for whichever toolchain reports the highest rustc version number. For example the rustc versions might be:

  • rustc 1.33.0-beta.3 (4df66ba86 2019-01-21)
  • rustc 1.32.0 (9fda7c223 2019-01-16)

in which case (for my use case) I would prefer to use rustfmt from 1.33.0-beta.3.

I worked on a prototype for a little bit. I know it's rough around the edges but I think it does what you have outlined in this issue. The example runs and prints out some components that I had on my system.

Here is the repository: https://github.com/gsquire/toolchain_find

Super! Want to cap it off by sending a PR to cargo-expand to use your crate? Then I'll close out this issue and check it off the list.

To confirm that it works, run:

rustup component remove rustfmt --toolchain nightly
rustup component add rustfmt --toolchain beta

# install cargo-expand from the current directory with your changes
cd cargo-expand
cargo install --path . --force

# try to expand just the main function from the main example in your crate
cd toolchain_find
cargo expand --example main main

The last line will require it to successfully find rustfmt. You should see it print just the main function with the printlns expanded, without use std::prelude::v1::*; and other header stuff at the top.

Sure, I'll see how that all goes and share the PR here when I think it's complete.

I was able to successfully go through that test case and it worked as intended. Hopefully you can reproduce it as well. The PR is: dtolnay/cargo-expand#45

Nicely done. I will close out this issue and mark it off the list.

I filed gsquire/toolchain_find#1 for one small follow up.