1use anyhow::{Result, anyhow};
2use std::path::Path;
3
4pub fn read_env_yaml(project_dir: &Path) -> Result<Option<Vec<u8>>> {
5 let p = project_dir.join("env.yaml");
6 match std::fs::read(&p) {
7 Ok(content) => Ok(Some(content)),
8 Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),
9 Err(e) => Err(anyhow!("Failed to read {}: {}", p.display(), e)),
10 }
11}
12
13pub fn create_raw_bundle_wasm(
14 wasm_path: &Path,
15 env_yaml: Option<&[u8]>,
16 output_path: &Path,
17) -> Result<()> {
18 let file = std::fs::File::create(output_path)
19 .map_err(|e| anyhow!("Failed to create {}: {}", output_path.display(), e))?;
20 let mut builder = tar::Builder::new(file);
21 append_bytes(&mut builder, "manifest.json", br#"{"kind":"wasm"}"#)?;
22 let wasm_bytes = std::fs::read(wasm_path)
23 .map_err(|e| anyhow!("Failed to read {}: {}", wasm_path.display(), e))?;
24 validate_wasm(&wasm_bytes, wasm_path)?;
25 append_bytes(&mut builder, "backend.wasm", &wasm_bytes)?;
26 if let Some(env) = env_yaml {
27 append_bytes(&mut builder, "env.yaml", env)?;
28 }
29 builder.finish()?;
30 Ok(())
31}
32
33pub fn create_raw_bundle_forte(
34 dist_dir: &Path,
35 env_yaml: Option<&[u8]>,
36 output_path: &Path,
37) -> Result<()> {
38 let file = std::fs::File::create(output_path)
39 .map_err(|e| anyhow!("Failed to create {}: {}", output_path.display(), e))?;
40 let mut builder = tar::Builder::new(file);
41 append_bytes(&mut builder, "manifest.json", br#"{"kind":"wasmjs"}"#)?;
42
43 let backend_wasm = dist_dir.join("backend.wasm");
44 let wasm_bytes = std::fs::read(&backend_wasm)
45 .map_err(|e| anyhow!("Failed to read {}: {}", backend_wasm.display(), e))?;
46 validate_wasm(&wasm_bytes, &backend_wasm)?;
47 append_bytes(&mut builder, "backend.wasm", &wasm_bytes)?;
48
49 let server_js = dist_dir.join("server.js");
50 let server_bytes = std::fs::read(&server_js)
51 .map_err(|e| anyhow!("Failed to read {}: {}", server_js.display(), e))?;
52 append_bytes(&mut builder, "entry.js", &server_bytes)?;
53
54 if let Some(env) = env_yaml {
55 append_bytes(&mut builder, "env.yaml", env)?;
56 }
57
58 builder.finish()?;
59 Ok(())
60}
61
62fn validate_wasm(wasm_bytes: &[u8], source: &Path) -> Result<()> {
71 let mut validator =
72 wasmparser::Validator::new_with_features(wasmparser::WasmFeatures::all());
73 validator.validate_all(wasm_bytes).map_err(|e| {
74 anyhow!(
75 "{} is not a valid WebAssembly component: {e}\n\
76 Rebuild it with a current forte-sdk; older SDKs emitted components \
77 that only load on wasmtime 43.",
78 source.display()
79 )
80 })?;
81 Ok(())
82}
83
84fn append_bytes<W: std::io::Write>(
85 builder: &mut tar::Builder<W>,
86 path: &str,
87 data: &[u8],
88) -> Result<()> {
89 let mut header = tar::Header::new_gnu();
90 header.set_size(data.len() as u64);
91 header.set_mode(0o644);
92 header.set_cksum();
93 builder
94 .append_data(&mut header, path, data)
95 .map_err(|e| anyhow!("tar append failed for {}: {}", path, e))?;
96 Ok(())
97}