biov 0.1.0

A uv-style tool manager for bioinformatics: reproducible Docker-backed tools with digest-pinned lockfiles (installs as `bv`)
use anyhow::Context;
use owo_colors::OwoColorize;

use bv_core::project::BvLock;

use crate::commands::add::{format_size, short_digest};

pub fn run() -> anyhow::Result<()> {
    let cwd = std::env::current_dir()?;
    let bv_lock_path = cwd.join("bv.lock");

    if !bv_lock_path.exists() {
        println!("No bv.lock found. Run `bv add <tool>` to add tools to this project.");
        return Ok(());
    }

    let lockfile = BvLock::from_path(&bv_lock_path).context("failed to read bv.lock")?;

    if lockfile.tools.is_empty() {
        println!("No tools installed. Run `bv add <tool>` to get started.");
        return Ok(());
    }

    let mut tools: Vec<_> = lockfile.tools.values().collect();
    tools.sort_by(|a, b| a.tool_id.cmp(&b.tool_id));

    let w_tool = tools
        .iter()
        .map(|e| e.tool_id.len())
        .max()
        .unwrap_or(4)
        .max(4);
    let w_ver = tools
        .iter()
        .map(|e| e.version.len())
        .max()
        .unwrap_or(7)
        .max(7);

    println!(
        "  {:<w_tool$}  {:<w_ver$}  {:<12}  {:<8}  {}",
        "Tool".bold(),
        "Version".bold(),
        "Digest".bold(),
        "Size".bold(),
        "Added".bold(),
    );
    println!("  {}", "-".repeat(w_tool + w_ver + 12 + 8 + 10 + 8));

    for entry in tools {
        let digest_short = short_digest(&entry.image_digest);
        let size = entry
            .image_size_bytes
            .map(format_size)
            .unwrap_or_else(|| "-".into());
        let date = entry.resolved_at.format("%Y-%m-%d").to_string();

        println!(
            "  {:<w_tool$}  {:<w_ver$}  {:<12}  {:<8}  {}",
            entry.tool_id,
            entry.version,
            digest_short,
            size,
            date.dimmed(),
        );
    }

    Ok(())
}