Skip to content

Commit 873ba6e

Browse files
committed
Add cargo marker install rustc-driver
1 parent 8d6c683 commit 873ba6e

File tree

3 files changed

+128
-6
lines changed

3 files changed

+128
-6
lines changed

cargo-marker/src/driver.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//! This module hosts functions required to run rustc as a driver.
2+
//!
3+
//! The rustc driver depends on rustc, which interfaces is unstable. This means
4+
//! that each driver version is bound to a specific version of rustc. The same
5+
//! goes for Clippy. However, Clippy has the advantage, that it's distributes via
6+
//! rustup, which handles the version matching for it. We're not so lucky, at
7+
//! least not yet. Therefore, we're responsible that the driver is compiled and
8+
//! run with the correct toolchain.
9+
//!
10+
//! If no driver is installed, the user will be requested to run the setup command.
11+
//! That command will first ensure that the required toolchain is installed and then
12+
//! run `cargo install` for the driver with a specific toolchain. The version and
13+
//! toolchain are hardcoded in this crate.
14+
//!
15+
//! If a driver is already installed. We'll first run the driver to request the
16+
//! required toolchain and then run the driver using that toolchain. Requesting
17+
//! the toolchain works, since the argument will be processed before rustc is run.
18+
//! At least, that's the idea.
19+
20+
use std::process::Command;
21+
22+
use once_cell::sync::Lazy;
23+
24+
use crate::ExitStatus;
25+
26+
/// This is the driver version and toolchain, that is used by the setup command
27+
/// to install the driver.
28+
static DEFAULT_DRIVER_INFO: Lazy<RustcDriverInfo> = Lazy::new(|| RustcDriverInfo {
29+
toolchain: "nightly-2022-11-03".to_string(),
30+
version: "0.1.0".to_string(),
31+
});
32+
33+
struct RustcDriverInfo {
34+
toolchain: String,
35+
version: String,
36+
}
37+
38+
/// This function checks if the specified toolchain is installed. This requires
39+
/// rustup. A dependency we have to live with for now.
40+
fn check_toolchain(toolchain: &str) -> Result<(), ExitStatus> {
41+
let mut cmd = Command::new("cargo");
42+
cmd.args([&format!("+{toolchain}"), "-V"]);
43+
if cmd.output().is_err() {
44+
eprintln!("error: the required toolchain `{toolchain}` can't be found");
45+
eprintln!();
46+
eprintln!("You can install the toolchain by running: rustup toolchain install {toolchain}");
47+
Err(ExitStatus::InvalidToolchain)
48+
} else {
49+
Ok(())
50+
}
51+
}
52+
53+
/// This tries to install the rustc driver specified in [`DEFAULT_DRIVER_INFO`].
54+
pub fn install_driver(verbose: bool) -> Result<(), ExitStatus> {
55+
// Prerequisites
56+
let toolchain = &DEFAULT_DRIVER_INFO.toolchain;
57+
check_toolchain(&toolchain)?;
58+
59+
// Build driver
60+
let mut cmd = Command::new("cargo");
61+
cmd.arg(&format!("+{toolchain}"));
62+
63+
if verbose {
64+
cmd.arg("--verbose");
65+
}
66+
67+
#[cfg(feature = "dev-build")]
68+
cmd.args(["build", "--bin", "linter_driver_rustc"]);
69+
#[cfg(not(feature = "dev-build"))]
70+
cmd.args([
71+
"install",
72+
"marker_rustc_driver",
73+
"--version",
74+
&DEFAULT_DRIVER_INFO.version,
75+
]);
76+
77+
let status = cmd
78+
.spawn()
79+
.expect("unable to start cargo install for the driver")
80+
.wait()
81+
.expect("unable to wait on cargo install for the driver");
82+
if status.success() {
83+
Ok(())
84+
} else {
85+
// The user can see cargo's output, as the command output was passed on
86+
// to the user via the `.spawn()` call.
87+
Err(ExitStatus::DriverInstallationFailed)
88+
}
89+
}

cargo-marker/src/main.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,32 @@ use std::{
99
};
1010

1111
use clap::{self, Arg, ArgAction};
12-
use once_cell::sync::Lazy;
12+
use once_cell::sync::{Lazy, OnceCell};
13+
14+
mod driver;
1315

1416
const CARGO_ARGS_SEPARATOR: &str = "--";
1517
const VERSION: &str = concat!("cargo-marker ", env!("CARGO_PKG_VERSION"));
1618
const LINT_KRATES_BASE_DIR: &str = "./target/marker";
1719
static LINT_KRATES_TARGET_DIR: Lazy<String> = Lazy::new(|| prepare_lint_build_dir("build", "target"));
1820
static LINT_KRATES_OUT_DIR: Lazy<String> = Lazy::new(|| prepare_lint_build_dir("lints", "out"));
21+
static VERBOSE: OnceCell<bool> = OnceCell::new();
22+
23+
#[derive(Debug)]
24+
pub enum ExitStatus {
25+
/// The toolchain validation failed. This could happen, if rustup is not
26+
/// installed or the required toolchain is not installed.
27+
InvalidToolchain = 100,
28+
DriverInstallationFailed = 200,
29+
}
30+
31+
fn set_verbose(verbose: bool) {
32+
VERBOSE.set(verbose).unwrap();
33+
}
34+
35+
fn is_verbose() -> bool {
36+
VERBOSE.get().copied().unwrap_or_default()
37+
}
1938

2039
/// This creates the absolute path for a given build directory.
2140
fn prepare_lint_build_dir(dir_name: &str, info_name: &str) -> String {
@@ -38,18 +57,23 @@ fn prepare_lint_build_dir(dir_name: &str, info_name: &str) -> String {
3857
.to_string()
3958
}
4059

41-
fn main() {
60+
fn main() -> Result<(), ExitStatus> {
4261
let matches = get_clap_config().get_matches_from(
4362
std::env::args()
4463
.enumerate()
4564
.filter_map(|(index, value)| (!(index == 1 && value == "marker")).then_some(value))
4665
.take_while(|s| s != CARGO_ARGS_SEPARATOR),
4766
);
4867

68+
set_verbose(matches.get_flag("verbose"));
69+
4970
if matches.get_flag("version") {
50-
let version_info = env!("CARGO_PKG_VERSION");
51-
println!("cargo-marker version: {version_info}");
52-
exit(0);
71+
print_version();
72+
return Ok(());
73+
}
74+
75+
if !validate_toolchain() {
76+
return Err(ExitStatus::InvalidToolchain);
5377
}
5478

5579
let verbose = matches.get_flag("verbose");
@@ -87,6 +111,15 @@ fn main() {
87111
}
88112
}
89113

114+
fn print_version() {
115+
println!("cargo-marker version: {}", env!("CARGO_PKG_VERSION"));
116+
117+
if is_verbose() {
118+
println!("driver toolchain: {DRIVER_TOOLCHAIN}")
119+
}
120+
}
121+
122+
90123
fn run_driver(driver_path: &PathBuf, lint_crates: &str) {
91124
println!();
92125
println!("Start linting:");

util/update-toolchain.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
if [[ $1 == nightly-????-??-?? ]]
44
then
5-
sed -i "s/nightly-2022-11-03/$1/g" ./marker_driver_rustc/src/main.rs ./rust-toolchain .github/workflows/* ./util/update-toolchain.sh
5+
sed -i "s/nightly-2022-11-03/$1/g" ./marker_driver_rustc/src/main.rs ./rust-toolchain .github/workflows/* ./util/update-toolchain.sh cargo-marker/src/main.rs
66
else
77
echo "Please enter a valid toolchain like \`nightly-2022-01-01\`"
88
fi;

0 commit comments

Comments
 (0)