Implement Perl build helper commands and integrate into CLI

- Added `run_helper_configure` and `run_helper_install` functions in `perl.rs` to handle Perl-specific build configurations and installations.
- Introduced new internal commands in `cli.rs` for Perl configuration and installation.
- Updated `internal.rs` to execute Perl helper commands using the new functions.
- Enhanced `shell_helpers.rs` to include scripts for Perl configure and install commands.
- Modified `hooks.rs` to apply build helper context and directories for post-extract and post-configure commands.
- Added tests to ensure the correct execution of Perl build helper commands and their integration with the build process.
This commit is contained in:
2026-04-04 17:31:39 -05:00
parent 34d52d11a9
commit d54e6d56e8
14 changed files with 1367 additions and 108 deletions
Generated
+1 -1
View File
@@ -451,7 +451,7 @@ checksum = "807800ff3288b621186fe0a8f3392c4652068257302709c24efd918c3dffcdc2"
[[package]] [[package]]
name = "depot" name = "depot"
version = "0.35.1" version = "0.36.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ar", "ar",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "depot" name = "depot"
version = "0.35.1" version = "0.36.0"
edition = "2024" edition = "2024"
[lints.rust] [lints.rust]
+1 -1
View File
@@ -1,6 +1,6 @@
project( project(
'depot', 'depot',
version: '0.35.1', version: '0.36.0',
meson_version: '>=0.60.0', meson_version: '>=0.60.0',
default_options: ['buildtype=release'], default_options: ['buildtype=release'],
) )
+219
View File
@@ -1,5 +1,6 @@
//! GNU Autotools build system (configure && make && make install) //! GNU Autotools build system (configure && make && make install)
use crate::builder::BuildHelperContext;
use crate::builder::state::{BuildStep, StateTracker}; use crate::builder::state::{BuildStep, StateTracker};
use crate::cross::CrossConfig; use crate::cross::CrossConfig;
use crate::fakeroot; use crate::fakeroot;
@@ -501,6 +502,202 @@ pub(crate) fn ensure_host_build(
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display())) .with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
} }
pub(crate) fn run_helper_configure(
context: &BuildHelperContext,
source_dir: Option<&Path>,
build_dir: Option<&Path>,
cross: Option<&CrossConfig>,
env_vars: &[(String, String)],
extra_args: &[String],
) -> Result<()> {
let flags = context.build_flags();
let source_dir = source_dir
.map(Path::to_path_buf)
.unwrap_or(std::env::current_dir().context("Failed to determine current directory")?);
let build_dir = build_dir.map(Path::to_path_buf).unwrap_or_else(|| {
flags
.build_dir
.as_ref()
.map(|dir| source_dir.join(dir))
.unwrap_or_else(|| source_dir.clone())
});
fs::create_dir_all(&build_dir)
.with_context(|| format!("Failed to create build directory: {}", build_dir.display()))?;
let mut helper_env = env_vars.to_vec();
let cc = if let Some(cc_cfg) = cross {
cc_cfg.cc.clone()
} else {
helper_env
.iter()
.find(|(key, _)| key == "CC")
.map(|(_, value)| value.clone())
.unwrap_or_else(|| flags.cc.clone())
};
if let Some(cflags_str) = helper_env
.iter()
.find(|(key, _)| key == "CFLAGS")
.map(|(_, value)| value.clone())
.filter(|value| !value.trim().is_empty())
{
let expanded = expand_shell_commands(&cflags_str, &cc)?;
crate::builder::set_env_var(&mut helper_env, "CFLAGS", expanded);
}
let configure_path = helper_configure_path(context, &source_dir);
let mut configure_cmd = Command::new(&configure_path);
configure_cmd.current_dir(&build_dir);
crate::builder::prepare_tool_command(&mut configure_cmd, &helper_env);
let help_text = configure_help_text(&configure_path, &build_dir, &helper_env);
configure_cmd.arg(format!("--prefix={}", flags.prefix));
for default_dir_arg in default_configure_install_dirs(&flags, help_text.as_deref()) {
configure_cmd.arg(default_dir_arg);
}
let supports_host =
configure_supports_option(help_text.as_deref(), "--host", &flags.configure_file);
let supports_build =
configure_supports_option(help_text.as_deref(), "--build", &flags.configure_file);
let requested_host = if let Some(cc_cfg) = cross {
Some(cc_cfg.host_triple().to_string())
} else if !flags.chost.is_empty() {
Some(flags.chost.clone())
} else {
None
}
.map(|host| {
if flags.lib32_variant {
lib32_host_triple(&host)
} else {
host
}
});
let requested_build = if cross.is_some() {
CrossConfig::build_triple().ok()
} else if !flags.cbuild.is_empty() {
Some(flags.cbuild.clone())
} else {
None
};
if let Some(host) = requested_host {
if supports_host {
configure_cmd.arg(format!("--host={host}"));
} else {
crate::log_info!(" configure does not support --host; skipping {}", host);
}
}
if let Some(build) = requested_build {
if supports_build {
configure_cmd.arg(format!("--build={build}"));
} else {
crate::log_info!(" configure does not support --build; skipping {}", build);
}
}
for arg in &flags.configure {
configure_cmd.arg(expand_with_envs(&context.expand_vars(arg), &helper_env));
}
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Autotools, &flags)?
{
add_auto_configure_arg_if_supported(&mut configure_cmd, help_text.as_deref(), &arg);
}
for arg in extra_args {
add_auto_configure_arg_if_supported(
&mut configure_cmd,
help_text.as_deref(),
&expand_with_envs(&context.expand_vars(arg), &helper_env),
);
}
let status = crate::interrupts::command_status(&mut configure_cmd)
.with_context(|| format!("Failed to run helper configure in {}", build_dir.display()))?;
if !status.success() {
anyhow::bail!("configure failed with status: {}", status);
}
Ok(())
}
pub(crate) fn run_helper_install(
context: &BuildHelperContext,
build_dir: Option<&Path>,
env_vars: &[(String, String)],
extra_args: &[String],
) -> Result<()> {
let flags = context.build_flags();
let source_dir = helper_source_dir();
let build_dir = build_dir.map(Path::to_path_buf).unwrap_or_else(|| {
flags
.build_dir
.as_ref()
.map(|dir| source_dir.join(dir))
.unwrap_or_else(|| source_dir.clone())
});
let destdir = std::env::var("DESTDIR").context("DESTDIR must be set for autotools_install")?;
let make_exec = resolve_make_exec(&flags.make_exec);
let install_dirs = resolve_make_dirs(
&build_dir,
&flags.make_install_dirs,
"build.flags.make_install_dirs",
)?;
let install_targets = phase_targets(
&flags.make_install_target,
&flags.make_install_targets,
Some("install"),
);
for install_dir in install_dirs {
let mut install_cmd = fakeroot::wrap_install_command(make_exec, Path::new(&destdir));
install_cmd.current_dir(&install_dir);
if make_exec_supports_make_assignments(make_exec)
&& !has_make_variable_override(&flags.make_install_vars, "DESTDIR")
{
install_cmd.arg(format!("DESTDIR={destdir}"));
}
add_make_variable_overrides_if_supported(
&mut install_cmd,
make_exec,
&flags.make_install_vars,
"install",
)?;
for install_target in &install_targets {
install_cmd.arg(install_target);
}
for arg in extra_args {
install_cmd.arg(context.expand_vars(arg));
}
let mut install_env = env_vars.to_vec();
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir.clone());
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
let status = crate::interrupts::command_status(&mut install_cmd).with_context(|| {
format!(
"Failed to run helper {} {} in {}",
make_exec,
install_targets.join(" "),
install_dir.display()
)
})?;
if !status.success() {
anyhow::bail!(
"{} {} failed with status: {} (dir: {})",
make_exec,
install_targets.join(" "),
status,
install_dir.display()
);
}
}
Ok(())
}
fn num_cpus() -> usize { fn num_cpus() -> usize {
std::thread::available_parallelism() std::thread::available_parallelism()
.map(|n| n.get()) .map(|n| n.get())
@@ -544,6 +741,22 @@ fn resolve_configure_path(spec: &PackageSpec, actual_src: &Path) -> PathBuf {
} }
} }
fn helper_configure_path(context: &BuildHelperContext, actual_src: &Path) -> PathBuf {
let flags = context.build_flags();
let configured = context.expand_vars(&flags.configure_file);
let trimmed = configured.trim();
if trimmed.is_empty() {
return actual_src.join("configure");
}
let path = Path::new(trimmed);
if path.is_absolute() {
path.to_path_buf()
} else {
actual_src.join(path)
}
}
fn configure_help_text( fn configure_help_text(
configure_path: &Path, configure_path: &Path,
build_dir: &Path, build_dir: &Path,
@@ -823,6 +1036,12 @@ fn nonempty_trimmed(value: &str) -> Option<&str> {
(!trimmed.is_empty()).then_some(trimmed) (!trimmed.is_empty()).then_some(trimmed)
} }
fn helper_source_dir() -> PathBuf {
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
.map(PathBuf::from)
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
}
pub(crate) fn resolve_make_exec(configured: &str) -> &str { pub(crate) fn resolve_make_exec(configured: &str) -> &str {
nonempty_trimmed(configured).unwrap_or("make") nonempty_trimmed(configured).unwrap_or("make")
} }
+140
View File
@@ -1,5 +1,6 @@
//! CMake build system //! CMake build system
use crate::builder::BuildHelperContext;
use crate::builder::state::{BuildStep, StateTracker}; use crate::builder::state::{BuildStep, StateTracker};
use crate::cross::CrossConfig; use crate::cross::CrossConfig;
use crate::fakeroot; use crate::fakeroot;
@@ -359,6 +360,139 @@ pub(crate) fn ensure_host_build(
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display())) .with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
} }
pub(crate) fn run_helper_configure(
context: &BuildHelperContext,
source_dir: Option<&Path>,
build_dir: Option<&Path>,
cross: Option<&CrossConfig>,
env_vars: &[(String, String)],
extra_args: &[String],
) -> Result<()> {
let flags = context.build_flags();
let source_dir = source_dir
.map(Path::to_path_buf)
.unwrap_or(std::env::current_dir().context("Failed to determine current directory")?);
let build_dir = build_dir.map(Path::to_path_buf).unwrap_or_else(|| {
flags
.build_dir
.as_ref()
.map(|dir| source_dir.join(dir))
.unwrap_or_else(|| source_dir.join("build"))
});
let prefix = effective_cmake_install_prefix(&flags);
fs::create_dir_all(&build_dir)
.with_context(|| format!("Failed to create build directory: {}", build_dir.display()))?;
let toolchain_file = if let Some(cc_cfg) = cross {
Some(cc_cfg.generate_cmake_toolchain(&build_dir)?)
} else {
None
};
let mut cmake_cmd = Command::new("cmake");
cmake_cmd.current_dir(&build_dir);
cmake_cmd.arg("-S").arg(&source_dir);
cmake_cmd.arg("-B").arg(&build_dir);
cmake_cmd.arg(format!("-DCMAKE_INSTALL_PREFIX={prefix}"));
cmake_cmd.arg("-DCMAKE_BUILD_TYPE=Release");
for arg in cmake_install_dir_args(&flags, prefix) {
cmake_cmd.arg(arg);
}
for arg in cmake_lib32_target_args(&flags, cross) {
cmake_cmd.arg(arg);
}
if let Some(toolchain_file) = &toolchain_file {
cmake_cmd.arg(format!(
"-DCMAKE_TOOLCHAIN_FILE={}",
toolchain_file.display()
));
}
let make_exec_override = flags.make_exec.trim();
if !make_exec_override.is_empty() {
if !cmake_configure_flags_specify_generator(&flags.configure)
&& let Some(generator) = cmake_generator_for_make_exec(make_exec_override)
{
cmake_cmd.arg("-G").arg(generator);
}
if !cmake_configure_flags_set_make_program(&flags.configure) {
cmake_cmd.arg(format!("-DCMAKE_MAKE_PROGRAM={make_exec_override}"));
}
}
for flag in &flags.configure {
cmake_cmd.arg(expand_with_envs(&context.expand_vars(flag), env_vars));
}
for arg in crate::builder::static_build_args_for(crate::package::BuildType::CMake, &flags)? {
cmake_cmd.arg(arg);
}
for arg in extra_args {
cmake_cmd.arg(expand_with_envs(&context.expand_vars(arg), env_vars));
}
crate::builder::prepare_tool_command(&mut cmake_cmd, &env_vars.to_vec());
let status = crate::interrupts::command_status(&mut cmake_cmd)
.context("Failed to run helper cmake configure")?;
if !status.success() {
anyhow::bail!("cmake configure failed");
}
Ok(())
}
pub(crate) fn run_helper_install(
context: &BuildHelperContext,
build_dir: Option<&Path>,
env_vars: &[(String, String)],
extra_args: &[String],
) -> Result<()> {
let flags = context.build_flags();
let source_dir = helper_source_dir();
let build_dir = build_dir.map(Path::to_path_buf).unwrap_or_else(|| {
flags
.build_dir
.as_ref()
.map(|dir| source_dir.join(dir))
.unwrap_or_else(|| source_dir.join("build"))
});
let destdir = std::env::var("DESTDIR").context("DESTDIR must be set for cmake_install")?;
let install_targets = phase_targets(&flags.make_install_target, &flags.make_install_targets);
let mut install_cmd = fakeroot::wrap_install_command("cmake", Path::new(&destdir));
if install_targets.is_empty() {
install_cmd.arg("--install").arg(&build_dir);
} else {
install_cmd.arg("--build").arg(&build_dir);
install_cmd.arg("--target");
for target in &install_targets {
install_cmd.arg(target);
}
}
for arg in extra_args {
install_cmd.arg(context.expand_vars(arg));
}
let mut install_env = env_vars.to_vec();
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir);
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
let status = crate::interrupts::command_status(&mut install_cmd)
.context("Failed to run helper cmake install")?;
if !status.success() {
if install_targets.is_empty() {
anyhow::bail!("cmake install failed");
}
anyhow::bail!(
"cmake install target(s) '{}' failed",
install_targets.join(" ")
);
}
Ok(())
}
/// Expand environment variables in a string (e.g., $DEPOT_SYSROOT) /// Expand environment variables in a string (e.g., $DEPOT_SYSROOT)
fn expand_env_vars(input: &str) -> String { fn expand_env_vars(input: &str) -> String {
let mut result = input.to_string(); let mut result = input.to_string();
@@ -580,6 +714,12 @@ fn num_cpus() -> usize {
.unwrap_or(1) .unwrap_or(1)
} }
fn helper_source_dir() -> PathBuf {
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
.map(PathBuf::from)
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
}
/// Resolve `source_subdir` with multiple fallbacks: /// Resolve `source_subdir` with multiple fallbacks:
/// - empty -> use `src_dir` /// - empty -> use `src_dir`
/// - absolute path -> use if exists /// - absolute path -> use if exists
+18 -8
View File
@@ -51,6 +51,8 @@ pub fn build(
let mut env_vars = crate::builder::standard_build_env(spec, cross, true, export_compiler_flags); let mut env_vars = crate::builder::standard_build_env(spec, cross, true, export_compiler_flags);
let shell_helpers = crate::shell_helpers::ShellHelpers::new(&install_destdir)?; let shell_helpers = crate::shell_helpers::ShellHelpers::new(&install_destdir)?;
shell_helpers.apply_to_env_vars(&mut env_vars); shell_helpers.apply_to_env_vars(&mut env_vars);
crate::builder::apply_build_helper_context_env(&mut env_vars, spec)?;
crate::builder::apply_build_helper_dirs_env(&mut env_vars, Some(src_dir), Some(&build_dir));
// For custom builds, look for a build.sh script in the source directory // For custom builds, look for a build.sh script in the source directory
let build_script = src_dir.join("build.sh"); let build_script = src_dir.join("build.sh");
@@ -280,19 +282,27 @@ fn build_function_mode_install_command(
"DEPOT_OUTPUT_NAME='{q_name}'; DEPOT_OUTPUT_DESTDIR='{q_dest}'; DESTDIR=\"$DEPOT_OUTPUT_DESTDIR\"; export DEPOT_OUTPUT_NAME DEPOT_OUTPUT_DESTDIR DESTDIR\n" "DEPOT_OUTPUT_NAME='{q_name}'; DEPOT_OUTPUT_DESTDIR='{q_dest}'; DESTDIR=\"$DEPOT_OUTPUT_DESTDIR\"; export DEPOT_OUTPUT_NAME DEPOT_OUTPUT_DESTDIR DESTDIR\n"
)); ));
wrapper.push_str("depot_output_installed=0\n"); wrapper.push_str("depot_output_installed=0\n");
wrapper.push_str(&format!(
"if depot_has_function depot_install_{fn_suffix}; then depot_install_{fn_suffix}; depot_output_installed=1;\n"
));
wrapper.push_str(&format!(
"elif depot_has_function install_{fn_suffix}; then install_{fn_suffix}; depot_output_installed=1;\n"
));
if out.name == *primary { if out.name == *primary {
wrapper wrapper.push_str(
.push_str("elif depot_has_function depot_install; then depot_install; depot_output_installed=1;\n"); "if depot_has_function depot_install; then depot_install; depot_output_installed=1;\n",
);
wrapper.push_str( wrapper.push_str(
"elif depot_has_function install; then install; depot_output_installed=1;\n", "elif depot_has_function install; then install; depot_output_installed=1;\n",
); );
wrapper.push_str(&format!(
"elif depot_has_function depot_install_{fn_suffix}; then depot_install_{fn_suffix}; depot_output_installed=1;\n"
));
wrapper.push_str(&format!(
"elif depot_has_function install_{fn_suffix}; then install_{fn_suffix}; depot_output_installed=1;\n"
));
wrapper.push_str("elif [ \"$depot_build_ran\" = 1 ]; then depot_output_installed=1;\n"); wrapper.push_str("elif [ \"$depot_build_ran\" = 1 ]; then depot_output_installed=1;\n");
} else {
wrapper.push_str(&format!(
"if depot_has_function depot_install_{fn_suffix}; then depot_install_{fn_suffix}; depot_output_installed=1;\n"
));
wrapper.push_str(&format!(
"elif depot_has_function install_{fn_suffix}; then install_{fn_suffix}; depot_output_installed=1;\n"
));
} }
wrapper.push_str("fi\n"); wrapper.push_str("fi\n");
wrapper.push_str("if [ \"$depot_output_installed\" != 1 ]; then\n"); wrapper.push_str("if [ \"$depot_output_installed\" != 1 ]; then\n");
+95
View File
@@ -1,5 +1,6 @@
//! Meson build system //! Meson build system
use crate::builder::BuildHelperContext;
use crate::builder::state::{BuildStep, StateTracker}; use crate::builder::state::{BuildStep, StateTracker};
use crate::cross::CrossConfig; use crate::cross::CrossConfig;
use crate::fakeroot; use crate::fakeroot;
@@ -267,12 +268,106 @@ pub(crate) fn ensure_host_build(
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display())) .with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
} }
pub(crate) fn run_helper_configure(
context: &BuildHelperContext,
source_dir: Option<&Path>,
build_dir: Option<&Path>,
cross: Option<&CrossConfig>,
env_vars: &[(String, String)],
extra_args: &[String],
) -> Result<()> {
let flags = context.build_flags();
let source_dir = source_dir
.map(Path::to_path_buf)
.unwrap_or(std::env::current_dir().context("Failed to determine current directory")?);
let build_dir = build_dir
.map(Path::to_path_buf)
.unwrap_or_else(|| resolve_build_dir(&source_dir, &flags));
fs::create_dir_all(&build_dir)
.with_context(|| format!("Failed to create build directory: {}", build_dir.display()))?;
let mut helper_env = env_vars.to_vec();
configure_pkg_config_env(&mut helper_env, &flags, cross);
let cross_file = if let Some(cc_cfg) = cross {
Some(cc_cfg.generate_meson_cross_file(&build_dir)?)
} else if flags.lib32_variant {
Some(generate_lib32_meson_cross_file(&flags, &build_dir)?)
} else {
None
};
let mut meson_cmd = Command::new("meson");
meson_cmd.current_dir(&source_dir);
meson_cmd.arg("setup");
meson_cmd.arg(&build_dir);
for arg in meson_setup_args(&flags, cross_file.as_deref(), &helper_env) {
meson_cmd.arg(arg);
}
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Meson, &flags)? {
meson_cmd.arg(arg);
}
for arg in extra_args {
meson_cmd.arg(context.expand_vars(arg));
}
crate::builder::prepare_tool_command(&mut meson_cmd, &helper_env);
let status = crate::interrupts::command_status(&mut meson_cmd)
.context("Failed to run helper meson setup")?;
if !status.success() {
bail!("meson setup failed");
}
Ok(())
}
pub(crate) fn run_helper_install(
context: &BuildHelperContext,
build_dir: Option<&Path>,
env_vars: &[(String, String)],
extra_args: &[String],
) -> Result<()> {
let flags = context.build_flags();
let build_dir = build_dir
.map(Path::to_path_buf)
.unwrap_or_else(|| resolve_build_dir(&helper_source_dir(), &flags));
let destdir = std::env::var("DESTDIR").context("DESTDIR must be set for meson_install")?;
let mut install_cmd = fakeroot::wrap_install_command("meson", Path::new(&destdir));
install_cmd.arg("install");
install_cmd.arg("-C").arg(&build_dir);
for arg in extra_args {
install_cmd.arg(context.expand_vars(arg));
}
let mut install_env = env_vars.to_vec();
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir);
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
let status = crate::interrupts::command_status(&mut install_cmd)
.context("Failed to run helper meson install")?;
if !status.success() {
bail!("meson install failed");
}
Ok(())
}
fn num_cpus() -> usize { fn num_cpus() -> usize {
std::thread::available_parallelism() std::thread::available_parallelism()
.map(|n| n.get()) .map(|n| n.get())
.unwrap_or(1) .unwrap_or(1)
} }
fn helper_source_dir() -> PathBuf {
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
.map(PathBuf::from)
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
}
fn resolve_build_dir(actual_src: &Path, flags: &crate::package::BuildFlags) -> PathBuf { fn resolve_build_dir(actual_src: &Path, flags: &crate::package::BuildFlags) -> PathBuf {
if let Some(dir) = flags if let Some(dir) = flags
.build_dir .build_dir
+162
View File
@@ -22,6 +22,9 @@ use walkdir::WalkDir;
pub type EnvVars = Vec<(String, String)>; pub type EnvVars = Vec<(String, String)>;
pub(crate) const DEPOT_BUILD_HOST_DIR_ENV: &str = "DEPOT_BUILD_HOST_DIR"; pub(crate) const DEPOT_BUILD_HOST_DIR_ENV: &str = "DEPOT_BUILD_HOST_DIR";
pub(crate) const DEPOT_BUILD_HELPER_CONTEXT_ENV: &str = "DEPOT_BUILD_HELPER_CONTEXT";
pub(crate) const DEPOT_BUILD_HELPER_SOURCE_DIR_ENV: &str = "DEPOT_BUILD_HELPER_SOURCE_DIR";
pub(crate) const DEPOT_BUILD_HELPER_BUILD_DIR_ENV: &str = "DEPOT_BUILD_HELPER_BUILD_DIR";
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetBuildKind { pub enum TargetBuildKind {
@@ -45,6 +48,154 @@ pub(crate) struct InstallDirs {
pub infodir: String, pub infodir: String,
} }
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub(crate) struct BuildHelperContext {
pub package_name: String,
pub package_version: String,
pub spec_dir: PathBuf,
pub flags: BuildFlags,
pub lib32_variant: bool,
pub host_build_dir: Option<String>,
}
impl BuildHelperContext {
pub(crate) fn from_spec(spec: &PackageSpec) -> Self {
Self {
package_name: spec.package.name.clone(),
package_version: spec.package.version.clone(),
spec_dir: spec.spec_dir.clone(),
flags: spec.build.flags.clone(),
lib32_variant: spec.build.flags.lib32_variant,
host_build_dir: spec.build.flags.host_build_dir.clone(),
}
}
pub(crate) fn expand_vars(&self, input: &str) -> String {
let specdir = self.spec_dir.to_string_lossy();
input
.replace("$name", &self.package_name)
.replace("$version", &self.package_version)
.replace("$specdir", &specdir)
.replace("$DEPOT_SPECDIR", &specdir)
}
pub(crate) fn build_flags(&self) -> BuildFlags {
let mut flags = self.flags.clone();
flags.lib32_variant = self.lib32_variant;
flags.host_build_dir = self.host_build_dir.clone();
flags
}
}
pub(crate) fn apply_build_helper_context_env(
env_vars: &mut EnvVars,
spec: &PackageSpec,
) -> Result<()> {
let encoded = toml::to_string(&BuildHelperContext::from_spec(spec))
.context("Failed to serialize build helper context")?;
set_env_var(env_vars, DEPOT_BUILD_HELPER_CONTEXT_ENV, encoded);
Ok(())
}
pub(crate) fn apply_build_helper_dirs_env(
env_vars: &mut EnvVars,
source_dir: Option<&Path>,
build_dir: Option<&Path>,
) {
if let Some(source_dir) = source_dir {
set_env_var(
env_vars,
DEPOT_BUILD_HELPER_SOURCE_DIR_ENV,
source_dir.to_string_lossy().into_owned(),
);
}
if let Some(build_dir) = build_dir {
set_env_var(
env_vars,
DEPOT_BUILD_HELPER_BUILD_DIR_ENV,
build_dir.to_string_lossy().into_owned(),
);
}
}
pub(crate) fn run_autotools_helper_configure(
context: &BuildHelperContext,
source_dir: Option<&Path>,
build_dir: Option<&Path>,
cross: Option<&CrossConfig>,
env_vars: &EnvVars,
extra_args: &[String],
) -> Result<()> {
autotools::run_helper_configure(context, source_dir, build_dir, cross, env_vars, extra_args)
}
pub(crate) fn run_autotools_helper_install(
context: &BuildHelperContext,
build_dir: Option<&Path>,
env_vars: &EnvVars,
extra_args: &[String],
) -> Result<()> {
autotools::run_helper_install(context, build_dir, env_vars, extra_args)
}
pub(crate) fn run_cmake_helper_configure(
context: &BuildHelperContext,
source_dir: Option<&Path>,
build_dir: Option<&Path>,
cross: Option<&CrossConfig>,
env_vars: &EnvVars,
extra_args: &[String],
) -> Result<()> {
cmake::run_helper_configure(context, source_dir, build_dir, cross, env_vars, extra_args)
}
pub(crate) fn run_cmake_helper_install(
context: &BuildHelperContext,
build_dir: Option<&Path>,
env_vars: &EnvVars,
extra_args: &[String],
) -> Result<()> {
cmake::run_helper_install(context, build_dir, env_vars, extra_args)
}
pub(crate) fn run_meson_helper_configure(
context: &BuildHelperContext,
source_dir: Option<&Path>,
build_dir: Option<&Path>,
cross: Option<&CrossConfig>,
env_vars: &EnvVars,
extra_args: &[String],
) -> Result<()> {
meson::run_helper_configure(context, source_dir, build_dir, cross, env_vars, extra_args)
}
pub(crate) fn run_meson_helper_install(
context: &BuildHelperContext,
build_dir: Option<&Path>,
env_vars: &EnvVars,
extra_args: &[String],
) -> Result<()> {
meson::run_helper_install(context, build_dir, env_vars, extra_args)
}
pub(crate) fn run_perl_helper_configure(
context: &BuildHelperContext,
source_dir: Option<&Path>,
env_vars: &EnvVars,
extra_args: &[String],
) -> Result<()> {
perl::run_helper_configure(context, source_dir, env_vars, extra_args)
}
pub(crate) fn run_perl_helper_install(
context: &BuildHelperContext,
build_dir: Option<&Path>,
env_vars: &EnvVars,
extra_args: &[String],
) -> Result<()> {
perl::run_helper_install(context, build_dir, env_vars, extra_args)
}
pub fn set_env_var(env_vars: &mut EnvVars, key: &str, value: impl Into<String>) { pub fn set_env_var(env_vars: &mut EnvVars, key: &str, value: impl Into<String>) {
let value = value.into(); let value = value.into();
if let Some((_, existing)) = env_vars.iter_mut().find(|(k, _)| k == key) { if let Some((_, existing)) = env_vars.iter_mut().find(|(k, _)| k == key) {
@@ -1353,6 +1504,17 @@ mod tests {
assert_eq!(lib32_dirs.libexecdir, "/usr/lib32"); assert_eq!(lib32_dirs.libexecdir, "/usr/lib32");
} }
#[test]
fn test_build_helper_context_restores_runtime_build_flags() {
let mut spec = mk_spec(Vec::new(), Vec::new());
spec.build.flags.lib32_variant = true;
spec.build.flags.host_build_dir = Some("/tmp/build-host".into());
let restored = BuildHelperContext::from_spec(&spec).build_flags();
assert!(restored.lib32_variant);
assert_eq!(restored.host_build_dir.as_deref(), Some("/tmp/build-host"));
}
#[test] #[test]
fn test_install_dirs_respect_explicit_overrides_and_derived_defaults() { fn test_install_dirs_respect_explicit_overrides_and_derived_defaults() {
let dirs = install_dirs(&BuildFlags { let dirs = install_dirs(&BuildFlags {
+141
View File
@@ -1,5 +1,6 @@
//! Perl MakeMaker build system (`perl Makefile.PL && make && make test && make install`) //! Perl MakeMaker build system (`perl Makefile.PL && make && make test && make install`)
use crate::builder::BuildHelperContext;
use crate::builder::autotools; use crate::builder::autotools;
use crate::builder::state::{BuildStep, StateTracker}; use crate::builder::state::{BuildStep, StateTracker};
use crate::cross::CrossConfig; use crate::cross::CrossConfig;
@@ -261,6 +262,124 @@ pub fn build(
Ok(()) Ok(())
} }
pub(crate) fn run_helper_configure(
context: &BuildHelperContext,
source_dir: Option<&Path>,
env_vars: &[(String, String)],
extra_args: &[String],
) -> Result<()> {
let flags = context.build_flags();
let source_dir = source_dir
.map(Path::to_path_buf)
.unwrap_or(std::env::current_dir().context("Failed to determine current directory")?);
let configure_script = helper_configure_script(context, &source_dir);
let mut helper_env = env_vars.to_vec();
crate::builder::set_env_var(&mut helper_env, "PERL_MM_USE_DEFAULT", "1");
if !flags.rootfs.is_empty() && flags.rootfs != "/" {
crate::builder::set_env_var(
&mut helper_env,
"PKG_CONFIG_SYSROOT_DIR",
flags.rootfs.clone(),
);
}
let mut configure_cmd =
Command::new(resolved_command_path("perl").unwrap_or_else(|| PathBuf::from("perl")));
configure_cmd.current_dir(&source_dir);
configure_cmd.arg(&configure_script);
if !has_assignment_prefix(&flags.configure, "INSTALLDIRS") {
configure_cmd.arg("INSTALLDIRS=vendor");
}
for arg in &flags.configure {
configure_cmd.arg(context.expand_vars(arg));
}
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Perl, &flags)? {
configure_cmd.arg(arg);
}
for arg in extra_args {
configure_cmd.arg(context.expand_vars(arg));
}
crate::builder::prepare_tool_command(&mut configure_cmd, &helper_env);
let status = command_status_with_sh_fallback(&mut configure_cmd)
.context("Failed to run helper perl configure")?;
if !status.success() {
anyhow::bail!("perl Makefile.PL failed with status: {}", status);
}
Ok(())
}
pub(crate) fn run_helper_install(
context: &BuildHelperContext,
build_dir: Option<&Path>,
env_vars: &[(String, String)],
extra_args: &[String],
) -> Result<()> {
let flags = context.build_flags();
let build_dir = build_dir
.map(Path::to_path_buf)
.unwrap_or_else(helper_source_dir);
let destdir = std::env::var("DESTDIR").context("DESTDIR must be set for perl_install")?;
let make_exec = autotools::resolve_make_exec(&flags.make_exec);
let install_dirs = autotools::resolve_make_dirs(
&build_dir,
&flags.make_install_dirs,
"build.flags.make_install_dirs",
)?;
let install_targets = autotools::phase_targets(
&flags.make_install_target,
&flags.make_install_targets,
Some("install"),
);
for install_dir in install_dirs {
let mut install_cmd = fakeroot::wrap_install_command(make_exec, Path::new(&destdir));
install_cmd.current_dir(&install_dir);
if autotools::make_exec_supports_make_assignments(make_exec)
&& !autotools::has_make_variable_override(&flags.make_install_vars, "DESTDIR")
{
install_cmd.arg(format!("DESTDIR={destdir}"));
}
autotools::add_make_variable_overrides_if_supported(
&mut install_cmd,
make_exec,
&flags.make_install_vars,
"install",
)?;
for target in &install_targets {
install_cmd.arg(target);
}
for arg in extra_args {
install_cmd.arg(context.expand_vars(arg));
}
let mut install_env = env_vars.to_vec();
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir.clone());
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
let status = command_status_with_sh_fallback(&mut install_cmd).with_context(|| {
format!(
"Failed to run helper {} {} in {}",
make_exec,
install_targets.join(" "),
install_dir.display()
)
})?;
if !status.success() {
anyhow::bail!(
"{} {} failed with status: {} (dir: {})",
make_exec,
install_targets.join(" "),
status,
install_dir.display()
);
}
}
Ok(())
}
fn resolve_perl_configure_script(spec: &PackageSpec, actual_src: &Path) -> PathBuf { fn resolve_perl_configure_script(spec: &PackageSpec, actual_src: &Path) -> PathBuf {
let configured = spec.expand_vars(&spec.build.flags.configure_file); let configured = spec.expand_vars(&spec.build.flags.configure_file);
let trimmed = configured.trim(); let trimmed = configured.trim();
@@ -276,6 +395,22 @@ fn resolve_perl_configure_script(spec: &PackageSpec, actual_src: &Path) -> PathB
} }
} }
fn helper_configure_script(context: &BuildHelperContext, actual_src: &Path) -> PathBuf {
let flags = context.build_flags();
let configured = context.expand_vars(&flags.configure_file);
let trimmed = configured.trim();
if trimmed.is_empty() {
return actual_src.join("Makefile.PL");
}
let path = Path::new(trimmed);
if path.is_absolute() {
path.to_path_buf()
} else {
actual_src.join(path)
}
}
fn command_status_with_sh_fallback(cmd: &mut Command) -> std::io::Result<std::process::ExitStatus> { fn command_status_with_sh_fallback(cmd: &mut Command) -> std::io::Result<std::process::ExitStatus> {
match crate::interrupts::command_status(cmd) { match crate::interrupts::command_status(cmd) {
Ok(status) => Ok(status), Ok(status) => Ok(status),
@@ -346,6 +481,12 @@ fn has_assignment_prefix(args: &[String], name: &str) -> bool {
}) })
} }
fn helper_source_dir() -> PathBuf {
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
.map(PathBuf::from)
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
+40
View File
@@ -316,6 +316,46 @@ pub enum InternalCommands {
}, },
#[command(hide = true)] #[command(hide = true)]
Clone { repo: String, dest: Option<PathBuf> }, Clone { repo: String, dest: Option<PathBuf> },
#[command(hide = true)]
AutotoolsConfigure {
#[arg(value_name = "ARG", num_args = 0.., allow_hyphen_values = true)]
args: Vec<String>,
},
#[command(hide = true)]
AutotoolsInstall {
#[arg(value_name = "ARG", num_args = 0.., allow_hyphen_values = true)]
args: Vec<String>,
},
#[command(hide = true)]
CmakeConfigure {
#[arg(value_name = "ARG", num_args = 0.., allow_hyphen_values = true)]
args: Vec<String>,
},
#[command(hide = true)]
CmakeInstall {
#[arg(value_name = "ARG", num_args = 0.., allow_hyphen_values = true)]
args: Vec<String>,
},
#[command(hide = true)]
MesonConfigure {
#[arg(value_name = "ARG", num_args = 0.., allow_hyphen_values = true)]
args: Vec<String>,
},
#[command(hide = true)]
MesonInstall {
#[arg(value_name = "ARG", num_args = 0.., allow_hyphen_values = true)]
args: Vec<String>,
},
#[command(hide = true)]
PerlConfigure {
#[arg(value_name = "ARG", num_args = 0.., allow_hyphen_values = true)]
args: Vec<String>,
},
#[command(hide = true)]
PerlInstall {
#[arg(value_name = "ARG", num_args = 0.., allow_hyphen_values = true)]
args: Vec<String>,
},
} }
#[derive(Debug, Clone, Args)] #[derive(Debug, Clone, Args)]
+256
View File
@@ -1,4 +1,6 @@
use super::*; use super::*;
use crate::builder::BuildHelperContext;
use std::path::{Path, PathBuf};
fn current_process_env_vars() -> Vec<(String, String)> { fn current_process_env_vars() -> Vec<(String, String)> {
const ALLOWED_ENV_VARS: &[&str] = &[ const ALLOWED_ENV_VARS: &[&str] = &[
@@ -13,6 +15,10 @@ fn current_process_env_vars() -> Vec<(String, String)> {
"CFLAGS", "CFLAGS",
"CXX", "CXX",
"CXXFLAGS", "CXXFLAGS",
crate::builder::DEPOT_BUILD_HELPER_BUILD_DIR_ENV,
crate::builder::DEPOT_BUILD_HELPER_CONTEXT_ENV,
crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV,
crate::builder::DEPOT_BUILD_HOST_DIR_ENV,
"DEPOT_ROOTFS", "DEPOT_ROOTFS",
"DEPOT_SPECDIR", "DEPOT_SPECDIR",
"DESTDIR", "DESTDIR",
@@ -41,6 +47,42 @@ fn current_process_env_vars() -> Vec<(String, String)> {
.collect() .collect()
} }
fn current_build_helper_context() -> Result<BuildHelperContext> {
let raw = std::env::var(crate::builder::DEPOT_BUILD_HELPER_CONTEXT_ENV).with_context(|| {
format!(
"{} must be set for internal build helpers",
crate::builder::DEPOT_BUILD_HELPER_CONTEXT_ENV
)
})?;
toml::from_str(&raw).context("Failed to parse build helper context")
}
fn current_helper_source_dir() -> Option<PathBuf> {
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
.ok()
.map(PathBuf::from)
}
fn current_helper_build_dir() -> Option<PathBuf> {
std::env::var(crate::builder::DEPOT_BUILD_HELPER_BUILD_DIR_ENV)
.ok()
.map(PathBuf::from)
}
fn current_cross_config() -> Result<Option<crate::cross::CrossConfig>> {
let Some(prefix) = std::env::var("CROSS_PREFIX")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
else {
return Ok(None);
};
crate::cross::CrossConfig::from_prefix(&prefix)
.map(Some)
.with_context(|| format!("Failed to resolve cross-compilation tools for {}", prefix))
}
pub(crate) fn run_internal_command(command: InternalCommands) -> Result<()> { pub(crate) fn run_internal_command(command: InternalCommands) -> Result<()> {
match command { match command {
InternalCommands::PythonBuild { InternalCommands::PythonBuild {
@@ -101,5 +143,219 @@ pub(crate) fn run_internal_command(command: InternalCommands) -> Result<()> {
&[], &[],
) )
} }
InternalCommands::AutotoolsConfigure { args } => {
let env_vars = current_process_env_vars();
let context = current_build_helper_context()?;
let cross = current_cross_config()?;
crate::builder::run_autotools_helper_configure(
&context,
current_helper_source_dir().as_deref(),
current_helper_build_dir().as_deref(),
cross.as_ref(),
&env_vars,
&args,
)
}
InternalCommands::AutotoolsInstall { args } => {
let env_vars = current_process_env_vars();
let context = current_build_helper_context()?;
crate::builder::run_autotools_helper_install(
&context,
current_helper_build_dir().as_deref(),
&env_vars,
&args,
)
}
InternalCommands::CmakeConfigure { args } => {
let env_vars = current_process_env_vars();
let context = current_build_helper_context()?;
let cross = current_cross_config()?;
crate::builder::run_cmake_helper_configure(
&context,
current_helper_source_dir().as_deref(),
current_helper_build_dir().as_deref(),
cross.as_ref(),
&env_vars,
&args,
)
}
InternalCommands::CmakeInstall { args } => {
let env_vars = current_process_env_vars();
let context = current_build_helper_context()?;
crate::builder::run_cmake_helper_install(
&context,
current_helper_build_dir().as_deref(),
&env_vars,
&args,
)
}
InternalCommands::MesonConfigure { args } => {
let env_vars = current_process_env_vars();
let context = current_build_helper_context()?;
let cross = current_cross_config()?;
crate::builder::run_meson_helper_configure(
&context,
current_helper_source_dir().as_deref(),
current_helper_build_dir().as_deref(),
cross.as_ref(),
&env_vars,
&args,
)
}
InternalCommands::MesonInstall { args } => {
let env_vars = current_process_env_vars();
let context = current_build_helper_context()?;
crate::builder::run_meson_helper_install(
&context,
current_helper_build_dir().as_deref(),
&env_vars,
&args,
)
}
InternalCommands::PerlConfigure { args } => {
let env_vars = current_process_env_vars();
let context = current_build_helper_context()?;
crate::builder::run_perl_helper_configure(
&context,
current_helper_source_dir().as_deref(),
&env_vars,
&args,
)
}
InternalCommands::PerlInstall { args } => {
let env_vars = current_process_env_vars();
let context = current_build_helper_context()?;
crate::builder::run_perl_helper_install(
&context,
current_helper_build_dir().as_deref(),
&env_vars,
&args,
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::package::BuildFlags;
use crate::test_support::TestEnv;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use tempfile::tempdir;
fn write_executable(path: &Path, contents: &str) -> Result<()> {
fs::write(path, contents).with_context(|| format!("Failed to write {}", path.display()))?;
let mut perms = fs::metadata(path)?.permissions();
perms.set_mode(0o755);
fs::set_permissions(path, perms)?;
Ok(())
}
fn helper_context(flags: BuildFlags, spec_dir: &Path) -> BuildHelperContext {
BuildHelperContext {
package_name: "demo".into(),
package_version: "1.0".into(),
spec_dir: spec_dir.to_path_buf(),
flags,
lib32_variant: false,
host_build_dir: None,
}
}
#[test]
fn meson_configure_uses_build_helper_context_defaults() -> Result<()> {
let source = tempdir()?;
let tools = tempdir()?;
let log = tools.path().join("meson.log");
let flags = BuildFlags {
prefix: "/opt/demo".into(),
build_dir: Some("builddir".into()),
..BuildFlags::default()
};
write_executable(
&tools.path().join("meson"),
&format!("#!/bin/sh\nprintf '%s\\n' \"$@\" > '{}'\n", log.display()),
)?;
let mut env = TestEnv::new();
env.set_var("PATH", tools.path());
env.set_var(
crate::builder::DEPOT_BUILD_HELPER_CONTEXT_ENV,
toml::to_string(&helper_context(flags, source.path()))?,
);
env.set_var(
crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV,
source.path(),
);
run_internal_command(InternalCommands::MesonConfigure {
args: vec!["-Dfeature=enabled".into()],
})?;
let output = fs::read_to_string(&log)?;
assert!(output.contains("setup"));
assert!(output.contains("--prefix=/opt/demo"));
assert!(output.contains("--buildtype=release"));
assert!(output.contains("-Dfeature=enabled"));
assert!(output.contains(source.path().join("builddir").to_string_lossy().as_ref()));
Ok(())
}
#[test]
fn cmake_install_uses_fakeroot_and_destdir() -> Result<()> {
let source = tempdir()?;
let build_dir = source.path().join("build");
let tools = tempdir()?;
let fakeroot_log = tools.path().join("fakeroot.log");
let cmake_log = tools.path().join("cmake.log");
let destdir = source.path().join("dest");
fs::create_dir_all(&build_dir)?;
fs::create_dir_all(&destdir)?;
write_executable(
&tools.path().join("fakeroot"),
&format!(
"#!/bin/sh\nprintf '%s\\n' \"$@\" > '{}'\n[ \"$1\" = \"--\" ]\nshift\nexec \"$@\"\n",
fakeroot_log.display()
),
)?;
write_executable(
&tools.path().join("cmake"),
&format!(
"#!/bin/sh\n{{ printf 'DESTDIR=%s\\n' \"$DESTDIR\"; printf '%s\\n' \"$@\"; }} > '{}'\n",
cmake_log.display()
),
)?;
let mut env = TestEnv::new();
env.set_var("PATH", tools.path());
env.set_var("DESTDIR", &destdir);
env.set_var(
crate::builder::DEPOT_BUILD_HELPER_CONTEXT_ENV,
toml::to_string(&helper_context(BuildFlags::default(), source.path()))?,
);
env.set_var(
crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV,
source.path(),
);
env.set_var(crate::builder::DEPOT_BUILD_HELPER_BUILD_DIR_ENV, &build_dir);
run_internal_command(InternalCommands::CmakeInstall {
args: vec!["--component".into(), "runtime".into()],
})?;
let fakeroot_output = fs::read_to_string(&fakeroot_log)?;
assert!(fakeroot_output.contains("--"));
assert!(fakeroot_output.contains("cmake"));
let cmake_output = fs::read_to_string(&cmake_log)?;
assert!(cmake_output.contains(&format!("DESTDIR={}", destdir.display())));
assert!(cmake_output.contains("--install"));
assert!(cmake_output.contains(build_dir.to_string_lossy().as_ref()));
assert!(cmake_output.contains("--component"));
assert!(cmake_output.contains("runtime"));
Ok(())
} }
} }
+25 -6
View File
@@ -6,10 +6,16 @@ use crate::cli::{
use crate::test_support::TestEnv; use crate::test_support::TestEnv;
use git2::{Oid, Repository}; use git2::{Oid, Repository};
use std::path::Path; use std::path::Path;
use std::sync::Mutex; use std::sync::{Mutex, MutexGuard};
static ASSUME_YES_TEST_LOCK: Mutex<()> = Mutex::new(()); static ASSUME_YES_TEST_LOCK: Mutex<()> = Mutex::new(());
fn assume_yes_test_lock() -> MutexGuard<'static, ()> {
ASSUME_YES_TEST_LOCK
.lock()
.unwrap_or_else(|err| err.into_inner())
}
fn rootfs_args(rootfs: impl Into<PathBuf>) -> RootfsArgs { fn rootfs_args(rootfs: impl Into<PathBuf>) -> RootfsArgs {
RootfsArgs { RootfsArgs {
rootfs: rootfs.into(), rootfs: rootfs.into(),
@@ -189,6 +195,16 @@ fn register_installed_test_package(
Ok(()) Ok(())
} }
fn register_required_development_package_if_configured(
config: &config::Config,
rootfs: &Path,
) -> Result<()> {
if let Some(package_name) = builder::requested_development_package() {
register_installed_test_package(config, rootfs, &package_name, "1.0.0")?;
}
Ok(())
}
fn write_test_repo_spec(path: &Path, name: &str, version: &str) -> Result<()> { fn write_test_repo_spec(path: &Path, name: &str, version: &str) -> Result<()> {
if let Some(parent) = path.parent() { if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?; fs::create_dir_all(parent)?;
@@ -2216,7 +2232,7 @@ file = "missing.patch"
#[test] #[test]
fn build_command_checks_manual_sources_before_dependency_resolution() -> Result<()> { fn build_command_checks_manual_sources_before_dependency_resolution() -> Result<()> {
let _guard = ASSUME_YES_TEST_LOCK.lock().expect("assume-yes test lock"); let _guard = assume_yes_test_lock();
let temp = tempfile::tempdir().context("Failed to create temp dir")?; let temp = tempfile::tempdir().context("Failed to create temp dir")?;
let rootfs = temp.path().join("rootfs"); let rootfs = temp.path().join("rootfs");
let spec_dir = temp.path().join("packages").join("demo"); let spec_dir = temp.path().join("packages").join("demo");
@@ -2534,7 +2550,7 @@ fn build_type_runs_automatic_tests_matches_builder_behavior() {
#[test] #[test]
fn requested_test_deps_prompt_can_disable_tests() -> Result<()> { fn requested_test_deps_prompt_can_disable_tests() -> Result<()> {
let _guard = ASSUME_YES_TEST_LOCK.lock().expect("assume-yes test lock"); let _guard = assume_yes_test_lock();
let mut spec = test_package_spec(package::BuildType::Meson, None, &[]); let mut spec = test_package_spec(package::BuildType::Meson, None, &[]);
spec.dependencies.test = vec!["pytest".into()]; spec.dependencies.test = vec!["pytest".into()];
@@ -2553,7 +2569,7 @@ fn requested_test_deps_prompt_can_disable_tests() -> Result<()> {
#[test] #[test]
fn requested_test_deps_prompt_is_ignored_for_non_automatic_test_builders() -> Result<()> { fn requested_test_deps_prompt_is_ignored_for_non_automatic_test_builders() -> Result<()> {
let _guard = ASSUME_YES_TEST_LOCK.lock().expect("assume-yes test lock"); let _guard = assume_yes_test_lock();
let mut spec = test_package_spec(package::BuildType::Custom, None, &[]); let mut spec = test_package_spec(package::BuildType::Custom, None, &[]);
spec.dependencies.test = vec!["pytest".into()]; spec.dependencies.test = vec!["pytest".into()];
@@ -2572,7 +2588,7 @@ fn requested_test_deps_prompt_is_ignored_for_non_automatic_test_builders() -> Re
#[test] #[test]
fn requested_test_deps_prompt_is_ignored_for_multilib_builds() -> Result<()> { fn requested_test_deps_prompt_is_ignored_for_multilib_builds() -> Result<()> {
let _guard = ASSUME_YES_TEST_LOCK.lock().expect("assume-yes test lock"); let _guard = assume_yes_test_lock();
let mut spec = test_package_spec(package::BuildType::Meson, None, &[]); let mut spec = test_package_spec(package::BuildType::Meson, None, &[]);
spec.build.flags.build_32 = true; spec.build.flags.build_32 = true;
spec.dependencies.test = vec!["pytest".into()]; spec.dependencies.test = vec!["pytest".into()];
@@ -2777,7 +2793,7 @@ fn live_rootfs_child_install_batches_group_consecutive_binary_steps() -> Result<
#[test] #[test]
fn build_command_requires_install_deps_flag_for_missing_dependencies() -> Result<()> { fn build_command_requires_install_deps_flag_for_missing_dependencies() -> Result<()> {
let _guard = ASSUME_YES_TEST_LOCK.lock().expect("assume-yes test lock"); let _guard = assume_yes_test_lock();
let temp = tempfile::tempdir().context("Failed to create temp dir")?; let temp = tempfile::tempdir().context("Failed to create temp dir")?;
let rootfs = temp.path().join("rootfs"); let rootfs = temp.path().join("rootfs");
let repo_root = temp.path().join("packages"); let repo_root = temp.path().join("packages");
@@ -2841,6 +2857,9 @@ optional = []
) )
.with_context(|| format!("Failed to write {}", dep_spec.display()))?; .with_context(|| format!("Failed to write {}", dep_spec.display()))?;
let config = config::Config::for_rootfs(&rootfs);
register_required_development_package_if_configured(&config, &rootfs)?;
let result = run(Cli { let result = run(Cli {
command: Commands::Build(BuildArgs { command: Commands::Build(BuildArgs {
rootfs_args: rootfs_args(rootfs.clone()), rootfs_args: rootfs_args(rootfs.clone()),
+261 -87
View File
@@ -15,6 +15,14 @@ const DEPOT_SUBDESTDIR_HELPER_ENV: &str = "DEPOT_SUBDESTDIR_HELPER";
const DEPOT_PYTHON_BUILD_HELPER_ENV: &str = "DEPOT_PYTHON_BUILD_HELPER"; const DEPOT_PYTHON_BUILD_HELPER_ENV: &str = "DEPOT_PYTHON_BUILD_HELPER";
const DEPOT_PYTHON_INSTALL_HELPER_ENV: &str = "DEPOT_PYTHON_INSTALL_HELPER"; const DEPOT_PYTHON_INSTALL_HELPER_ENV: &str = "DEPOT_PYTHON_INSTALL_HELPER";
const DEPOT_CLONE_HELPER_ENV: &str = "DEPOT_CLONE_HELPER"; const DEPOT_CLONE_HELPER_ENV: &str = "DEPOT_CLONE_HELPER";
const DEPOT_AUTOTOOLS_CONFIGURE_HELPER_ENV: &str = "DEPOT_AUTOTOOLS_CONFIGURE_HELPER";
const DEPOT_AUTOTOOLS_INSTALL_HELPER_ENV: &str = "DEPOT_AUTOTOOLS_INSTALL_HELPER";
const DEPOT_CMAKE_CONFIGURE_HELPER_ENV: &str = "DEPOT_CMAKE_CONFIGURE_HELPER";
const DEPOT_CMAKE_INSTALL_HELPER_ENV: &str = "DEPOT_CMAKE_INSTALL_HELPER";
const DEPOT_MESON_CONFIGURE_HELPER_ENV: &str = "DEPOT_MESON_CONFIGURE_HELPER";
const DEPOT_MESON_INSTALL_HELPER_ENV: &str = "DEPOT_MESON_INSTALL_HELPER";
const DEPOT_PERL_CONFIGURE_HELPER_ENV: &str = "DEPOT_PERL_CONFIGURE_HELPER";
const DEPOT_PERL_INSTALL_HELPER_ENV: &str = "DEPOT_PERL_INSTALL_HELPER";
const DEPOT_EXECUTABLE_ENV: &str = "DEPOT_EXECUTABLE"; const DEPOT_EXECUTABLE_ENV: &str = "DEPOT_EXECUTABLE";
/// Ephemeral helper command directory to prepend to PATH while running scripts. /// Ephemeral helper command directory to prepend to PATH while running scripts.
@@ -28,6 +36,14 @@ pub struct ShellHelpers {
python_build_path: PathBuf, python_build_path: PathBuf,
python_install_path: PathBuf, python_install_path: PathBuf,
clone_path: PathBuf, clone_path: PathBuf,
autotools_configure_path: PathBuf,
autotools_install_path: PathBuf,
cmake_configure_path: PathBuf,
cmake_install_path: PathBuf,
meson_configure_path: PathBuf,
meson_install_path: PathBuf,
perl_configure_path: PathBuf,
perl_install_path: PathBuf,
} }
impl ShellHelpers { impl ShellHelpers {
@@ -49,99 +65,43 @@ impl ShellHelpers {
.context("Failed to locate depot executable for shell helpers")?; .context("Failed to locate depot executable for shell helpers")?;
let haul_path = bin_dir.join("haul"); let haul_path = bin_dir.join("haul");
fs::write(&haul_path, HAUL_SCRIPT).with_context(|| { write_helper_script(&haul_path, HAUL_SCRIPT)?;
format!(
"Failed to write shell helper command: {}",
haul_path.display()
)
})?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&haul_path)
.with_context(|| format!("Failed to stat helper: {}", haul_path.display()))?
.permissions();
perms.set_mode(0o755);
fs::set_permissions(&haul_path, perms)
.with_context(|| format!("Failed to chmod helper: {}", haul_path.display()))?;
}
let subdestdir_path = bin_dir.join("subdestdir"); let subdestdir_path = bin_dir.join("subdestdir");
fs::write(&subdestdir_path, SUBDESTDIR_SCRIPT).with_context(|| { write_helper_script(&subdestdir_path, SUBDESTDIR_SCRIPT)?;
format!(
"Failed to write shell helper command: {}",
subdestdir_path.display()
)
})?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&subdestdir_path)
.with_context(|| format!("Failed to stat helper: {}", subdestdir_path.display()))?
.permissions();
perms.set_mode(0o755);
fs::set_permissions(&subdestdir_path, perms).with_context(|| {
format!("Failed to chmod helper: {}", subdestdir_path.display())
})?;
}
let python_build_path = bin_dir.join("python_build"); let python_build_path = bin_dir.join("python_build");
fs::write(&python_build_path, PYTHON_BUILD_SCRIPT).with_context(|| { write_helper_script(&python_build_path, PYTHON_BUILD_SCRIPT)?;
format!(
"Failed to write shell helper command: {}",
python_build_path.display()
)
})?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&python_build_path)
.with_context(|| format!("Failed to stat helper: {}", python_build_path.display()))?
.permissions();
perms.set_mode(0o755);
fs::set_permissions(&python_build_path, perms).with_context(|| {
format!("Failed to chmod helper: {}", python_build_path.display())
})?;
}
let python_install_path = bin_dir.join("python_install"); let python_install_path = bin_dir.join("python_install");
fs::write(&python_install_path, PYTHON_INSTALL_SCRIPT).with_context(|| { write_helper_script(&python_install_path, PYTHON_INSTALL_SCRIPT)?;
format!(
"Failed to write shell helper command: {}",
python_install_path.display()
)
})?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&python_install_path)
.with_context(|| {
format!("Failed to stat helper: {}", python_install_path.display())
})?
.permissions();
perms.set_mode(0o755);
fs::set_permissions(&python_install_path, perms).with_context(|| {
format!("Failed to chmod helper: {}", python_install_path.display())
})?;
}
let clone_path = bin_dir.join("depot_clone"); let clone_path = bin_dir.join("depot_clone");
fs::write(&clone_path, CLONE_SCRIPT).with_context(|| { write_helper_script(&clone_path, CLONE_SCRIPT)?;
format!(
"Failed to write shell helper command: {}", let autotools_configure_path = bin_dir.join("autotools_configure");
clone_path.display() write_helper_script(&autotools_configure_path, AUTOTOOLS_CONFIGURE_SCRIPT)?;
)
})?; let autotools_install_path = bin_dir.join("autotools_install");
#[cfg(unix)] write_helper_script(&autotools_install_path, AUTOTOOLS_INSTALL_SCRIPT)?;
{
use std::os::unix::fs::PermissionsExt; let cmake_configure_path = bin_dir.join("cmake_configure");
let mut perms = fs::metadata(&clone_path) write_helper_script(&cmake_configure_path, CMAKE_CONFIGURE_SCRIPT)?;
.with_context(|| format!("Failed to stat helper: {}", clone_path.display()))?
.permissions(); let cmake_install_path = bin_dir.join("cmake_install");
perms.set_mode(0o755); write_helper_script(&cmake_install_path, CMAKE_INSTALL_SCRIPT)?;
fs::set_permissions(&clone_path, perms)
.with_context(|| format!("Failed to chmod helper: {}", clone_path.display()))?; let meson_configure_path = bin_dir.join("meson_configure");
} write_helper_script(&meson_configure_path, MESON_CONFIGURE_SCRIPT)?;
let meson_install_path = bin_dir.join("meson_install");
write_helper_script(&meson_install_path, MESON_INSTALL_SCRIPT)?;
let perl_configure_path = bin_dir.join("perl_configure");
write_helper_script(&perl_configure_path, PERL_CONFIGURE_SCRIPT)?;
let perl_install_path = bin_dir.join("perl_install");
write_helper_script(&perl_install_path, PERL_INSTALL_SCRIPT)?;
let path_value = crate::runtime_env::prepend_helper_to_safe_path(&bin_dir); let path_value = crate::runtime_env::prepend_helper_to_safe_path(&bin_dir);
@@ -155,6 +115,14 @@ impl ShellHelpers {
python_build_path, python_build_path,
python_install_path, python_install_path,
clone_path, clone_path,
autotools_configure_path,
autotools_install_path,
cmake_configure_path,
cmake_install_path,
meson_configure_path,
meson_install_path,
perl_configure_path,
perl_install_path,
}) })
} }
@@ -192,6 +160,46 @@ impl ShellHelpers {
DEPOT_CLONE_HELPER_ENV, DEPOT_CLONE_HELPER_ENV,
self.clone_path.to_string_lossy().into_owned(), self.clone_path.to_string_lossy().into_owned(),
); );
set_env_var(
env_vars,
DEPOT_AUTOTOOLS_CONFIGURE_HELPER_ENV,
self.autotools_configure_path.to_string_lossy().into_owned(),
);
set_env_var(
env_vars,
DEPOT_AUTOTOOLS_INSTALL_HELPER_ENV,
self.autotools_install_path.to_string_lossy().into_owned(),
);
set_env_var(
env_vars,
DEPOT_CMAKE_CONFIGURE_HELPER_ENV,
self.cmake_configure_path.to_string_lossy().into_owned(),
);
set_env_var(
env_vars,
DEPOT_CMAKE_INSTALL_HELPER_ENV,
self.cmake_install_path.to_string_lossy().into_owned(),
);
set_env_var(
env_vars,
DEPOT_MESON_CONFIGURE_HELPER_ENV,
self.meson_configure_path.to_string_lossy().into_owned(),
);
set_env_var(
env_vars,
DEPOT_MESON_INSTALL_HELPER_ENV,
self.meson_install_path.to_string_lossy().into_owned(),
);
set_env_var(
env_vars,
DEPOT_PERL_CONFIGURE_HELPER_ENV,
self.perl_configure_path.to_string_lossy().into_owned(),
);
set_env_var(
env_vars,
DEPOT_PERL_INSTALL_HELPER_ENV,
self.perl_install_path.to_string_lossy().into_owned(),
);
set_env_var( set_env_var(
env_vars, env_vars,
DEPOT_EXECUTABLE_ENV, DEPOT_EXECUTABLE_ENV,
@@ -204,10 +212,26 @@ impl ShellHelpers {
/// through `/bin/sh`, avoiding direct execution from mounts that may be `noexec`. /// through `/bin/sh`, avoiding direct execution from mounts that may be `noexec`.
pub fn wrap_shell_command(command: &str) -> String { pub fn wrap_shell_command(command: &str) -> String {
format!( format!(
"haul() {{ /bin/sh \"${{{DEPOT_HAUL_HELPER_ENV}:?}}\" \"$@\"; }}\nsubdestdir() {{ /bin/sh \"${{{DEPOT_SUBDESTDIR_HELPER_ENV}:?}}\" \"$@\"; }}\npython_build() {{ /bin/sh \"${{{DEPOT_PYTHON_BUILD_HELPER_ENV}:?}}\" \"$@\"; }}\npython_install() {{ /bin/sh \"${{{DEPOT_PYTHON_INSTALL_HELPER_ENV}:?}}\" \"$@\"; }}\ndepot_clone() {{ /bin/sh \"${{{DEPOT_CLONE_HELPER_ENV}:?}}\" \"$@\"; }}\n{command}" "haul() {{ /bin/sh \"${{{DEPOT_HAUL_HELPER_ENV}:?}}\" \"$@\"; }}\nsubdestdir() {{ /bin/sh \"${{{DEPOT_SUBDESTDIR_HELPER_ENV}:?}}\" \"$@\"; }}\npython_build() {{ /bin/sh \"${{{DEPOT_PYTHON_BUILD_HELPER_ENV}:?}}\" \"$@\"; }}\npython_install() {{ /bin/sh \"${{{DEPOT_PYTHON_INSTALL_HELPER_ENV}:?}}\" \"$@\"; }}\ndepot_clone() {{ /bin/sh \"${{{DEPOT_CLONE_HELPER_ENV}:?}}\" \"$@\"; }}\nautotools_configure() {{ /bin/sh \"${{{DEPOT_AUTOTOOLS_CONFIGURE_HELPER_ENV}:?}}\" \"$@\"; }}\nautotools_install() {{ /bin/sh \"${{{DEPOT_AUTOTOOLS_INSTALL_HELPER_ENV}:?}}\" \"$@\"; }}\ncmake_configure() {{ /bin/sh \"${{{DEPOT_CMAKE_CONFIGURE_HELPER_ENV}:?}}\" \"$@\"; }}\ncmake_install() {{ /bin/sh \"${{{DEPOT_CMAKE_INSTALL_HELPER_ENV}:?}}\" \"$@\"; }}\nmeson_configure() {{ /bin/sh \"${{{DEPOT_MESON_CONFIGURE_HELPER_ENV}:?}}\" \"$@\"; }}\nmeson_install() {{ /bin/sh \"${{{DEPOT_MESON_INSTALL_HELPER_ENV}:?}}\" \"$@\"; }}\nperl_configure() {{ /bin/sh \"${{{DEPOT_PERL_CONFIGURE_HELPER_ENV}:?}}\" \"$@\"; }}\nperl_install() {{ /bin/sh \"${{{DEPOT_PERL_INSTALL_HELPER_ENV}:?}}\" \"$@\"; }}\n{command}"
) )
} }
fn write_helper_script(path: &Path, content: &str) -> Result<()> {
fs::write(path, content)
.with_context(|| format!("Failed to write shell helper command: {}", path.display()))?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(path)
.with_context(|| format!("Failed to stat helper: {}", path.display()))?
.permissions();
perms.set_mode(0o755);
fs::set_permissions(path, perms)
.with_context(|| format!("Failed to chmod helper: {}", path.display()))?;
}
Ok(())
}
/// Convert a package name into a safe shell identifier suffix. /// Convert a package name into a safe shell identifier suffix.
pub fn shell_ident_suffix(pkg_name: &str) -> String { pub fn shell_ident_suffix(pkg_name: &str) -> String {
let mut out = String::with_capacity(pkg_name.len().max(1)); let mut out = String::with_capacity(pkg_name.len().max(1));
@@ -474,6 +498,114 @@ fail() {
exec "$DEPOT_EXECUTABLE" internal clone "$@" exec "$DEPOT_EXECUTABLE" internal clone "$@"
"#; "#;
const AUTOTOOLS_CONFIGURE_SCRIPT: &str = r#"#!/bin/sh
set -eu
fail() {
echo "autotools_configure: $*" >&2
exit 1
}
[ "${DEPOT_EXECUTABLE:-}" != "" ] || fail "DEPOT_EXECUTABLE is not set"
exec "$DEPOT_EXECUTABLE" internal autotools-configure "$@"
"#;
const AUTOTOOLS_INSTALL_SCRIPT: &str = r#"#!/bin/sh
set -eu
fail() {
echo "autotools_install: $*" >&2
exit 1
}
[ "${DEPOT_EXECUTABLE:-}" != "" ] || fail "DEPOT_EXECUTABLE is not set"
[ "${DESTDIR:-}" != "" ] || fail "DESTDIR is not set"
exec "$DEPOT_EXECUTABLE" internal autotools-install "$@"
"#;
const CMAKE_CONFIGURE_SCRIPT: &str = r#"#!/bin/sh
set -eu
fail() {
echo "cmake_configure: $*" >&2
exit 1
}
[ "${DEPOT_EXECUTABLE:-}" != "" ] || fail "DEPOT_EXECUTABLE is not set"
exec "$DEPOT_EXECUTABLE" internal cmake-configure "$@"
"#;
const CMAKE_INSTALL_SCRIPT: &str = r#"#!/bin/sh
set -eu
fail() {
echo "cmake_install: $*" >&2
exit 1
}
[ "${DEPOT_EXECUTABLE:-}" != "" ] || fail "DEPOT_EXECUTABLE is not set"
[ "${DESTDIR:-}" != "" ] || fail "DESTDIR is not set"
exec "$DEPOT_EXECUTABLE" internal cmake-install "$@"
"#;
const MESON_CONFIGURE_SCRIPT: &str = r#"#!/bin/sh
set -eu
fail() {
echo "meson_configure: $*" >&2
exit 1
}
[ "${DEPOT_EXECUTABLE:-}" != "" ] || fail "DEPOT_EXECUTABLE is not set"
exec "$DEPOT_EXECUTABLE" internal meson-configure "$@"
"#;
const MESON_INSTALL_SCRIPT: &str = r#"#!/bin/sh
set -eu
fail() {
echo "meson_install: $*" >&2
exit 1
}
[ "${DEPOT_EXECUTABLE:-}" != "" ] || fail "DEPOT_EXECUTABLE is not set"
[ "${DESTDIR:-}" != "" ] || fail "DESTDIR is not set"
exec "$DEPOT_EXECUTABLE" internal meson-install "$@"
"#;
const PERL_CONFIGURE_SCRIPT: &str = r#"#!/bin/sh
set -eu
fail() {
echo "perl_configure: $*" >&2
exit 1
}
[ "${DEPOT_EXECUTABLE:-}" != "" ] || fail "DEPOT_EXECUTABLE is not set"
exec "$DEPOT_EXECUTABLE" internal perl-configure "$@"
"#;
const PERL_INSTALL_SCRIPT: &str = r#"#!/bin/sh
set -eu
fail() {
echo "perl_install: $*" >&2
exit 1
}
[ "${DEPOT_EXECUTABLE:-}" != "" ] || fail "DEPOT_EXECUTABLE is not set"
[ "${DESTDIR:-}" != "" ] || fail "DESTDIR is not set"
exec "$DEPOT_EXECUTABLE" internal perl-install "$@"
"#;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{INTERNAL_DEPOT_DIR, ShellHelpers, shell_ident_suffix, wrap_shell_command}; use super::{INTERNAL_DEPOT_DIR, ShellHelpers, shell_ident_suffix, wrap_shell_command};
@@ -557,15 +689,57 @@ mod tests {
.any(|(key, _)| key == "DEPOT_PYTHON_INSTALL_HELPER") .any(|(key, _)| key == "DEPOT_PYTHON_INSTALL_HELPER")
); );
assert!(envs.iter().any(|(key, _)| key == "DEPOT_CLONE_HELPER")); assert!(envs.iter().any(|(key, _)| key == "DEPOT_CLONE_HELPER"));
assert!(
envs.iter()
.any(|(key, _)| key == "DEPOT_AUTOTOOLS_CONFIGURE_HELPER")
);
assert!(
envs.iter()
.any(|(key, _)| key == "DEPOT_AUTOTOOLS_INSTALL_HELPER")
);
assert!(
envs.iter()
.any(|(key, _)| key == "DEPOT_CMAKE_CONFIGURE_HELPER")
);
assert!(
envs.iter()
.any(|(key, _)| key == "DEPOT_CMAKE_INSTALL_HELPER")
);
assert!(
envs.iter()
.any(|(key, _)| key == "DEPOT_MESON_CONFIGURE_HELPER")
);
assert!(
envs.iter()
.any(|(key, _)| key == "DEPOT_MESON_INSTALL_HELPER")
);
assert!(
envs.iter()
.any(|(key, _)| key == "DEPOT_PERL_CONFIGURE_HELPER")
);
assert!(
envs.iter()
.any(|(key, _)| key == "DEPOT_PERL_INSTALL_HELPER")
);
assert!(envs.iter().any(|(key, _)| key == "DEPOT_EXECUTABLE")); assert!(envs.iter().any(|(key, _)| key == "DEPOT_EXECUTABLE"));
} }
#[test] #[test]
fn wrap_shell_command_exposes_python_helpers() { fn wrap_shell_command_exposes_python_helpers() {
let wrapped = wrap_shell_command("python_build\npython_install\ndepot_clone foo"); let wrapped = wrap_shell_command(
"python_build\npython_install\ndepot_clone foo\nmeson_configure\ncmake_install",
);
assert!(wrapped.contains("python_build()")); assert!(wrapped.contains("python_build()"));
assert!(wrapped.contains("python_install()")); assert!(wrapped.contains("python_install()"));
assert!(wrapped.contains("depot_clone()")); assert!(wrapped.contains("depot_clone()"));
assert!(wrapped.contains("autotools_configure()"));
assert!(wrapped.contains("autotools_install()"));
assert!(wrapped.contains("cmake_configure()"));
assert!(wrapped.contains("cmake_install()"));
assert!(wrapped.contains("meson_configure()"));
assert!(wrapped.contains("meson_install()"));
assert!(wrapped.contains("perl_configure()"));
assert!(wrapped.contains("perl_install()"));
} }
#[test] #[test]
+7 -4
View File
@@ -13,9 +13,12 @@ use crate::builder::state::{BuildStep, StateTracker};
fn hook_env_vars( fn hook_env_vars(
spec: &PackageSpec, spec: &PackageSpec,
shell_helpers: &crate::shell_helpers::ShellHelpers, shell_helpers: &crate::shell_helpers::ShellHelpers,
source_dir: &Path,
) -> Result<crate::builder::EnvVars> { ) -> Result<crate::builder::EnvVars> {
let mut env_vars = crate::builder::standard_build_env(spec, None, true, true); let mut env_vars = crate::builder::standard_build_env(spec, None, true, true);
shell_helpers.apply_to_env_vars(&mut env_vars); shell_helpers.apply_to_env_vars(&mut env_vars);
crate::builder::apply_build_helper_context_env(&mut env_vars, spec)?;
crate::builder::apply_build_helper_dirs_env(&mut env_vars, Some(source_dir), None);
Ok(env_vars) Ok(env_vars)
} }
@@ -96,7 +99,7 @@ fn run_post_extract_commands(spec: &PackageSpec, source: &Source, src_dir: &Path
); );
let helper_root = tempfile::tempdir().context("Failed to create post-extract helper root")?; let helper_root = tempfile::tempdir().context("Failed to create post-extract helper root")?;
let shell_helpers = crate::shell_helpers::ShellHelpers::new(helper_root.path())?; let shell_helpers = crate::shell_helpers::ShellHelpers::new(helper_root.path())?;
let env_vars = hook_env_vars(spec, &shell_helpers)?; let env_vars = hook_env_vars(spec, &shell_helpers, src_dir)?;
for cmd in &source.post_extract { for cmd in &source.post_extract {
let cmd_str = spec.expand_vars(cmd); let cmd_str = spec.expand_vars(cmd);
@@ -132,7 +135,7 @@ pub fn run_post_configure_commands(
crate::log_info!("Running {} post-configure command(s)...", commands.len()); crate::log_info!("Running {} post-configure command(s)...", commands.len());
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?; let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
let mut env_vars = hook_env_vars(spec, &shell_helpers)?; let mut env_vars = hook_env_vars(spec, &shell_helpers, src_dir)?;
crate::builder::set_env_var( crate::builder::set_env_var(
&mut env_vars, &mut env_vars,
"DESTDIR", "DESTDIR",
@@ -168,7 +171,7 @@ pub fn run_post_compile_commands(spec: &PackageSpec, src_dir: &Path, destdir: &P
crate::log_info!("Running {} post-compile command(s)...", commands.len()); crate::log_info!("Running {} post-compile command(s)...", commands.len());
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?; let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
let mut env_vars = hook_env_vars(spec, &shell_helpers)?; let mut env_vars = hook_env_vars(spec, &shell_helpers, src_dir)?;
crate::builder::set_env_var( crate::builder::set_env_var(
&mut env_vars, &mut env_vars,
"DESTDIR", "DESTDIR",
@@ -208,7 +211,7 @@ pub fn run_post_install_commands_in_dir(
crate::log_info!("Running {} post-install command(s)...", commands.len()); crate::log_info!("Running {} post-install command(s)...", commands.len());
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?; let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
let mut env_vars = hook_env_vars(spec, &shell_helpers)?; let mut env_vars = hook_env_vars(spec, &shell_helpers, work_dir)?;
crate::builder::set_env_var( crate::builder::set_env_var(
&mut env_vars, &mut env_vars,
"DESTDIR", "DESTDIR",