hysp 0.1.2

📦 An independent package manager that every hacker deserves.
Documentation
use crate::engine::{helpers::local_config, msgx::info};
use anyhow::Result;
use std::env;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;

enum Health {
    ExistsWithPermissions,
    ExistsWithoutPermissions,
    DoesNotExist,
}

pub async fn check_health() -> 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);
            }
        };

    check_and_log_directory("Hysp data", &hysp_data_dir).await?;
    check_and_log_directory("Hysp bin", &hysp_bin_dir).await?;

    if is_directory_in_path(&hysp_bin_dir) {
        info(
            &format!("Hysp bin directory {}: is in PATH", hysp_bin_dir),
            colored::Color::BrightBlue,
        );
    } else {
        info(
            &format!("Hysp bin directory {}: isn't in PATH", hysp_bin_dir),
            colored::Color::Red,
        );
    }

    Ok(())
}

fn check_directory(path: &str) -> Result<Health> {
    match fs::metadata(path) {
        Ok(metadata) => {
            if metadata.is_dir() {
                let permissions = metadata.permissions();
                let mode = permissions.mode();

                if mode & 0o600 == 0o600 {
                    return Ok(Health::ExistsWithPermissions);
                } else {
                    return Ok(Health::ExistsWithoutPermissions);
                }
            } else {
                Err(anyhow::anyhow!(
                    "Path exists but is not a directory: {}",
                    path
                ))
            }
        }
        Err(e) => {
            if let std::io::ErrorKind::NotFound = e.kind() {
                info(
                    &format!("Path doesn't exist: {}", path),
                    colored::Color::Cyan,
                );
                return Ok(Health::DoesNotExist);
            } else {
                return Err(e.into());
            }
        }
    }
}
async fn check_and_log_directory(dir_name: &str, dir_path: &str) -> Result<()> {
    match check_directory(dir_path)? {
        Health::ExistsWithPermissions => info(
            &format!(
                "{} directory exists with required permissions at:  {} ",
                dir_name, dir_path
            ),
            colored::Color::Cyan,
        ),
        Health::ExistsWithoutPermissions => info(
            &format!(
                "{} directory exists but doesn't have enough permissions at:   {} ",
                dir_name, dir_path
            ),
            colored::Color::Red,
        ),
        Health::DoesNotExist => info(
            &format!("{} directory doesn't exist at:   {} ", dir_name, dir_path),
            colored::Color::BrightRed,
        ),
    };
    Ok(())
}

fn is_directory_in_path(directory: &str) -> bool {
    if let Some(paths) = env::var_os("PATH") {
        if let Some(paths_str) = paths.to_str() {
            let path_list: Vec<&str> = paths_str.split(':').collect();
            let dir_path = Path::new(directory);

            for path in path_list {
                if Path::new(path) == dir_path {
                    return true;
                }
            }
        }
    }
    false
}