batuta/pipeline/stages/
build.rs1use anyhow::{Context as AnyhowContext, Result};
4
5#[cfg(feature = "native")]
6use tracing::info;
7
8#[cfg(not(feature = "native"))]
10macro_rules! info {
11 ($($arg:tt)*) => {{}};
12}
13
14use crate::pipeline::types::{PipelineContext, PipelineStage, ValidationResult};
15
16pub struct BuildStage {
18 pub(crate) release: bool,
19 pub(crate) target: Option<String>,
20 pub(crate) wasm: bool,
21}
22
23impl BuildStage {
24 pub fn new(release: bool, target: Option<String>, wasm: bool) -> Self {
25 Self { release, target, wasm }
26 }
27}
28
29#[async_trait::async_trait]
30impl PipelineStage for BuildStage {
31 fn name(&self) -> &'static str {
32 "Build"
33 }
34
35 async fn execute(&self, mut ctx: PipelineContext) -> Result<PipelineContext> {
36 info!("Building Rust project (release: {})", self.release);
37
38 let cargo_toml = ctx.output_path.join("Cargo.toml");
40 if !cargo_toml.exists() {
41 anyhow::bail!("No Cargo.toml found in output directory");
42 }
43
44 let mut args = vec!["build"];
46
47 if self.release {
48 args.push("--release");
49 }
50
51 if let Some(target) = &self.target {
52 args.push("--target");
53 args.push(target);
54 }
55
56 if self.wasm {
58 args.push("--target");
59 args.push("wasm32-unknown-unknown");
60 }
61
62 let output = std::process::Command::new("cargo")
64 .args(&args)
65 .current_dir(&ctx.output_path)
66 .output()
67 .context("Failed to run cargo build")?;
68
69 if !output.status.success() {
70 let stderr = String::from_utf8_lossy(&output.stderr);
71 anyhow::bail!("Cargo build failed: {}", stderr);
72 }
73
74 ctx.metadata.insert(
75 "build_mode".to_string(),
76 serde_json::json!(if self.release { "release" } else { "debug" }),
77 );
78
79 if self.wasm {
80 ctx.metadata.insert("wasm_build".to_string(), serde_json::json!(true));
81 }
82
83 Ok(ctx)
84 }
85
86 fn validate(&self, ctx: &PipelineContext) -> Result<ValidationResult> {
87 let build_dir = if self.release {
89 ctx.output_path.join("target/release")
90 } else {
91 ctx.output_path.join("target/debug")
92 };
93
94 let passed = build_dir.exists();
95
96 Ok(ValidationResult {
97 stage: self.name().to_string(),
98 passed,
99 message: if passed {
100 "Build artifacts found".to_string()
101 } else {
102 "Build directory not found".to_string()
103 },
104 details: None,
105 })
106 }
107}