factorio-rs-cli 0.1.2

CLI for transpiling Rust into Lua Factorio mods
use std::path::{Path, PathBuf};

#[derive(Debug, thiserror::Error)]
pub enum CliError {
    #[error("failed to read `{path}`")]
    ReadFile {
        path: PathBuf,
        source: std::io::Error,
    },

    #[error("failed to write `{path}`")]
    WriteFile {
        path: PathBuf,
        source: std::io::Error,
    },

    #[error("failed to create `{path}`")]
    CreateDir {
        path: PathBuf,
        source: std::io::Error,
    },

    #[error("failed to read directory `{path}`")]
    ReadDir {
        path: PathBuf,
        source: std::io::Error,
    },

    #[error("failed to remove `{path}`")]
    RemoveDir {
        path: PathBuf,
        source: std::io::Error,
    },

    #[error("`{path}` already exists")]
    AlreadyExists { path: PathBuf },

    #[error("could not find `{path}`")]
    NotFound { path: PathBuf },

    #[error("invalid project path `{path}`")]
    InvalidProjectPath { path: PathBuf },

    #[error("no Rust source files found in `{path}`")]
    NoSourceFiles { path: PathBuf },

    #[error("failed to parse `{path}`")]
    ConfigParse {
        path: PathBuf,
        source: toml::de::Error,
    },

    #[error("failed to parse `{path}`")]
    CargoManifestParse {
        path: PathBuf,
        source: toml::de::Error,
    },

    #[error("failed to serialize info.json")]
    InfoJsonSerialize { source: serde_json::Error },

    #[error("failed to write zip archive `{path}`")]
    ZipWrite {
        path: PathBuf,
        source: zip::result::ZipError,
    },

    #[error("Factorio was not found on this system ({hint})")]
    FactorioNotFound { hint: String },

    #[error("failed to launch Factorio (`{target}`)")]
    LaunchFactorio {
        target: String,
        source: std::io::Error,
    },

    #[error(transparent)]
    Frontend(#[from] factorio_frontend::FrontendError),

    #[error(transparent)]
    Codegen(#[from] factorio_codegen::LuaGeneratorError),
}

pub type CliResult<T> = Result<T, CliError>;

pub fn project_root(manifest_path: Option<&Path>) -> CliResult<PathBuf> {
    let path = match manifest_path {
        None => std::env::current_dir().map_err(|source| CliError::ReadDir {
            path: PathBuf::from("."),
            source,
        })?,
        Some(path) => path.to_path_buf(),
    };

    if path.is_dir() {
        return Ok(path);
    }

    if path.is_file() {
        return path
            .parent()
            .map(Path::to_path_buf)
            .ok_or(CliError::InvalidProjectPath { path });
    }

    Err(CliError::NotFound { path })
}