knott 0.1.17

Fast Rust package manager helper for Arch Linux repos and the AUR
Documentation
use crate::aur::AurClient;
use crate::cli::Options;
use crate::localdb::LocalDb;
use crate::output;
use crate::pacman::Toolchain;
use crate::version::vercmp;
use anyhow::Result;
use std::cmp::Ordering;

pub async fn print_foreign(options: &Options, tools: &Toolchain) -> Result<i32> {
    let names = tools.foreign_names().await.unwrap_or_default();

    if options.quiet {
        for name in &names {
            output::inline_line(name);
        }
        return Ok(0);
    }

    let local = LocalDb::load_default().unwrap_or_else(|_| LocalDb::empty());
    for name in &names {
        if let Some(pkg) = local.get(name) {
            output::line(format!(
                "{} {}",
                output::inline(&pkg.name),
                output::inline(&pkg.version)
            ));
        } else {
            output::inline_line(name);
        }
    }

    Ok(0)
}

pub async fn print_aur_updates(
    options: &Options,
    tools: &Toolchain,
    aur: &AurClient,
) -> Result<i32> {
    let updates = aur_updates(options, tools, aur).await?;

    for update in &updates {
        if options.quiet {
            output::inline_line(&update.name);
        } else {
            output::line(format!(
                "{} {} -> {}",
                output::inline(&update.name),
                output::inline(&update.local_version),
                output::inline(&update.aur_version)
            ));
        }
    }

    Ok(0)
}

pub async fn aur_update_targets(
    options: &Options,
    tools: &Toolchain,
    aur: &AurClient,
) -> Result<Vec<String>> {
    Ok(aur_updates(options, tools, aur)
        .await?
        .into_iter()
        .map(|update| update.name)
        .collect())
}

#[derive(Debug, Clone)]
struct AurUpdate {
    name: String,
    local_version: String,
    aur_version: String,
}

async fn aur_updates(
    options: &Options,
    tools: &Toolchain,
    aur: &AurClient,
) -> Result<Vec<AurUpdate>> {
    let local = LocalDb::load_default().unwrap_or_else(|_| LocalDb::empty());
    let mut names = tools.foreign_names().await.unwrap_or_else(|_| {
        local
            .packages()
            .map(|pkg| pkg.name.clone())
            .collect::<Vec<_>>()
    });
    names.sort();
    names.dedup();

    if let Some(limit) = options.limit {
        names.truncate(limit);
    }

    let aur_packages = aur.info(&names).await?;
    let mut updates = Vec::new();

    for pkg in aur_packages {
        let Some(local_pkg) = local.get(&pkg.name) else {
            continue;
        };

        if vercmp(&local_pkg.version, &pkg.version) == Ordering::Less {
            updates.push(AurUpdate {
                name: pkg.name,
                local_version: local_pkg.version.clone(),
                aur_version: pkg.version,
            });
        }
    }

    Ok(updates)
}