use {Dotfile, Error};
use util;
use std::path::PathBuf;
use std::fs;
use std::os::unix;
#[derive(Debug)]
pub struct Config {
pub home_path: PathBuf,
}
pub fn build(dotfile: &Dotfile, config: &Config) -> Result<(), Error> {
let dest_path = self::path(dotfile, config);
if dest_path.exists() {
if dest_path.is_dir() {
warn!("there is an existing directory at '{}', will not create symlink", dest_path.display());
return Ok(());
} else {
let metadata = fs::symlink_metadata(&dest_path)?;
if metadata.file_type().is_symlink() {
let current_target = fs::read_link(&dest_path)?;
if current_target.canonicalize()? == dotfile.full_path.canonicalize()? {
fs::remove_file(&dest_path)?;
} else {
ilog!("there is an existing symlink to a different file at '{}', deleting it", dest_path.display());
}
} else {
warn!("there is an existing file at '{}', will not create symlink", dest_path.display());
return Ok(());
}
}
}
if let Some(parent) = dest_path.parent() {
if !parent.exists() {
fs::create_dir_all(parent)?;
}
}
println!("{} -> {}", dotfile.full_path.display(), dest_path.display());
unix::fs::symlink(&dotfile.full_path, &dest_path)?;
Ok(())
}
pub fn destroy(dotfile: &Dotfile, config: &Config) -> Result<(), Error> {
use std::io::ErrorKind::NotFound;
let dest_path = self::path(dotfile, config);
println!("destroying dotfile: {}", dest_path.display());
match fs::remove_file(&dest_path) {
Ok(..) => Ok(()),
Err(ref e) if e.kind() == NotFound => Ok(()),
Err(e) => Err(e.into()),
}
}
pub fn exists(dotfile: &Dotfile, config: &Config) -> Result<bool, Error> {
let symlink_path = self::path(dotfile, config);
if !symlink_path.exists() { return Ok(false); }
let metadata = fs::symlink_metadata(&symlink_path)?;
Ok(metadata.file_type().is_symlink())
}
pub fn path(dotfile: &Dotfile, config: &Config) -> PathBuf {
config.home_path.join(&dotfile.relative_path)
}
impl Default for Config
{
fn default() -> Config {
Config {
home_path: util::home_dir(),
}
}
}