libxinux 1.0.2

Collection of API & ABI for Xinux
Documentation
use std::collections::HashMap;

use anyhow::Result;
use serde::Deserialize;

use crate::{
    utils::{misc::get_pname_from_storepath, storedb::get_storebatch},
    Package, PackageAttr,
};

#[derive(Debug, Deserialize, Clone)]
struct EnvPackage {
    outputs: EnvOutput,
    pname: String,
}

#[derive(Debug, Deserialize, Clone)]
struct EnvOutput {
    out: String,
}

pub async fn list(db: &rusqlite::Connection) -> Result<Vec<Package>> {
    let output = std::process::Command::new("nix-env")
        .arg("-q")
        .arg("--out-path")
        .arg("--installed")
        .arg("--json")
        .output()?;
    let stdout = String::from_utf8(output.stdout)?;
    let packages: HashMap<String, EnvPackage> = serde_json::from_str(&stdout)?;

    let mut stmt = db.prepare("SELECT attribute, version FROM pkgs WHERE pname = ?")?;

    let mut pkgs = Vec::new();

    for (_name, pkg) in packages {
        let mut rows = stmt.query([&pkg.pname])?;
        let push;
        if let Ok(Some(row)) = rows.next() {
            push = Some(Package {
                attr: PackageAttr::NixPkgs { attr: row.get(0)? },
                version: row.get(1)?,
                pname: Some(pkg.pname),
                ..Default::default()
            });
        } else {
            continue;
        }
        if let Ok(None) = rows.next() {
            if let Some(push) = push {
                pkgs.push(push);
            }
        }
    }

    Ok(pkgs)
}

pub async fn list_accurate() -> Result<Vec<Package>> {
    let output = std::process::Command::new("nix-env")
        .arg("-q")
        .arg("--out-path")
        .arg("--installed")
        .arg("--json")
        .output()?;
    let stdout = String::from_utf8(output.stdout)?;
    let packages: HashMap<String, EnvPackage> = serde_json::from_str(&stdout)?;
    let paths = packages
        .values()
        .map(|x| x.outputs.out.split('/').last().unwrap_or(&x.outputs.out))
        .collect::<Vec<_>>();

    let storebatch = get_storebatch(paths.iter().map(AsRef::as_ref).collect()).await?;
    Ok(storebatch
        .packages
        .into_iter()
        .map(|x| Package {
            attr: PackageAttr::NixPkgs {
                attr: x.attribute.join("."),
            },
            version: x.version.clone(),
            pname: get_pname_from_storepath(x.store.as_str(), x.version).ok(),
            ..Default::default()
        })
        .collect())
}