use anyhow::Result;
use clap::Parser;
use colored::*;
use std::path::PathBuf;
#[derive(Parser, Debug)]
pub struct BuildCommand {
#[arg(required = true)]
pub package_file: PathBuf,
#[arg(long)]
pub r#type: Option<String>,
#[arg(long, short, num_args = 1.., default_values_t = vec!["current".to_string()])]
pub platform: Vec<String>,
#[arg(long, num_args = 1..)]
pub sub: Option<Vec<String>>,
#[arg(long)]
pub sign: Option<String>,
#[arg(long)]
pub test: bool,
#[arg(long, short = 'o')]
pub output_dir: Option<PathBuf>,
#[arg(long)]
pub install_deps: bool,
#[arg(long)]
pub version_override: Option<String>,
#[arg(long, default_value = "native")]
pub method: String,
#[arg(long)]
pub image: Option<String>,
#[arg(long)]
pub fakeroot: bool,
#[arg(long)]
pub pure: bool,
#[arg(long, default_value = "@core/base:dev")]
pub root_package: String,
}
pub fn run(mut args: BuildCommand) -> Result<()> {
let mut _temp_root = None;
if args.pure {
if args.method == "docker" {
return Err(anyhow::anyhow!(
"--pure is not compatible with --method docker"
));
}
args.method = "bwrap".to_string();
let temp = tempfile::Builder::new().prefix("zoi-pure-").tempdir()?;
println!(
"{} Initializing pure build environment in {}...",
"::".bold().blue(),
temp.path().display()
);
let etc_dir = temp.path().join("etc");
std::fs::create_dir_all(&etc_dir)?;
std::fs::write(etc_dir.join("os-release"), "ID=zoios\nID_LIKE=zoios\n")?;
crate::pkg::sysroot::set_sysroot(temp.path().to_path_buf());
_temp_root = Some(temp);
let root_dep = crate::pkg::dependencies::parse_dependency_string(&args.root_package)?;
crate::pkg::install::dep_install::install_dependency(
&root_dep,
"pure-root",
crate::pkg::types::Scope::System,
true,
true,
&std::sync::Mutex::new(std::collections::HashSet::new()),
&mut Vec::new(),
None,
)?;
}
if args.install_deps {
install_dependencies_for_build(&args, args.test)?;
}
if args.test {
println!("Running tests before building...");
crate::pkg::package::test::run(&args)?;
println!("Tests passed, proceeding with build...");
}
crate::pkg::package::build::run(
&args.package_file,
args.r#type.as_deref(),
&args.platform,
args.sign,
args.output_dir.as_deref(),
args.version_override.as_deref(),
args.sub,
false,
&args.method,
args.image.as_deref(),
args.fakeroot,
args.install_deps,
args.test,
)
}
pub fn install_dependencies_for_build(args: &BuildCommand, include_test: bool) -> Result<()> {
for platform in &args.platform {
let current_platform = if platform == "current" {
crate::pkg::utils::get_platform()?
} else {
platform.clone()
};
if let Some(mut dep_strings) = crate::pkg::package::build::get_build_dependencies(
&args.package_file,
args.r#type.as_deref(),
¤t_platform,
args.version_override.as_deref(),
false,
)? {
if include_test
&& let Some(test_deps) = crate::pkg::package::build::get_test_dependencies(
&args.package_file,
¤t_platform,
args.version_override.as_deref(),
false,
)?
{
dep_strings.extend(test_deps);
}
if !dep_strings.is_empty() {
println!(
"{} Installing build/test dependencies...",
"::".bold().blue()
);
let processed = std::sync::Mutex::new(std::collections::HashSet::new());
let mut installed = Vec::new();
for dep_str in dep_strings {
let dep = crate::pkg::dependencies::parse_dependency_string(&dep_str)?;
crate::pkg::install::dep_install::install_dependency(
&dep,
"build",
if crate::pkg::sysroot::get_sysroot().is_some() {
crate::pkg::types::Scope::System
} else {
crate::pkg::types::Scope::User
},
true,
true,
&processed,
&mut installed,
None,
)?;
}
}
}
}
Ok(())
}