sim-cli 0.3.0

CLI tool for running and comparing Solana simulator backtests
use std::{env, io::Cursor};

use eyre::{Result, bail};

const S3_BUCKET: &str = "cli.simulator.termina.technology";

pub async fn update() -> Result<()> {
    let s3_key = platform_key()?;
    let url = format!("https://{S3_BUCKET}/{s3_key}");

    println!("Downloading {url} ...");
    let bytes = reqwest::get(&url)
        .await?
        .error_for_status()?
        .bytes()
        .await?;

    let current_exe = env::current_exe()?.canonicalize()?;
    let parent = current_exe
        .parent()
        .ok_or_else(|| eyre::eyre!("could not determine parent directory of current executable"))?;

    let tmp = tempfile::NamedTempFile::new_in(parent)?;
    let tmp_path = tmp.path().to_owned();

    let gz = flate2::read::GzDecoder::new(Cursor::new(&bytes));
    let mut archive = tar::Archive::new(gz);
    let mut found = false;
    for entry in archive.entries()? {
        let mut entry = entry?;
        if entry.path()?.ends_with("sim") {
            entry.unpack(&tmp_path)?;
            found = true;
            break;
        }
    }
    if !found {
        bail!("sim binary not found in archive");
    }

    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        std::fs::set_permissions(&tmp_path, std::fs::Permissions::from_mode(0o755))?;
    }

    std::fs::rename(&tmp_path, &current_exe)?;

    println!("Updated: {}", current_exe.display());
    Ok(())
}

fn platform_key() -> Result<&'static str> {
    match (env::consts::OS, env::consts::ARCH) {
        ("linux", "x86_64") => Ok("sim-linux-x86_64.tar.gz"),
        ("macos", "aarch64") => Ok("sim-darwin-aarch64.tar.gz"),
        (os, arch) => bail!("unsupported platform: {os}-{arch}"),
    }
}