brev/
lib.rs

1extern crate dirs;
2extern crate glob;
3extern crate tempfile;
4
5use std::io::prelude::*;
6use std::{env, fmt, fs, io, iter, path, process};
7
8mod output;
9mod status;
10
11pub use output::{output, OutputError};
12pub use status::{status, StatusError};
13
14#[cfg(unix)]
15pub fn signal_from_exit_status(exit_status: process::ExitStatus) -> Option<i32> {
16  use std::os::unix::process::ExitStatusExt;
17  exit_status.signal()
18}
19
20#[cfg(windows)]
21pub fn signal_from_exit_status(_exit_status: process::ExitStatus) -> Option<i32> {
22  // The rust standard library does not expose a way to extract a signal
23  // from a process exit status, so just return None
24  None
25}
26
27pub fn home() -> path::PathBuf {
28  dirs::home_dir().unwrap_or_else(|| panic!("home: failed to get home directory"))
29}
30
31pub fn empty<T, C: iter::FromIterator<T>>() -> C {
32  iter::empty().collect()
33}
34
35pub fn tmpdir<S: AsRef<str>>(prefix: S) -> (tempfile::TempDir, String) {
36  let tmp = tempfile::Builder::new()
37    .prefix(prefix.as_ref())
38    .tempdir()
39    .unwrap_or_else(|err| panic!("tmpdir: failed to create temporary directory: {}", err));
40  let path = tmp
41    .path()
42    .to_str()
43    .unwrap_or_else(|| panic!("tmpdir: path was not valid UTF-8"))
44    .to_owned();
45  return (tmp, path);
46}
47
48pub fn glob<P: AsRef<str>>(pattern: P) -> Vec<String> {
49  match glob::glob(pattern.as_ref()) {
50    Ok(matches) => matches
51      .filter_map(Result::ok)
52      .filter_map(|p| p.as_path().to_str().map(str::to_owned))
53      .collect(),
54    Err(err) => panic!("glob: error globbing: {}", err),
55  }
56}
57
58pub fn touch<P: AsRef<path::Path>>(path: P) {
59  if let Err(err) = fs::OpenOptions::new().create(true).append(true).open(path) {
60    panic!("touch: {}", err)
61  }
62}
63
64pub fn mkdir<P: AsRef<path::Path>>(path: P) {
65  if let Err(err) = fs::create_dir(path) {
66    panic!("mkdir: {}", err)
67  }
68}
69
70pub fn rmdir<P: AsRef<path::Path>>(path: P) {
71  if let Err(err) = fs::remove_dir(path) {
72    panic!("rmdir: {}", err)
73  }
74}
75
76pub fn rm<P: AsRef<path::Path>>(path: P) {
77  if let Err(err) = fs::remove_file(path) {
78    panic!("rm: {}", err);
79  }
80}
81
82pub fn slurp<P: AsRef<path::Path>>(path: P) -> String {
83  let mut file = fs::File::open(path).unwrap_or_else(|err| panic!("slurp {}", err));
84
85  let mut s = String::new();
86
87  if let Err(err) = file.read_to_string(&mut s) {
88    panic!("slurp: {}", err)
89  }
90
91  s
92}
93
94pub fn read<P: AsRef<path::Path>>(path: P) -> Vec<u8> {
95  let mut file = fs::File::open(path).unwrap_or_else(|err| panic!("read {}", err));
96
97  let mut v = vec![];
98
99  if let Err(err) = file.read_to_end(&mut v) {
100    panic!("read: {}", err)
101  }
102
103  v
104}
105
106pub fn dump<P: AsRef<path::Path>, D: AsRef<[u8]>>(path: P, data: D) {
107  let bytes = data.as_ref();
108  let count = bytes.len();
109  let mut file = fs::File::create(path).unwrap_or_else(|err| panic!("dump {}", err));
110  match file.write(bytes) {
111    Err(err) => panic!("dump: {}", err),
112    Ok(n) => {
113      if n != count {
114        panic!("dump: only {} of {} bytes written", n, count);
115      }
116    }
117  }
118}
119
120pub fn cd<P: AsRef<path::Path>>(path: P) {
121  if let Err(err) = env::set_current_dir(path) {
122    panic!("cd: {}", err)
123  }
124}
125
126pub fn cwd() -> String {
127  match env::current_dir() {
128    Ok(pathbuf) => pathbuf
129      .to_str()
130      .unwrap_or_else(|| panic!("cwd: cwd was not a valid UTF-8 string"))
131      .to_string(),
132    Err(err) => panic!("cwd: {}", err),
133  }
134}
135
136pub fn can(command: &str) -> bool {
137  let paths = match env::var_os("PATH") {
138    Some(os_paths) => os_paths
139      .to_str()
140      .unwrap_or_else(|| panic!("can: PATH environment variable is not valid UTF-8"))
141      .to_owned(),
142    None => panic!("can: PATH environment variable is not set"),
143  };
144
145  for path in paths.split(":") {
146    let candidate = format!("{}/{}", path, command);
147    if isfile(&candidate) {
148      return true;
149    }
150  }
151  false
152}
153
154pub fn isfile<P: AsRef<path::Path>>(path: P) -> bool {
155  match fs::metadata(path) {
156    Ok(metadata) => metadata.is_file(),
157    Err(err) => {
158      if let io::ErrorKind::NotFound = err.kind() {
159        return false;
160      };
161      panic!("isfile: could not retrieve metadata: {}", err);
162    }
163  }
164}
165
166pub fn isdir<P: AsRef<path::Path>>(path: P) -> bool {
167  match fs::metadata(path) {
168    Ok(metadata) => metadata.is_dir(),
169    Err(err) => {
170      if let io::ErrorKind::NotFound = err.kind() {
171        return false;
172      };
173      panic!("isfile: could not retrieve metadata: {}", err);
174    }
175  }
176}
177
178pub fn say(d: &fmt::Display) {
179  println!("{}", d)
180}
181
182pub fn out(d: &fmt::Display) {
183  if let Err(err) = write!(&mut io::stdout(), "{}", d) {
184    panic!("warn: {}", err);
185  }
186}
187
188pub fn err(d: &fmt::Display) {
189  if let Err(err) = write!(&mut io::stderr(), "{}", d) {
190    panic!("warn: {}", err);
191  }
192}
193
194pub fn warn(d: &fmt::Display) {
195  if let Err(err) = writeln!(&mut io::stderr(), "{}", d) {
196    panic!("warn: {}", err);
197  }
198}
199
200pub fn die(d: &fmt::Display) -> ! {
201  warn(d);
202  process::exit(-1)
203}
204
205#[macro_export]
206macro_rules! warn {
207  ($($arg:tt)*) => {{
208    extern crate std;
209    use std::io::prelude::*;
210    if let Err(_) = writeln!(&mut std::io::stderr(), $($arg)*) {
211      std::process::exit(-1);
212    };
213  }};
214}
215
216#[macro_export]
217macro_rules! die {
218  ($($arg:tt)*) => {{
219    extern crate std;
220    warn!($($arg)*);
221    std::process::exit(-1)
222  }};
223}
224
225mod tests;