diff options
-rw-r--r-- | xtask/src/lib.rs | 111 | ||||
-rw-r--r-- | xtask/src/not_bash.rs | 60 |
2 files changed, 79 insertions, 92 deletions
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index bf4d85dcb..2b7a461e5 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs | |||
@@ -12,21 +12,18 @@ mod ast_src; | |||
12 | 12 | ||
13 | use std::{ | 13 | use std::{ |
14 | env, | 14 | env, |
15 | io::Write, | ||
16 | path::{Path, PathBuf}, | 15 | path::{Path, PathBuf}, |
17 | process::{Command, Stdio}, | ||
18 | }; | 16 | }; |
17 | |||
19 | use walkdir::{DirEntry, WalkDir}; | 18 | use walkdir::{DirEntry, WalkDir}; |
20 | 19 | ||
21 | use crate::{ | 20 | use crate::{ |
22 | codegen::Mode, | 21 | codegen::Mode, |
23 | not_bash::{date_iso, fs2, pushd, rm_rf, run}, | 22 | not_bash::{date_iso, fs2, pushd, pushenv, rm_rf, run}, |
24 | }; | 23 | }; |
25 | 24 | ||
26 | pub use anyhow::{bail, Context as _, Result}; | 25 | pub use anyhow::{bail, Context as _, Result}; |
27 | 26 | ||
28 | const RUSTFMT_TOOLCHAIN: &str = "stable"; | ||
29 | |||
30 | pub fn project_root() -> PathBuf { | 27 | pub fn project_root() -> PathBuf { |
31 | Path::new( | 28 | Path::new( |
32 | &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()), | 29 | &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()), |
@@ -54,77 +51,44 @@ pub fn rust_files(path: &Path) -> impl Iterator<Item = PathBuf> { | |||
54 | 51 | ||
55 | pub fn run_rustfmt(mode: Mode) -> Result<()> { | 52 | pub fn run_rustfmt(mode: Mode) -> Result<()> { |
56 | let _dir = pushd(project_root()); | 53 | let _dir = pushd(project_root()); |
54 | let _e = pushenv("RUSTUP_TOOLCHAIN", "stable"); | ||
57 | ensure_rustfmt()?; | 55 | ensure_rustfmt()?; |
58 | 56 | match mode { | |
59 | if Command::new("cargo") | 57 | Mode::Overwrite => run!("cargo fmt"), |
60 | .env("RUSTUP_TOOLCHAIN", RUSTFMT_TOOLCHAIN) | 58 | Mode::Verify => run!("cargo fmt -- --check"), |
61 | .args(&["fmt", "--"]) | 59 | }?; |
62 | .args(if mode == Mode::Verify { &["--check"][..] } else { &[] }) | 60 | Ok(()) |
63 | .stderr(Stdio::inherit()) | ||
64 | .status()? | ||
65 | .success() | ||
66 | { | ||
67 | Ok(()) | ||
68 | } else { | ||
69 | bail!("Rustfmt failed"); | ||
70 | } | ||
71 | } | 61 | } |
72 | 62 | ||
73 | fn reformat(text: impl std::fmt::Display) -> Result<String> { | 63 | fn reformat(text: impl std::fmt::Display) -> Result<String> { |
64 | let _e = pushenv("RUSTUP_TOOLCHAIN", "stable"); | ||
74 | ensure_rustfmt()?; | 65 | ensure_rustfmt()?; |
75 | let mut rustfmt = Command::new("rustfmt") | 66 | let stdout = run!( |
76 | .env("RUSTUP_TOOLCHAIN", RUSTFMT_TOOLCHAIN) | 67 | "rustfmt --config-path {} --config fn_single_line=true", project_root().join("rustfmt.toml").display(); |
77 | .args(&["--config-path"]) | 68 | <text.to_string().as_bytes() |
78 | .arg(project_root().join("rustfmt.toml")) | 69 | )?; |
79 | .args(&["--config", "fn_single_line=true"]) | ||
80 | .stdin(Stdio::piped()) | ||
81 | .stdout(Stdio::piped()) | ||
82 | .spawn()?; | ||
83 | write!(rustfmt.stdin.take().unwrap(), "{}", text)?; | ||
84 | let output = rustfmt.wait_with_output()?; | ||
85 | let stdout = String::from_utf8(output.stdout)?; | ||
86 | let preamble = "Generated file, do not edit by hand, see `xtask/src/codegen`"; | 70 | let preamble = "Generated file, do not edit by hand, see `xtask/src/codegen`"; |
87 | Ok(format!("//! {}\n\n{}", preamble, stdout)) | 71 | Ok(format!("//! {}\n\n{}\n", preamble, stdout)) |
88 | } | 72 | } |
89 | 73 | ||
90 | fn ensure_rustfmt() -> Result<()> { | 74 | fn ensure_rustfmt() -> Result<()> { |
91 | match Command::new("rustfmt") | 75 | let out = run!("rustfmt --version")?; |
92 | .args(&["--version"]) | 76 | if !out.contains("stable") { |
93 | .env("RUSTUP_TOOLCHAIN", RUSTFMT_TOOLCHAIN) | 77 | bail!( |
94 | .stdout(Stdio::piped()) | 78 | "Failed to run rustfmt from toolchain 'stable'. \ |
95 | .stderr(Stdio::null()) | 79 | Please run `rustup component add rustfmt --toolchain stable` to install it.", |
96 | .spawn() | 80 | ) |
97 | .and_then(|child| child.wait_with_output()) | ||
98 | { | ||
99 | Ok(output) | ||
100 | if output.status.success() | ||
101 | && std::str::from_utf8(&output.stdout)?.contains(RUSTFMT_TOOLCHAIN) => | ||
102 | { | ||
103 | Ok(()) | ||
104 | } | ||
105 | _ => { | ||
106 | bail!( | ||
107 | "Failed to run rustfmt from toolchain '{0}'. \ | ||
108 | Please run `rustup component add rustfmt --toolchain {0}` to install it.", | ||
109 | RUSTFMT_TOOLCHAIN, | ||
110 | ); | ||
111 | } | ||
112 | } | 81 | } |
82 | Ok(()) | ||
113 | } | 83 | } |
114 | 84 | ||
115 | pub fn run_clippy() -> Result<()> { | 85 | pub fn run_clippy() -> Result<()> { |
116 | match Command::new("cargo") | 86 | if run!("cargo clippy --version").is_err() { |
117 | .args(&["clippy", "--version"]) | 87 | bail!( |
118 | .stderr(Stdio::null()) | ||
119 | .stdout(Stdio::null()) | ||
120 | .status() | ||
121 | { | ||
122 | Ok(status) if status.success() => (), | ||
123 | _ => bail!( | ||
124 | "Failed run cargo clippy. \ | 88 | "Failed run cargo clippy. \ |
125 | Please run `rustup component add clippy` to install it.", | 89 | Please run `rustup component add clippy` to install it.", |
126 | ), | 90 | ) |
127 | }; | 91 | } |
128 | 92 | ||
129 | let allowed_lints = [ | 93 | let allowed_lints = [ |
130 | "clippy::collapsible_if", | 94 | "clippy::collapsible_if", |
@@ -138,33 +102,18 @@ pub fn run_clippy() -> Result<()> { | |||
138 | 102 | ||
139 | pub fn run_fuzzer() -> Result<()> { | 103 | pub fn run_fuzzer() -> Result<()> { |
140 | let _d = pushd("./crates/ra_syntax"); | 104 | let _d = pushd("./crates/ra_syntax"); |
105 | let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly"); | ||
141 | if run!("cargo fuzz --help").is_err() { | 106 | if run!("cargo fuzz --help").is_err() { |
142 | run!("cargo install cargo-fuzz")?; | 107 | run!("cargo install cargo-fuzz")?; |
143 | }; | 108 | }; |
144 | 109 | ||
145 | // Expecting nightly rustc | 110 | // Expecting nightly rustc |
146 | match Command::new("rustc") | 111 | let out = run!("rustc --version")?; |
147 | .args(&["--version"]) | 112 | if !out.contains("nightly") { |
148 | .env("RUSTUP_TOOLCHAIN", "nightly") | 113 | bail!("fuzz tests require nightly rustc") |
149 | .stdout(Stdio::piped()) | ||
150 | .stderr(Stdio::null()) | ||
151 | .spawn() | ||
152 | .and_then(|child| child.wait_with_output()) | ||
153 | { | ||
154 | Ok(output) | ||
155 | if output.status.success() | ||
156 | && std::str::from_utf8(&output.stdout)?.contains("nightly") => {} | ||
157 | _ => bail!("fuzz tests require nightly rustc"), | ||
158 | } | 114 | } |
159 | 115 | ||
160 | let status = Command::new("cargo") | 116 | run!("cargo fuzz run parser")?; |
161 | .env("RUSTUP_TOOLCHAIN", "nightly") | ||
162 | .args(&["fuzz", "run", "parser"]) | ||
163 | .stderr(Stdio::inherit()) | ||
164 | .status()?; | ||
165 | if !status.success() { | ||
166 | bail!("{}", status); | ||
167 | } | ||
168 | Ok(()) | 117 | Ok(()) |
169 | } | 118 | } |
170 | 119 | ||
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs index ef1699934..a6431e586 100644 --- a/xtask/src/not_bash.rs +++ b/xtask/src/not_bash.rs | |||
@@ -3,6 +3,8 @@ | |||
3 | use std::{ | 3 | use std::{ |
4 | cell::RefCell, | 4 | cell::RefCell, |
5 | env, | 5 | env, |
6 | ffi::OsString, | ||
7 | io::Write, | ||
6 | path::{Path, PathBuf}, | 8 | path::{Path, PathBuf}, |
7 | process::{Command, Stdio}, | 9 | process::{Command, Stdio}, |
8 | }; | 10 | }; |
@@ -57,7 +59,10 @@ macro_rules! _run { | |||
57 | run!($($expr),*; echo = true) | 59 | run!($($expr),*; echo = true) |
58 | }; | 60 | }; |
59 | ($($expr:expr),* ; echo = $echo:expr) => { | 61 | ($($expr:expr),* ; echo = $echo:expr) => { |
60 | $crate::not_bash::run_process(format!($($expr),*), $echo) | 62 | $crate::not_bash::run_process(format!($($expr),*), $echo, None) |
63 | }; | ||
64 | ($($expr:expr),* ; <$stdin:expr) => { | ||
65 | $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin)) | ||
61 | }; | 66 | }; |
62 | } | 67 | } |
63 | pub(crate) use _run as run; | 68 | pub(crate) use _run as run; |
@@ -77,6 +82,21 @@ impl Drop for Pushd { | |||
77 | } | 82 | } |
78 | } | 83 | } |
79 | 84 | ||
85 | pub struct Pushenv { | ||
86 | _p: (), | ||
87 | } | ||
88 | |||
89 | pub fn pushenv(var: &str, value: &str) -> Pushenv { | ||
90 | Env::with(|env| env.pushenv(var.into(), value.into())); | ||
91 | Pushenv { _p: () } | ||
92 | } | ||
93 | |||
94 | impl Drop for Pushenv { | ||
95 | fn drop(&mut self) { | ||
96 | Env::with(|env| env.popenv()) | ||
97 | } | ||
98 | } | ||
99 | |||
80 | pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> { | 100 | pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> { |
81 | let path = path.as_ref(); | 101 | let path = path.as_ref(); |
82 | if !path.exists() { | 102 | if !path.exists() { |
@@ -90,15 +110,15 @@ pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> { | |||
90 | } | 110 | } |
91 | 111 | ||
92 | #[doc(hidden)] | 112 | #[doc(hidden)] |
93 | pub fn run_process(cmd: String, echo: bool) -> Result<String> { | 113 | pub fn run_process(cmd: String, echo: bool, stdin: Option<&[u8]>) -> Result<String> { |
94 | run_process_inner(&cmd, echo).with_context(|| format!("process `{}` failed", cmd)) | 114 | run_process_inner(&cmd, echo, stdin).with_context(|| format!("process `{}` failed", cmd)) |
95 | } | 115 | } |
96 | 116 | ||
97 | pub fn date_iso() -> Result<String> { | 117 | pub fn date_iso() -> Result<String> { |
98 | run!("date --iso --utc") | 118 | run!("date --iso --utc") |
99 | } | 119 | } |
100 | 120 | ||
101 | fn run_process_inner(cmd: &str, echo: bool) -> Result<String> { | 121 | fn run_process_inner(cmd: &str, echo: bool, stdin: Option<&[u8]>) -> Result<String> { |
102 | let mut args = shelx(cmd); | 122 | let mut args = shelx(cmd); |
103 | let binary = args.remove(0); | 123 | let binary = args.remove(0); |
104 | let current_dir = Env::with(|it| it.cwd().to_path_buf()); | 124 | let current_dir = Env::with(|it| it.cwd().to_path_buf()); |
@@ -107,12 +127,17 @@ fn run_process_inner(cmd: &str, echo: bool) -> Result<String> { | |||
107 | println!("> {}", cmd) | 127 | println!("> {}", cmd) |
108 | } | 128 | } |
109 | 129 | ||
110 | let output = Command::new(binary) | 130 | let mut command = Command::new(binary); |
111 | .args(args) | 131 | command.args(args).current_dir(current_dir).stderr(Stdio::inherit()); |
112 | .current_dir(current_dir) | 132 | let output = match stdin { |
113 | .stdin(Stdio::null()) | 133 | None => command.stdin(Stdio::null()).output(), |
114 | .stderr(Stdio::inherit()) | 134 | Some(stdin) => { |
115 | .output()?; | 135 | command.stdin(Stdio::piped()).stdout(Stdio::piped()); |
136 | let mut process = command.spawn()?; | ||
137 | process.stdin.take().unwrap().write_all(stdin)?; | ||
138 | process.wait_with_output() | ||
139 | } | ||
140 | }?; | ||
116 | let stdout = String::from_utf8(output.stdout)?; | 141 | let stdout = String::from_utf8(output.stdout)?; |
117 | 142 | ||
118 | if echo { | 143 | if echo { |
@@ -133,13 +158,15 @@ fn shelx(cmd: &str) -> Vec<String> { | |||
133 | 158 | ||
134 | struct Env { | 159 | struct Env { |
135 | pushd_stack: Vec<PathBuf>, | 160 | pushd_stack: Vec<PathBuf>, |
161 | pushenv_stack: Vec<(OsString, Option<OsString>)>, | ||
136 | } | 162 | } |
137 | 163 | ||
138 | impl Env { | 164 | impl Env { |
139 | fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T { | 165 | fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T { |
140 | thread_local! { | 166 | thread_local! { |
141 | static ENV: RefCell<Env> = RefCell::new(Env { | 167 | static ENV: RefCell<Env> = RefCell::new(Env { |
142 | pushd_stack: vec![env::current_dir().unwrap()] | 168 | pushd_stack: vec![env::current_dir().unwrap()], |
169 | pushenv_stack: vec![], | ||
143 | }); | 170 | }); |
144 | } | 171 | } |
145 | ENV.with(|it| f(&mut *it.borrow_mut())) | 172 | ENV.with(|it| f(&mut *it.borrow_mut())) |
@@ -154,6 +181,17 @@ impl Env { | |||
154 | self.pushd_stack.pop().unwrap(); | 181 | self.pushd_stack.pop().unwrap(); |
155 | env::set_current_dir(self.cwd()).unwrap(); | 182 | env::set_current_dir(self.cwd()).unwrap(); |
156 | } | 183 | } |
184 | fn pushenv(&mut self, var: OsString, value: OsString) { | ||
185 | self.pushenv_stack.push((var.clone(), env::var_os(&var))); | ||
186 | env::set_var(var, value) | ||
187 | } | ||
188 | fn popenv(&mut self) { | ||
189 | let (var, value) = self.pushenv_stack.pop().unwrap(); | ||
190 | match value { | ||
191 | None => env::remove_var(var), | ||
192 | Some(value) => env::set_var(var, value), | ||
193 | } | ||
194 | } | ||
157 | fn cwd(&self) -> &Path { | 195 | fn cwd(&self) -> &Path { |
158 | self.pushd_stack.last().unwrap() | 196 | self.pushd_stack.last().unwrap() |
159 | } | 197 | } |