libxinux 1.0.2

Collection of API & ABI for Xinux
Documentation
use crate::{
    profile::list::{list, name_from_attr},
    utils, PackageAttr, PackageUpdate,
};
use anyhow::{anyhow, Result};
use log::debug;
use tokio::process::Command;

pub async fn updatable() -> Result<Vec<PackageUpdate>> {
    utils::misc::updatable(list()?).await
}

pub async fn updatable_all() -> Result<Vec<PackageUpdate>> {
    let installed = list()?;
    let mut updatable = vec![];

    for pkg in installed {
        debug!("Checking for updates: {:?}", pkg);
        match &pkg.attr {
            PackageAttr::NixPkgs { attr } => {
                let output = Command::new("nix")
                    .arg("eval")
                    .arg(format!("nixpkgs#{}.version", attr))
                    .arg("--raw")
                    .output()
                    .await;
                if let Ok(output) = output {
                    let output = String::from_utf8(output.stdout)?;
                    let version = output.trim();

                    if version.is_empty() {
                        continue;
                    } else if pkg.version.is_none() || version != pkg.version.as_ref().unwrap() {
                        updatable.push(PackageUpdate {
                            attr: pkg.attr.clone(),
                            new_version: version.to_string(),
                            old_version: pkg.version.unwrap_or_default(),
                        });
                    }
                }
            }
            PackageAttr::External { url, attr } => {
                let output = Command::new("nix")
                    .arg("eval")
                    .arg(format!("{}#{}.version", url, attr))
                    .arg("--raw")
                    .output()
                    .await;
                if let Ok(output) = output {
                    let output = String::from_utf8(output.stdout)?;
                    let version = output.trim();

                    if version.is_empty() {
                        continue;
                    } else if pkg.version.is_none() || version != pkg.version.as_ref().unwrap() {
                        updatable.push(PackageUpdate {
                            attr: pkg.attr.clone(),
                            new_version: version.to_string(),
                            old_version: pkg.version.unwrap_or_default(),
                        });
                    }
                }
            }
        }
    }
    Ok(updatable)
}

pub async fn update(pkgs: &[&str]) -> Result<()> {
    let list = list()?
        .into_iter()
        .map(|x| x.attr.to_string())
        .collect::<Vec<_>>();
    let mut pkgs_to_update = Vec::new();
    for pkg in pkgs {
        if list.contains(&pkg.to_string()) {
            if let Ok(name) = name_from_attr(pkg) {
                pkgs_to_update.push(name);
            }
        } else {
            println!("Package {} is not installed", pkg);
        }
    }

    if pkgs_to_update.is_empty() {
        return Err(anyhow!("No packages to update"));
    }

    let output = Command::new("nix")
        .arg("profile")
        .arg("upgrade")
        .args(pkgs_to_update)
        .status()
        .await?;
    debug!("{}", output);
    Ok(())
}

pub async fn update_all() -> Result<()> {
    let output = Command::new("nix")
        .arg("profile")
        .arg("upgrade")
        .arg("--all")
        .status()
        .await?;
    debug!("{}", output);
    Ok(())
}