mc-launcher-core 0.1.0

This is an mc launcher core written in Rust.
Documentation
use std::{
    fs,
    path::{Path, PathBuf},
    process::Command,
};

use crate::{core::version::VersionJson, loader::LoaderKind, LauncherError, Result};

pub fn loader_profile_path(minecraft_dir: impl AsRef<Path>, version_id: &str) -> PathBuf {
    minecraft_dir
        .as_ref()
        .join("versions")
        .join(version_id)
        .join(format!("{version_id}.json"))
}

pub fn write_loader_profile(
    minecraft_dir: impl AsRef<Path>,
    profile: &VersionJson,
) -> Result<PathBuf> {
    let version_id = profile
        .id
        .as_deref()
        .ok_or_else(|| LauncherError::MissingField {
            context: "loader profile".to_string(),
            field: "id".to_string(),
        })?;
    let path = loader_profile_path(minecraft_dir, version_id);
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)?;
    }
    fs::write(&path, serde_json::to_vec_pretty(profile)?)?;
    Ok(path)
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InstallerInvocation {
    pub loader: LoaderKind,
    pub java_executable: PathBuf,
    pub installer_path: PathBuf,
    pub minecraft_dir: PathBuf,
}

pub fn installer_command_args(invocation: &InstallerInvocation) -> Vec<String> {
    vec![
        "-jar".to_string(),
        invocation.installer_path.to_string_lossy().to_string(),
        "--installClient".to_string(),
        invocation.minecraft_dir.to_string_lossy().to_string(),
    ]
}

pub fn run_loader_installer(invocation: &InstallerInvocation) -> Result<()> {
    let status = Command::new(&invocation.java_executable)
        .args(installer_command_args(invocation))
        .status()?;

    if status.success() {
        Ok(())
    } else {
        Err(LauncherError::InstallerFailed {
            loader: invocation.loader,
            status: status.code(),
        })
    }
}