1use std::{
4 ffi::{OsStr, OsString},
5 fmt,
6 path::PathBuf,
7 process::{Command, ExitStatus},
8};
9
10use anyhow::Error;
11use pico_args::Arguments;
12
13#[derive(Debug)]
14struct ExecError {
15 program: OsString,
16 args: Vec<OsString>,
17 status: ExitStatus,
18}
19
20impl<'a> fmt::Display for ExecError {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 write!(
23 f,
24 "subprocess {} failed with status {}",
25 self.program.to_string_lossy(),
26 self.status
27 )
28 }
29}
30
31impl std::error::Error for ExecError {}
32
33#[derive(Debug)]
35pub struct DisplayArgs<T>(pub T);
36
37impl<T> fmt::Display for DisplayArgs<T>
38where
39 T: Iterator + Clone,
40 T::Item: AsRef<OsStr>,
41{
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 let mut args = self.0.clone();
44 let mut next = args.next();
45 while let Some(arg) = next {
46 let s = arg.as_ref().to_string_lossy();
48 write!(f, "{}", s)?;
49 next = args.next();
50 if next.is_some() {
51 write!(f, " ")?;
52 }
53 }
54 Ok(())
55 }
56}
57
58pub fn empty_env() -> Vec<(&'static str, &'static OsStr)> {
60 Vec::new()
61}
62
63pub fn cmd<P, E, A, V>(program: P, args: A, env: E, verbose: bool) -> Result<(), Error>
68where
69 P: AsRef<OsStr>,
70 A: IntoIterator,
71 A::IntoIter: Clone,
72 A::Item: AsRef<OsStr>,
73 E: IntoIterator<Item = (&'static str, V)>,
74 V: AsRef<OsStr>,
75{
76 let program = program.as_ref();
77 let args = args.into_iter();
78 let env = env.into_iter();
79 if verbose {
80 println!(
81 "* {} {}",
82 program.to_string_lossy(),
83 DisplayArgs(args.clone())
84 );
85 }
86 let status = Command::new(program)
87 .args(args.clone())
88 .envs(env)
89 .status()?;
90 if !status.success() {
91 return Err(ExecError {
92 program: program.to_owned(),
93 args: args.map(|arg| arg.as_ref().to_owned()).collect(),
94 status,
95 }
96 .into());
97 }
98 Ok(())
99}
100
101pub fn get_prefix_opt(args: &mut Arguments) -> anyhow::Result<PathBuf> {
107 match args.opt_value_from_str("--prefix")? {
108 Some(prefix) => Ok(prefix),
109 None => {
110 let mut home = PathBuf::from(std::env::var("HOME")?);
111 home.push(".local");
112 Ok(home)
113 }
114 }
115}