use std::path::PathBuf;
use serde::Serialize;
use crate::packs::orchestration::ExecutionContext;
use crate::{DodotError, Result};
#[derive(Debug, Clone, Serialize)]
pub struct AdoptResult {
pub message: String,
pub details: Vec<String>,
}
pub fn adopt(
pack_name: &str,
files: &[PathBuf],
force: bool,
ctx: &ExecutionContext,
) -> Result<AdoptResult> {
let pack_path = ctx.paths.pack_path(pack_name);
if !ctx.fs.exists(&pack_path) {
return Err(DodotError::PackNotFound {
name: pack_name.into(),
});
}
let mut details = Vec::new();
for file in files {
if !ctx.fs.exists(file) {
return Err(DodotError::Fs {
path: file.clone(),
source: std::io::Error::new(std::io::ErrorKind::NotFound, "file not found"),
});
}
let filename = file
.file_name()
.ok_or_else(|| DodotError::Other(format!("no filename: {}", file.display())))?;
let pack_filename = filename.to_string_lossy();
let pack_filename = pack_filename.strip_prefix('.').unwrap_or(&pack_filename);
let dest = pack_path.join(pack_filename);
if ctx.fs.exists(&dest) && !force {
return Err(DodotError::SymlinkConflict { path: dest });
}
ctx.fs.rename(file, &dest)?;
ctx.fs.symlink(&dest, file)?;
details.push(format!(
"{} → {}/{}",
file.display(),
pack_name,
pack_filename
));
}
Ok(AdoptResult {
message: format!("Adopted {} file(s) into '{pack_name}'.", files.len()),
details,
})
}