use std::{fs, path::Path};
use crate::{
config::{Config, LinkMethod},
error::{DotlingError, Result, io_err},
git::Git,
printer::Printer,
repo,
};
pub fn run(printer: &Printer, file: &str) -> Result<()> {
let repo_root = repo::get_repo_root()?;
let config = Config::load(&repo_root)?;
let git = Git::new(repo_root.clone());
let entry = find_entry(&config, file)?;
match entry.method {
LinkMethod::Symlink => {
let dest_path = repo::src_to_dest_path(&entry.dest)?;
printer.annotation(&format!(
"\"{}\" is deployed as a symlink — it already IS the repo source.",
dest_path.display()
));
printer.hint("Use `dotling push` to commit and push changes.");
Ok(())
}
LinkMethod::Copy => {
let dest_path = repo::src_to_dest_path(&entry.dest)?;
let src_path = repo_root.join(&entry.src);
if !dest_path.exists() {
return Err(DotlingError::PathNotFound(dest_path));
}
printer.arrow("pull-back", &dest_path, &src_path);
fs::copy(&dest_path, &src_path).map_err(io_err(&src_path))?;
git.stage(&src_path)?;
printer.ok("staged", &src_path);
printer.hint("Use `dotling push` to commit and push.");
Ok(())
}
}
}
fn find_entry<'a>(config: &'a Config, file: &str) -> Result<&'a crate::config::LinkEntry> {
let expanded = repo::resolve_path(Path::new(file))?;
let dest_str = repo::path_with_tilde(&expanded);
if let Some(entry) = config.find_by_dest(&dest_str) {
return Ok(entry);
}
let filename = Path::new(file)
.file_name()
.map_or_else(|| file.to_string(), |f| f.to_string_lossy().to_string());
let matches: Vec<_> = config
.entries
.iter()
.filter(|e| {
Path::new(&e.dest)
.file_name()
.is_some_and(|f| f.to_string_lossy() == filename)
|| Path::new(&e.src)
.file_name()
.is_some_and(|f| f.to_string_lossy() == filename)
})
.collect();
match matches.len() {
0 => Err(DotlingError::NotTracked(expanded)),
1 => Ok(matches[0]),
_ => {
let paths: Vec<_> = matches.iter().map(|e| e.dest.as_str()).collect();
Err(DotlingError::NotTracked(std::path::PathBuf::from(format!(
"ambiguous filename '{}' — matches: {}. Use the full dest path.",
filename,
paths.join(", ")
))))
}
}
}