CarbonJS 0.1.9

A KubeJS script manager
use crate::config::{get_config, get_instance_config};
use crate::files::{check_if_path_exists, copy_dir_contents, remove_files_in_dir};
use crate::PackageInfo;
extern crate simplelog;

use serde_json::{json, Map};
use simplelog::*;
use std::convert::Infallible;
use std::fs::{self, File};
use std::io::BufWriter;
use std::path::PathBuf;

const DIRS: [&str; 4] = [
    "server_scripts",
    "startup_scripts",
    "client_scripts",
    "assets",
];

use reqwest;

pub async fn add_package(
    pkg: PackageInfo,
    name: &str,
    version: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let temp_dir = tempfile::tempdir().map_err(|e| format!("Failed to create temp dir: {}", e))?;

    let mut builder = git2::build::RepoBuilder::new();
    if !version.is_empty() {
        builder.branch(version);
    }

    let repo;
    let response = reqwest::get(pkg.repository.as_str()).await?;
    if response.status().is_success() {
        repo = builder
            .clone(pkg.repository.as_str(), temp_dir.path())
            .map_err(|e| format!("Failed to clone repo: {}", e))?;
    } else {
        error!("Repository does not exist");
        return Ok(());
    }

    let repo_path = repo.path().to_owned();

    let head = repo.head()?;
    let branch_name = head.shorthand().ok_or_else(|| {
        std::io::Error::new(std::io::ErrorKind::Other, "Failed to get branch name")
    })?;

    let mut config = get_config(temp_dir.path())?;

    let instance_config = get_instance_config()?;

    if !config.minecraftVersion.is_empty() {
        if !config.minecraftVersion.contains(&instance_config.version) {
            error!("Minecraft version mismatch");
            return Ok(());
        }
    }

    if !config.modloaders.is_empty() {
        if !config.modloaders.contains(&instance_config.modloader) {
            error!("Modloader mismatch");
            return Ok(());
        }
    }

    let mut pkg_dir = temp_dir.path().to_owned();
    let current_dir = std::env::current_dir()?;

    for dir in DIRS {
        let dir = PathBuf::from(dir);
        let source_path = temp_dir.path().join(&dir);
        let target_path = current_dir.join("kubejs").join(&dir);

        if check_if_path_exists(&source_path)? {
            copy_dir_contents(&source_path, &target_path)?;
        }
    }

    let carbon_folder = current_dir.join("kubejs").join("carbon").join(&config.name);
    if !check_if_path_exists(&carbon_folder)? {
        std::fs::create_dir_all(&carbon_folder)?;
    }

    let source_path = temp_dir.path();
    let target_path = carbon_folder;
    copy_dir_contents(&source_path, &target_path)?;

    info!(
        "{}",
        format!(
            "Successfully installed {:?} with the version of ({:?}).",
            config.name, config.version
        )
    );

    let config_path = current_dir.join("kubejs/carbon.json");

    let file = File::open(&config_path)?;
    let reader = std::io::BufReader::new(file);
    let mut instance_config: serde_json::Value = serde_json::from_reader(reader)?;

    if !instance_config["dependencies"].is_object() {
        instance_config["dependencies"] = json!(Map::new());
    }

    let dependencies = instance_config["dependencies"].as_object_mut().unwrap();

    dependencies.insert(config.name.clone(), json!(branch_name));

    let file = File::create(&config_path)?;
    let writer = BufWriter::new(file);
    serde_json::to_writer_pretty(writer, &instance_config)?;

    Ok(())
}

pub fn remove_package(pkg: PackageInfo, name: &str) -> Result<(), Box<dyn std::error::Error>> {
    let instance_config = get_instance_config()?;
    let current_dir = std::env::current_dir()?;
    let carbon_folder = current_dir.join("kubejs").join("carbon");
    let config_path = current_dir.join("kubejs/carbon.json");
    let kubejs_path = current_dir.join("kubejs");

    let carbon_folder = carbon_folder.join(name);

    if carbon_folder.exists() && carbon_folder.is_dir() {
        for entry in fs::read_dir(&carbon_folder)? {
            let entry = entry?;
            let dir_name = entry.file_name();
            let dir_path = carbon_folder.join(&dir_name);

            if dir_path.is_dir() {
                for file_entry in fs::read_dir(&dir_path)? {
                    let file_entry = file_entry?;
                    let file_name = file_entry.file_name();
                    let kubejs_file_path = kubejs_path.join(&dir_name).join(&file_name);

                    if kubejs_file_path.exists() && kubejs_file_path.is_file() {
                        fs::remove_file(kubejs_file_path)?;
                    }
                }
            }
        }
    }

    fs::remove_dir_all(&carbon_folder)?;

    let file = File::open(&config_path)?;
    let reader = std::io::BufReader::new(file);
    let mut instance_config: serde_json::Value = serde_json::from_reader(reader)?;

    if !instance_config["dependencies"].is_object() {
        instance_config["dependencies"] = json!(Map::new());
    }

    let dependencies = instance_config["dependencies"].as_object_mut().unwrap();

    if !dependencies.contains_key(name) {
        error!("Package not found");
        return Ok(());
    }

    dependencies.remove(name);

    let file = File::create(&config_path)?;

    let writer = BufWriter::new(file);

    serde_json::to_writer_pretty(writer, &instance_config)?;

    info!("{}", format!("Successfully removed {:?}.", pkg.name));

    Ok(())
}