about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-17 05:46:07 +0000
committerbors <bors@rust-lang.org>2024-04-17 05:46:07 +0000
commit1ba78212ffbe152c4921a8e39b1bd31b8d13523c (patch)
tree484674be85ee47591277823e88c5942d29f64cca
parentf5e250180c342bb52808c9a934c962a8fe40afc7 (diff)
parent1fff3bef4de408bdea2dd005755770ed3a92bb3d (diff)
downloadrust-1ba78212ffbe152c4921a8e39b1bd31b8d13523c.tar.gz
rust-1ba78212ffbe152c4921a8e39b1bd31b8d13523c.zip
Auto merge of #12680 - Alexendoo:cargo-dev-setup-toolchain, r=llogiq
Add `cargo dev setup toolchain`

Adds a `cargo dev setup toolchain` subcommand that creates a rustup toolchain with symlinks to the local `cargo-clippy` and `clippy-driver`. Allows you to then do `cargo +clippy clippy` in other projects to run the locally built Clippy

Sometimes more convenient when you're testing changes on a separate project than `cd`ing back & forth to use `cargo dev lint [project]`

changelog: none
-rw-r--r--book/src/development/adding_lints.md26
-rw-r--r--clippy_dev/src/fmt.rs1
-rw-r--r--clippy_dev/src/lib.rs1
-rw-r--r--clippy_dev/src/main.rs55
-rw-r--r--clippy_dev/src/new_lint.rs1
-rw-r--r--clippy_dev/src/setup/mod.rs1
-rw-r--r--clippy_dev/src/setup/toolchain.rs75
7 files changed, 131 insertions, 29 deletions
diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md
index e30a5f9fe10..b80ac6370e7 100644
--- a/book/src/development/adding_lints.md
+++ b/book/src/development/adding_lints.md
@@ -18,7 +18,6 @@ because that's clearly a non-descriptive name.
     - [Cargo lints](#cargo-lints)
   - [Rustfix tests](#rustfix-tests)
   - [Testing manually](#testing-manually)
-  - [Running directly](#running-directly)
   - [Lint declaration](#lint-declaration)
   - [Lint registration](#lint-registration)
   - [Lint passes](#lint-passes)
@@ -176,23 +175,26 @@ the tests.
 
 Manually testing against an example file can be useful if you have added some
 `println!`s and the test suite output becomes unreadable. To try Clippy with
-your local modifications, run
+your local modifications, run the following from the Clippy directory:
 
-```
+```bash
 cargo dev lint input.rs
 ```
 
-from the working copy root. With tests in place, let's have a look at
-implementing our lint now.
+To run Clippy on an existing project rather than a single file you can use
+
+```bash
+cargo dev lint /path/to/project
+```
+
+Or set up a rustup toolchain that points to the local Clippy binaries
 
-## Running directly
+```bash
+cargo dev setup toolchain
 
-While it's easier to just use `cargo dev lint`, it might be desirable to get
-`target/release/cargo-clippy` and `target/release/clippy-driver` to work as well in some cases.
-By default, they don't work because clippy dynamically links rustc. To help them find rustc,
-add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches)
-to your library search path.
-On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path.
+# Then in `/path/to/project` you can run
+cargo +clippy clippy
+```
 
 ## Lint declaration
 
diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs
index ee559d45dd1..25623144181 100644
--- a/clippy_dev/src/fmt.rs
+++ b/clippy_dev/src/fmt.rs
@@ -35,7 +35,6 @@ struct FmtContext {
 }
 
 // the "main" function of cargo dev fmt
-#[allow(clippy::missing_panics_doc)]
 pub fn run(check: bool, verbose: bool) {
     fn try_run(context: &FmtContext) -> Result<bool, CliError> {
         let mut success = true;
diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs
index bb62e902cd5..385191e0361 100644
--- a/clippy_dev/src/lib.rs
+++ b/clippy_dev/src/lib.rs
@@ -9,6 +9,7 @@
     unused_lifetimes,
     unused_qualifications
 )]
+#![allow(clippy::missing_panics_doc)]
 
 // The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate.
 #[allow(unused_extern_crates)]
diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs
index 5bd9994e18d..397a0e99082 100644
--- a/clippy_dev/src/main.rs
+++ b/clippy_dev/src/main.rs
@@ -46,6 +46,13 @@ fn main() {
             }
         },
         Some(("setup", sub_command)) => match sub_command.subcommand() {
+            Some(("git-hook", matches)) => {
+                if matches.get_flag("remove") {
+                    setup::git_hook::remove_hook();
+                } else {
+                    setup::git_hook::install_hook(matches.get_flag("force-override"));
+                }
+            },
             Some(("intellij", matches)) => {
                 if matches.get_flag("remove") {
                     setup::intellij::remove_rustc_src();
@@ -57,12 +64,12 @@ fn main() {
                     );
                 }
             },
-            Some(("git-hook", matches)) => {
-                if matches.get_flag("remove") {
-                    setup::git_hook::remove_hook();
-                } else {
-                    setup::git_hook::install_hook(matches.get_flag("force-override"));
-                }
+            Some(("toolchain", matches)) => {
+                setup::toolchain::create(
+                    matches.get_flag("force"),
+                    matches.get_flag("release"),
+                    matches.get_one::<String>("name").unwrap(),
+                );
             },
             Some(("vscode-tasks", matches)) => {
                 if matches.get_flag("remove") {
@@ -210,6 +217,19 @@ fn get_clap_config() -> ArgMatches {
                 .about("Support for setting up your personal development environment")
                 .arg_required_else_help(true)
                 .subcommands([
+                    Command::new("git-hook")
+                        .about("Add a pre-commit git hook that formats your code to make it look pretty")
+                        .args([
+                            Arg::new("remove")
+                                .long("remove")
+                                .action(ArgAction::SetTrue)
+                                .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"),
+                            Arg::new("force-override")
+                                .long("force-override")
+                                .short('f')
+                                .action(ArgAction::SetTrue)
+                                .help("Forces the override of an existing git pre-commit hook"),
+                        ]),
                     Command::new("intellij")
                         .about("Alter dependencies so Intellij Rust can find rustc internals")
                         .args([
@@ -225,18 +245,23 @@ fn get_clap_config() -> ArgMatches {
                                 .conflicts_with("remove")
                                 .required(true),
                         ]),
-                    Command::new("git-hook")
-                        .about("Add a pre-commit git hook that formats your code to make it look pretty")
+                    Command::new("toolchain")
+                        .about("Install a rustup toolchain pointing to the local clippy build")
                         .args([
-                            Arg::new("remove")
-                                .long("remove")
-                                .action(ArgAction::SetTrue)
-                                .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"),
-                            Arg::new("force-override")
-                                .long("force-override")
+                            Arg::new("force")
+                                .long("force")
                                 .short('f')
                                 .action(ArgAction::SetTrue)
-                                .help("Forces the override of an existing git pre-commit hook"),
+                                .help("Override an existing toolchain"),
+                            Arg::new("release")
+                                .long("release")
+                                .short('r')
+                                .action(ArgAction::SetTrue)
+                                .help("Point to --release clippy binaries"),
+                            Arg::new("name")
+                                .long("name")
+                                .default_value("clippy")
+                                .help("The name of the created toolchain"),
                         ]),
                     Command::new("vscode-tasks")
                         .about("Add several tasks to vscode for formatting, validation and testing")
diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs
index 5d9cde06cd8..2940d56350f 100644
--- a/clippy_dev/src/new_lint.rs
+++ b/clippy_dev/src/new_lint.rs
@@ -36,7 +36,6 @@ impl<T> Context for io::Result<T> {
 /// # Errors
 ///
 /// This function errors out if the files couldn't be created or written to.
-#[allow(clippy::missing_panics_doc)]
 pub fn create(
     pass: &String,
     lint_name: Option<&String>,
diff --git a/clippy_dev/src/setup/mod.rs b/clippy_dev/src/setup/mod.rs
index f691ae4fa45..b0d31814639 100644
--- a/clippy_dev/src/setup/mod.rs
+++ b/clippy_dev/src/setup/mod.rs
@@ -1,5 +1,6 @@
 pub mod git_hook;
 pub mod intellij;
+pub mod toolchain;
 pub mod vscode;
 
 use std::path::Path;
diff --git a/clippy_dev/src/setup/toolchain.rs b/clippy_dev/src/setup/toolchain.rs
new file mode 100644
index 00000000000..8d98c6c92d9
--- /dev/null
+++ b/clippy_dev/src/setup/toolchain.rs
@@ -0,0 +1,75 @@
+use std::env::consts::EXE_SUFFIX;
+use std::env::current_dir;
+use std::ffi::OsStr;
+use std::fs;
+use std::path::{Path, PathBuf};
+use walkdir::WalkDir;
+
+use super::verify_inside_clippy_dir;
+
+pub fn create(force: bool, release: bool, name: &str) {
+    if !verify_inside_clippy_dir() {
+        return;
+    }
+
+    let rustup_home = std::env::var("RUSTUP_HOME").unwrap();
+    let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap();
+
+    let src = PathBuf::from_iter([&rustup_home, "toolchains", &toolchain]);
+    let dest = PathBuf::from_iter([&rustup_home, "toolchains", name]);
+
+    if dest.exists() {
+        if force {
+            fs::remove_dir_all(&dest).unwrap();
+        } else {
+            println!("{} already exists, pass `--force` to override it", dest.display());
+            return;
+        }
+    }
+
+    for entry in WalkDir::new(&src) {
+        let entry = entry.unwrap();
+        let relative = entry.path().strip_prefix(&src).unwrap();
+
+        if relative.starts_with("bin")
+            && matches!(
+                relative.file_stem().and_then(OsStr::to_str),
+                Some("cargo-clippy" | "clippy-driver")
+            )
+        {
+            continue;
+        }
+
+        let target = dest.join(relative);
+        if entry.file_type().is_dir() {
+            fs::create_dir(&target).unwrap();
+        } else {
+            fs::hard_link(entry.path(), target).unwrap();
+        }
+    }
+
+    symlink_bin("cargo-clippy", &dest, release);
+    symlink_bin("clippy-driver", &dest, release);
+
+    println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`");
+    println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes");
+}
+
+fn symlink_bin(bin: &str, dest: &Path, release: bool) {
+    #[cfg(windows)]
+    use std::os::windows::fs::symlink_file as symlink;
+
+    #[cfg(not(windows))]
+    use std::os::unix::fs::symlink;
+
+    let profile = if release { "release" } else { "debug" };
+    let file_name = format!("{bin}{EXE_SUFFIX}");
+
+    let mut src = current_dir().unwrap();
+    src.extend(["target", profile, &file_name]);
+
+    let mut dest = dest.to_path_buf();
+    dest.extend(["bin", &file_name]);
+
+    symlink(src, dest).unwrap();
+}