use std::{
path::{Path, PathBuf},
process::Command,
};
use aion_package::{ExcludedModule, PackageOptions, ProjectReport, package_project};
use anyhow::{Context, Result, bail};
use serde::Serialize;
use serde_json::Value;
use crate::output::to_value;
#[derive(Serialize)]
struct PackageOutput<'a> {
packages: Vec<PackagedOutput>,
excluded: &'a [ExcludedModule],
}
#[derive(Serialize)]
struct PackagedOutput {
workflow_type: String,
output: String,
version: String,
deployed_name: String,
modules: usize,
}
pub(crate) fn run(path: &Path, out: Option<&Path>, build: bool) -> Result<Value> {
if build {
run_gleam_build(path)?;
}
let options = PackageOptions {
output_override: out.map(absolute_out).transpose()?,
};
let report = package_project(path, &options)
.with_context(|| format!("failed to package workflow project at {}", path.display()))?;
to_value(report_output(&report))
}
fn absolute_out(out: &Path) -> Result<PathBuf> {
std::path::absolute(out)
.with_context(|| format!("failed to resolve --out path {}", out.display()))
}
fn run_gleam_build(path: &Path) -> Result<()> {
let status = Command::new("gleam")
.arg("build")
.current_dir(path)
.status()
.with_context(|| format!("failed to run `gleam build` in {}", path.display()))?;
if !status.success() {
bail!("`gleam build` failed in {} with {status}", path.display());
}
Ok(())
}
fn report_output(report: &ProjectReport) -> PackageOutput<'_> {
PackageOutput {
packages: report
.packages
.iter()
.map(|packaged| PackagedOutput {
workflow_type: packaged.workflow_type.clone(),
output: packaged.output_path.display().to_string(),
version: packaged.version.content_hash.to_string(),
deployed_name: packaged.package.deployed_entry_module(),
modules: packaged.package.beams().len(),
})
.collect(),
excluded: &report.excluded,
}
}