2019-09-30 03:58:53 -05:00
|
|
|
//! FIXME: write short doc here
|
|
|
|
|
2019-10-23 10:13:40 -05:00
|
|
|
pub mod codegen;
|
2019-08-18 13:33:31 -05:00
|
|
|
|
2019-11-13 13:51:57 -06:00
|
|
|
use anyhow::Context;
|
|
|
|
pub use anyhow::Result;
|
2018-10-14 09:32:57 -05:00
|
|
|
use std::{
|
2019-11-13 13:51:57 -06:00
|
|
|
env, fs,
|
2019-07-04 15:05:17 -05:00
|
|
|
io::{Error as IoError, ErrorKind},
|
2018-10-15 13:54:27 -05:00
|
|
|
path::{Path, PathBuf},
|
2019-03-05 15:19:36 -06:00
|
|
|
process::{Command, Output, Stdio},
|
2018-10-14 09:32:57 -05:00
|
|
|
};
|
|
|
|
|
2019-10-23 10:13:40 -05:00
|
|
|
use crate::codegen::Mode;
|
2019-08-18 13:34:55 -05:00
|
|
|
|
2019-01-24 06:58:38 -06:00
|
|
|
const TOOLCHAIN: &str = "stable";
|
2018-10-15 13:54:27 -05:00
|
|
|
|
|
|
|
pub fn project_root() -> PathBuf {
|
2019-11-01 15:20:44 -05:00
|
|
|
Path::new(
|
|
|
|
&env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
|
|
|
|
)
|
|
|
|
.ancestors()
|
|
|
|
.nth(1)
|
|
|
|
.unwrap()
|
|
|
|
.to_path_buf()
|
2018-10-15 13:54:27 -05:00
|
|
|
}
|
2018-10-31 14:50:43 -05:00
|
|
|
|
2019-09-18 06:24:20 -05:00
|
|
|
pub struct Cmd<'a> {
|
|
|
|
pub unix: &'a str,
|
|
|
|
pub windows: &'a str,
|
|
|
|
pub work_dir: &'a str,
|
2019-07-27 06:35:18 -05:00
|
|
|
}
|
|
|
|
|
2019-09-18 06:24:20 -05:00
|
|
|
impl Cmd<'_> {
|
2019-07-27 06:35:18 -05:00
|
|
|
pub fn run(self) -> Result<()> {
|
|
|
|
if cfg!(windows) {
|
|
|
|
run(self.windows, self.work_dir)
|
|
|
|
} else {
|
|
|
|
run(self.unix, self.work_dir)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn run_with_output(self) -> Result<Output> {
|
|
|
|
if cfg!(windows) {
|
|
|
|
run_with_output(self.windows, self.work_dir)
|
|
|
|
} else {
|
|
|
|
run_with_output(self.unix, self.work_dir)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-31 14:50:43 -05:00
|
|
|
pub fn run(cmdline: &str, dir: &str) -> Result<()> {
|
2019-03-05 15:19:36 -06:00
|
|
|
do_run(cmdline, dir, |c| {
|
|
|
|
c.stdout(Stdio::inherit());
|
|
|
|
})
|
|
|
|
.map(|_| ())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run_with_output(cmdline: &str, dir: &str) -> Result<Output> {
|
|
|
|
do_run(cmdline, dir, |_| {})
|
2018-10-31 14:50:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run_rustfmt(mode: Mode) -> Result<()> {
|
2018-10-31 15:57:38 -05:00
|
|
|
match Command::new("rustup")
|
|
|
|
.args(&["run", TOOLCHAIN, "--", "cargo", "fmt", "--version"])
|
|
|
|
.stderr(Stdio::null())
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
.status()
|
|
|
|
{
|
|
|
|
Ok(status) if status.success() => (),
|
2019-11-13 13:51:57 -06:00
|
|
|
_ => install_rustfmt().context("install rustfmt")?,
|
2018-10-31 15:57:38 -05:00
|
|
|
};
|
|
|
|
|
2019-10-23 10:13:40 -05:00
|
|
|
if mode == Mode::Verify {
|
2019-02-08 05:49:43 -06:00
|
|
|
run(&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN), ".")?;
|
2018-10-31 14:50:43 -05:00
|
|
|
} else {
|
|
|
|
run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2018-10-31 15:57:38 -05:00
|
|
|
|
2018-12-29 15:19:35 -06:00
|
|
|
pub fn install_rustfmt() -> Result<()> {
|
2018-10-31 15:57:38 -05:00
|
|
|
run(&format!("rustup install {}", TOOLCHAIN), ".")?;
|
2019-02-08 05:49:43 -06:00
|
|
|
run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".")
|
2018-10-31 15:57:38 -05:00
|
|
|
}
|
2018-12-09 04:29:13 -06:00
|
|
|
|
2019-11-18 06:22:51 -06:00
|
|
|
pub fn install_pre_commit_hook() -> Result<()> {
|
|
|
|
let result_path =
|
|
|
|
PathBuf::from(format!("./.git/hooks/pre-commit{}", std::env::consts::EXE_SUFFIX));
|
2018-12-09 06:27:13 -06:00
|
|
|
if !result_path.exists() {
|
2019-11-18 06:22:51 -06:00
|
|
|
let me = std::env::current_exe()?;
|
|
|
|
fs::copy(me, result_path)?;
|
2018-12-09 04:29:13 -06:00
|
|
|
} else {
|
2019-06-15 13:48:50 -05:00
|
|
|
Err(IoError::new(ErrorKind::AlreadyExists, "Git hook already created"))?;
|
2018-12-09 04:29:13 -06:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2018-12-31 07:14:06 -06:00
|
|
|
|
2019-06-03 08:43:06 -05:00
|
|
|
pub fn run_clippy() -> Result<()> {
|
|
|
|
match Command::new("rustup")
|
|
|
|
.args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"])
|
|
|
|
.stderr(Stdio::null())
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
.status()
|
|
|
|
{
|
|
|
|
Ok(status) if status.success() => (),
|
2019-11-13 13:51:57 -06:00
|
|
|
_ => install_clippy().context("install clippy")?,
|
2019-06-03 08:43:06 -05:00
|
|
|
};
|
|
|
|
|
2019-06-04 01:24:47 -05:00
|
|
|
let allowed_lints = [
|
|
|
|
"clippy::collapsible_if",
|
|
|
|
"clippy::map_clone", // FIXME: remove when Iterator::copied stabilizes (1.36.0)
|
2019-06-04 17:05:38 -05:00
|
|
|
"clippy::needless_pass_by_value",
|
|
|
|
"clippy::nonminimal_bool",
|
|
|
|
"clippy::redundant_pattern_matching",
|
2019-06-04 01:24:47 -05:00
|
|
|
];
|
2019-06-03 08:43:06 -05:00
|
|
|
run(
|
|
|
|
&format!(
|
|
|
|
"rustup run {} -- cargo clippy --all-features --all-targets -- -A {}",
|
|
|
|
TOOLCHAIN,
|
|
|
|
allowed_lints.join(" -A ")
|
|
|
|
),
|
|
|
|
".",
|
|
|
|
)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn install_clippy() -> Result<()> {
|
|
|
|
run(&format!("rustup install {}", TOOLCHAIN), ".")?;
|
|
|
|
run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".")
|
|
|
|
}
|
|
|
|
|
2018-12-31 07:14:06 -06:00
|
|
|
pub fn run_fuzzer() -> Result<()> {
|
|
|
|
match Command::new("cargo")
|
|
|
|
.args(&["fuzz", "--help"])
|
|
|
|
.stderr(Stdio::null())
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
.status()
|
|
|
|
{
|
|
|
|
Ok(status) if status.success() => (),
|
|
|
|
_ => run("cargo install cargo-fuzz", ".")?,
|
|
|
|
};
|
|
|
|
|
2019-02-08 05:49:43 -06:00
|
|
|
run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax")
|
2018-12-31 07:14:06 -06:00
|
|
|
}
|
2019-01-26 17:03:52 -06:00
|
|
|
|
2019-11-18 06:22:51 -06:00
|
|
|
pub fn reformat_staged_files() -> Result<()> {
|
|
|
|
let root = project_root();
|
|
|
|
let output = Command::new("git")
|
|
|
|
.arg("diff")
|
|
|
|
.arg("--diff-filter=MAR")
|
|
|
|
.arg("--name-only")
|
|
|
|
.arg("--cached")
|
|
|
|
.current_dir(&root)
|
|
|
|
.output()?;
|
|
|
|
if !output.status.success() {
|
|
|
|
anyhow::bail!(
|
|
|
|
"`git diff --diff-filter=MAR --name-only --cached` exited with {}",
|
|
|
|
output.status
|
|
|
|
);
|
|
|
|
}
|
|
|
|
for line in String::from_utf8(output.stdout)?.lines() {
|
|
|
|
run(&format!("git update-index --add {}", root.join(line).to_string_lossy()), ".")?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-03-05 15:19:36 -06:00
|
|
|
fn do_run<F>(cmdline: &str, dir: &str, mut f: F) -> Result<Output>
|
|
|
|
where
|
|
|
|
F: FnMut(&mut Command),
|
|
|
|
{
|
|
|
|
eprintln!("\nwill run: {}", cmdline);
|
|
|
|
let proj_dir = project_root().join(dir);
|
|
|
|
let mut args = cmdline.split_whitespace();
|
|
|
|
let exec = args.next().unwrap();
|
|
|
|
let mut cmd = Command::new(exec);
|
|
|
|
f(cmd.args(args).current_dir(proj_dir).stderr(Stdio::inherit()));
|
2019-11-13 13:51:57 -06:00
|
|
|
let output = cmd.output().with_context(|| format!("running `{}`", cmdline))?;
|
2019-03-05 15:19:36 -06:00
|
|
|
if !output.status.success() {
|
2019-11-13 13:51:57 -06:00
|
|
|
anyhow::bail!("`{}` exited with {}", cmdline, output.status);
|
2019-03-05 15:19:36 -06:00
|
|
|
}
|
|
|
|
Ok(output)
|
|
|
|
}
|