xf 0.7.0

File-aware dynamic command runner
Documentation
use std::{
    env::{self, args, current_exe},
    fs,
    path::Path,
    process::exit,
};

use anyhow::{anyhow, Result};
use xf::Runner;

fn main() {
    match run() {
        Ok(code) => exit(code),
        Err(err) => {
            eprintln!("error: {}", err);
        }
    }
}

fn run() -> Result<i32> {
    let args: Vec<String> = args().collect();
    if let Some(arg) = args.get(1) {
        if arg.as_str() == "--xf-version" {
            print_xf_version();
            return Ok(0);
        }
    }
    let cwd = env::current_dir().map_err(|e| anyhow!("Fail to found cwd, {}", e))?;
    let exe_name = current_exe()?;
    let exe_name = exe_name
        .file_stem()
        .and_then(|v| v.to_str())
        .ok_or_else(|| anyhow!("Fail to get exe name"))?;
    let rules = load_config_by_user_var(exe_name).or_else(|| load_config_by_home_var(exe_name));
    let runner = Runner::create(rules, exe_name)?;
    runner.run(&cwd, &args[1..])
}

fn load_config_by_user_var(exe_name: &str) -> Option<String> {
    let env_name = format!("{}_CONFIG_PATH", exe_name.to_uppercase());
    let config_file = match env::var(env_name) {
        Ok(v) => v,
        Err(_) => return None,
    };
    let config_file = Path::new(&config_file);
    load_config_file(config_file)
}

fn load_config_by_home_var(exe_name: &str) -> Option<String> {
    let env_name = if cfg!(windows) { "USERPROFILE" } else { "HOME" };
    let config_file = match env::var(env_name) {
        Ok(v) => v,
        Err(_) => return None,
    };
    let mut config_file = Path::new(&config_file).to_path_buf();
    config_file.push(format!(".{}", exe_name));
    load_config_file(&config_file)
}

fn load_config_file(path: &Path) -> Option<String> {
    if !path.exists() {
        return None;
    }
    fs::read_to_string(path).ok()
}

fn print_xf_version() {
    println!(
        r#"{name} {version}
{author}
{desc} - {repo}"#,
        name = env!("CARGO_CRATE_NAME"),
        version = env!("CARGO_PKG_VERSION"),
        author = env!("CARGO_PKG_AUTHORS"),
        desc = env!("CARGO_PKG_DESCRIPTION"),
        repo = env!("CARGO_PKG_REPOSITORY")
    )
}