1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
use super::errors::*; use regex::Regex; use std::path::{Path, PathBuf}; pub struct Paths; impl Paths { pub fn shebang(path: &Path) -> Result<String> { let text = std::fs::read_to_string(path) .chain_err(|| ErrorKind::ShebangNotFound(path.to_path_buf()))?; let re = Regex::new(r"#!\s*([/:\.\w\-]+)") .chain_err(|| ErrorKind::ShebangNotFound(path.to_path_buf()))?; match re.captures(&text) { Some(caps) => { if caps.len() > 1 { Ok(caps[1].to_string()) } else { Err(Error::from_kind(ErrorKind::ShebangNotFound( path.to_path_buf(), ))) } } None => Err(Error::from_kind(ErrorKind::ShebangNotFound( path.to_path_buf(), ))), } } pub fn which(name: &str) -> Result<PathBuf> { let extensions = vec![".exe", ".bat", ".cmd", ""]; for ext in extensions.iter() { let exe_name = format!("{}{}", name, ext); match Paths::which_exact(&exe_name) { Some(path) => { return Ok(path); } None => {} }; } Err(Error::from_kind(ErrorKind::UnrecognizedCommand( name.to_string(), ))) } fn which_exact(name: &str) -> Option<PathBuf> { std::env::var_os("PATH").and_then(|paths| { std::env::split_paths(&paths) .filter_map(|dir| { let full_path = dir.join(&name); if full_path.is_file() { Some(full_path) } else { None } }) .next() }) } pub fn extension(path: &Path) -> String { match path.extension() { Some(os_str) => match os_str.to_str() { Some(ext) => ext.to_string(), None => "".to_string(), }, None => "".to_string(), } } } #[cfg(test)] #[test] fn which_test() { match crate::paths::Paths::which("git") { Ok(git_path) => assert!( git_path.exists(), "path {} does not exist.", git_path.display() ), Err(e) => assert!(false, "which('git') returned an error: {}", e), } }