bonds-cli 0.1.6

CLI for creating and managing symlink-based bonds
Documentation
use bonds_cli::ui;
use bonds_core::{BondError, BondManager, BondsConfig};
use std::path::PathBuf;

/// Migrate command handler, which moves the target of a bond to a new location. The command retrieves the bond by its ID or name, resolves the destination directory (either from the provided argument or from the default configuration), and constructs the new target path by preserving the basename of the existing target. If the bond is already at the destination, it informs the user and exits without making changes. Otherwise, it delegates to the bond manager's `update_bond` method to handle the migration, which includes updating symlinks and the database record. Upon successful migration, it provides user feedback with details of the old and new target paths.
/// **Example usage:**
/// ```bash
/// bond migrate <id | name> [destination]
/// ```
pub fn cmd_migrate(
    manager: &BondManager,
    id: &str,
    dest: Option<PathBuf>,
) -> Result<(), BondError> {
    let bond = manager.get_bond(id)?;

    // Resolve destination directory
    let dest_dir = match dest {
        Some(d) => std::path::absolute(&d)
            .map_err(|_| BondError::InvalidPath(format!("cannot resolve path: {}", d.display())))?,
        None => {
            let config = BondsConfig::load()?;
            config.default_target.ok_or_else(|| {
                BondError::Config("no destination given and no default directory configured".into())
            })?
        }
    };

    // Preserve the existing target's basename
    let basename = bond.target().file_name().ok_or_else(|| {
        BondError::InvalidPath(format!(
            "target has no file name: {}",
            bond.target().display()
        ))
    })?;

    let new_target = dest_dir.join(basename);

    // No-op if already there
    if new_target == bond.target() {
        ui::warning(format!(
            "Bond '{}' is already at {}",
            id,
            new_target.display()
        ));
        return Ok(());
    }

    // Delegate to update_bond -- it handles symlink removal, creation, and DB update
    let updated = manager.update_bond(bond.id(), None, Some(new_target), None)?;
    ui::status_ok("✓ SUCCESS");
    ui::success("Bond migrated successfully:");
    ui::subheading(format!("   {}", updated.id()));
    ui::key(format!("   {}", updated.source().display()));
    ui::normal("    ⤡ ");
    ui::path(format!("    {}\n", updated.target().display()));
    // ui::success(format!("Bond migrated: {}", id));
    // ui::info(format!(
    //     "  {} -> {}",
    //     updated.source().display(),
    //     updated.target().display()
    // ));
    Ok(())
}