mirror of
https://github.com/zhom/banderole.git
synced 2026-06-13 01:27:47 +02:00
refactor: move template into src
This commit is contained in:
@@ -13,9 +13,9 @@ impl EmbeddedTemplate {
|
||||
/// Get the embedded template files
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cargo_toml: include_str!("../template/Cargo.toml"),
|
||||
build_rs: include_str!("../template/build.rs"),
|
||||
main_rs: include_str!("../template/src/main.rs"),
|
||||
cargo_toml: include_str!("./template/crg.toml"),
|
||||
build_rs: include_str!("./template/build.rs"),
|
||||
main_rs: include_str!("./template/src/main.rs"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let dest_path = Path::new(&out_dir).join("data.rs");
|
||||
|
||||
// Check if we have embedded data files
|
||||
let zip_data_path = Path::new("embedded_data.zip");
|
||||
let build_id_path = Path::new("build_id.txt");
|
||||
|
||||
if zip_data_path.exists() && build_id_path.exists() {
|
||||
// Read the build ID
|
||||
let build_id = fs::read_to_string(build_id_path)
|
||||
.expect("Failed to read build ID");
|
||||
|
||||
// Copy the zip file to the OUT_DIR so include_bytes! can find it
|
||||
let out_zip_path = Path::new(&out_dir).join("embedded_data.zip");
|
||||
fs::copy(zip_data_path, &out_zip_path)
|
||||
.expect("Failed to copy embedded data to OUT_DIR");
|
||||
|
||||
// Generate the data.rs file with embedded data
|
||||
let data_rs_content = format!(
|
||||
r#"
|
||||
// Generated at build time - contains embedded application data
|
||||
const ZIP_DATA: &[u8] = include_bytes!("embedded_data.zip");
|
||||
const BUILD_ID: &str = "{}";
|
||||
"#,
|
||||
build_id.trim()
|
||||
);
|
||||
|
||||
fs::write(&dest_path, data_rs_content)
|
||||
.expect("Failed to write data.rs");
|
||||
} else {
|
||||
// Generate placeholder data for template compilation
|
||||
let data_rs_content = r#"
|
||||
// Placeholder data for template compilation
|
||||
const ZIP_DATA: &[u8] = &[];
|
||||
const BUILD_ID: &str = "template";
|
||||
"#;
|
||||
|
||||
fs::write(&dest_path, data_rs_content)
|
||||
.expect("Failed to write placeholder data.rs");
|
||||
}
|
||||
|
||||
// Tell Cargo to rerun this script if the embedded data changes
|
||||
println!("cargo:rerun-if-changed=embedded_data.zip");
|
||||
println!("cargo:rerun-if-changed=build_id.txt");
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "banderole-app"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
directories = "6"
|
||||
zip = "4"
|
||||
serde_json = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
# No build dependencies needed - data is embedded at compile time
|
||||
|
||||
# Optimize for size and performance
|
||||
[profile.release]
|
||||
opt-level = "z" # Optimize for size
|
||||
lto = true # Enable Link Time Optimization
|
||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations
|
||||
panic = "abort" # Abort on panic (smaller binary)
|
||||
strip = true # Strip symbols from binary
|
||||
@@ -0,0 +1,139 @@
|
||||
use anyhow::{Context, Result};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::Cursor;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
use zip::ZipArchive;
|
||||
use directories::BaseDirs;
|
||||
|
||||
// These will be replaced during the build process with actual embedded data
|
||||
// The build script will generate a data.rs file with the actual data
|
||||
include!(concat!(env!("OUT_DIR"), "/data.rs"));
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
// Get cache directory
|
||||
let cache_dir = get_cache_dir()?;
|
||||
let app_dir = cache_dir.join(&BUILD_ID);
|
||||
let ready_file = app_dir.join(".ready");
|
||||
|
||||
// Check if already extracted and ready
|
||||
if ready_file.exists() && is_extraction_valid(&app_dir)? {
|
||||
return run_app(&app_dir, &args[1..]);
|
||||
}
|
||||
|
||||
// Extract application if needed
|
||||
extract_application(&app_dir)?;
|
||||
|
||||
// Mark as ready
|
||||
fs::write(&ready_file, "ready")?;
|
||||
|
||||
// Run the application
|
||||
run_app(&app_dir, &args[1..])
|
||||
}
|
||||
|
||||
fn get_cache_dir() -> Result<PathBuf> {
|
||||
let cache_dir = BaseDirs::new().unwrap().cache_dir().join("banderole");
|
||||
fs::create_dir_all(&cache_dir).context("Failed to create cache directory")?;
|
||||
Ok(cache_dir)
|
||||
}
|
||||
|
||||
fn is_extraction_valid(app_dir: &Path) -> Result<bool> {
|
||||
let app_package_json = app_dir.join("app").join("package.json");
|
||||
let node_executable = if cfg!(windows) {
|
||||
app_dir.join("node").join("node.exe")
|
||||
} else {
|
||||
app_dir.join("node").join("bin").join("node")
|
||||
};
|
||||
|
||||
Ok(app_package_json.exists() && node_executable.exists())
|
||||
}
|
||||
|
||||
fn extract_application(app_dir: &Path) -> Result<()> {
|
||||
// Create app directory
|
||||
fs::create_dir_all(app_dir).context("Failed to create app directory")?;
|
||||
|
||||
// Extract embedded zip data
|
||||
let cursor = Cursor::new(ZIP_DATA);
|
||||
let mut archive = ZipArchive::new(cursor).context("Failed to open embedded zip archive")?;
|
||||
|
||||
for i in 0..archive.len() {
|
||||
let mut file = archive.by_index(i).context("Failed to read zip entry")?;
|
||||
let outpath = app_dir.join(file.name());
|
||||
|
||||
if file.name().ends_with('/') {
|
||||
// Directory
|
||||
fs::create_dir_all(&outpath).context("Failed to create directory")?;
|
||||
} else {
|
||||
// File
|
||||
if let Some(parent) = outpath.parent() {
|
||||
fs::create_dir_all(parent).context("Failed to create parent directory")?;
|
||||
}
|
||||
|
||||
let mut outfile = fs::File::create(&outpath).context("Failed to create output file")?;
|
||||
std::io::copy(&mut file, &mut outfile).context("Failed to extract file")?;
|
||||
|
||||
// Set executable permissions on Unix systems
|
||||
#[cfg(unix)]
|
||||
{
|
||||
if let Some(mode) = file.unix_mode() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let permissions = std::fs::Permissions::from_mode(mode);
|
||||
fs::set_permissions(&outpath, permissions).context("Failed to set permissions")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_app(app_dir: &Path, args: &[String]) -> Result<()> {
|
||||
let app_path = app_dir.join("app");
|
||||
let node_executable = if cfg!(windows) {
|
||||
app_dir.join("node").join("node.exe")
|
||||
} else {
|
||||
app_dir.join("node").join("bin").join("node")
|
||||
};
|
||||
|
||||
// Change to app directory
|
||||
env::set_current_dir(&app_path).context("Failed to change to app directory")?;
|
||||
|
||||
// Find main script from package.json
|
||||
let main_script = find_main_script(&app_path)?;
|
||||
|
||||
// Build command arguments
|
||||
let mut cmd_args = vec![main_script];
|
||||
cmd_args.extend(args.iter().cloned());
|
||||
|
||||
// Execute Node.js application
|
||||
let status = Command::new(&node_executable)
|
||||
.args(&cmd_args)
|
||||
.stdin(Stdio::inherit())
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
.status()
|
||||
.context("Failed to execute Node.js application")?;
|
||||
|
||||
std::process::exit(status.code().unwrap_or(1));
|
||||
}
|
||||
|
||||
fn find_main_script(app_path: &Path) -> Result<String> {
|
||||
let package_json_path = app_path.join("package.json");
|
||||
|
||||
if package_json_path.exists() {
|
||||
let package_content = fs::read_to_string(&package_json_path)
|
||||
.context("Failed to read package.json")?;
|
||||
|
||||
if let Ok(package_json) = serde_json::from_str::<serde_json::Value>(&package_content) {
|
||||
if let Some(main) = package_json["main"].as_str() {
|
||||
return Ok(main.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default to index.js
|
||||
Ok("index.js".to_string())
|
||||
}
|
||||
Reference in New Issue
Block a user