aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/not_bash.rs
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src/not_bash.rs')
-rw-r--r--xtask/src/not_bash.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs
new file mode 100644
index 000000000..a2e47c7af
--- /dev/null
+++ b/xtask/src/not_bash.rs
@@ -0,0 +1,96 @@
1//! A bad shell -- small cross platform module for writing glue code
2use std::{
3 cell::RefCell,
4 env,
5 path::PathBuf,
6 process::{Command, Stdio},
7};
8
9use anyhow::{bail, Context, Result};
10
11macro_rules! _run {
12 ($($expr:expr),*) => {
13 run!($($expr),*; echo = true)
14 };
15 ($($expr:expr),* ; echo = $echo:expr) => {
16 $crate::not_bash::run_process(format!($($expr),*), $echo)
17 };
18}
19pub(crate) use _run as run;
20
21pub struct Pushd {
22 _p: (),
23}
24
25pub fn pushd(path: impl Into<PathBuf>) -> Pushd {
26 Env::with(|env| env.pushd(path.into()));
27 Pushd { _p: () }
28}
29
30impl Drop for Pushd {
31 fn drop(&mut self) {
32 Env::with(|env| env.popd())
33 }
34}
35
36#[doc(hidden)]
37pub fn run_process(cmd: String, echo: bool) -> Result<String> {
38 run_process_inner(&cmd, echo).with_context(|| format!("process `{}` failed", cmd))
39}
40
41fn run_process_inner(cmd: &str, echo: bool) -> Result<String> {
42 let cwd = Env::with(|env| env.cwd());
43 let mut args = shelx(cmd);
44 let binary = args.remove(0);
45
46 if echo {
47 println!("> {}", cmd)
48 }
49
50 let output = Command::new(binary)
51 .args(args)
52 .current_dir(cwd)
53 .stdin(Stdio::null())
54 .stderr(Stdio::inherit())
55 .output()?;
56 let stdout = String::from_utf8(output.stdout)?;
57
58 if echo {
59 print!("{}", stdout)
60 }
61
62 if !output.status.success() {
63 bail!("returned non-zero status: {}", output.status)
64 }
65
66 Ok(stdout)
67}
68
69// FIXME: some real shell lexing here
70fn shelx(cmd: &str) -> Vec<String> {
71 cmd.split_whitespace().map(|it| it.to_string()).collect()
72}
73
74#[derive(Default)]
75struct Env {
76 pushd_stack: Vec<PathBuf>,
77}
78
79impl Env {
80 fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T {
81 thread_local! {
82 static ENV: RefCell<Env> = Default::default();
83 }
84 ENV.with(|it| f(&mut *it.borrow_mut()))
85 }
86
87 fn pushd(&mut self, dir: PathBuf) {
88 self.pushd_stack.push(dir)
89 }
90 fn popd(&mut self) {
91 self.pushd_stack.pop().unwrap();
92 }
93 fn cwd(&self) -> PathBuf {
94 self.pushd_stack.last().cloned().unwrap_or_else(|| env::current_dir().unwrap())
95 }
96}