diff options
author | Aleksey Kladov <[email protected]> | 2020-02-14 14:59:19 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-02-14 15:47:09 +0000 |
commit | ce29497e4324d3e2f2c7c696a212672dbdb46884 (patch) | |
tree | d75fa5d9994ec174371a16b1d42720833ecda85c /xtask/src/not_bash.rs | |
parent | bd3a41cc33a25491c19468aaf24dbba4b467edaf (diff) |
Replace Cmd with not-bash
Diffstat (limited to 'xtask/src/not_bash.rs')
-rw-r--r-- | xtask/src/not_bash.rs | 96 |
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 | ||
2 | use std::{ | ||
3 | cell::RefCell, | ||
4 | env, | ||
5 | path::PathBuf, | ||
6 | process::{Command, Stdio}, | ||
7 | }; | ||
8 | |||
9 | use anyhow::{bail, Context, Result}; | ||
10 | |||
11 | macro_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 | } | ||
19 | pub(crate) use _run as run; | ||
20 | |||
21 | pub struct Pushd { | ||
22 | _p: (), | ||
23 | } | ||
24 | |||
25 | pub fn pushd(path: impl Into<PathBuf>) -> Pushd { | ||
26 | Env::with(|env| env.pushd(path.into())); | ||
27 | Pushd { _p: () } | ||
28 | } | ||
29 | |||
30 | impl Drop for Pushd { | ||
31 | fn drop(&mut self) { | ||
32 | Env::with(|env| env.popd()) | ||
33 | } | ||
34 | } | ||
35 | |||
36 | #[doc(hidden)] | ||
37 | pub fn run_process(cmd: String, echo: bool) -> Result<String> { | ||
38 | run_process_inner(&cmd, echo).with_context(|| format!("process `{}` failed", cmd)) | ||
39 | } | ||
40 | |||
41 | fn 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 | ||
70 | fn shelx(cmd: &str) -> Vec<String> { | ||
71 | cmd.split_whitespace().map(|it| it.to_string()).collect() | ||
72 | } | ||
73 | |||
74 | #[derive(Default)] | ||
75 | struct Env { | ||
76 | pushd_stack: Vec<PathBuf>, | ||
77 | } | ||
78 | |||
79 | impl 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 | } | ||