use std::{path::PathBuf, process::ExitCode};
use anyhow::{Context, Result, bail};
use async_fs as fs;
use clap::Parser;
use console::style;
use crate::standalone::metadata::Metadata;
mod base_exe;
mod files;
mod result;
mod target;
use self::base_exe::get_or_download_base_executable;
use self::files::{remove_source_file_ext, write_executable_file_to};
use self::target::BuildTarget;
#[derive(Debug, Clone, Parser)]
pub struct BuildCommand {
pub input: PathBuf,
#[clap(short, long)]
pub output: Option<PathBuf>,
#[clap(short, long)]
pub target: Option<BuildTarget>,
}
impl BuildCommand {
pub async fn run(self) -> Result<ExitCode> {
let target = self.target.unwrap_or_else(BuildTarget::current_system);
let output_path = self
.output
.clone()
.unwrap_or_else(|| remove_source_file_ext(&self.input));
let output_path = output_path.with_extension(target.exe_extension());
if output_path == self.input {
if self.output.is_some() {
bail!("output path cannot be the same as input path");
}
bail!(
"output path cannot be the same as input path, please specify a different output path"
);
}
let source_code = fs::read(&self.input)
.await
.context("failed to read input file")?;
let base_exe_path = get_or_download_base_executable(target).await?;
println!(
"Compiling standalone binary from {}",
style(self.input.display()).green()
);
let patched_bin = Metadata::create_env_patched_bin(base_exe_path, source_code)
.await
.context("failed to create patched binary")?;
println!(
"Writing standalone binary to {}",
style(output_path.display()).blue()
);
write_executable_file_to(output_path, patched_bin).await?;
Ok(ExitCode::SUCCESS)
}
}