use crate::error::SkipStep; use color_eyre::eyre::Result; use std::env; use std::ffi::OsStr; use std::fmt::Debug; use std::path::{Path, PathBuf}; use tracing::{debug, error}; pub trait PathExt where Self: Sized, { fn if_exists(self) -> Option; fn is_descendant_of(&self, ancestor: &Path) -> bool; /// Returns the path if it exists or ErrorKind::SkipStep otherwise fn require(self) -> Result; } impl PathExt for T where T: AsRef, { fn if_exists(self) -> Option { if self.as_ref().exists() { debug!("Path {:?} exists", self.as_ref()); Some(self) } else { debug!("Path {:?} doesn't exist", self.as_ref()); None } } fn is_descendant_of(&self, ancestor: &Path) -> bool { self.as_ref().iter().zip(ancestor.iter()).all(|(a, b)| a == b) } fn require(self) -> Result { if self.as_ref().exists() { debug!("Path {:?} exists", self.as_ref()); Ok(self) } else { Err(SkipStep(format!("Path {:?} doesn't exist", self.as_ref())).into()) } } } pub fn which + Debug>(binary_name: T) -> Option { match which_crate::which(&binary_name) { Ok(path) => { debug!("Detected {:?} as {:?}", &path, &binary_name); Some(path) } Err(e) => { match e { which_crate::Error::CannotFindBinaryPath => { debug!("Cannot find {:?}", &binary_name); } _ => { error!("Detecting {:?} failed: {}", &binary_name, e); } } None } } } pub fn sudo() -> Option { which("doas") .or_else(|| which("sudo")) .or_else(|| which("gsudo")) .or_else(|| which("pkexec")) } pub fn editor() -> Vec { env::var("EDITOR") .unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" })) .split_whitespace() .map(|s| s.to_owned()) .collect() } pub fn require + Debug>(binary_name: T) -> Result { match which_crate::which(&binary_name) { Ok(path) => { debug!("Detected {:?} as {:?}", &path, &binary_name); Ok(path) } Err(e) => match e { which_crate::Error::CannotFindBinaryPath => { Err(SkipStep(format!("Cannot find {:?} in PATH", &binary_name)).into()) } _ => { panic!("Detecting {:?} failed: {}", &binary_name, e); } }, } } #[allow(dead_code)] pub fn require_option(option: Option, cause: String) -> Result { if let Some(value) = option { Ok(value) } else { Err(SkipStep(cause).into()) } }