forked from the-distro/ofborg
ofborg/nix.rs: Create Command's separately and add some rudimentary tests
This commit is contained in:
parent
b17005eabb
commit
b29650ffed
|
@ -31,6 +31,12 @@ impl Nix {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn safely_build_attrs(&self, nixpkgs: &Path, file: &str, attrs: Vec<String>) -> Result<File,File> {
|
pub fn safely_build_attrs(&self, nixpkgs: &Path, file: &str, attrs: Vec<String>) -> Result<File,File> {
|
||||||
|
let cmd = self.safely_build_attrs_cmd(nixpkgs, file, attrs);
|
||||||
|
|
||||||
|
return self.run(cmd, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn safely_build_attrs_cmd(&self, nixpkgs: &Path, file: &str, attrs: Vec<String>) -> Command {
|
||||||
let mut attrargs: Vec<String> = Vec::with_capacity(3 + (attrs.len() * 2));
|
let mut attrargs: Vec<String> = Vec::with_capacity(3 + (attrs.len() * 2));
|
||||||
attrargs.push(file.to_owned());
|
attrargs.push(file.to_owned());
|
||||||
attrargs.push(String::from("--no-out-link"));
|
attrargs.push(String::from("--no-out-link"));
|
||||||
|
@ -40,14 +46,14 @@ impl Nix {
|
||||||
attrargs.push(attr);
|
attrargs.push(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.safely("nix-build", nixpkgs, attrargs, true);
|
return self.safe_command("nix-build", nixpkgs, attrargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn safely(&self, cmd: &str, nixpkgs: &Path, args: Vec<String>, keep_stdout: bool) -> Result<File,File> {
|
pub fn safely(&self, cmd: &str, nixpkgs: &Path, args: Vec<String>, keep_stdout: bool) -> Result<File,File> {
|
||||||
let mut nixpath = OsString::new();
|
return self.run(self.safe_command(cmd, nixpkgs, args), keep_stdout);
|
||||||
nixpath.push("nixpkgs=");
|
}
|
||||||
nixpath.push(nixpkgs.as_os_str());
|
|
||||||
|
|
||||||
|
pub fn run(&self, mut cmd: Command, keep_stdout: bool) -> Result<File,File> {
|
||||||
let stderr = tempfile().expect("Fetching a stderr tempfile");
|
let stderr = tempfile().expect("Fetching a stderr tempfile");
|
||||||
let mut reader = stderr.try_clone().expect("Cloning stderr to the reader");
|
let mut reader = stderr.try_clone().expect("Cloning stderr to the reader");
|
||||||
|
|
||||||
|
@ -60,22 +66,11 @@ impl Nix {
|
||||||
stdout = Stdio::null();
|
stdout = Stdio::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let status = cmd
|
||||||
let status = Command::new(cmd)
|
|
||||||
.env_clear()
|
|
||||||
.current_dir(nixpkgs)
|
|
||||||
.stdout(Stdio::from(stdout))
|
.stdout(Stdio::from(stdout))
|
||||||
.stderr(Stdio::from(stderr))
|
.stderr(Stdio::from(stderr))
|
||||||
.env("HOME", "/homeless-shelter")
|
|
||||||
.env("NIX_PATH", nixpath)
|
|
||||||
.env("NIX_REMOTE", &self.remote)
|
|
||||||
.args(&["--show-trace"])
|
|
||||||
.args(&["--option", "restrict-eval", "true"])
|
|
||||||
.args(&["--option", "build-timeout", &format!("{}", self.build_timeout)])
|
|
||||||
.args(&["--argstr", "system", &self.system])
|
|
||||||
.args(args)
|
|
||||||
.status()
|
.status()
|
||||||
.expect(format!("Running {:?}", cmd).as_ref());
|
.expect(format!("Running a program ...").as_ref());
|
||||||
|
|
||||||
reader.seek(SeekFrom::Start(0)).expect("Seeking to Start(0)");
|
reader.seek(SeekFrom::Start(0)).expect("Seeking to Start(0)");
|
||||||
|
|
||||||
|
@ -85,4 +80,217 @@ impl Nix {
|
||||||
return Err(reader)
|
return Err(reader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn safe_command(&self, cmd: &str, nixpkgs: &Path, args: Vec<String>) -> Command {
|
||||||
|
let mut nixpath = OsString::new();
|
||||||
|
nixpath.push("nixpkgs=");
|
||||||
|
nixpath.push(nixpkgs.as_os_str());
|
||||||
|
|
||||||
|
let mut command = Command::new(cmd);
|
||||||
|
command.env_clear();
|
||||||
|
command.current_dir(nixpkgs);
|
||||||
|
command.env("HOME", "/homeless-shelter");
|
||||||
|
command.env("NIX_PATH", nixpath);
|
||||||
|
command.env("NIX_REMOTE", &self.remote);
|
||||||
|
command.args(&["--show-trace"]);
|
||||||
|
command.args(&["--option", "restrict-eval", "true"]);
|
||||||
|
command.args(&["--option", "build-timeout", &format!("{}", self.build_timeout)]);
|
||||||
|
command.args(&["--argstr", "system", &self.system]);
|
||||||
|
command.args(args);
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
fn nix() -> Nix {
|
||||||
|
Nix::new("x86_64-linux".to_owned(), "daemon".to_owned(), 1800)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_path() -> PathBuf {
|
||||||
|
let mut cwd = env::current_dir().unwrap();
|
||||||
|
cwd.push(Path::new("./test-srcs/build"));
|
||||||
|
return cwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn passing_eval_path() -> PathBuf {
|
||||||
|
let mut cwd = env::current_dir().unwrap();
|
||||||
|
cwd.push(Path::new("./test-srcs/eval"));
|
||||||
|
return cwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Expect {
|
||||||
|
Pass,
|
||||||
|
Fail,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_run(res: Result<File,File>, expected: Expect, require: Vec<&str>) {
|
||||||
|
let expectation_held: bool = match expected {
|
||||||
|
Expect::Pass => res.is_ok(),
|
||||||
|
Expect::Fail => res.is_err(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let file: File = match res {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(file) => file,
|
||||||
|
};
|
||||||
|
|
||||||
|
let lines: Vec<String> = BufReader::new(file)
|
||||||
|
.lines()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|line| line.is_ok())
|
||||||
|
.map(|line| line.unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let buildlog = lines
|
||||||
|
.into_iter()
|
||||||
|
.map(|line| format!(" | {}", line))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
let total_requirements = require.len();
|
||||||
|
let mut missed_requirements: usize = 0;
|
||||||
|
let requirements_held: Vec<Result<String, String>> =
|
||||||
|
require.into_iter()
|
||||||
|
.map(|line| line.to_owned())
|
||||||
|
.map(|line|
|
||||||
|
if buildlog.contains(&line) {
|
||||||
|
Ok(line)
|
||||||
|
} else {
|
||||||
|
missed_requirements += 1;
|
||||||
|
Err(line)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut prefixes: Vec<String> = vec![
|
||||||
|
"".to_owned(),
|
||||||
|
"".to_owned(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if !expectation_held {
|
||||||
|
prefixes.push(format!(
|
||||||
|
"The run was expected to {:?}, but did not.",
|
||||||
|
expected
|
||||||
|
));
|
||||||
|
prefixes.push("".to_owned());
|
||||||
|
} else {
|
||||||
|
prefixes.push(format!(
|
||||||
|
"The run was expected to {:?}, and did.",
|
||||||
|
expected
|
||||||
|
));
|
||||||
|
prefixes.push("".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut suffixes = vec![
|
||||||
|
"".to_owned(),
|
||||||
|
format!("{} out of {} required lines matched.",
|
||||||
|
(total_requirements - missed_requirements),
|
||||||
|
total_requirements
|
||||||
|
),
|
||||||
|
"".to_owned(),
|
||||||
|
];
|
||||||
|
|
||||||
|
for expected_line in requirements_held {
|
||||||
|
suffixes.push(format!(" - {:?}", expected_line));
|
||||||
|
}
|
||||||
|
suffixes.push("".to_owned());
|
||||||
|
|
||||||
|
let output_blocks: Vec<Vec<String>> = vec![
|
||||||
|
prefixes,
|
||||||
|
vec![buildlog, "".to_owned()],
|
||||||
|
suffixes,
|
||||||
|
];
|
||||||
|
|
||||||
|
let output_blocks_strings: Vec<String> =
|
||||||
|
output_blocks
|
||||||
|
.into_iter()
|
||||||
|
.map(|lines| lines.join("\n"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let output: String = output_blocks_strings
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
if expectation_held && missed_requirements == 0 {
|
||||||
|
} else {
|
||||||
|
panic!(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::io::BufRead;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn safely_build_attrs_success() {
|
||||||
|
let nix = nix();
|
||||||
|
|
||||||
|
let ret: Result<File,File> = nix.safely_build_attrs(
|
||||||
|
build_path().as_path(),
|
||||||
|
"default.nix",
|
||||||
|
vec![String::from("success")]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_run(ret, Expect::Pass, vec![
|
||||||
|
"-success.drv",
|
||||||
|
"building path(s)",
|
||||||
|
"hi",
|
||||||
|
"-success"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn safely_build_attrs_failure() {
|
||||||
|
let nix = nix();
|
||||||
|
|
||||||
|
let ret: Result<File,File> = nix.safely_build_attrs(
|
||||||
|
build_path().as_path(),
|
||||||
|
"default.nix",
|
||||||
|
vec![String::from("failed")]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_run(ret, Expect::Fail, vec![
|
||||||
|
"-failed.drv",
|
||||||
|
"building path(s)",
|
||||||
|
"hi",
|
||||||
|
"failed to produce output path"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strict_sandboxing() {
|
||||||
|
let ret: Result<File,File> = nix().safely_build_attrs(
|
||||||
|
build_path().as_path(),
|
||||||
|
"default.nix",
|
||||||
|
vec![String::from("sandbox-violation")]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_run(ret, Expect::Fail, vec![
|
||||||
|
"error: while evaluating the attribute",
|
||||||
|
"access to path",
|
||||||
|
"is forbidden in restricted mode"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn instantiation() {
|
||||||
|
let ret: Result<File,File> = nix().safely(
|
||||||
|
"nix-instantiate",
|
||||||
|
passing_eval_path().as_path(),
|
||||||
|
vec![],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_run(ret, Expect::Pass, vec![
|
||||||
|
"the result might be removed by the garbage collector",
|
||||||
|
"-failed.drv",
|
||||||
|
"-success.drv"
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
27
ofborg/test-srcs/build/default.nix
Normal file
27
ofborg/test-srcs/build/default.nix
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
let
|
||||||
|
nix = import <nix/config.nix>;
|
||||||
|
in {
|
||||||
|
success = derivation {
|
||||||
|
name = "success";
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
builder = nix.shell;
|
||||||
|
args = [
|
||||||
|
"-c"
|
||||||
|
"echo hi; echo ${toString builtins.currentTime} > $out" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
failed = derivation {
|
||||||
|
name = "failed";
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
builder = nix.shell;
|
||||||
|
args = [
|
||||||
|
"-c"
|
||||||
|
"echo hi; echo ${toString builtins.currentTime}" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
sandbox-violation = derivation {
|
||||||
|
name = "sandbox-violation";
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
builder = ./../../src;
|
||||||
|
};
|
||||||
|
}
|
4
ofborg/test-srcs/build/succeed.sh
Normal file
4
ofborg/test-srcs/build/succeed.sh
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "$@"
|
||||||
|
echo hi
|
21
ofborg/test-srcs/eval/default.nix
Normal file
21
ofborg/test-srcs/eval/default.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
let
|
||||||
|
nix = import <nix/config.nix>;
|
||||||
|
in rec {
|
||||||
|
success = derivation {
|
||||||
|
name = "success";
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
builder = nix.shell;
|
||||||
|
args = [
|
||||||
|
"-c"
|
||||||
|
"echo hi; echo ${toString builtins.currentTime} > $out" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
failed = derivation {
|
||||||
|
name = "failed";
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
builder = nix.shell;
|
||||||
|
args = [
|
||||||
|
"-c"
|
||||||
|
"echo hi; echo ${toString builtins.currentTime}; echo ${success}" ];
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue