use anyhow::{Context, Result};
use std::path::PathBuf;
use crate::Target;
use whisker_build::CaptureShims;
pub struct Builder {
workspace_root: PathBuf,
crate_dir: PathBuf,
package: String,
target: Target,
features: Vec<String>,
capture: Option<CaptureShims>,
}
impl Builder {
pub fn new(
workspace_root: PathBuf,
crate_dir: PathBuf,
package: String,
target: Target,
) -> Self {
Self {
workspace_root,
crate_dir,
package,
target,
features: Vec::new(),
capture: None,
}
}
pub fn with_features(mut self, features: Vec<String>) -> Self {
self.features = features;
self
}
pub fn features(&self) -> &[String] {
&self.features
}
pub fn with_capture(mut self, capture: CaptureShims) -> Self {
self.capture = Some(capture);
self
}
pub async fn build(&self) -> Result<()> {
match self.target {
Target::Android => self.build_android().await,
Target::IosSimulator => self.build_ios_simulator().await,
}
}
pub fn captures_shims(&self) -> bool {
self.capture.is_some()
}
async fn build_android(&self) -> Result<()> {
let ws = self.workspace_root.clone();
let crate_dir = self.crate_dir.clone();
let pkg = self.package.clone();
let features = self.features.clone();
let capture = self.capture.clone();
tokio::task::spawn_blocking(move || -> Result<()> {
let gen_android = crate_dir.join("gen/android");
let modules = whisker_build::modules::discover(&ws.join("Cargo.toml"), &pkg)?;
whisker_build::android::stage_module_kotlin_sources(&gen_android, &modules)?;
whisker_build::android::run_gradle_assemble(
&gen_android,
whisker_build::Profile::Debug,
&features,
capture.as_ref(),
)?;
Ok(())
})
.await
.context("spawn_blocking Android build")?
}
async fn build_ios_simulator(&self) -> Result<()> {
let ws = self.workspace_root.clone();
let crate_dir = self.crate_dir.clone();
let pkg = self.package.clone();
tokio::task::spawn_blocking(move || -> Result<()> {
let modules = whisker_build::modules::discover(&ws.join("Cargo.toml"), &pkg)?;
let gen_ios = crate_dir.join("gen/ios");
let whisker_runtime_path = ws.join("platforms/ios");
let whisker_ios_macros_path = ws.join("platforms/ios/macros");
whisker_build::ios::stage_module_swift_sources(
&gen_ios,
&whisker_runtime_path,
&whisker_ios_macros_path,
&modules,
)?;
Ok(())
})
.await
.context("spawn_blocking iOS module-source stage")?
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_can_be_constructed_for_each_target() {
for t in [Target::Android, Target::IosSimulator] {
let b = Builder::new(
PathBuf::from("/tmp/ws"),
PathBuf::from("/tmp/ws/examples/x"),
"x".into(),
t,
);
assert!(!b.captures_shims());
assert!(b.features.is_empty());
}
}
#[test]
fn with_features_replaces_the_feature_list() {
let b = Builder::new(
PathBuf::from("/tmp/ws"),
PathBuf::from("/tmp/ws/examples/x"),
"x".into(),
Target::Android,
)
.with_features(vec!["whisker/hot-reload".into(), "extra".into()]);
assert_eq!(b.features, vec!["whisker/hot-reload", "extra"]);
}
#[test]
fn with_capture_flips_captures_shims() {
let shims = CaptureShims {
rustc_shim: PathBuf::from("/tmp/rs"),
linker_shim: PathBuf::from("/tmp/ls"),
rustc_cache_dir: PathBuf::from("/tmp/rc"),
linker_cache_dir: PathBuf::from("/tmp/lc"),
real_linker: PathBuf::from("/usr/bin/cc"),
target_triple: Some("aarch64-linux-android".into()),
};
let b = Builder::new(
PathBuf::from("/tmp/ws"),
PathBuf::from("/tmp/ws/examples/x"),
"x".into(),
Target::Android,
)
.with_capture(shims);
assert!(b.captures_shims());
}
}