From 7b6c5c8bf1a53b64e4e0b1613945d7c5ee277088 Mon Sep 17 00:00:00 2001 From: itowlson Date: Tue, 20 Aug 2024 14:40:27 +1200 Subject: [PATCH] Allow multiple commands in a component build section Signed-off-by: itowlson --- crates/build/src/lib.rs | 61 +++++++++++++--------------- crates/doctor/src/rustlang/target.rs | 2 +- crates/manifest/src/schema/common.rs | 23 ++++++++++- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/crates/build/src/lib.rs b/crates/build/src/lib.rs index 0c7cbdfa2..861cf12e8 100644 --- a/crates/build/src/lib.rs +++ b/crates/build/src/lib.rs @@ -81,39 +81,36 @@ fn build_components( fn build_component(build_info: ComponentBuildInfo, app_dir: &Path) -> Result<()> { match build_info.build { Some(b) => { - terminal::step!( - "Building", - "component {} with `{}`", - build_info.id, - b.command - ); - let workdir = construct_workdir(app_dir, b.workdir.as_ref())?; - if b.workdir.is_some() { - println!("Working directory: {}", quoted_path(&workdir)); - } - - let exit_status = Exec::shell(&b.command) - .cwd(workdir) - .stdout(Redirection::None) - .stderr(Redirection::None) - .stdin(Redirection::None) - .popen() - .map_err(|err| { - anyhow!( - "Cannot spawn build process '{:?}' for component {}: {}", - &b.command, + for command in b.commands() { + terminal::step!("Building", "component {} with `{}`", build_info.id, command); + let workdir = construct_workdir(app_dir, b.workdir.as_ref())?; + if b.workdir.is_some() { + println!("Working directory: {}", quoted_path(&workdir)); + } + + let exit_status = Exec::shell(command) + .cwd(workdir) + .stdout(Redirection::None) + .stderr(Redirection::None) + .stdin(Redirection::None) + .popen() + .map_err(|err| { + anyhow!( + "Cannot spawn build process '{:?}' for component {}: {}", + &b.command, + build_info.id, + err + ) + })? + .wait()?; + + if !exit_status.success() { + bail!( + "Build command for component {} failed with status {:?}", build_info.id, - err - ) - })? - .wait()?; - - if !exit_status.success() { - bail!( - "Build command for component {} failed with status {:?}", - build_info.id, - exit_status, - ); + exit_status, + ); + } } Ok(()) diff --git a/crates/doctor/src/rustlang/target.rs b/crates/doctor/src/rustlang/target.rs index ff5572be2..9d2c3daf6 100644 --- a/crates/doctor/src/rustlang/target.rs +++ b/crates/doctor/src/rustlang/target.rs @@ -19,7 +19,7 @@ impl Diagnostic for TargetDiagnostic { let uses_rust = manifest.components.values().any(|c| { c.build .as_ref() - .map(|b| b.command.starts_with("cargo")) + .map(|b| b.commands().any(|c| c.starts_with("cargo"))) .unwrap_or_default() }); diff --git a/crates/manifest/src/schema/common.rs b/crates/manifest/src/schema/common.rs index 9fbf937af..e93a1f491 100644 --- a/crates/manifest/src/schema/common.rs +++ b/crates/manifest/src/schema/common.rs @@ -83,7 +83,7 @@ pub enum WasiFilesMount { #[serde(deny_unknown_fields)] pub struct ComponentBuildConfig { /// `command = "cargo build"` - pub command: String, + pub command: Commands, /// `workdir = "components/main" #[serde(default, skip_serializing_if = "Option::is_none")] pub workdir: Option, @@ -92,6 +92,27 @@ pub struct ComponentBuildConfig { pub watch: Vec, } +impl ComponentBuildConfig { + /// The commands to execute for the build + pub fn commands(&self) -> impl Iterator { + let as_vec = match &self.command { + Commands::Single(cmd) => vec![cmd], + Commands::Multiple(cmds) => cmds.iter().collect(), + }; + as_vec.into_iter() + } +} + +/// Component build command or commands +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum Commands { + /// `command = "cargo build"` + Single(String), + /// `command = ["cargo build", "wac encode compose-deps.wac -d my:pkg=app.wasm --registry fermyon.com"]` + Multiple(Vec), +} + fn is_false(v: &bool) -> bool { !*v }