rtpm 0.0.1

The official tool to simplify the management of plugins for Rtop.
Documentation
use crate::git::clone::clone;
use crate::git::pull::{do_fetch, do_merge};
use crate::util::structs::{PluginManifest, RTPMConfig, RtopConfig};
use crate::util::utils::{
    build_cargo_project, read_json_file, save_json_to_file, search_plugin, user_input_choice,
};
use colored::Colorize;
use git2::{AnnotatedCommit, Remote, Repository};
use std::fs::DirEntry;
use std::path::{Path, PathBuf};

pub fn update_packages() {
    println!(":: {}", "Update of all Rtop plugins...\n".green().bold());
    let plugins_path: PathBuf = dirs::data_dir().unwrap().join("rtop").join("plugins");
    let base_rtop_path: PathBuf = dirs::config_dir().unwrap().join("rtop");
    let rtop_config_path: PathBuf = base_rtop_path.join("config.json");
    let mut rtop_config: RtopConfig = read_json_file(&rtop_config_path);
    let rtpm_config_path: PathBuf = base_rtop_path.join("rtpm.json");
    let mut rtpm_config: RTPMConfig = read_json_file(&rtpm_config_path);

    for plugin_result in std::fs::read_dir(plugins_path.clone()).unwrap() {
        let plugin: &DirEntry = plugin_result.as_ref().unwrap();
        let folder_name: String = plugin.file_name().into_string().unwrap();
        let plugin_index: usize = if let Some(plugin_index) =
            rtpm_config.plugins.iter().position(|r| r.id == folder_name)
        {
            plugin_index
        } else {
            continue;
        };
        let plugin_manifest_path: PathBuf = if rtpm_config.plugins[plugin_index].plugin_type == 0 {
            if let Some(repository_path) = search_plugin(
                folder_name.as_str(),
                rtpm_config.clone(),
                &rtpm_config_path,
                false,
            ) {
                repository_path
                    .join("plugins")
                    .join(format!("{}.json", folder_name))
            } else {
                println!(
                    ":: {}",
                    format!(
                        "The plugin {} doesn't exist or is not available.",
                        folder_name
                    )
                    .red()
                    .bold()
                );
                continue;
            }
        } else {
            plugin.path().join("manifest.json")
        };

        let plugin_manifest: PluginManifest = read_json_file(&plugin_manifest_path);
        println!(
            ":: {}",
            format!(
                "Updating the plugin: {} ({})...",
                plugin_manifest.name.bold(),
                plugin_manifest.url
            )
            .green()
        );

        let git_repository: Repository = Repository::open(plugin.path()).unwrap();
        let mut remote: Remote = git_repository.find_remote("origin").unwrap();
        let fetch = do_fetch(&git_repository, &["main"], &mut remote);
        let need_compilation: bool;
        let fetch_commit: AnnotatedCommit = if fetch.0.is_err() {
            println!(
                ":: {}",
                format!(
                    "An error occurred while fetching the plugin: {}",
                    fetch.0.err().unwrap().message()
                )
                .red()
                .bold()
            );
            continue;
        } else {
            need_compilation = fetch.1;
            fetch.0.unwrap()
        };
        if !need_compilation {
            println!();
            continue;
        }

        if let Err(error) = do_merge(&git_repository, "main", &fetch_commit) {
            if error.message() == "no merge base found" {
                println!(
                    ":: {}",
                    "Unable to update the plugin, re-installation..."
                        .red()
                        .bold()
                );
                std::fs::remove_dir_all(plugin.path()).unwrap();
                clone(&plugin_manifest.url, &plugin.path());
                println!(":: {}", "Plugin re-installed!".green());
            } else {
                println!(
                    ":: {}",
                    format!(
                        "An error occurred while merging the plugin: {}",
                        error.message()
                    )
                    .red()
                    .bold()
                );
            }
            continue;
        }

        println!(":: {}", "Plugin updated, compilation...".green());

        let plugin_cargo_toml_path: PathBuf = dirs::data_dir()
            .unwrap()
            .join("rtop")
            .join("plugins")
            .join(plugin_manifest.id.clone())
            .join("Cargo.toml");

        println!(":: {}", "Backup previous executable...".green());

        let rtop_plugin_index: usize = rtop_config
            .plugins
            .iter()
            .position(|r| {
                r.path.starts_with(
                    &plugin
                        .path()
                        .join("target")
                        .into_os_string()
                        .into_string()
                        .unwrap(),
                )
            })
            .unwrap();
        let shared_lib_path: String = rtop_config.plugins[rtop_plugin_index].path.clone();
        let shared_lib_temp_path: PathBuf = plugins_path
            .clone()
            .join(Path::new(&shared_lib_path).file_name().unwrap());
        std::fs::copy(shared_lib_path.clone(), shared_lib_temp_path.clone()).unwrap();

        let cargo_build: bool = build_cargo_project(&plugin_cargo_toml_path);
        if !cargo_build {
            println!(":: {}", "An error occurred during compilation!".red());
            print!(
                ":: {} ",
                "Do you want to keep the old version anyway? (y/n)".purple()
            );
            if user_input_choice() {
                println!(":: {}", "Recovery of the plugin backup...".green());
                std::fs::rename(shared_lib_temp_path, shared_lib_path).unwrap();
                println!(":: {}", "Backup recovered!".green());
            } else {
                println!(
                    ":: {}",
                    "Cleaning the previously installed plugin...".green()
                );
                let rtpm_plugin_index: usize = rtpm_config
                    .plugins
                    .iter()
                    .position(|r| r.id == plugin_manifest.id)
                    .unwrap();
                rtpm_config.plugins.remove(rtpm_plugin_index);

                let rtop_plugin_index: usize = rtop_config
                    .plugins
                    .iter()
                    .position(|r| {
                        r.path.starts_with(
                            &plugin
                                .path()
                                .join("target")
                                .into_os_string()
                                .into_string()
                                .unwrap(),
                        )
                    })
                    .unwrap();
                rtop_config.plugins.remove(rtop_plugin_index);
                std::fs::remove_dir_all(plugin.path()).unwrap();
                save_json_to_file(&rtpm_config, rtpm_config_path.clone());
                save_json_to_file(&rtop_config, rtop_config_path.clone());
                std::fs::remove_file(shared_lib_temp_path).unwrap();
            }
            continue;
        }

        println!(
            ":: {}",
            format!(
                "Update of the plugin: {} ({}) is terminated!\n",
                plugin_manifest.name.bold(),
                plugin_manifest.url
            )
            .green()
        );
        let new_plugin_manifest: PluginManifest = read_json_file(&plugin_manifest_path);
        if plugin_manifest.version != new_plugin_manifest.version {
            rtpm_config.plugins[plugin_index].version = new_plugin_manifest.version;
        }
    }
    save_json_to_file(&rtpm_config, rtpm_config_path);
    println!(
        ":: {}",
        "Update of all Rtop plugins completed!".green().bold()
    );
}