hysp 0.1.2

📦 An independent package manager that every hacker deserves.
Documentation
use crate::engine::args::ListArgs;
use crate::engine::config::parse_metadata_info;
use crate::engine::config::pkg_config_structure::PackageInfo;
use crate::engine::helpers::{
    local_config, print_metadata_package_info, print_package_info, read_file_content,
};
use crate::engine::msgx::{abort, info};
use anyhow::{Context, Result};
use std::fs;
use std::path::{Path, PathBuf};

const TOML_EXTENSION: &str = ".toml";

pub async fn list_pkgs(pkg_list_args: ListArgs) -> Result<()> {
    let (_hysp_remote, hysp_data_dir, _hysp_bin_dir, hysp_metadata, architecture) =
        match local_config().await {
            Ok((remote, data_dir, bin_dir, metadata, architecture)) => {
                (remote, data_dir, bin_dir, metadata, architecture)
            }
            Err(err) => {
                eprintln!("{}", err);
                std::process::exit(1);
            }
        };

    match (pkg_list_args.available, pkg_list_args.installed) {
        (true, false) => {
            print_available_pkg(&hysp_metadata, pkg_list_args.verbose, architecture).await?;
        }
        (false, true) => {
            print_installed_pkgs(&hysp_data_dir, pkg_list_args.verbose).await?;
        }
        _ => {
            abort("No such arg available");
        }
    }

    Ok(())
}

async fn print_available_pkg(
    metadata_toml: &str,
    verbose: bool,
    architecture: String,
) -> Result<(), anyhow::Error> {
    let metadata_toml_info = parse_metadata_info(metadata_toml).await?;
    info("Available packages in metadata", colored::Color::Green);
    if verbose {
        for package in metadata_toml_info.packages.clone() {
            print_metadata_package_info(metadata_toml_info.clone(), &package.name);
        }
    } else {
        for package in metadata_toml_info.packages {
            let package_arch = package.architecture.clone();
            if package_arch == architecture {
                println!("{} ", package.name);
            }
        }
    }

    Ok(())
}

async fn print_installed_pkgs(hysp_data_dir: &str, verbose: bool) -> Result<()> {
    let packages: Vec<(String, String)> = iterate_over_package_files(hysp_data_dir).collect();

    if packages.is_empty() {
        info("No packages installed via hysp", colored::Color::Red);
    } else {
        info("Installed packages ", colored::Color::Blue);
        for (file_path, file_name) in packages {
            if verbose {
                get_package_info(&file_path).await?;
            } else {
                println!("{}", file_name);
            }
        }
    }
    Ok(())
}

fn iterate_over_package_files(file_path: &str) -> impl Iterator<Item = (String, String)> + '_ {
    fs::read_dir(file_path)
        .expect("Failed to read directory")
        .filter_map(|entry| entry.ok().map(|e| e.path()))
        .filter_map(extract_file_info)
}

fn extract_file_info(entry: PathBuf) -> Option<(String, String)> {
    let file_name = entry.file_name()?.to_str()?;
    let stripped_name = Path::new(file_name).file_stem()?.to_str()?;
    let (file_path, file_name) = if stripped_name.ends_with(TOML_EXTENSION) {
        let file_path = entry.to_string_lossy().to_string();
        let file_name = stripped_name
            .strip_suffix(TOML_EXTENSION)
            .expect("Expected TOML extension")
            .to_string();
        (file_path, file_name)
    } else {
        let file_path = entry.to_string_lossy().to_string();
        let file_name = stripped_name.to_string();
        (file_path, file_name)
    };
    Some((file_path, file_name))
}

async fn get_package_info(pkg_file: &str) -> Result<()> {
    let package_toml = read_file_content(pkg_file)
        .await
        .context("Failed to read package file")?;
    let parsed_package_info: PackageInfo =
        toml::from_str(&package_toml).context("Failed to parse package TOML")?;

    print_package_info(parsed_package_info);

    Ok(())
}