vertigo_cli/build/
build_run.rs1use std::path::PathBuf;
2
3use crate::commons::{ErrorCode, models::IndexModel};
4
5use super::{
6 build_opts::BuildOpts,
7 cargo_build::run_cargo_build,
8 cargo_workspace::{Workspace, get_workspace},
9 check_env::check_env,
10 find_target::find_wasm_in_target,
11 wasm_opt::run_wasm_opt,
12 wasm_path::WasmPath,
13};
14
15pub fn run(opts: BuildOpts) -> Result<(), ErrorCode> {
16 let ws = match get_workspace() {
17 Ok(ws) => ws,
18 Err(err) => {
19 log::error!("Can't read workspace");
20 return Err(err);
21 }
22 };
23
24 run_with_ws(opts, &ws, false)
25}
26
27pub fn run_with_ws(opts: BuildOpts, ws: &Workspace, allow_error: bool) -> Result<(), ErrorCode> {
28 let package_name = match opts.inner.package_name.as_deref() {
29 Some(name) => name.to_string(),
30 None => match ws.infer_package_name() {
31 Some(name) => {
32 log::info!("Inferred package name = {name}");
33 name
34 }
35 None => {
36 log::error!(
37 "Can't find vertigo project in {} (no cdylib member)",
38 ws.get_root_dir()
39 );
40 return Err(ErrorCode::CantFindCdylibMember);
41 }
42 },
43 };
44
45 check_env()?;
46
47 let release = opts.inner.release_mode.unwrap_or(true);
48
49 let dest_dir = WasmPath::new(PathBuf::from(&opts.common.dest_dir));
50
51 dest_dir.remove_dir_all();
54 dest_dir.create_dir_all();
55
56 let target_path = match run_cargo_build(
59 &package_name,
60 &opts.get_public_path(),
61 ws,
62 allow_error,
63 release,
64 &opts.inner.cargo_opts,
65 )? {
66 Ok(path) => path,
67 Err(_) => return Err(ErrorCode::BuildFailed),
68 };
69
70 let vertigo_statics_dir = target_path.join("static");
73
74 let mut run_script_content = match std::fs::read(vertigo_statics_dir.join("wasm_run.js")) {
75 Ok(content) => content,
76 Err(err) => {
77 log::error!("Can't read wasm_run from statics directory: {err}");
78 return Err(ErrorCode::CantReadWasmRunFromStatics);
79 }
80 };
81
82 if !opts.inner.wasm_run_source_map {
83 erase_last_two_lines(&mut run_script_content);
84 }
85
86 let run_script_hash_name = opts
87 .new_path_in_static_make(&["wasm_run.js"])
88 .save_with_hash(&run_script_content)?;
89
90 if opts.inner.wasm_run_source_map {
91 let run_script_sourcemap_content =
92 match std::fs::read_to_string(vertigo_statics_dir.join("wasm_run.js.map")) {
93 Ok(content) => {
94 content.replace("wasm_run.js", &run_script_hash_name)
96 }
97 Err(err) => {
98 log::error!("Can't read wasm_run sourcemap from statics directory: {err}");
99 return Err(ErrorCode::CantReadWasmRunFromStatics);
100 }
101 };
102
103 opts.new_path_in_static_make(&["wasm_run.js.map"])
104 .save(&run_script_sourcemap_content.into_bytes())?;
105 }
106
107 let wasm_path_target = find_wasm_in_target(&target_path, &package_name);
110 let wasm_path = opts.new_path_in_static_from(&wasm_path_target);
111
112 let wasm_path_hash =
115 if opts.inner.wasm_opt.unwrap_or(true) && run_wasm_opt(&wasm_path_target, &wasm_path) {
116 let wasm_path_hash = wasm_path.save_with_hash(wasm_path.read()?.as_slice())?;
118 wasm_path.remove_file()?;
119 wasm_path_hash
120 } else {
121 let wasm_content = wasm_path_target.read()?;
123 wasm_path.save_with_hash(wasm_content.as_slice())?
124 };
125
126 let index = IndexModel {
129 run_js: opts.public_path_to(run_script_hash_name),
130 wasm: opts.public_path_to(wasm_path_hash),
131 };
132
133 let index_content = serde_json::to_string_pretty(&index).map_err(|err| {
134 log::error!("Can't serialize index.json: {err}");
135 ErrorCode::CantWriteOrRemoveFile
136 })?;
137 opts.new_path_in_static_make(&["index.json"])
138 .save(index_content.as_bytes())?;
139
140 if let Ok(dir) = std::fs::read_dir(vertigo_statics_dir.join("included")) {
143 for entry in dir {
144 match entry {
145 Ok(entry) => {
146 let src_file_path = WasmPath::new(entry.path());
147 let content = src_file_path.read()?;
148 let dest_file_path = opts.new_path_in_static_from(&src_file_path);
149 dest_file_path.save(&content)?;
150 }
151 Err(err) => {
152 log::warn!("Can't read entry: {err}");
153 return Err(ErrorCode::CantReadStaticFile);
154 }
155 }
156 }
157 }
158
159 Ok(())
160}
161
162fn erase_last_two_lines(content: &mut Vec<u8>) {
163 let mut last_newline_pos = None;
165 let mut second_last_newline_pos = None;
166
167 for (i, &byte) in content.iter().enumerate() {
168 if byte == b'\n' {
169 second_last_newline_pos = last_newline_pos; last_newline_pos = Some(i); }
172 }
173
174 if let Some(second_last) = second_last_newline_pos {
176 content.truncate(second_last);
177 }
178}