vendor 0.2.0

Easy to use package manager library
Documentation
use crate::{helpers, project, MESSAGES};

use colored::Colorize;
use flate2::write::GzEncoder;
use flate2::Compression;
use global_placeholders::global;
use indicatif::{ProgressBar, ProgressStyle};
use macros_rs::{fmtstr, str, string, ternary};
use std::fs::File;

#[derive(Debug, serde::Deserialize)]
struct AuthFile {
    token: String,
    access: String,
}

#[derive(Debug, serde::Deserialize)]
struct Response {
    message: serde_json::Value,
}

fn remove_tar(file: &str) {
    if let Err(_) = std::fs::remove_file(file) {
        eprintln!(" {}", MESSAGES.get("tar_error").unwrap().bright_red());
        std::process::exit(1);
    }
}

fn write_tar(file_name: &String) -> Result<(), std::io::Error> {
    let current_dir = std::env::current_dir().expect(MESSAGES.get("tar_error").unwrap());
    log::info!("creating file: {}", file_name);
    let tar_gz = File::create(file_name)?;
    let enc = GzEncoder::new(tar_gz, Compression::default());
    let mut tar = tar::Builder::new(enc);

    tar.append_dir_all(".", format!("{}", current_dir.display()))?;
    Ok(())
}

pub fn publish() {
    let name = global!("vendor.name");
    let registry_link = global!("vendor.registry");

    match home::home_dir() {
        Some(path) => {
            if !std::path::Path::new(fmtstr!("{}/.{name}/temp", path.display())).is_dir() {
                std::fs::create_dir_all(format!("{}/.{name}/temp", path.display())).unwrap();
                println!("created {}/.{name}", path.display());
            }

            let package = project::package::read();
            let client = reqwest::blocking::Client::new();
            let file_name = format!("{}/.{name}/temp/{}.tgz", path.display(), package.info.name.replace("/", ":"));

            if std::path::Path::new(&file_name).is_file() {
                remove_tar(&file_name);
            }

            let auth = match std::fs::read_to_string(format!("{}/.{name}/credentials/{}].json", path.display(), registry_link.replace("://", "["))) {
                Ok(content) => match serde_json::from_str::<AuthFile>(&content) {
                    Ok(json) => json,
                    Err(_) => {
                        eprintln!("{} {}", "".red(), MESSAGES.get("publish_error_login").unwrap().bright_red());
                        std::process::exit(1);
                    }
                },
                Err(_) => {
                    eprintln!("{} {}", "".red(), MESSAGES.get("publish_error_login").unwrap().bright_red());
                    std::process::exit(1);
                }
            };

            println!(
                "{} {}@{}",
                MESSAGES.get("publish_msg").unwrap().bright_yellow(),
                format!("{}", package.info.name).bold(),
                format!("{}", package.info.version).bold()
            );

            let pb = ProgressBar::new_spinner();
            pb.enable_steady_tick(std::time::Duration::from_millis(80));
            pb.set_style(ProgressStyle::with_template("{spinner:.yellow} {msg}").unwrap().tick_strings(&[
                "[    ]", "[=   ]", "[==  ]", "[=== ]", "[ ===]", "[  ==]", "[   =]", "[    ]", "[   =]", "[  ==]", "[ ===]", "[====]", "[=== ]", "[==  ]", "[=   ]", "",
            ]));
            pb.set_message(string!(MESSAGES.get("publish_wait").unwrap()));

            if let Err(err) = write_tar(&file_name) {
                eprintln!("{} {}", "".red(), MESSAGES.get("publish_error_generic").unwrap().bright_red());
                eprintln!(" {} {}", "-".bright_red(), err.to_string().bright_red());
                remove_tar(&file_name);
                std::process::exit(1);
            }

            let form = reqwest::blocking::multipart::Form::new()
                .text("group", "local")
                .text("access", auth.access)
                .text("url", package.info.url)
                .text("name", package.info.name)
                .text("index", package.info.index)
                .text("author", package.info.author)
                .text("version", package.info.version)
                .text("license", package.info.license)
                .text("repository", package.info.repository)
                .text("description", package.info.description)
                .text("dependencies", format!("{:?}", package.dependencies))
                .text("visibility", ternary!(package.registry.public, "public", "private"))
                .file("tarball", &file_name)
                .unwrap();

            let response = client
                .post(format!("{registry_link}/api/v{}/create", env!("CARGO_PKG_VERSION").split(".").collect::<Vec<&str>>().join("")))
                .multipart(form)
                .header(reqwest::header::AUTHORIZATION, reqwest::header::HeaderValue::from_static(str!(auth.token.clone())))
                .send();

            match response {
                Ok(response) => {
                    match serde_json::from_str::<Response>(&response.text().unwrap()) {
                        Ok(json) => {
                            if &json.message["created"].to_string() == "null" {
                                let error = json.message["error"].to_string().clone();
                                pb.finish_with_message(format!(
                                    "\x08{} {}",
                                    "".red(),
                                    format!(
                                        "{}\n - {}",
                                        MESSAGES.get("publish_error").unwrap(),
                                        ternary!(helpers::trim_start_end(&error) == "ul", MESSAGES.get("publish_error_token").unwrap(), helpers::trim_start_end(&error))
                                    )
                                    .bright_red()
                                ));
                                remove_tar(&file_name);
                                std::process::exit(1);
                            } else {
                                pb.finish_with_message(format!(
                                    "\x08{} {}",
                                    "".green(),
                                    format!("{}{}", MESSAGES.get("publish_done").unwrap(), &json.message["created"]).bright_green()
                                ));
                                remove_tar(&file_name);
                            }
                        }
                        Err(_) => {
                            eprint!("\r{} {}\n", "".red(), MESSAGES.get("publish_error_generic").unwrap().bright_red());
                            remove_tar(&file_name);
                            std::process::exit(1);
                        }
                    };
                }
                Err(err) => {
                    eprint!("\r{} {}\n", "".red(), format!("{}: {}", MESSAGES.get("publish_error").unwrap(), err.to_string()).bright_red());
                    remove_tar(&file_name);
                    std::process::exit(1);
                }
            };
        }
        None => {
            eprintln!("{}", MESSAGES.get("home_error").unwrap().red());
            std::process::exit(1);
        }
    }
}