use std::fs;
use std::os::unix::fs as unix_fs;
use std::path::Path;
use arcbox_constants::paths::is_arcbox_owned;
use arcbox_helper::validate::{CliName, CliTarget};
pub fn link(name: &CliName, target: &CliTarget) -> Result<(), String> {
let link_path = Path::new("/usr/local/bin").join(name.as_str());
let target_path = Path::new(target.as_str());
if !target_path.exists() {
return Err(format!("CLI target does not exist: {target}"));
}
match fs::symlink_metadata(&link_path) {
Ok(meta) if meta.file_type().is_symlink() => {
let existing = fs::read_link(&link_path)
.map_err(|e| format!("failed to read symlink {}: {e}", link_path.display()))?;
if existing == target_path {
return Ok(());
}
if !is_arcbox_owned(&existing) {
return Err(format!(
"{} is a symlink to {} (not ArcBox-owned, not replacing)",
link_path.display(),
existing.display()
));
}
fs::remove_file(&link_path)
.map_err(|e| format!("failed to remove {}: {e}", link_path.display()))?;
}
Ok(_) => {
return Err(format!(
"{} exists and is not a symlink (not replacing)",
link_path.display()
));
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
Err(e) => {
return Err(format!("failed to stat {}: {e}", link_path.display()));
}
}
fs::create_dir_all("/usr/local/bin")
.map_err(|e| format!("failed to create /usr/local/bin: {e}"))?;
unix_fs::symlink(target_path, &link_path).map_err(|e| {
format!(
"failed to create symlink {} -> {target}: {e}",
link_path.display()
)
})
}
pub fn unlink(name: &CliName) -> Result<(), String> {
let link_path = Path::new("/usr/local/bin").join(name.as_str());
match fs::symlink_metadata(&link_path) {
Ok(meta) if meta.file_type().is_symlink() => {
let target = fs::read_link(&link_path)
.map_err(|e| format!("failed to read symlink {}: {e}", link_path.display()))?;
if is_arcbox_owned(&target) {
fs::remove_file(&link_path)
.map_err(|e| format!("failed to remove {}: {e}", link_path.display()))?;
}
Ok(())
}
Ok(_) => Ok(()),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),
Err(e) => Err(format!("failed to stat {}: {e}", link_path.display())),
}
}