From fcb9e2ef516cff0b6d5168bc6465e4615d2aa96e Mon Sep 17 00:00:00 2001 From: _ov4 Date: Wed, 21 Oct 2026 11:22:38 +0000 Subject: ci(bundle): publish portable Windows and macOS desktop packages Build and check Bundle alongside each native compiler. Publish a single Windows exe with an embedded compiler extracted into the startup directory, and a macOS tar.xz containing the app and compiler. Check Linux without publishing a desktop package and require all six nightly attachments. Include licenses in embedded assets and app resources. Verify local builds, package smoke checks and release replacement with a simulated GitHub API. Co-Authored-By: Claude Opus 5.5 --- bundle/src-tauri/src/compiler.rs | 41 ++++++++++++++++++++++++++++++++++++++++ bundle/src-tauri/src/main.rs | 9 ++++++--- 2 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 bundle/src-tauri/src/compiler.rs (limited to 'bundle/src-tauri/src') diff --git a/bundle/src-tauri/src/compiler.rs b/bundle/src-tauri/src/compiler.rs new file mode 100644 index 0000000..275a707 --- /dev/null +++ b/bundle/src-tauri/src/compiler.rs @@ -0,0 +1,41 @@ +use std::path::PathBuf; + +// Keep startup failures available to the UI, including an unwritable working directory. +pub struct Compiler(pub Result); + +impl Compiler { + pub fn load() -> Self { + Self(executable().map_err(|error| format!("Cannot load compiler: {error}"))) + } +} + +#[cfg(not(windows))] +fn executable() -> std::io::Result { + Ok(std::env::current_exe()?.with_file_name("cpsc")) +} + +#[cfg(windows)] +fn executable() -> std::io::Result { + use std::{ + fs::{self, File}, + io, + }; + + let directory = std::env::current_dir()?; + let destination = directory.join("cpsc.exe"); + let staged = directory.join(format!(".cpsc-{}.tmp", std::process::id())); + let result = (|| { + let mut compressed = flate2::read::GzDecoder::new( + &include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/binaries/cpsc.exe.gz"))[..], + ); + let mut file = File::create(&staged)?; + io::copy(&mut compressed, &mut file)?; + drop(file); + fs::rename(&staged, &destination)?; + Ok(destination) + })(); + if result.is_err() { + let _ = fs::remove_file(staged); + } + result +} diff --git a/bundle/src-tauri/src/main.rs b/bundle/src-tauri/src/main.rs index 96f040c..07f25b3 100644 --- a/bundle/src-tauri/src/main.rs +++ b/bundle/src-tauri/src/main.rs @@ -1,6 +1,8 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +mod compiler; mod runner; +use compiler::Compiler; use runner::{OutputEvent, Runner}; use tauri::{ipc::Channel, Manager, State}; @@ -20,10 +22,9 @@ async fn run_file( input: String, output: Channel, runner: State<'_, Runner>, + compiler: State<'_, Compiler>, ) -> Result<(), String> { - let executable = std::env::current_exe() - .map_err(|error| error.to_string())? - .with_file_name(if cfg!(windows) { "cpsc.exe" } else { "cpsc" }); + let executable = compiler.inner().0.clone()?; let result = runner .run(executable, path.into(), input, |stream, bytes| { let _ = output.send(OutputEvent::Data { @@ -47,9 +48,11 @@ async fn stop_run(runner: State<'_, Runner>) -> Result<(), String> { } fn main() { + let compiler = Compiler::load(); tauri::Builder::default() .plugin(tauri_plugin_dialog::init()) .manage(Runner::default()) + .manage(compiler) .invoke_handler(tauri::generate_handler![ read_file, write_file, run_file, stop_run ]) -- cgit v1.3.1-4-g156e