use std::path::PathBuf;
use crate::commons::{ErrorCode, models::IndexModel};
use super::{
build_opts::BuildOpts,
cargo_build::run_cargo_build,
cargo_workspace::{Workspace, get_workspace},
check_env::check_env,
find_target::{find_package_rlib_in_target, find_wasm_in_target, profile_name},
wasm_opt::run_wasm_opt,
wasm_path::WasmPath,
};
pub fn run(opts: BuildOpts) -> Result<(), ErrorCode> {
let ws = match get_workspace() {
Ok(ws) => ws,
Err(err) => {
log::error!("Can't read workspace");
return Err(err);
}
};
run_with_ws(opts, &ws, false)
}
pub fn run_with_ws(opts: BuildOpts, ws: &Workspace, allow_error: bool) -> Result<(), ErrorCode> {
let package_name = match opts.inner.package_name.as_deref() {
Some(name) => name.to_string(),
None => match ws.infer_package_name() {
Some(name) => {
log::info!("Inferred package name = {name}");
name
}
None => {
log::error!(
"Can't find vertigo project in {} (no cdylib member)",
ws.get_root_dir()
);
return Err(ErrorCode::CantFindCdylibMember);
}
},
};
check_env()?;
let release = opts.inner.release_mode.unwrap_or(true);
let profile = profile_name(release);
let dest_dir = WasmPath::new(PathBuf::from(&opts.common.dest_dir));
dest_dir.remove_dir_all();
dest_dir.create_dir_all();
find_package_rlib_in_target(&package_name, profile).remove_file()?;
let target_path = match run_cargo_build(
&package_name,
&opts.get_public_path(),
ws,
allow_error,
release,
&opts.inner.cargo_opts,
)? {
Ok(path) => path,
Err(_) => return Err(ErrorCode::BuildFailed),
};
let vertigo_statics_dir = target_path.join("static");
let mut run_script_content = match std::fs::read(vertigo_statics_dir.join("wasm_run.js")) {
Ok(content) => content,
Err(err) => {
log::error!("Can't read wasm_run from statics directory: {err}");
return Err(ErrorCode::CantReadWasmRunFromStatics);
}
};
if !opts.inner.wasm_run_source_map {
erase_last_two_lines(&mut run_script_content);
}
let run_script_hash_name = opts
.new_path_in_static_make(&["wasm_run.js"])
.save_with_hash(&run_script_content)?;
if opts.inner.wasm_run_source_map {
let run_script_sourcemap_content =
match std::fs::read_to_string(vertigo_statics_dir.join("wasm_run.js.map")) {
Ok(content) => {
content.replace("wasm_run.js", &run_script_hash_name)
}
Err(err) => {
log::error!("Can't read wasm_run sourcemap from statics directory: {err}");
return Err(ErrorCode::CantReadWasmRunFromStatics);
}
};
opts.new_path_in_static_make(&["wasm_run.js.map"])
.save(&run_script_sourcemap_content.into_bytes())?;
}
let wasm_path_target = find_wasm_in_target(&package_name, profile);
let wasm_path = opts.new_path_in_static_from(&wasm_path_target);
let wasm_path_hash =
if opts.inner.wasm_opt.unwrap_or(true) && run_wasm_opt(&wasm_path_target, &wasm_path) {
let wasm_path_hash = wasm_path.save_with_hash(wasm_path.read()?.as_slice())?;
wasm_path.remove_file()?;
wasm_path_hash
} else {
let wasm_content = wasm_path_target.read()?;
wasm_path.save_with_hash(wasm_content.as_slice())?
};
let index = IndexModel {
run_js: opts.public_path_to(run_script_hash_name),
wasm: opts.public_path_to(wasm_path_hash),
};
let index_content = serde_json::to_string_pretty(&index).map_err(|err| {
log::error!("Can't serialize index.json: {err}");
ErrorCode::CantWriteOrRemoveFile
})?;
opts.new_path_in_static_make(&["index.json"])
.save(index_content.as_bytes())?;
if let Ok(dir) = std::fs::read_dir(vertigo_statics_dir.join("included")) {
for entry in dir {
match entry {
Ok(entry) => {
let src_file_path = WasmPath::new(entry.path());
let content = src_file_path.read()?;
let dest_file_path = opts.new_path_in_static_from(&src_file_path);
dest_file_path.save(&content)?;
}
Err(err) => {
log::warn!("Can't read entry: {err}");
return Err(ErrorCode::CantReadStaticFile);
}
}
}
}
Ok(())
}
fn erase_last_two_lines(content: &mut Vec<u8>) {
let mut last_newline_pos = None;
let mut second_last_newline_pos = None;
for (i, &byte) in content.iter().enumerate() {
if byte == b'\n' {
second_last_newline_pos = last_newline_pos; last_newline_pos = Some(i); }
}
if let Some(second_last) = second_last_newline_pos {
content.truncate(second_last);
}
}