use std::{
env::{self, VarError},
ffi::OsStr,
fs::{self, read_dir},
io::ErrorKind,
path::PathBuf,
process::{exit, Command},
};
use toml::{map::Map, Value};
pub fn build(module: &str) {
let cargo_dir = env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|err| {
eprintln!("`flawless::build` failed to read the `CARGO_MANIFEST_DIR` environment variable.");
eprintln!("Error: {}", err);
if err == VarError::NotPresent {
eprintln!("Hint: `flawless::build` should only be used from a Rust `build.rs` script.");
}
exit(-1);
});
let modules_dir = PathBuf::from(cargo_dir).join("workflows");
let mut modules = read_dir(&modules_dir).unwrap_or_else(|err| {
eprintln!("`flawless::build` douldn't read directory {modules_dir:?}, {err:?}.");
if err.kind() == ErrorKind::NotFound {
eprintln!("Hint: `flawless::build` modules should be placed inside the `workflows` directory.");
}
exit(-1);
});
let module_path = modules.find(|entry| entry.as_ref().unwrap().file_name().to_string_lossy() == module);
if module_path.is_none() {
eprintln!("`flawless::build` failed to find module '{module}' in `{modules_dir:?}`.");
exit(-1);
}
let module_path = module_path.unwrap().unwrap().path(); if !module_path.is_dir() {
eprintln!("`flawless::build` error: `{:?}` is not a directory.", module_path);
exit(-1);
}
let module_cargo_path = module_path.join("Cargo.toml");
let cargo_toml = fs::read_to_string(&module_cargo_path).unwrap_or_else(|err| {
eprintln!("`flawless::build` failed to read `{:?}`", module_cargo_path);
eprintln!("Error: {err}");
exit(-1);
});
let toml: Value = toml::from_str(&cargo_toml).unwrap_or_else(|err| {
eprintln!("`flawless::build` failed to parse toml `{:?}`", module_cargo_path);
eprintln!("Error: {err}");
exit(-1);
});
let package_name = toml
.get("package")
.map_or(Value::Table(Map::new()), |v| v.clone())
.get("name")
.map_or(Value::Table(Map::new()), |v| v.clone());
let package_name = package_name.as_str().unwrap_or_else(|| {
eprintln!("`flawless::build` failed to retrieve package name from `{:?}`.", module_cargo_path);
exit(-1);
});
let out_dir = match env::var("OUT_DIR") {
Ok(out_dir) => out_dir,
Err(err) => {
eprintln!("`flawless::build` failed to read the `OUT_DIR` environment variable.");
eprintln!("Error: {}", err);
if err == VarError::NotPresent {
eprintln!("Hint: `flawless::build` should only be used from a Rust `build.rs` script.");
}
exit(-1);
}
};
let out_dir = PathBuf::from(out_dir).join("flawless").join(module);
let output = Command::new("cargo")
.current_dir(module_path)
.args(&["rustc"])
.args(&["--lib"])
.args(&["--release"])
.args(&["--crate-type", "cdylib"])
.args(&["--target", "wasm32-unknown-unknown"])
.args(&[OsStr::new("--target-dir"), out_dir.as_os_str()])
.args(&["--color=always"])
.output()
.expect("Building flawless module failed");
if !output.status.success() {
eprintln!("`flawless::build` failed to compile `{module}` module.");
eprintln!("{}", String::from_utf8_lossy(&output.stderr));
exit(-1);
}
let module_wasm_path =
out_dir.join("wasm32-unknown-unknown").join("release").join(format!("{package_name}.wasm"));
println!("cargo::rustc-env=FLAWLESS_UTIL_BUILD_{}={}", module, module_wasm_path.to_string_lossy());
}