Skip to content

Commit 447414f

Browse files
committed
docker: switch build env to rustops/crates-build-env
1 parent f3f55af commit 447414f

File tree

10 files changed

+151
-73
lines changed

10 files changed

+151
-73
lines changed

ci/run/minicrater-linux.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
set -euo pipefail
33
IFS=$'\n\t'
44

5-
cargo run -- prepare-local --docker-env=mini
5+
cargo run -- create-lists
66
MINICRATER_SHOW_OUTPUT=1 cargo test -- --ignored --nocapture --test-threads 1

docs/cli-usage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ of its output is into the `./work` directory, where it maintains its
1010
own rustup installation, crate mirrors, etc.
1111

1212
```
13-
cargo run -- prepare-local --docker-env mini
13+
cargo run -- prepare-local
1414
cargo run -- define-ex --crate-select=demo --cap-lints=forbid stable beta
1515
cargo run -- run-graph --threads NUM_CPUS
1616
cargo run -- gen-report work/ex/default/

src/agent/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ fn run_heartbeat(url: &str, token: &str) {
4747
});
4848
}
4949

50-
pub fn run(url: &str, token: &str, threads_count: usize) -> Fallible<()> {
50+
pub fn run(url: &str, token: &str, threads_count: usize, docker_env: &str) -> Fallible<()> {
5151
let agent = Agent::new(url, token)?;
5252
let db = results::ResultsUploader::new(&agent.api);
5353

5454
run_heartbeat(url, token);
5555

5656
loop {
5757
let ex = agent.experiment()?;
58-
::runner::run_ex(&ex, &db, threads_count, &agent.config)?;
58+
::runner::run_ex(&ex, &db, threads_count, &agent.config, docker_env)?;
5959
agent.api.complete_experiment()?;
6060
}
6161
}

src/cli.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use crater::agent;
1414
use crater::config::Config;
1515
use crater::crates::Crate;
1616
use crater::db::Database;
17-
use crater::docker;
1817
use crater::experiments::{Assignee, CapLints, CrateSelect, Experiment, Mode, Status};
1918
use crater::report;
2019
use crater::results::{DatabaseDB, DeleteResults};
@@ -27,6 +26,8 @@ use std::path::PathBuf;
2726
use std::str::FromStr;
2827
use structopt::clap::AppSettings;
2928

29+
static DEFAULT_DOCKER_ENV: &str = "rustops/crates-build-env";
30+
3031
// An experiment name
3132
#[derive(Debug, Clone)]
3233
pub struct Ex(String);
@@ -75,10 +76,7 @@ pub enum Crater {
7576
name = "prepare-local",
7677
about = "acquire toolchains, build containers, build crate lists"
7778
)]
78-
PrepareLocal {
79-
#[structopt(name = "docker env", long = "docker-env", default_value = "full")]
80-
env: DockerEnv,
81-
},
79+
PrepareLocal,
8280

8381
#[structopt(name = "create-lists", about = "create all the lists of crates")]
8482
CreateLists {
@@ -189,6 +187,8 @@ pub enum Crater {
189187
ex: Ex,
190188
#[structopt(name = "threads", short = "t", long = "threads", default_value = "1")]
191189
threads: usize,
190+
#[structopt(name = "docker-env", long = "docker-env")]
191+
docker_env: Option<String>,
192192
},
193193

194194
#[structopt(name = "gen-report", about = "generate the experiment report")]
@@ -227,6 +227,8 @@ pub enum Crater {
227227
token: String,
228228
#[structopt(name = "threads", short = "t", long = "threads", default_value = "1")]
229229
threads: usize,
230+
#[structopt(name = "docker-env", long = "docker-env")]
231+
docker_env: Option<String>,
230232
},
231233

232234
#[structopt(
@@ -275,12 +277,9 @@ impl Crater {
275277
action.apply(&db, &config)?;
276278
}
277279
}
278-
Crater::PrepareLocal { ref env } => {
280+
Crater::PrepareLocal => {
279281
let config = Config::load()?;
280282
let db = Database::open()?;
281-
282-
let docker_env = &env.0;
283-
docker::build_container(docker_env)?;
284283
actions::UpdateLists::default().apply(&db, &config)?;
285284
}
286285
Crater::DefineEx {
@@ -367,7 +366,15 @@ impl Crater {
367366
bail!("missing experiment {}", ex.0);
368367
}
369368
}
370-
Crater::RunGraph { ref ex, threads } => {
369+
Crater::RunGraph {
370+
ref ex,
371+
threads,
372+
ref docker_env,
373+
} => {
374+
let docker_env = docker_env
375+
.as_ref()
376+
.map(|e| e.as_str())
377+
.unwrap_or(DEFAULT_DOCKER_ENV);
371378
let config = Config::load()?;
372379
let db = Database::open()?;
373380

@@ -387,7 +394,7 @@ impl Crater {
387394
}
388395

389396
let result_db = DatabaseDB::new(&db);
390-
runner::run_ex(&experiment, &result_db, threads, &config)?;
397+
runner::run_ex(&experiment, &result_db, threads, &config, docker_env)?;
391398
experiment.set_status(&db, Status::NeedsReport)?;
392399
} else {
393400
bail!("missing experiment {}", ex.0);
@@ -481,8 +488,13 @@ impl Crater {
481488
ref url,
482489
ref token,
483490
threads,
491+
ref docker_env,
484492
} => {
485-
agent::run(url, token, threads)?;
493+
let docker_env = docker_env
494+
.as_ref()
495+
.map(|e| e.as_str())
496+
.unwrap_or(DEFAULT_DOCKER_ENV);
497+
agent::run(url, token, threads, docker_env)?;
486498
}
487499
Crater::DumpTasksGraph { ref dest, ref ex } => {
488500
let config = Config::load()?;

src/docker.rs

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,6 @@ use std::fs;
66
use std::path::{Path, PathBuf};
77
use utils::size::Size;
88

9-
pub(crate) static IMAGE_NAME: &'static str = "crater";
10-
11-
/// Builds the docker container image, 'crater', what will be used
12-
/// to isolate builds from each other. This expects the Dockerfile
13-
/// to exist in the `docker` directory, at runtime.
14-
pub fn build_container(docker_env: &str) -> Fallible<()> {
15-
let dockerfile = format!("docker/Dockerfile.{}", docker_env);
16-
RunCommand::new("docker")
17-
.args(&["build", "-f", &dockerfile, "-t", IMAGE_NAME, "docker"])
18-
.enable_timeout(false)
19-
.run()
20-
}
21-
229
pub(crate) fn is_running() -> bool {
2310
info!("checking if the docker daemon is running");
2411
RunCommand::new("docker")
@@ -28,6 +15,41 @@ pub(crate) fn is_running() -> bool {
2815
.is_ok()
2916
}
3017

18+
pub(crate) struct DockerEnv {
19+
image: String,
20+
local: bool,
21+
}
22+
23+
impl DockerEnv {
24+
pub(crate) fn new(image: &str) -> Self {
25+
DockerEnv {
26+
image: image.to_string(),
27+
local: !image.contains('/'),
28+
}
29+
}
30+
31+
pub(crate) fn ensure_exists_locally(&self) -> Fallible<()> {
32+
if !self.local {
33+
self.pull()?;
34+
} else {
35+
info!("docker environment is local, skipping pull");
36+
}
37+
38+
info!("checking the image {} is available locally", self.image);
39+
RunCommand::new("docker")
40+
.args(&["image", "inspect", &self.image])
41+
.hide_output(true)
42+
.run()?;
43+
44+
Ok(())
45+
}
46+
47+
fn pull(&self) -> Fallible<()> {
48+
info!("pulling image {} from Docker Hub", self.image);
49+
RunCommand::new("docker").args(&["pull", &self.image]).run()
50+
}
51+
}
52+
3153
#[derive(Copy, Clone)]
3254
pub(crate) enum MountPerms {
3355
ReadWrite,
@@ -55,21 +77,25 @@ impl MountConfig {
5577
}
5678
}
5779

58-
pub(crate) struct ContainerBuilder {
59-
image: String,
80+
pub(crate) struct ContainerBuilder<'a> {
81+
image: &'a DockerEnv,
6082
mounts: Vec<MountConfig>,
6183
env: Vec<(String, String)>,
6284
memory_limit: Option<Size>,
85+
workdir: Option<String>,
86+
cmd: Vec<String>,
6387
enable_networking: bool,
6488
}
6589

66-
impl ContainerBuilder {
67-
pub(crate) fn new<S: Into<String>>(image: S) -> Self {
90+
impl<'a> ContainerBuilder<'a> {
91+
pub(crate) fn new(image: &'a DockerEnv) -> Self {
6892
ContainerBuilder {
69-
image: image.into(),
93+
image,
7094
mounts: Vec::new(),
7195
env: Vec::new(),
96+
workdir: None,
7297
memory_limit: None,
98+
cmd: Vec::new(),
7399
enable_networking: true,
74100
}
75101
}
@@ -93,11 +119,21 @@ impl ContainerBuilder {
93119
self
94120
}
95121

122+
pub(crate) fn workdir<S: Into<String>>(mut self, workdir: S) -> Self {
123+
self.workdir = Some(workdir.into());
124+
self
125+
}
126+
96127
pub(crate) fn memory_limit(mut self, limit: Option<Size>) -> Self {
97128
self.memory_limit = limit;
98129
self
99130
}
100131

132+
pub(crate) fn cmd(mut self, cmd: Vec<String>) -> Self {
133+
self.cmd = cmd;
134+
self
135+
}
136+
101137
pub(crate) fn enable_networking(mut self, enable: bool) -> Self {
102138
self.enable_networking = enable;
103139
self
@@ -117,6 +153,11 @@ impl ContainerBuilder {
117153
args.push(format! {"{}={}", var, value})
118154
}
119155

156+
if let Some(workdir) = self.workdir {
157+
args.push("-w".into());
158+
args.push(workdir);
159+
}
160+
120161
if let Some(limit) = self.memory_limit {
121162
args.push("-m".into());
122163
args.push(limit.to_string());
@@ -127,7 +168,11 @@ impl ContainerBuilder {
127168
args.push("none".into());
128169
}
129170

130-
args.push(self.image);
171+
args.push(self.image.image.clone());
172+
173+
for arg in self.cmd {
174+
args.push(arg);
175+
}
131176

132177
let (out, _) = RunCommand::new("docker").args(&*args).run_capture()?;
133178
Ok(Container { id: out[0].clone() })

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub mod config;
7272
pub mod crates;
7373
pub mod db;
7474
pub mod dirs;
75-
pub mod docker;
75+
mod docker;
7676
pub mod experiments;
7777
mod native;
7878
mod prelude;

src/run.rs

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use dirs::{CARGO_HOME, RUSTUP_HOME};
2-
use docker::{ContainerBuilder, MountPerms, IMAGE_NAME};
2+
use docker::DockerEnv;
3+
use docker::{ContainerBuilder, MountPerms};
34
use failure::Error;
45
use futures::{future, Future, Stream};
56
use native;
@@ -123,8 +124,8 @@ impl RunCommand {
123124
self
124125
}
125126

126-
pub(crate) fn sandboxed(self) -> SandboxedCommand {
127-
SandboxedCommand::new(self)
127+
pub(crate) fn sandboxed(self, docker_env: &DockerEnv) -> SandboxedCommand {
128+
SandboxedCommand::new(self, docker_env)
128129
}
129130

130131
pub(crate) fn run(self) -> Fallible<()> {
@@ -187,14 +188,14 @@ impl RunCommand {
187188
}
188189
}
189190

190-
pub(crate) struct SandboxedCommand {
191+
pub(crate) struct SandboxedCommand<'a> {
191192
command: RunCommand,
192-
container: ContainerBuilder,
193+
container: ContainerBuilder<'a>,
193194
}
194195

195-
impl SandboxedCommand {
196-
fn new(command: RunCommand) -> Self {
197-
let container = ContainerBuilder::new(IMAGE_NAME)
196+
impl<'a> SandboxedCommand<'a> {
197+
fn new(command: RunCommand, docker_env: &'a DockerEnv) -> Self {
198+
let container = ContainerBuilder::new(docker_env)
198199
.env("USER_ID", native::current_user().to_string())
199200
.enable_networking(false);
200201

@@ -218,16 +219,21 @@ impl SandboxedCommand {
218219

219220
pub(crate) fn run(mut self) -> Fallible<()> {
220221
// Build the full CLI
221-
let mut cmd = match self.command.binary {
222-
Binary::Global(path) => path,
223-
Binary::InstalledByCrater(path) => path,
224-
}
225-
.to_string_lossy()
226-
.as_ref()
227-
.to_string();
222+
let mut cmd = Vec::new();
223+
cmd.push(
224+
match self.command.binary {
225+
Binary::Global(path) => path,
226+
Binary::InstalledByCrater(path) => {
227+
PathBuf::from("/opt/crater/cargo-home/bin").join(path)
228+
}
229+
}
230+
.to_string_lossy()
231+
.as_ref()
232+
.to_string(),
233+
);
234+
228235
for arg in self.command.args {
229-
cmd.push(' ');
230-
cmd.push_str(arg.to_string_lossy().as_ref());
236+
cmd.push(arg.to_string_lossy().to_string());
231237
}
232238

233239
let source_dir = match self.command.cd {
@@ -237,10 +243,11 @@ impl SandboxedCommand {
237243

238244
self.container = self
239245
.container
240-
.mount(source_dir, "/source", MountPerms::ReadOnly)
241-
.env("SOURCE_DIR", "/source")
242-
.env("USER_ID", native::current_user().to_string())
243-
.env("CMD", cmd);
246+
.mount(source_dir, "/opt/crater/workdir", MountPerms::ReadOnly)
247+
.env("SOURCE_DIR", "/opt/crater/workdir")
248+
.env("MAP_USER_ID", native::current_user().to_string())
249+
.workdir("/opt/crater/workdir")
250+
.cmd(cmd);
244251

245252
for (key, value) in self.command.env {
246253
self.container = self.container.env(
@@ -252,10 +259,14 @@ impl SandboxedCommand {
252259
if self.command.local_rustup {
253260
self.container = self
254261
.container
255-
.mount(&*CARGO_HOME, "/cargo-home", MountPerms::ReadOnly)
256-
.mount(&*RUSTUP_HOME, "/rustup-home", MountPerms::ReadOnly)
257-
.env("CARGO_HOME", "/cargo-home")
258-
.env("RUSTUP_HOME", "/rustup-home");
262+
.mount(&*CARGO_HOME, "/opt/crater/cargo-home", MountPerms::ReadOnly)
263+
.mount(
264+
&*RUSTUP_HOME,
265+
"/opt/crater/rustup-home",
266+
MountPerms::ReadOnly,
267+
)
268+
.env("CARGO_HOME", "/opt/crater/cargo-home")
269+
.env("RUSTUP_HOME", "/opt/crater/rustup-home");
259270
}
260271

261272
self.container.run(self.command.quiet)

0 commit comments

Comments
 (0)