alerta-cli 0.1.2

CLI tool for showing simple GUI dialogs on X11
use std::{
    env,
    error::Error,
    fs::{self, File},
    io::{self, Seek as _, SeekFrom, Write as _},
    path::{Path, PathBuf},
    process::Command,
    thread,
    time::Duration,
};

const ENV_VAR: &str = "SIZEBENCH";

const TARGET_TRIPLE: &str = include_str!(concat!(env!("OUT_DIR"), "/target.txt"));

type Result<T> = std::result::Result<T, Box<dyn Error>>;

fn cargo_build(release: bool) {
    let mut command = Command::new(env::var_os("CARGO").expect("`$CARGO` is not set"));
    command.args(["build", "--bin", "alerta", "--target", TARGET_TRIPLE]);
    if release {
        command.arg("--release");
    }
    let status = command.status().unwrap();
    assert!(status.success());
    thread::sleep(Duration::from_millis(1000));
}

fn upx(release: bool, infile: &str, outfile: &str) {
    let infile = path(release).with_file_name(infile);
    let outfile = path(release).with_file_name(outfile);
    fs::remove_file(&outfile).ok();
    let mut upx = Command::new("upx");
    if release {
        upx.arg("--brute");
    }
    let status = upx
        .arg("-o")
        .arg(outfile)
        .arg(infile)
        .status()
        .map_err(|e| format!("failed to run `upx`: {e}"))
        .unwrap();
    assert!(status.success());
}

fn path(release: bool) -> PathBuf {
    let profile = if release { "release" } else { "debug" };
    PathBuf::from(format!("../../target/{TARGET_TRIPLE}/{profile}/alerta"))
}

fn size(path: impl AsRef<Path>) -> Result<u64> {
    let path = path.as_ref();
    let mut f =
        File::open(path).map_err(|e| format!("failed to open '{}': {e}", path.display()))?;
    f.seek(SeekFrom::End(0))?;
    Ok(f.stream_position()?)
}

fn main() -> Result<()> {
    let mut summary = None;
    if let Some(step) = env::var_os("GITHUB_STEP_SUMMARY")
        && env::var_os(ENV_VAR).is_some()
    {
        summary = Some(File::options().append(true).create(true).open(step)?);
    }

    let mut append = |s: &str| -> io::Result<()> {
        if let Some(f) = &mut summary {
            writeln!(f, "{s}")?;
        }

        println!("{s}");
        Ok(())
    };

    let release = env::var_os(ENV_VAR).is_some();
    let profile = if release { "release" } else { "debug" };
    append("### `alerta` Binary Size")?;
    append("")?;
    append(&format!("Build profile: **`{profile}`**"))?;

    let path_release = path(release);
    let path_upx = path_release.with_file_name("alerta-upx");

    cargo_build(release);
    let size_release = size(&path_release)? / 1024;

    append("| File | Size |")?;
    append("|------|------|")?;
    append(&format!(
        "| `{}` | {size_release} KiB |",
        path_release.display()
    ))?;

    upx(release, "alerta", "alerta-upx");
    let size_upx = size(&path_upx)? / 1024;

    append(&format!("| `{}` | {size_upx} KiB |", path_upx.display()))?;

    Ok(())
}