use std::path::{Path, PathBuf};
use std::process::Command;
use aion_package::{Package, PackageOptions, ProjectReport, package_project};
pub fn build_project(relative: &str) -> Result<ProjectReport, Box<dyn std::error::Error>> {
let repo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
let project_root = repo_root.join(relative);
let lock_dir = repo_root.join("target/example-build-locks");
std::fs::create_dir_all(&lock_dir)?;
let lock_path = lock_dir.join(format!("{}.lock", relative.replace(['/', '\\'], "-")));
let lock_file = std::fs::File::create(&lock_path)?;
fs4::FileExt::lock(&lock_file).map_err(|error| {
format!(
"failed to take the build lock {}: {error}",
lock_path.display()
)
})?;
build_and_package(&project_root)
}
pub fn built_package(
relative: &str,
workflow_type: &str,
) -> Result<Package, Box<dyn std::error::Error>> {
let report = build_project(relative)?;
let declared: Vec<&str> = report
.packages
.iter()
.map(|packaged| packaged.workflow_type.as_str())
.collect();
report
.packages
.iter()
.find(|packaged| packaged.workflow_type == workflow_type)
.map(|packaged| packaged.package.clone())
.ok_or_else(|| {
format!("{relative} does not declare workflow type {workflow_type}: {declared:?}")
.into()
})
}
fn build_and_package(project_root: &Path) -> Result<ProjectReport, Box<dyn std::error::Error>> {
let status = Command::new("gleam")
.arg("build")
.current_dir(project_root)
.status()
.map_err(|error| {
format!(
"the from-source archive gate requires the `gleam` CLI on PATH \
(failed to spawn `gleam build` in {}: {error}). This gate fails \
loudly by design — never reintroduce a skip: stale prebuilt \
archives are how unvalidated SDK binaries shipped",
project_root.display()
)
})?;
if !status.success() {
return Err(format!(
"`gleam build` failed in {} with {status}",
project_root.display()
)
.into());
}
Ok(package_project(project_root, &PackageOptions::default())?)
}