Added cargo dev setup git-hook
This commit is contained in:
parent
0941d9f14d
commit
0a5f28c4b0
@ -14,9 +14,9 @@ use walkdir::WalkDir;
|
||||
|
||||
pub mod bless;
|
||||
pub mod fmt;
|
||||
pub mod setup;
|
||||
pub mod new_lint;
|
||||
pub mod serve;
|
||||
pub mod setup;
|
||||
pub mod stderr_length_check;
|
||||
pub mod update_lints;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use clippy_dev::{bless, fmt, setup, new_lint, serve, stderr_length_check, update_lints};
|
||||
use clippy_dev::{bless, fmt, new_lint, serve, setup, stderr_length_check, update_lints};
|
||||
fn main() {
|
||||
let matches = get_clap_config();
|
||||
|
||||
@ -36,7 +36,11 @@ fn main() {
|
||||
("limit_stderr_length", _) => {
|
||||
stderr_length_check::check();
|
||||
},
|
||||
("ide_setup", Some(matches)) => setup::intellij::run(matches.value_of("rustc-repo-path")),
|
||||
("setup", Some(sub_command)) => match sub_command.subcommand() {
|
||||
("intellij", Some(matches)) => setup::intellij::run(matches.value_of("rustc-repo-path")),
|
||||
("git-hook", Some(matches)) => setup::git_hook::run(matches.is_present("force-override")),
|
||||
_ => {},
|
||||
},
|
||||
("serve", Some(matches)) => {
|
||||
let port = matches.value_of("port").unwrap().parse().unwrap();
|
||||
let lint = matches.value_of("lint");
|
||||
@ -140,16 +144,31 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
|
||||
.about("Ensures that stderr files do not grow longer than a certain amount of lines."),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("ide_setup")
|
||||
.about("Alter dependencies so Intellij Rust can find rustc internals")
|
||||
.arg(
|
||||
Arg::with_name("rustc-repo-path")
|
||||
.long("repo-path")
|
||||
.short("r")
|
||||
.help("The path to a rustc repo that will be used for setting the dependencies")
|
||||
.takes_value(true)
|
||||
.value_name("path")
|
||||
.required(true),
|
||||
SubCommand::with_name("setup")
|
||||
.about("Support for setting up your personal development environment")
|
||||
.subcommand(
|
||||
SubCommand::with_name("intellij")
|
||||
.about("Alter dependencies so Intellij Rust can find rustc internals")
|
||||
.arg(
|
||||
Arg::with_name("rustc-repo-path")
|
||||
.long("repo-path")
|
||||
.short("r")
|
||||
.help("The path to a rustc repo that will be used for setting the dependencies")
|
||||
.takes_value(true)
|
||||
.value_name("path")
|
||||
.required(true),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("git-hook")
|
||||
.about("Add a pre-commit git hook that formats your code to make it look pretty")
|
||||
.arg(
|
||||
Arg::with_name("force-override")
|
||||
.long("force-override")
|
||||
.short("f")
|
||||
.help("Forces the override of an existing git pre-commit hook")
|
||||
.required(false),
|
||||
),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
|
61
clippy_dev/src/setup/git_hook.rs
Normal file
61
clippy_dev/src/setup/git_hook.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
/// Rusts setup uses `git rev-parse --git-common-dir` to get the root directory of the repo.
|
||||
/// I've decided against this for the sake of simplicity and to make sure that it doesn't install
|
||||
/// the hook if `clippy_dev` would be used in the rust tree. The hook also references this tool
|
||||
/// for formatting and should therefor only be used in a normal clone of clippy
|
||||
const REPO_GIT_DIR: &str = ".git";
|
||||
const HOOK_SOURCE_PATH: &str = "util/etc/pre-commit.sh";
|
||||
const HOOK_TARGET_PATH: &str = ".git/hooks/pre-commit";
|
||||
|
||||
pub fn run(force_override: bool) {
|
||||
if let Err(_) = check_precondition(force_override) {
|
||||
return;
|
||||
}
|
||||
|
||||
// So a little bit of a funny story. Git on unix requires the pre-commit file
|
||||
// to have the `execute` permission to be set. The Rust functions for modifying
|
||||
// these flags doesn't seem to work when executed with normal user permissions.
|
||||
//
|
||||
// However, there is a little hack that is also being used by Rust itself in their
|
||||
// setup script. Git saves the `execute` flag when syncing files. This means
|
||||
// that we can check in a file with execution permissions and the sync it to create
|
||||
// a file with the flag set. We then copy this file here. The copy function will also
|
||||
// include the `execute` permission.
|
||||
match fs::copy(HOOK_SOURCE_PATH, HOOK_TARGET_PATH) {
|
||||
Ok(_) => println!("Git hook successfully installed :)"),
|
||||
Err(err) => println!(
|
||||
"error: unable to copy `{}` to `{}` ({})",
|
||||
HOOK_SOURCE_PATH, HOOK_TARGET_PATH, err
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_precondition(force_override: bool) -> Result<(), ()> {
|
||||
// Make sure that we can find the git repository
|
||||
let git_path = Path::new(REPO_GIT_DIR);
|
||||
if !git_path.exists() || !git_path.is_dir() {
|
||||
println!("error: clippy_dev was unable to find the `.git` directory");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Make sure that we don't override an existing hook by accident
|
||||
let path = Path::new(HOOK_TARGET_PATH);
|
||||
if path.exists() {
|
||||
if !force_override {
|
||||
println!("warn: The found `.git` directory already has a commit hook");
|
||||
}
|
||||
|
||||
if force_override || super::ask_yes_no_question("Do you want to override it?") {
|
||||
if fs::remove_file(path).is_err() {
|
||||
println!("error: unable to delete existing pre-commit git hook");
|
||||
return Err(());
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1 +1,30 @@
|
||||
pub mod intellij;
|
||||
use std::io::{self, Write};
|
||||
pub mod git_hook;
|
||||
pub mod intellij;
|
||||
|
||||
/// This function will asked the user the given question and wait for user input
|
||||
/// either `true` for yes and `false` for no.
|
||||
fn ask_yes_no_question(question: &str) -> bool {
|
||||
// This code was proudly stolen from rusts bootstrapping tool.
|
||||
|
||||
fn ask_with_result(question: &str) -> io::Result<bool> {
|
||||
let mut input = String::new();
|
||||
Ok(loop {
|
||||
print!("{}: [y/N] ", question);
|
||||
io::stdout().flush()?;
|
||||
input.clear();
|
||||
io::stdin().read_line(&mut input)?;
|
||||
break match input.trim().to_lowercase().as_str() {
|
||||
"y" | "yes" => true,
|
||||
"n" | "no" | "" => false,
|
||||
_ => {
|
||||
println!("error: unrecognized option '{}'", input.trim());
|
||||
println!("note: press Ctrl+C to exit");
|
||||
continue;
|
||||
},
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
ask_with_result(question).unwrap_or_default()
|
||||
}
|
||||
|
3
util/etc/pre-commit.sh
Executable file
3
util/etc/pre-commit.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
cargo dev fmt
|
Loading…
x
Reference in New Issue
Block a user