use super::artifact::{check_built_artifact, read_manifest, record_build, Rebuild};
use crate::config::{self, Arch};
use crate::idl::{generate_idl, Generator};
use anyhow::{Context, Result};
use std::process::Command;
pub fn split_features(features: &[String]) -> Vec<String> {
features
.iter()
.flat_map(|f| f.split(|c: char| c == ',' || c.is_whitespace()))
.filter(|f| !f.is_empty())
.map(str::to_string)
.collect()
}
pub fn features_arg(features: &[String]) -> Option<String> {
let list = split_features(features);
(!list.is_empty()).then(|| list.join(","))
}
pub fn resolve_arch(arch: Option<Arch>) -> Result<Option<Arch>> {
match arch {
Some(arch) => Ok(Some(arch)),
None => config::build_arch(),
}
}
pub fn build_sbf(quiet: bool, features: &[String], arch: Option<Arch>) -> Result<()> {
println!("Building program");
let mut cmd = Command::new("cargo");
cmd.arg("build-sbf");
if let Some(arch) = arch {
cmd.arg("--arch").arg(arch.as_str());
}
if let Some(features) = features_arg(features) {
cmd.arg("--features").arg(features);
}
if quiet {
cmd.arg("--").arg("--quiet");
}
let status = cmd.spawn()?.wait().context("Failed to build project")?;
if !status.success() {
anyhow::bail!("Build failed with exit code: {:?}", status.code());
}
println!("Build completed successfully!");
Ok(())
}
pub fn run_build(
quiet: bool,
features: &[String],
arch: Option<Arch>,
program_id: Option<&str>,
idl_generator: Option<Generator>,
) -> Result<()> {
let arch = resolve_arch(arch)?;
let manifest = read_manifest();
let build_features = split_features(features);
build_sbf(quiet, features, arch)?;
check_built_artifact(
manifest.as_ref(),
Rebuild::Build {
build_features: &build_features,
},
)?;
record_build(manifest.as_ref(), &build_features, arch);
if let Err(e) = generate_idl("target/idl", program_id, idl_generator) {
let full_message = e
.chain()
.map(|cause| cause.to_string())
.collect::<Vec<_>>()
.join(": ");
println!("⚠️ Skipped IDL generation: {full_message}");
if full_message.contains("declare_id") {
println!(
" If your program doesn't use `declare_id!`, pass `--program-id <ADDRESS>` to `pinoc build`."
);
} else if full_message.contains("[idl].generator") {
println!(" Fix the `[idl].generator` value in Pinoc.toml, or override it with `--idl-generator <shank|codama>`.");
}
}
Ok(())
}