From fd8e9ea2322ee0bab488a93c4d03d5b11ed7065d Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:16:04 -0400 Subject: [PATCH 1/6] refactor: move `bevy_lint_driver` to `bevy_lint` --- Cargo.toml | 5 ----- bevy_lint/Cargo.toml | 5 +++++ src/bin/lint_driver.rs => bevy_lint/src/bin/driver.rs | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename src/bin/lint_driver.rs => bevy_lint/src/bin/driver.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 7d76d19c..1cb2e3ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,11 +14,6 @@ default-run = "bevy" name = "bevy" path = "src/bin/main.rs" -# Integrates custom lints with `rustc` -[[bin]] -name = "bevy_lint_driver" -path = "src/bin/lint_driver.rs" - [dependencies] # CLI argument parsing clap = { version = "4.5.16", features = ["derive"] } diff --git a/bevy_lint/Cargo.toml b/bevy_lint/Cargo.toml index 32dc83f0..8849ec52 100644 --- a/bevy_lint/Cargo.toml +++ b/bevy_lint/Cargo.toml @@ -4,6 +4,11 @@ version = "0.1.0-dev" edition = "2021" license = "MIT OR Apache-2.0" +# Integrates custom lints with `rustc`. +[[bin]] +name = "bevy_lint_driver" +path = "src/bin/driver.rs" + # Contains a series of useful utilities when writing lints. The version and commit were chosen to # work with the currently pinned nightly Rust version. When the Rust version changes, this too # needs to be updated! diff --git a/src/bin/lint_driver.rs b/bevy_lint/src/bin/driver.rs similarity index 100% rename from src/bin/lint_driver.rs rename to bevy_lint/src/bin/driver.rs From fb9339cf62dff74c3544c5927be6cfc26da3ebea Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:45:17 -0400 Subject: [PATCH 2/6] feat: remove direct dependency from `bevy_cli` to `bevy_lint` --- Cargo.lock | 2 +- Cargo.toml | 3 --- bevy_lint/Cargo.toml | 8 ++++++ bevy_lint/src/bin/main.rs | 38 ++++++++++++++++++++++++++ src/lint.rs | 56 +++++++++++++++++++++------------------ 5 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 bevy_lint/src/bin/main.rs diff --git a/Cargo.lock b/Cargo.lock index 98e70cdc..c9eee873 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,7 +132,6 @@ name = "bevy_cli" version = "0.1.0-dev" dependencies = [ "anyhow", - "bevy_lint", "cargo-generate", "clap", ] @@ -141,6 +140,7 @@ dependencies = [ name = "bevy_lint" version = "0.1.0-dev" dependencies = [ + "anyhow", "clippy_utils", ] diff --git a/Cargo.toml b/Cargo.toml index 1cb2e3ef..086c5ab6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,3 @@ anyhow = "1.0.86" # Generates new Bevy projects from templates cargo-generate = "0.21.3" - -# Bevy-specific lints -bevy_lint = { version = "0.1.0-dev", path = "./bevy_lint" } diff --git a/bevy_lint/Cargo.toml b/bevy_lint/Cargo.toml index 8849ec52..1d5c3368 100644 --- a/bevy_lint/Cargo.toml +++ b/bevy_lint/Cargo.toml @@ -3,12 +3,20 @@ name = "bevy_lint" version = "0.1.0-dev" edition = "2021" license = "MIT OR Apache-2.0" +default-run = "bevy_lint" + +[[bin]] +name = "bevy_lint" +path = "src/bin/main.rs" # Integrates custom lints with `rustc`. [[bin]] name = "bevy_lint_driver" path = "src/bin/driver.rs" +[dependencies] +anyhow = "1.0.86" + # Contains a series of useful utilities when writing lints. The version and commit were chosen to # work with the currently pinned nightly Rust version. When the Rust version changes, this too # needs to be updated! diff --git a/bevy_lint/src/bin/main.rs b/bevy_lint/src/bin/main.rs new file mode 100644 index 00000000..253c5912 --- /dev/null +++ b/bevy_lint/src/bin/main.rs @@ -0,0 +1,38 @@ +use anyhow::{anyhow, ensure, Context}; +use std::{env, process::Command}; + +fn main() -> anyhow::Result<()> { + // The `bevy_lint` lives in the same folder as `bevy_lint_driver`, so we can easily find it + // using the path of the current executable. + let mut driver_path = env::current_exe() + .context("Failed to retrieve the path to the current executable.")? + .parent() + .ok_or(anyhow!("Path to file must have a parent."))? + .join("bevy_lint_driver"); + + #[cfg(target_os = "windows")] + driver_path.set_extension("exe"); + + ensure!( + driver_path.exists(), + "Could not find `bevy_lint_driver` at {driver_path:?}, please ensure it is installed!", + ); + + // Convert the local path to the absolute path. We don't want `rustc` getting + // confused! `canonicalize()` requires for the path to exist, so we do it after the nice error + // message. + driver_path = driver_path.canonicalize()?; + + // Run `cargo check`. + let status = Command::new("cargo") + .arg("check") + // This instructs `rustc` to call `bevy_lint_driver` instead of its default routine. + // This lets us register custom lints. + .env("RUSTC_WORKSPACE_WRAPPER", driver_path) + .status() + .context("Failed to spawn `cargo check`.")?; + + ensure!(status.success(), "Check failed with non-zero exit code."); + + Ok(()) +} diff --git a/src/lint.rs b/src/lint.rs index 5f3f5ee5..522da79c 100644 --- a/src/lint.rs +++ b/src/lint.rs @@ -1,38 +1,42 @@ use anyhow::{anyhow, ensure, Context}; -use std::{env, process::Command}; +use std::{env, path::PathBuf, process::Command}; +/// Runs `bevy_lint` if it is installed. pub fn lint() -> anyhow::Result<()> { - // The `bevy` CLI lives in the same folder as `bevy_lint_driver`, so we can easily find it - // using the path of the current executable. - let mut driver_path = env::current_exe() - .context("Failed to retrieve the path to the current executable.")? - .parent() - .ok_or(anyhow!("Path to file must have a parent."))? - .join("bevy_lint_driver"); + let bevy_lint_path = find_bevy_lint()?; - #[cfg(target_os = "windows")] - driver_path.set_extension("exe"); + // TODO: Add arguments. + let status = Command::new(bevy_lint_path).status()?; ensure!( - driver_path.exists(), - "Could not find `bevy_lint_driver` at {driver_path:?}, please ensure it is installed!", + status.success(), + "`bevy_lint` exited with a non-zero exit code." ); - // Convert the local path to the absolute path. We don't want `rustc` getting - // confused! `canonicalize()` requires for the path to exist, so we do it after the nice error - // message. - driver_path = driver_path.canonicalize()?; + Ok(()) +} - // Run `cargo check`. - let status = Command::new("cargo") - .arg("check") - // This instructs `rustc` to call `bevy_lint_driver` instead of its default routine. - // This lets us register custom lints. - .env("RUSTC_WORKSPACE_WRAPPER", driver_path) - .status() - .context("Failed to spawn `cargo check`.")?; +/// Tries the find the path to `bevy_lint`, if it is installed. +pub fn find_bevy_lint() -> anyhow::Result { + let mut bevy_lint_path = env::current_exe() + .context("Failed to retrieve the path to the current executable.")? + .parent() + .ok_or(anyhow!("Path to file must have a parent."))? + .join("bevy_lint"); + + #[cfg(target_os = "windows")] + bevy_lint_path.set_extension("exe"); - ensure!(status.success(), "Check failed with non-zero exit code."); + if cfg!(debug_assertions) { + ensure!( + bevy_lint_path.exists(), + "`bevy_lint` could not be found at {bevy_lint_path:?}. Please run `cargo build -p bevy_lint` first!", + ); + } else { + ensure!(bevy_lint_path.exists(), "`bevy_lint` could not be found at {bevy_lint_path:?}. Please follow the instructions in the Bevy CLI `README.md` to install it."); + } - Ok(()) + bevy_lint_path = bevy_lint_path.canonicalize()?; + + Ok(bevy_lint_path) } From 282609e09964942be3090a016092b90a12ecb856 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 2 Sep 2024 17:09:40 -0400 Subject: [PATCH 3/6] feat: pass all arguments to `bevy lint` to the underlying `bevy_lint` binary --- src/bin/main.rs | 12 ++++++++++-- src/lint.rs | 7 +++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 59afd6ce..b78a5b28 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -8,7 +8,9 @@ fn main() -> Result<()> { Subcommands::New(new) => { bevy_cli::template::generate_template(&new.name, new.template.as_deref())?; } - Subcommands::Lint => bevy_cli::lint::lint()?, + Subcommands::Lint { args } => { + bevy_cli::lint::lint(args)?; + } } Ok(()) @@ -32,7 +34,13 @@ pub enum Subcommands { /// Create a new Bevy project from a specified template. New(NewArgs), /// Check the current project using Bevy-specific lints. - Lint, + /// + /// To see the full list of options, run `bevy lint -- --help`. + Lint { + /// A list of arguments to be passed to `bevy_lint`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + args: Vec, + }, } /// Arguments for creating a new Bevy project. diff --git a/src/lint.rs b/src/lint.rs index 522da79c..f85216c5 100644 --- a/src/lint.rs +++ b/src/lint.rs @@ -1,12 +1,11 @@ use anyhow::{anyhow, ensure, Context}; use std::{env, path::PathBuf, process::Command}; -/// Runs `bevy_lint` if it is installed. -pub fn lint() -> anyhow::Result<()> { +/// Runs `bevy_lint` if it is installed with the given arguments. +pub fn lint(args: Vec) -> anyhow::Result<()> { let bevy_lint_path = find_bevy_lint()?; - // TODO: Add arguments. - let status = Command::new(bevy_lint_path).status()?; + let status = Command::new(bevy_lint_path).args(args).status()?; ensure!( status.success(), From 82ac5b403d83ac25a6546024bd66d0f442ea7a2f Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 2 Sep 2024 17:22:54 -0400 Subject: [PATCH 4/6] chore: improve documentation --- src/bin/main.rs | 7 ++++--- src/lint.rs | 9 ++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index b78a5b28..b5f4aa93 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -8,9 +8,7 @@ fn main() -> Result<()> { Subcommands::New(new) => { bevy_cli::template::generate_template(&new.name, new.template.as_deref())?; } - Subcommands::Lint { args } => { - bevy_cli::lint::lint(args)?; - } + Subcommands::Lint { args } => bevy_cli::lint::lint(args)?, } Ok(()) @@ -35,6 +33,9 @@ pub enum Subcommands { New(NewArgs), /// Check the current project using Bevy-specific lints. /// + /// This command requires `bevy_lint` to be installed, and will fail if it is not. Please see + /// for installation instructions. + /// /// To see the full list of options, run `bevy lint -- --help`. Lint { /// A list of arguments to be passed to `bevy_lint`. diff --git a/src/lint.rs b/src/lint.rs index f85216c5..38234c1d 100644 --- a/src/lint.rs +++ b/src/lint.rs @@ -1,7 +1,10 @@ use anyhow::{anyhow, ensure, Context}; use std::{env, path::PathBuf, process::Command}; -/// Runs `bevy_lint` if it is installed with the given arguments. +/// Runs `bevy_lint`, if it is installed, with the given arguments. +/// +/// Calling `lint(vec!["--workspace"])` is equivalent to calling `bevy_lint --workspace` in the +/// terminal. This will run [`find_bevy_lint()`] to locate `bevy_lint`. pub fn lint(args: Vec) -> anyhow::Result<()> { let bevy_lint_path = find_bevy_lint()?; @@ -16,6 +19,10 @@ pub fn lint(args: Vec) -> anyhow::Result<()> { } /// Tries the find the path to `bevy_lint`, if it is installed. +/// +/// The current strategy will find a file named `bevy_lint(.exe)` within the same directory as the +/// current executable, which is usually `~/.cargo/bin` or `target/debug`. It will **not** search +/// the `PATH`. pub fn find_bevy_lint() -> anyhow::Result { let mut bevy_lint_path = env::current_exe() .context("Failed to retrieve the path to the current executable.")? From dc4d4ba2aed52e101d24666a41a701fb50d5456c Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 2 Sep 2024 17:34:05 -0400 Subject: [PATCH 5/6] refactor: merge `driver` module with `bevy_lint_driver` binary --- bevy_lint/src/bin/driver.rs | 21 +++++++++++++-------- bevy_lint/src/driver.rs | 17 ----------------- bevy_lint/src/lib.rs | 3 ++- 3 files changed, 15 insertions(+), 26 deletions(-) delete mode 100644 bevy_lint/src/driver.rs diff --git a/bevy_lint/src/bin/driver.rs b/bevy_lint/src/bin/driver.rs index f6e5cd25..d0b34d36 100644 --- a/bevy_lint/src/bin/driver.rs +++ b/bevy_lint/src/bin/driver.rs @@ -1,12 +1,17 @@ -//! This is built into the `bevy_lint_driver` executable. This file does not actually contain any -//! logic, it simply calls [`bevy_lint::driver::main()`] and exits. - -// `bevy_lint` uses the `rustc_private` feature, so in order for us to call `bevy_lint` we must also -// opt-in to `rustc_private`. +// Enables linking to `rustc` crates. #![feature(rustc_private)] -use std::process::ExitCode; +extern crate rustc_driver; +extern crate rustc_span; + +use bevy_lint::BevyLintCallback; +use rustc_span::ErrorGuaranteed; + +fn main() -> Result<(), ErrorGuaranteed> { + // The arguments are formatted as `[DRIVER_PATH, RUSTC_PATH, ARGS...]`. We skip the driver path + // so that `RunCompiler` just sees `rustc`'s path. + let args: Vec = std::env::args().skip(1).collect(); -fn main() -> ExitCode { - bevy_lint::driver::main() + // Call the compiler with our custom callback. + rustc_driver::RunCompiler::new(&args, &mut BevyLintCallback).run() } diff --git a/bevy_lint/src/driver.rs b/bevy_lint/src/driver.rs deleted file mode 100644 index e442a6c2..00000000 --- a/bevy_lint/src/driver.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Contains code related to writing `bevy_lint_driver`. - -use crate::callback::BevyLintCallback; -use std::process::ExitCode; - -/// This is the main entrypoint into the driver, exported so that `bevy_cli` may call it. -pub fn main() -> ExitCode { - let args: Vec = dbg!(std::env::args().skip(1).collect()); - - // Call the compiler with our custom callback. - let result = rustc_driver::RunCompiler::new(&args, &mut BevyLintCallback).run(); - - match result { - Ok(_) => ExitCode::SUCCESS, - Err(_) => ExitCode::FAILURE, - } -} diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 8684529a..15553cfa 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -7,4 +7,5 @@ extern crate rustc_driver; extern crate rustc_interface; mod callback; -pub mod driver; + +pub use self::callback::BevyLintCallback; From 3188a93d6b552e2f3570cd4ac9e1b276b0e4c51b Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 3 Sep 2024 08:03:08 -0400 Subject: [PATCH 6/6] feat: address reviewer feedback --- src/lint.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lint.rs b/src/lint.rs index 38234c1d..c2f7a82e 100644 --- a/src/lint.rs +++ b/src/lint.rs @@ -36,10 +36,15 @@ pub fn find_bevy_lint() -> anyhow::Result { if cfg!(debug_assertions) { ensure!( bevy_lint_path.exists(), - "`bevy_lint` could not be found at {bevy_lint_path:?}. Please run `cargo build -p bevy_lint` first!", + "`bevy_lint` could not be found at {}. Please run `cargo build -p bevy_lint` first!", + bevy_lint_path.display(), ); } else { - ensure!(bevy_lint_path.exists(), "`bevy_lint` could not be found at {bevy_lint_path:?}. Please follow the instructions in the Bevy CLI `README.md` to install it."); + ensure!( + bevy_lint_path.exists(), + "`bevy_lint` could not be found at {}. Please follow the instructions at to install it.", + bevy_lint_path.display(), + ); } bevy_lint_path = bevy_lint_path.canonicalize()?;