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 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;