3 process::{Command, Stdio},
9 use itertools::Itertools;
11 pub use teraron::{Mode, Overwrite, Verify};
13 pub type Result<T> = std::result::Result<T, failure::Error>;
15 pub const GRAMMAR: &str = "crates/ra_syntax/src/grammar.ron";
16 pub const SYNTAX_KINDS: &str = "crates/ra_syntax/src/syntax_kinds/generated.rs.tera";
17 pub const AST: &str = "crates/ra_syntax/src/ast/generated.rs.tera";
18 const TOOLCHAIN: &str = "1.31.0";
26 pub fn collect_tests(s: &str) -> Vec<(usize, Test)> {
29 let comment_blocks = s
33 .group_by(|(_idx, line)| line.starts_with(prefix));
35 'outer: for (is_comment, block) in comment_blocks.into_iter() {
39 let mut block = block.map(|(idx, line)| (idx, &line[prefix.len()..]));
41 let (start_line, name) = loop {
43 Some((idx, line)) if line.starts_with("test ") => {
44 break (idx, line["test ".len()..].to_string());
47 None => continue 'outer,
50 let text: String = itertools::join(
51 block.map(|(_, line)| line).chain(::std::iter::once("")),
54 assert!(!text.trim().is_empty() && text.ends_with('\n'));
55 res.push((start_line, Test { name, text }))
60 pub fn generate(mode: Mode) -> Result<()> {
61 let grammar = project_root().join(GRAMMAR);
62 let syntax_kinds = project_root().join(SYNTAX_KINDS);
63 let ast = project_root().join(AST);
64 teraron::generate(&syntax_kinds, &grammar, mode)?;
65 teraron::generate(&ast, &grammar, mode)?;
69 pub fn project_root() -> PathBuf {
70 Path::new(&env!("CARGO_MANIFEST_DIR"))
77 pub fn run(cmdline: &str, dir: &str) -> Result<()> {
78 eprintln!("\nwill run: {}", cmdline);
79 let project_dir = project_root().join(dir);
80 let mut args = cmdline.split_whitespace();
81 let exec = args.next().unwrap();
82 let status = Command::new(exec)
84 .current_dir(project_dir)
86 if !status.success() {
87 bail!("`{}` exited with {}", cmdline, status);
92 pub fn run_rustfmt(mode: Mode) -> Result<()> {
93 match Command::new("rustup")
94 .args(&["run", TOOLCHAIN, "--", "cargo", "fmt", "--version"])
95 .stderr(Stdio::null())
96 .stdout(Stdio::null())
99 Ok(status) if status.success() => (),
100 _ => install_rustfmt()?,
105 &format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN),
109 run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
114 fn install_rustfmt() -> Result<()> {
115 run(&format!("rustup install {}", TOOLCHAIN), ".")?;
117 &format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN),
122 pub fn install_format_hook() -> Result<()> {
123 let result_path = Path::new("./.git/hooks/pre-commit");
124 if !result_path.exists() {
125 run("cargo build --package tools --bin pre-commit", ".")?;
127 copy("./target/debug/pre-commit.exe", result_path)?;
129 copy("./target/debug/pre-commit", result_path)?;
132 return Err(Error::new(ErrorKind::AlreadyExists, "Git hook already created").into());