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 83 84 85 86 87
use std::path::{Path, PathBuf}; use std::{fs, io}; pub fn entries(bin: &Path) -> io::Result<impl Iterator<Item = (PathBuf, PathBuf)>> { Ok(bin .read_dir()? .filter_map(Result::ok) .map(|entry| entry.path()) .filter_map(|sym| sym.read_link().map(|dest| (sym, dest)).ok())) } pub fn iterate( bin: &Path, repos: Vec<PathBuf>, ) -> io::Result<impl Iterator<Item = (PathBuf, PathBuf)>> { Ok(bin .read_dir()? .filter_map(Result::ok) .map(|entry| entry.path()) .filter_map(|sym| sym.read_link().map(|dest| (sym, dest)).ok()) .filter(move |(_, dest)| repos.iter().any(|repo| dest.starts_with(repo)))) } pub fn link_path(bin: &Path, exe: &Path) -> io::Result<PathBuf> { exe.file_name() .map(|osname| bin.join(osname)) .ok_or(io::Error::new( io::ErrorKind::NotFound, "no file name found", )) } pub fn create(bin: &Path, exe: &Path) -> io::Result<PathBuf> { fs::create_dir_all(bin).ok(); let sym = link_path(bin, exe)?; { #[cfg(target_family = "unix")] { use std::os::unix::fs::symlink; symlink(exe, &sym) } #[cfg(target_family = "windows")] { use std::os::windows::fs::symlink_file; symlink_file(exe, &sym) } } .map(|_| sym) } pub fn deref_rec(path: &Path) -> PathBuf { match path.read_link() { Ok(dest) => deref_rec(&match dest.is_relative() { false => dest, true => path.parent().unwrap().join(dest), }), Err(_) => path.into(), } } fn is_executable(path: &Path) -> bool { let path = deref_rec(path); path.is_file() && { #[cfg(target_family = "unix")] { use std::os::unix::fs::MetadataExt; path.metadata() .map(|meta| meta.mode() & 0o100 > 0) .unwrap_or(false) } #[cfg(target_family = "windows")] { path.extension() .map(|ostyp| ostyp.to_str().map(|typ| typ == "exe" || typ == "bat")) .flatten() .unwrap_or(false) } } } pub fn executables(dir: &Path) -> io::Result<impl Iterator<Item = PathBuf>> { Ok(dir .read_dir()? .filter_map(Result::ok) .map(|entry| entry.path()) .filter(|path| is_executable(path))) }