aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xtask/src/lib.rs111
-rw-r--r--xtask/src/not_bash.rs60
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
13use std::{ 13use std::{
14 env, 14 env,
15 io::Write,
16 path::{Path, PathBuf}, 15 path::{Path, PathBuf},
17 process::{Command, Stdio},
18}; 16};
17
19use walkdir::{DirEntry, WalkDir}; 18use walkdir::{DirEntry, WalkDir};
20 19
21use crate::{ 20use 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
26pub use anyhow::{bail, Context as _, Result}; 25pub use anyhow::{bail, Context as _, Result};
27 26
28const RUSTFMT_TOOLCHAIN: &str = "stable";
29
30pub fn project_root() -> PathBuf { 27pub 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
55pub fn run_rustfmt(mode: Mode) -> Result<()> { 52pub 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
73fn reformat(text: impl std::fmt::Display) -> Result<String> { 63fn 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
90fn ensure_rustfmt() -> Result<()> { 74fn 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
115pub fn run_clippy() -> Result<()> { 85pub 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
139pub fn run_fuzzer() -> Result<()> { 103pub 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 @@
3use std::{ 3use 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}
63pub(crate) use _run as run; 68pub(crate) use _run as run;
@@ -77,6 +82,21 @@ impl Drop for Pushd {
77 } 82 }
78} 83}
79 84
85pub struct Pushenv {
86 _p: (),
87}
88
89pub fn pushenv(var: &str, value: &str) -> Pushenv {
90 Env::with(|env| env.pushenv(var.into(), value.into()));
91 Pushenv { _p: () }
92}
93
94impl Drop for Pushenv {
95 fn drop(&mut self) {
96 Env::with(|env| env.popenv())
97 }
98}
99
80pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> { 100pub 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)]
93pub fn run_process(cmd: String, echo: bool) -> Result<String> { 113pub 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
97pub fn date_iso() -> Result<String> { 117pub fn date_iso() -> Result<String> {
98 run!("date --iso --utc") 118 run!("date --iso --utc")
99} 119}
100 120
101fn run_process_inner(cmd: &str, echo: bool) -> Result<String> { 121fn 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
134struct Env { 159struct Env {
135 pushd_stack: Vec<PathBuf>, 160 pushd_stack: Vec<PathBuf>,
161 pushenv_stack: Vec<(OsString, Option<OsString>)>,
136} 162}
137 163
138impl Env { 164impl 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 }