use std::env;
use std::fs;
use std::io;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use anyhow::anyhow;
use anyhow::Result;
use tracing::info;
use xz2::read::XzDecoder;
use zip_extract::extract;
use crate::helpers::version::LocalVersion;
use crate::packages::Package;
use crate::packages::PackageType;
pub fn get_home_dir() -> Result<PathBuf> {
let mut home_str = PathBuf::new();
#[cfg(target_family = "windows")]
{
home_str.push(std::env::var("USERPROFILE")?);
return Ok(home_str);
}
#[cfg(target_os = "macos")]
{
home_str.push("/Users/");
}
#[cfg(target_os = "linux")]
{
home_str.push("/home/");
}
if let Ok(value) = std::env::var("SUDO_USER") {
home_str.push(&value);
if fs::metadata(&home_str).is_ok() {
return Ok(home_str);
}
}
if let Ok(value) = std::env::var("USER") {
home_str.push(&value);
if fs::metadata(&home_str).is_ok() {
return Ok(home_str);
}
}
let home_value = std::env::var("HOME")?;
home_str = PathBuf::from(home_value);
Ok(home_str)
}
pub fn get_local_data_dir() -> Result<PathBuf> {
let mut home_dir = get_home_dir()?;
#[cfg(target_family = "windows")]
home_dir.push("AppData/Local");
home_dir.push(".local/share");
home_dir.push("hyper-jump");
Ok(home_dir)
}
pub async fn get_downloads_directory(package: Package) -> Result<PathBuf> {
let mut data_dir = get_local_data_dir()?;
let alias = package.alias();
data_dir.push(alias);
let does_folder_exist = tokio::fs::metadata(&data_dir).await.is_ok();
let is_folder_created = tokio::fs::create_dir_all(&data_dir).await.is_ok();
if !does_folder_exist && !is_folder_created {
return Err(anyhow!("Couldn't create downloads directory"));
}
Ok(data_dir)
}
pub fn get_file_type(package_type: PackageType) -> &'static str {
#[cfg(target_family = "windows")]
{
"zip"
}
#[cfg(target_os = "macos")]
{
match package_type {
PackageType::CardanoSubmitApi => "tar.gz",
PackageType::PartnerChainNode => "zip",
PackageType::PartnerChainCli => "zip",
PackageType::SidechainCli => "zip",
PackageType::CardanoNode => "tar.gz",
PackageType::CardanoCli => "tar.gz",
PackageType::Jujutsu => "tar.gz",
PackageType::Mithril => "tar.gz",
PackageType::Scrolls => "tar.gz",
PackageType::Aiken => "tar.gz",
PackageType::Zellij => "tar.gz",
PackageType::Neovim => "tar.gz",
PackageType::Dolos => "tar.xz",
PackageType::Oura => "tar.gz",
PackageType::Reth => "tar.gz",
}
}
#[cfg(target_os = "linux")]
{
match package_type {
PackageType::CardanoSubmitApi => "tar.gz",
PackageType::PartnerChainNode => "zip",
PackageType::PartnerChainCli => "zip",
PackageType::SidechainCli => "zip",
PackageType::CardanoNode => "tar.gz",
PackageType::CardanoCli => "tar.gz",
PackageType::Mithril => "tar.gz",
PackageType::Scrolls => "tar.gz",
PackageType::Zellij => "tar.gz",
PackageType::Neovim => "tar.gz",
PackageType::Aiken => "tar.gz",
PackageType::Dolos => "tar.xz",
PackageType::Oura => "tar.gz",
PackageType::Reth => "tar.gz",
}
}
}
pub fn get_platform_name() -> &'static str { std::env::consts::OS }
pub fn get_platform_name_download(package_type: PackageType) -> &'static str {
#[cfg(target_family = "windows")]
{
"win64"
}
#[cfg(target_os = "macos")]
{
#[cfg(target_arch = "aarch64")]
{
match package_type {
PackageType::CardanoSubmitApi => "",
PackageType::PartnerChainNode => "arm64",
PackageType::PartnerChainCli => "arm64",
PackageType::SidechainCli => "arm64",
PackageType::CardanoNode => "",
PackageType::CardanoCli => "",
PackageType::Jujutsu => "aarch64-apple-darwin",
PackageType::Mithril => "arm64",
PackageType::Scrolls => "aarch64-apple-darwin",
PackageType::Aiken => "aarch64-apple-darwin",
PackageType::Dolos => "aarch64-apple-darwin",
PackageType::Zellij => "aarch64-apple-darwin",
PackageType::Neovim => "arm64",
PackageType::Oura => "aarch64-apple-darwin",
PackageType::Reth => "aarch64-apple-darwin",
}
}
#[cfg(target_arch = "x86_64")]
{
match package_type {
PackageType::CardanoSubmitApi => "",
PackageType::PartnerChainNode => "x86_64",
PackageType::PartnerChainCli => "x86_64",
PackageType::SidechainCli => "x86_64",
PackageType::CardanoNode => "",
PackageType::CardanoCli => "",
PackageType::Jujutsu => "x86_64-apple-darwin",
PackageType::Mithril => "x86_64",
PackageType::Scrolls => "x86_64",
PackageType::Aiken => "x86_64-apple-darwin",
PackageType::Dolos => "x86_64-apple-darwin",
PackageType::Zellij => "x86_64-apple-darwin",
PackageType::Neovim => "x86_64",
PackageType::Oura => "x86_64-apple-darwin",
PackageType::Reth => "x86_64-apple-darwin",
}
}
}
#[cfg(target_os = "linux")]
{
match package_type {
PackageType::CardanoSubmitApi => "",
PackageType::PartnerChainNode => "",
PackageType::PartnerChainCli => "",
PackageType::SidechainCli => "",
PackageType::CardanoNode => "",
PackageType::CardanoCli => "",
PackageType::Jujutsu => "x86_64-unknown-linux-musl",
PackageType::Mithril => "x64",
PackageType::Scrolls => "x64",
PackageType::Aiken => "x86_64-unknown-linux-gnu",
PackageType::Dolos => "x86_64-unknown-linux-gnu",
PackageType::Zellij => "x86_64-unknown-linux-gnu",
PackageType::Neovim => "x86_64",
PackageType::Oura => "x86_64-unknown-linux-musl",
PackageType::Reth => "x86_64-unknown-linux-gnu",
}
}
}
pub async fn copy_package_proxy(package: Package) -> Result<()> {
let exe_path = env::current_exe().unwrap();
let mut installation_dir = get_installation_directory().await?;
if fs::metadata(&installation_dir).is_err() {
fs::create_dir_all(&installation_dir)?;
}
add_to_path(&installation_dir)?;
let alias = package.alias();
installation_dir.push(&alias);
if fs::metadata(&installation_dir).is_ok() {
let output = Command::new(&alias).arg("--&hyper-jump").output()?.stdout;
let version = String::from_utf8(output)?.trim().to_string();
if version == env!("CARGO_PKG_VERSION") {
return Ok(());
}
}
fs::copy(&exe_path, &installation_dir).map_err(|_| anyhow!("Could not copy the proxy"))?;
Ok(())
}
fn add_to_path(installation_dir: &Path) -> Result<()> {
let installation_dir = installation_dir.to_str().unwrap();
if !std::env::var("PATH")?.contains("bin") {
info!("Make sure to have {installation_dir} in PATH");
}
Ok(())
}
pub async fn get_installation_directory() -> Result<PathBuf> {
let mut installation_location = get_local_data_dir()?;
installation_location.push("bin");
Ok(installation_location)
}
pub async fn unarchive(package: Package, file: LocalVersion) -> Result<()> {
let path = format!("{}/{}.{}", file.path, file.file_name, file.file_format);
tokio::task::spawn_blocking(move || expand(package, file))
.await?
.map_err(|e| anyhow!(e))?;
tokio::fs::remove_file(path).await?;
Ok(())
}
fn expand(package: Package, tmp: LocalVersion) -> Result<()> {
use std::fs::File;
use std::os::unix::fs::PermissionsExt;
use anyhow::Context;
use flate2::read::GzDecoder;
use tar::Archive;
if fs::metadata(&tmp.file_name).is_ok() {
fs::remove_dir_all(&tmp.file_name)?;
}
let file_path = format!("{}/{}.{}", tmp.path, tmp.file_name, tmp.file_format);
let file = File::open(&file_path).map_err(|error| {
anyhow!(
"Failed to open file {}.{}, file doesn't exist. additional info: {error}",
tmp.file_name,
tmp.file_format,
)
})?;
let output = format!("{}/{}", tmp.path, tmp.file_name);
let decompress_stream: Box<dyn std::io::Read> = match tmp.file_format.as_str() {
"tar.gz" => Box::new(GzDecoder::new(&file)),
"tar.xz" => Box::new(XzDecoder::new(&file)),
"zip" => Box::new(io::empty()),
_ => return Err(anyhow!("Unsupported file format")),
};
let context_msg = format!(
"Failed to decompress or extract file {}.{}",
tmp.file_name, tmp.file_format
);
match tmp.file_format.as_str() {
"tar.gz" | "tar.xz" => {
let mut archive = Archive::new(decompress_stream);
archive.unpack(&output).with_context(|| context_msg)?;
}
"zip" => {
extract(&file, Path::new(&output), true).with_context(|| context_msg)?;
}
_ => return Err(anyhow!("Unsupported file format")),
}
let binary = &format!(
"{}/{}/{}",
tmp.file_name,
package.binary_path(),
package.binary_name()
);
let mut perms = fs::metadata(binary)?.permissions();
perms.set_mode(0o551);
fs::set_permissions(binary, perms)?;
Ok(())
}