diff options
| author | Aleksey Kladov <[email protected]> | 2020-04-30 14:14:55 +0100 |
|---|---|---|
| committer | Aleksey Kladov <[email protected]> | 2020-04-30 14:20:47 +0100 |
| commit | 5f0008040e9a168e5eaec0bbd754a6f14d12896a (patch) | |
| tree | 16c81aefd811feaee103ebb617cacaf13eb9e412 | |
| parent | 36775ef0d056b374b8e2b89f7399200e09d4daca (diff) | |
Allow to set env vars and pipe stdin via not_bash
| -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 | } |
