lumer 0.1.3

Lumer is a tool for managing Lumi projects
Documentation
use dirs::home_dir;
use lumer::run;
use miette::Result;
use std::process::{Command, ExitCode};
use std::{
    env::var_os,
    fs::{copy, create_dir_all, read_dir},
    io,
    path::Path,
};

#[tokio::main]
async fn main() -> Result<ExitCode> {
    ensure_lumic_installed().expect("failed to install lumic");
    ensure_stdlib().expect("failed to install lumi-std");
    run().await
}

fn ensure_lumic_installed() -> Result<(), io::Error> {
    if var_os("LUMER_SKIP_LUMIC").is_some() {
        return Ok(());
    }

    if Command::new("lumic")
        .arg("--version")
        .status()
        .is_ok_and(|status| status.success())
    {
        return Ok(());
    }

    println!("Installing lumic");
    let output = Command::new("cargo")
        .args(["install", "lumic"])
        .output()
        .map_err(|e| io::Error::other(format!("cargo failed: {}", e)))?;

    if !output.status.success() {
        eprintln!("lumic install failed - run: cargo install lumic");
        return Ok(());
    }

    println!("lumic ready");
    Ok(())
}

fn ensure_stdlib() -> Result<(), io::Error> {
    let home_dir =
        home_dir().ok_or(io::Error::new(io::ErrorKind::NotFound, "no home directory"))?;

    let stdlib_dir = home_dir
        .join(".local")
        .join("lib")
        .join("lumi")
        .join("lumi-std");

    if stdlib_dir.exists() {
        return Ok(());
    }

    let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
    let source_stdlib = manifest_dir.join("lumi-std");

    if !source_stdlib.exists() {
        eprintln!(
            "Warning: lumi-std not found at {}, skipping",
            source_stdlib.display()
        );
        return Ok(());
    }

    create_dir_all(&stdlib_dir)
        .map_err(|e| io::Error::other(format!("failed to create stdlib dir: {}", e)))?;

    for entry in read_dir(&source_stdlib)? {
        let entry = entry?;
        let src = entry.path();
        let dest = stdlib_dir.join(src.file_name().ok_or_else(|| {
            io::Error::new(io::ErrorKind::InvalidInput, "invalid file name in lumi-std")
        })?);

        if src.is_file() {
            copy(&src, &dest).map_err(|e| {
                io::Error::other(format!("failed to copy {}: {}", src.display(), e))
            })?;
        }
    }

    println!("Installed lumi-std to {}", stdlib_dir.display());
    Ok(())
}