use clap::Args;
use nativ_config::NativConfig;
use nativ_pipeline::{self, Target};
use std::path::Path;
use std::time::Instant;
#[derive(Args)]
pub struct BuildArgs {
#[arg(long)]
pub ios: bool,
#[arg(long)]
pub android: bool,
#[arg(short, long, default_value = ".")]
pub dir: String,
}
pub fn run(args: BuildArgs, verbose: bool, quiet: bool) -> Result<(), Box<dyn std::error::Error>> {
let project_dir = Path::new(&args.dir);
let config_path = project_dir.join("nativ.toml");
let config = NativConfig::load(&config_path)?;
let targets = nativ_pipeline::resolve_targets(args.ios, args.android, &config);
if targets.is_empty() {
return Err("No target platform specified. Enable ios or android in nativ.toml".into());
}
if !quiet {
let target_names: Vec<&str> = targets
.iter()
.map(|t| match t {
Target::Ios => "iOS",
Target::Android => "Android",
})
.collect();
println!(
"Compiling: {} -> {}",
config.app.name,
target_names.join(", ")
);
}
let start = Instant::now();
let results = nativ_pipeline::build(project_dir, &config, &targets)?;
let elapsed = start.elapsed();
if !quiet {
for result in &results {
let platform = match result.target {
Target::Ios => "iOS",
Target::Android => "Android",
};
println!(
" {platform}: {} files generated",
result.generated_files.len()
);
if verbose {
for file in &result.generated_files {
println!(" -> {}", file.display());
}
}
}
let total: usize = results.iter().map(|r| r.generated_files.len()).sum();
println!(
"Build complete: {total} files, {:.2}s",
elapsed.as_secs_f64()
);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
fn args_for(dir: &Path, ios: bool, android: bool) -> BuildArgs {
BuildArgs {
ios,
android,
dir: dir.display().to_string(),
}
}
#[test]
fn fails_when_config_is_missing() {
let tmp = tempfile::tempdir().unwrap();
let err = run(args_for(tmp.path(), true, false), false, true).unwrap_err();
assert!(err.to_string().contains("nativ.toml"), "{err}");
}
#[test]
fn fails_when_no_target_platform_enabled() {
let tmp = tempfile::tempdir().unwrap();
std::fs::write(
tmp.path().join("nativ.toml"),
"[app]\nname = \"t\"\n\n[build]\nios = false\nandroid = false\n",
)
.unwrap();
let err = run(args_for(tmp.path(), false, false), false, true).unwrap_err();
assert!(err.to_string().contains("No target platform"), "{err}");
}
#[test]
fn fails_when_src_dir_is_missing() {
let tmp = tempfile::tempdir().unwrap();
std::fs::write(tmp.path().join("nativ.toml"), "[app]\nname = \"t\"\n").unwrap();
let err = run(args_for(tmp.path(), true, false), false, true).unwrap_err();
assert!(err.to_string().contains("not found"), "{err}");
}
}