1use std::{
2 env::{self, VarError},
3 ffi::OsStr,
4 fs::{self, read_dir},
5 io::ErrorKind,
6 path::PathBuf,
7 process::{exit, Command},
8};
9
10use toml::{map::Map, Value};
11
12pub fn build_release(module: &str) {
14 build(module, true);
15}
16
17pub fn build_debug(module: &str) {
19 build(module, false);
20}
21
22fn build(module: &str, relase: bool) {
24 let cargo_dir = env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|err| {
26 eprintln!("`flawless::build` failed to read the `CARGO_MANIFEST_DIR` environment variable.");
27 eprintln!("Error: {}", err);
28 if err == VarError::NotPresent {
29 eprintln!("Hint: `flawless::build` should only be used from a Rust `build.rs` script.");
30 }
31 exit(-1);
32 });
33
34 let modules_dir = PathBuf::from(cargo_dir).join("workflows");
35 let mut modules = read_dir(&modules_dir).unwrap_or_else(|err| {
36 eprintln!("`flawless::build` couldn't read directory {modules_dir:?}, {err:?}.");
37 if err.kind() == ErrorKind::NotFound {
38 eprintln!("Hint: `flawless::build` modules should be placed inside the `workflows` directory.");
39 }
40 exit(-1);
41 });
42
43 let module_path = modules.find(|entry| entry.as_ref().unwrap().file_name().to_string_lossy() == module);
44 if module_path.is_none() {
45 eprintln!("`flawless::build` failed to find module '{module}' in `{modules_dir:?}`.");
46 exit(-1);
47 }
48
49 let module_path = module_path.unwrap().unwrap().path(); if !module_path.is_dir() {
51 eprintln!("`flawless::build` error: `{:?}` is not a directory.", module_path);
52 exit(-1);
53 }
54
55 let module_cargo_path = module_path.join("Cargo.toml");
57 let cargo_toml = fs::read_to_string(&module_cargo_path).unwrap_or_else(|err| {
58 eprintln!("`flawless::build` failed to read `{:?}`", module_cargo_path);
59 eprintln!("Error: {err}");
60 exit(-1);
61 });
62
63 let toml: Value = toml::from_str(&cargo_toml).unwrap_or_else(|err| {
64 eprintln!("`flawless::build` failed to parse toml `{:?}`", module_cargo_path);
65 eprintln!("Error: {err}");
66 exit(-1);
67 });
68
69 let package_name = toml
70 .get("package")
71 .map_or(Value::Table(Map::new()), |v| v.clone())
73 .get("name")
74 .map_or(Value::Table(Map::new()), |v| v.clone());
76 let package_name = package_name.as_str().unwrap_or_else(|| {
77 eprintln!("`flawless::build` failed to retrieve package name from `{:?}`.", module_cargo_path);
78 exit(-1);
79 });
80
81 let out_dir = match env::var("OUT_DIR") {
83 Ok(out_dir) => out_dir,
84 Err(err) => {
85 eprintln!("`flawless::build` failed to read the `OUT_DIR` environment variable.");
86 eprintln!("Error: {}", err);
87 if err == VarError::NotPresent {
88 eprintln!("Hint: `flawless::build` should only be used from a Rust `build.rs` script.");
89 }
90 exit(-1);
91 }
92 };
93
94 let out_dir = PathBuf::from(out_dir).join("flawless").join(module);
95
96 let mut cmd = Command::new("cargo");
97 cmd.current_dir(module_path)
98 .args(["rustc"])
99 .args(["--lib"])
100 .args(["--crate-type", "cdylib"])
101 .args(["--target", "wasm32-unknown-unknown"])
102 .args([OsStr::new("--target-dir"), out_dir.as_os_str()])
103 .args(["--color=always"]);
104 if relase {
105 cmd.args(["--release"]);
106 }
107 let output = cmd.output().expect("Building flawless module failed");
108 if !output.status.success() {
109 eprintln!("`flawless::build` failed to compile `{module}` module.");
110 eprintln!("{}", String::from_utf8_lossy(&output.stderr));
111 exit(-1);
112 }
113
114 let output_path = if relase { "release" } else { "debug" };
115
116 let module_wasm_path =
117 out_dir.join("wasm32-unknown-unknown").join(output_path).join(format!("{package_name}.wasm"));
118
119 println!("cargo::rustc-env=FLAWLESS_UTIL_BUILD_{}={}", module, module_wasm_path.to_string_lossy());
122}