1use crate::derivations::{load_derivation, Derivation};
2use crate::sandbox::{mount_path, mount_paths, run_in_sandbox};
3use std::env::set_var;
4use std::fs::File;
5use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
6use std::os::unix::process::CommandExt;
7use std::path::Path;
8use std::process::{Command, Stdio};
9
10pub struct BuildConfig<'a> {
11 derivation: &'a Derivation,
12 build_dir: &'a Path,
13 stdout: Option<&'a File>,
14 stderr: Option<&'a File>,
15}
16
17impl<'a> BuildConfig<'a> {
18 pub fn new(derivation: &'a Derivation, build_dir: &'a Path) -> BuildConfig<'a> {
19 BuildConfig {
20 derivation: derivation,
21 build_dir: build_dir,
22 stderr: None,
23 stdout: None,
24 }
25 }
26
27 pub fn stdout_to_file(&mut self, file: &'a File) {
28 self.stdout = Some(file);
29 }
30
31 pub fn stderr_to_file(&mut self, file: &'a File) {
32 self.stderr = Some(file);
33 }
34}
35
36pub fn build_derivation_sandboxed(config: &BuildConfig) -> Result<i32, String> {
37 let stdout_fd = config.stdout.map(|file| file.as_raw_fd());
41 let stderr_fd = config.stderr.map(|file| file.as_raw_fd());
42 run_in_sandbox(
45 config.build_dir,
46 || prepare_sandbox(config),
47 || run_build(config, stdout_fd, stderr_fd),
48 )
49}
50
51pub fn build_derivation_command(derivation: &Derivation, build_dir: &Path) -> Command {
52 let mut cmd = Command::new(&derivation.builder);
54 cmd.args(&derivation.args)
55 .envs(&derivation.env)
56 .current_dir(build_dir);
57 cmd
58}
59
60fn prepare_sandbox(config: &BuildConfig) -> Result<(), String> {
61 set_env(&config.derivation);
62 mount_standard_paths(config)?;
63 mount_input_drvs(config)?;
64 mount_paths(
65 config.derivation.input_srcs.iter().map(Path::new),
66 config.build_dir,
67 )
68}
69
70fn run_build(config: &BuildConfig, stdout_fd: Option<RawFd>, stderr_fd: Option<RawFd>) -> isize {
71 let mut cmd = build_derivation_command(&config.derivation, &Path::new("/"));
72 if let Some(stdout_fd) = stdout_fd {
73 cmd.stdout(unsafe { Stdio::from_raw_fd(stdout_fd) });
74 }
75 if let Some(stderr_fd) = stderr_fd {
76 cmd.stderr(unsafe { Stdio::from_raw_fd(stderr_fd) });
77 }
78 let exec_error = cmd.exec();
79 eprintln!("Error executing builder: {}", exec_error);
82 255
83}
84
85fn set_env(derivation: &Derivation) {
86 for (var_name, var_value) in &derivation.env {
87 set_var(var_name, var_value);
88 }
89}
90
91fn mount_input_drvs(config: &BuildConfig) -> Result<(), String> {
92 for (drv_path, outputs) in &config.derivation.input_drvs {
93 let derivation = load_derivation(drv_path)?;
94 for output in outputs {
95 let drv_output = derivation.outputs.get(output).ok_or_else(|| {
96 format!(
97 "Could not find output '{}' of derivation {:?}",
98 output, drv_path
99 )
100 })?;
101 mount_path(Path::new(&drv_output.path), config.build_dir)?;
102 }
104 }
105 Ok(())
106}
107
108fn mount_standard_paths(config: &BuildConfig) -> Result<(), String> {
109 mount_path(Path::new("/dev/null"), config.build_dir)
110}