Skip to content

Commit b8d46c2

Browse files
committed
Auto merge of #341 - pietroalbini:refactor-runcommand, r=pietroalbini
Refactor RunCommand and add SandboxedRunCommand Fixes #101
2 parents 93c40a5 + 2c3e40c commit b8d46c2

File tree

7 files changed

+329
-232
lines changed

7 files changed

+329
-232
lines changed

src/docker.rs

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@ pub static IMAGE_NAME: &'static str = "crater";
1313
/// to exist in the `docker` directory, at runtime.
1414
pub fn build_container(docker_env: &str) -> Result<()> {
1515
let dockerfile = format!("docker/Dockerfile.{}", docker_env);
16-
RunCommand::new(
17-
"docker",
18-
&["build", "-f", &dockerfile, "-t", IMAGE_NAME, "docker"],
19-
).enable_timeout(false)
20-
.run()
16+
RunCommand::new("docker")
17+
.args(&["build", "-f", &dockerfile, "-t", IMAGE_NAME, "docker"])
18+
.enable_timeout(false)
19+
.run()
2120
}
2221

2322
#[derive(Copy, Clone)]
@@ -26,67 +25,72 @@ pub enum MountPerms {
2625
ReadOnly,
2726
}
2827

29-
struct MountConfig<'a> {
28+
struct MountConfig {
3029
host_path: PathBuf,
31-
container_path: &'a str,
30+
container_path: PathBuf,
3231
perm: MountPerms,
3332
}
3433

35-
impl<'a> MountConfig<'a> {
34+
impl MountConfig {
3635
fn to_arg(&self) -> String {
3736
let perm = match self.perm {
3837
MountPerms::ReadWrite => "rw",
3938
MountPerms::ReadOnly => "ro",
4039
};
4140
format!(
4241
"{}:{}:{},Z",
43-
absolute(&self.host_path).display(),
44-
self.container_path,
42+
absolute(&self.host_path).to_string_lossy(),
43+
self.container_path.to_string_lossy(),
4544
perm
4645
)
4746
}
4847
}
4948

50-
pub struct ContainerBuilder<'a> {
51-
image: &'a str,
52-
mounts: Vec<MountConfig<'a>>,
53-
env: Vec<(&'static str, String)>,
49+
pub struct ContainerBuilder {
50+
image: String,
51+
mounts: Vec<MountConfig>,
52+
env: Vec<(String, String)>,
5453
memory_limit: Option<Size>,
55-
networking_disabled: bool,
54+
enable_networking: bool,
5655
}
5756

58-
impl<'a> ContainerBuilder<'a> {
59-
pub fn new(image: &'a str) -> Self {
57+
impl ContainerBuilder {
58+
pub fn new<S: Into<String>>(image: S) -> Self {
6059
ContainerBuilder {
61-
image,
60+
image: image.into(),
6261
mounts: Vec::new(),
6362
env: Vec::new(),
6463
memory_limit: None,
65-
networking_disabled: false,
64+
enable_networking: true,
6665
}
6766
}
6867

69-
pub fn mount(mut self, host_path: PathBuf, container_path: &'a str, perm: MountPerms) -> Self {
68+
pub fn mount<P1: Into<PathBuf>, P2: Into<PathBuf>>(
69+
mut self,
70+
host_path: P1,
71+
container_path: P2,
72+
perm: MountPerms,
73+
) -> Self {
7074
self.mounts.push(MountConfig {
71-
host_path,
72-
container_path,
75+
host_path: host_path.into(),
76+
container_path: container_path.into(),
7377
perm,
7478
});
7579
self
7680
}
7781

78-
pub fn env(mut self, key: &'static str, value: String) -> Self {
79-
self.env.push((key, value));
82+
pub fn env<S1: Into<String>, S2: Into<String>>(mut self, key: S1, value: S2) -> Self {
83+
self.env.push((key.into(), value.into()));
8084
self
8185
}
8286

83-
pub fn memory_limit(mut self, limit: Size) -> Self {
84-
self.memory_limit = Some(limit);
87+
pub fn memory_limit(mut self, limit: Option<Size>) -> Self {
88+
self.memory_limit = limit;
8589
self
8690
}
8791

88-
pub fn disable_networking(mut self) -> Self {
89-
self.networking_disabled = true;
92+
pub fn enable_networking(mut self, enable: bool) -> Self {
93+
self.enable_networking = enable;
9094
self
9195
}
9296

@@ -99,7 +103,7 @@ impl<'a> ContainerBuilder<'a> {
99103
args.push(mount.to_arg())
100104
}
101105

102-
for &(var, ref value) in &self.env {
106+
for &(ref var, ref value) in &self.env {
103107
args.push("-e".into());
104108
args.push(format!{"{}={}", var, value})
105109
}
@@ -109,14 +113,14 @@ impl<'a> ContainerBuilder<'a> {
109113
args.push(limit.to_string());
110114
}
111115

112-
if self.networking_disabled {
116+
if !self.enable_networking {
113117
args.push("--network".into());
114118
args.push("none".into());
115119
}
116120

117-
args.push(self.image.into());
121+
args.push(self.image);
118122

119-
let (out, _) = RunCommand::new("docker", &*args).run_capture()?;
123+
let (out, _) = RunCommand::new("docker").args(&*args).run_capture()?;
120124
Ok(Container { id: out[0].clone() })
121125
}
122126

@@ -158,12 +162,15 @@ impl Display for Container {
158162

159163
impl Container {
160164
pub fn run(&self, quiet: bool) -> Result<()> {
161-
RunCommand::new("docker", &["start", "-a", &self.id])
165+
RunCommand::new("docker")
166+
.args(&["start", "-a", &self.id])
162167
.quiet(quiet)
163168
.run()
164169
}
165170

166171
pub fn delete(&self) -> Result<()> {
167-
RunCommand::new("docker", &["rm", "-f", &self.id]).run()
172+
RunCommand::new("docker")
173+
.args(&["rm", "-f", &self.id])
174+
.run()
168175
}
169176
}

src/ex_prepare.rs

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use run::RunCommand;
88
use std::fs;
99
use std::path::{Path, PathBuf};
1010
use toml_frobber::TomlFrobber;
11-
use toolchain::{CargoState, Toolchain};
11+
use toolchain::Toolchain;
1212

1313
fn froml_dir(ex_name: &str) -> PathBuf {
1414
EXPERIMENT_DIR.join(ex_name).join("fromls")
@@ -37,7 +37,8 @@ pub fn capture_shas<DB: WriteResults>(ex: &Experiment, crates: &[Crate], db: &DB
3737
for krate in crates {
3838
if let Crate::GitHub(ref repo) = *krate {
3939
let dir = repo.mirror_dir();
40-
let r = RunCommand::new("git", &["rev-parse", "HEAD"])
40+
let r = RunCommand::new("git")
41+
.args(&["rev-parse", "HEAD"])
4142
.cd(&dir)
4243
.run_capture();
4344

@@ -148,36 +149,26 @@ pub fn capture_lockfile(
148149

149150
with_work_crate(ex, toolchain, krate, |path| {
150151
with_frobbed_toml(ex, krate, path)?;
151-
capture_lockfile_inner(config, ex, krate, path, toolchain)
152+
capture_lockfile_inner(ex, krate, path, toolchain)
152153
}).chain_err(|| format!("failed to generate lockfile for {}", krate))?;
153154

154155
Ok(())
155156
}
156157

157158
fn capture_lockfile_inner(
158-
config: &Config,
159159
ex: &Experiment,
160160
krate: &Crate,
161161
path: &Path,
162162
toolchain: &Toolchain,
163163
) -> Result<()> {
164-
let args = &[
165-
"generate-lockfile",
166-
"--manifest-path",
167-
"Cargo.toml",
168-
"-Zno-index-update",
169-
];
170-
toolchain
171-
.run_cargo(
172-
config,
173-
ex,
174-
path,
175-
args,
176-
CargoState::Unlocked,
177-
false,
178-
false,
179-
false,
180-
).chain_err(|| format!("unable to generate lockfile for {}", krate))?;
164+
RunCommand::new(toolchain.cargo().unstable_features(true))
165+
.args(&[
166+
"generate-lockfile",
167+
"--manifest-path",
168+
"Cargo.toml",
169+
"-Zno-index-update",
170+
]).cd(path)
171+
.run()?;
181172

182173
let src_lockfile = &path.join("Cargo.lock");
183174
let dst_lockfile = &lockfile(&ex.name, krate)?;
@@ -236,18 +227,10 @@ pub fn fetch_crate_deps(
236227
with_frobbed_toml(ex, krate, path)?;
237228
with_captured_lockfile(config, ex, krate, path)?;
238229

239-
let args = &["fetch", "--locked", "--manifest-path", "Cargo.toml"];
240-
toolchain
241-
.run_cargo(
242-
config,
243-
ex,
244-
path,
245-
args,
246-
CargoState::Unlocked,
247-
false,
248-
true,
249-
false,
250-
).chain_err(|| format!("unable to fetch deps for {}", krate))?;
230+
RunCommand::new(toolchain.cargo())
231+
.args(&["fetch", "--locked", "--manifest-path", "Cargo.toml"])
232+
.cd(path)
233+
.run()?;
251234

252235
Ok(())
253236
})

src/ex_run.rs

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,45 @@
11
use config::Config;
22
use crates::Crate;
3+
use docker::MountPerms;
34
use errors::*;
45
use ex_prepare::{with_captured_lockfile, with_frobbed_toml, with_work_crate};
56
use experiments::Experiment;
67
use results::{TestResult, WriteResults};
8+
use run::RunCommand;
79
use std::collections::HashSet;
810
use std::path::Path;
9-
use toolchain::{CargoState, Toolchain};
11+
use toolchain::Toolchain;
12+
13+
fn run_cargo(
14+
config: &Config,
15+
ex: &Experiment,
16+
source_path: &Path,
17+
toolchain: &Toolchain,
18+
quiet: bool,
19+
args: &[&str],
20+
) -> Result<()> {
21+
let target_dir = toolchain.target_dir(&ex.name);
22+
::std::fs::create_dir_all(&target_dir)?;
23+
24+
let mut rustflags = format!("--cap-lints={}", ex.cap_lints.to_str());
25+
if let Some(ref tc_rustflags) = toolchain.rustflags {
26+
rustflags.push(' ');
27+
rustflags.push_str(tc_rustflags);
28+
}
29+
30+
RunCommand::new(toolchain.cargo())
31+
.args(args)
32+
.quiet(quiet)
33+
.cd(source_path)
34+
.env("CARGO_TARGET_DIR", "/target")
35+
.env("CARGO_INCREMENTAL", "0")
36+
.env("RUST_BACKTRACE", "full")
37+
.env("RUSTFLAGS", rustflags)
38+
.sandboxed()
39+
.mount(target_dir, "/target", MountPerms::ReadWrite)
40+
.memory_limit(Some(config.sandbox.memory_limit))
41+
.run()
42+
}
1043

1144
pub struct RunTestResult {
1245
pub result: TestResult,
@@ -59,25 +92,21 @@ fn build(
5992
toolchain: &Toolchain,
6093
quiet: bool,
6194
) -> Result<()> {
62-
toolchain.run_cargo(
95+
run_cargo(
6396
config,
6497
ex,
6598
source_path,
66-
&["build", "--frozen"],
67-
CargoState::Locked,
99+
toolchain,
68100
quiet,
69-
false,
70-
true,
101+
&["build", "--frozen"],
71102
)?;
72-
toolchain.run_cargo(
103+
run_cargo(
73104
config,
74105
ex,
75106
source_path,
76-
&["test", "--frozen", "--no-run"],
77-
CargoState::Locked,
107+
toolchain,
78108
quiet,
79-
false,
80-
true,
109+
&["test", "--frozen", "--no-run"],
81110
)?;
82111
Ok(())
83112
}
@@ -89,15 +118,13 @@ fn test(
89118
toolchain: &Toolchain,
90119
quiet: bool,
91120
) -> Result<()> {
92-
toolchain.run_cargo(
121+
run_cargo(
93122
config,
94123
ex,
95124
source_path,
96-
&["test", "--frozen"],
97-
CargoState::Locked,
125+
toolchain,
98126
quiet,
99-
false,
100-
true,
127+
&["test", "--frozen"],
101128
)
102129
}
103130

@@ -145,18 +172,15 @@ pub fn test_check_only(
145172
toolchain: &Toolchain,
146173
quiet: bool,
147174
) -> Result<TestResult> {
148-
let r = toolchain.run_cargo(
175+
if run_cargo(
149176
config,
150177
ex,
151178
source_path,
152-
&["check", "--frozen", "--all", "--all-targets"],
153-
CargoState::Locked,
179+
toolchain,
154180
quiet,
155-
false,
156-
true,
157-
);
158-
159-
if r.is_ok() {
181+
&["check", "--frozen", "--all", "--all-targets"],
182+
).is_ok()
183+
{
160184
Ok(TestResult::TestPass)
161185
} else {
162186
Ok(TestResult::BuildFail)

src/git.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ pub fn shallow_clone_or_pull(url: &str, dir: &Path) -> Result<()> {
88

99
if !dir.exists() {
1010
info!("cloning {} into {}", url, dir.display());
11-
let r = RunCommand::new(
12-
"git",
13-
&["clone", "--depth", "1", &url, &dir.to_string_lossy()],
14-
).run()
15-
.chain_err(|| format!("unable to clone {}", url));
11+
let r = RunCommand::new("git")
12+
.args(&["clone", "--depth", "1", &url, &dir.to_string_lossy()])
13+
.run()
14+
.chain_err(|| format!("unable to clone {}", url));
1615

1716
if r.is_err() && dir.exists() {
1817
fs::remove_dir_all(dir)?;
@@ -21,8 +20,12 @@ pub fn shallow_clone_or_pull(url: &str, dir: &Path) -> Result<()> {
2120
r
2221
} else {
2322
info!("pulling existing url {} into {}", url, dir.display());
24-
RunCommand::new("git", &["fetch", "--all"]).cd(dir).run()?;
25-
RunCommand::new("git", &["reset", "--hard", "@{upstream}"])
23+
RunCommand::new("git")
24+
.args(&["fetch", "--all"])
25+
.cd(dir)
26+
.run()?;
27+
RunCommand::new("git")
28+
.args(&["reset", "--hard", "@{upstream}"])
2629
.cd(dir)
2730
.run()
2831
.chain_err(|| format!("unable to pull {}", url))

0 commit comments

Comments
 (0)