use std::process::Command; use std::fs::symlink_metadata; use std::path::PathBuf; use dirs::home_dir; use crate::config::Dot; use symlink::{symlink_auto, remove_symlink_auto}; fn prepare_dots(dots: Vec, dots_dir: PathBuf, no_hostname_check: bool) -> Vec { let mut hostname = "*".to_string(); if !no_hostname_check { // Deeply saddened there is no better way to do this :( let hostname_cmd = Command::new("hostname").output().expect("failed to get hostname: command \"hostname\" failed"); let hostname_stdout = hostname_cmd.stdout; let mut new_hostname = String::from_utf8(hostname_stdout.clone()).expect("failed to get hostname: unknown hostname encoding"); new_hostname.pop(); // stdout contains a newline hostname = new_hostname; } let prepared_dots = dots.iter().filter(|dot| if no_hostname_check { true } else { dot.host == "*" || dot.host == hostname }).map(|m| Dot { source: dots_dir.join(&m.source), destination: if m.destination.is_absolute() { m.destination.clone() } else { prepend_user_dir(&m.destination) }, host: m.host.clone() } ); prepared_dots.collect() } pub fn deploy_dots(dots: Vec, dots_dir: PathBuf, no_hostname_check: bool) { for dot in prepare_dots(dots, dots_dir, no_hostname_check) { println!("linking from {} to {}", dot.source.display(), dot.destination.display()); let _ = symlink_auto(&dot.source, &dot.destination).map_err(|err| eprintln!("failed to symlink: {}", err.to_string()) ); } } pub fn unlink_dots(dots: Vec, dots_dir: PathBuf, no_hostname_check: bool) { for dot in prepare_dots(dots, dots_dir, no_hostname_check) { println!("unlinking {}", dot.destination.display()); let metadata = symlink_metadata(dot.destination.clone()); if metadata.is_err() { eprintln!("failed to query metadata for {}: {}", dot.destination.display(), metadata.err().unwrap()); continue } if metadata.ok().unwrap().is_symlink() { let _ = remove_symlink_auto(dot.destination).map_err(|err| eprintln!("failed to remove symlink: {}", err) ); } } } fn prepend_user_dir(path: &PathBuf) -> PathBuf { home_dir().unwrap().join(path) }