refactor: move template into src

This commit is contained in:
zhom
2025-07-28 16:48:03 +04:00
parent b9d6b9a146
commit 4a976c0ed1
4 changed files with 3 additions and 3 deletions
+3 -3
View File
@@ -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"),
}
}
+50
View File
@@ -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");
}
+21
View File
@@ -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
+139
View File
@@ -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())
}