Skip to content

Commit 24e4bf7

Browse files
committed
Allow specifying volumes in Cross.toml.
1 parent acf83a5 commit 24e4bf7

File tree

4 files changed

+61
-24
lines changed

4 files changed

+61
-24
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
## [Unreleased]
77

8+
- Added support for mounting volumes.
9+
810
## [v0.2.1] - 2020-06-30
911

1012
- Disabled `powerpc64-unknown-linux-gnu` image.

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,18 @@ passthrough = [
195195
]
196196
```
197197

198+
### Mounting volumes into the build environment
199+
200+
In addition to passing environment variables, you can also specify environment
201+
variables pointing to paths which should be mounted into the container:
202+
203+
```toml
204+
[target.aarch64-unknown-linux-gnu.env]
205+
volumes = [
206+
"BUILD_DIR",
207+
]
208+
```
209+
198210
### Use Xargo instead of Cargo
199211

200212
By default, `cross` uses `xargo` to build your Cargo project only for all

src/docker.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,15 @@ pub fn run(target: &Target,
9292
} else {
9393
SafeCommand::new("cargo")
9494
};
95+
9596
cmd.args(args);
9697

9798
let runner = None;
9899

99100
let mut docker = docker_command("run")?;
100101

101102
if let Some(toml) = toml {
102-
for var in toml.env_passthrough(target)? {
103+
let validate_env_var = |var: &str| -> Result<()> {
103104
if var.contains('=') {
104105
bail!("environment variable names must not contain the '=' character");
105106
}
@@ -110,10 +111,27 @@ pub fn run(target: &Target,
110111
);
111112
}
112113

114+
Ok(())
115+
};
116+
117+
for var in toml.env_passthrough(target)? {
118+
validate_env_var(var)?;
119+
113120
// Only specifying the environment variable name in the "-e"
114121
// flag forwards the value from the parent shell
115122
docker.args(&["-e", var]);
116123
}
124+
125+
for var in toml.env_volumes(target)? {
126+
validate_env_var(var)?;
127+
128+
if let Ok(val) = env::var(var) {
129+
let host_path = Path::new(&val).canonicalize()?;
130+
let mount_path = &host_path;
131+
docker.args(&["-v", &format!("{}:{}", host_path.display(), mount_path.display())]);
132+
docker.args(&["-e", &format!("{}={}", var, mount_path.display())]);
133+
}
134+
}
117135
}
118136

119137
docker.args(&["-e", "PKG_CONFIG_ALLOW_CROSS=1"]);
@@ -152,10 +170,10 @@ pub fn run(target: &Target,
152170
.args(&["-v", &format!("{}:/cargo:Z", cargo_dir.display())])
153171
// Prevent `bin` from being mounted inside the Docker container.
154172
.args(&["-v", "/cargo/bin"])
155-
.args(&["-v", &format!("{}:/project:Z", mount_root.display())])
173+
.args(&["-v", &format!("{}:/{}:Z", mount_root.display(), mount_root.display())])
156174
.args(&["-v", &format!("{}:/rust:Z,ro", sysroot.display())])
157175
.args(&["-v", &format!("{}:/target:Z", target_dir.display())])
158-
.args(&["-w", "/project"]);
176+
.args(&["-w", &mount_root.display().to_string()]);
159177

160178
if atty::is(Stream::Stdin) {
161179
docker.arg("-i");

src/main.rs

+26-21
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use std::io::Write;
1515
use std::process::ExitStatus;
1616
use std::{env, io, process};
1717

18-
use error_chain::bail;
1918
use toml::{Value, value::Table};
2019

2120
use self::cargo::{Root, Subcommand};
@@ -363,38 +362,44 @@ impl Toml {
363362
/// Returns the list of environment variables to pass through for `target`,
364363
/// including variables specified under `build` and under `target`.
365364
pub fn env_passthrough(&self, target: &Target) -> Result<Vec<&str>> {
366-
let mut bwl = self.build_env_passthrough()?;
367-
let mut twl = self.target_env_passthrough(target)?;
365+
let mut bwl = self.build_env("passthrough")?;
366+
let mut twl = self.target_env(target, "passthrough")?;
368367
bwl.extend(twl.drain(..));
369368

370369
Ok(bwl)
371370
}
372371

373-
/// Returns the `build.env.passthrough` part of `Cross.toml`
374-
fn build_env_passthrough(&self) -> Result<Vec<&str>> {
375-
match self.table.get("build").and_then(|b| b.get("env")).and_then(|e| e.get("passthrough")) {
372+
/// Returns the list of volumes to pass through for `target`,
373+
/// including volumes specified under `build` and under `target`.
374+
pub fn env_volumes(&self, target: &Target) -> Result<Vec<&str>> {
375+
let mut bwl = self.build_env("volumes")?;
376+
let mut twl = self.target_env(target, "volumes")?;
377+
bwl.extend(twl.drain(..));
378+
379+
Ok(bwl)
380+
}
381+
382+
fn target_env(&self, target: &Target, key: &str) -> Result<Vec<&str>> {
383+
let triple = target.triple();
384+
385+
match self.table.get("target").and_then(|t| t.get(triple)).and_then(|t| t.get("env")).and_then(|e| e.get(key)) {
376386
Some(&Value::Array(ref vec)) => {
377-
if vec.iter().any(|val| val.as_str().is_none()) {
378-
bail!("every build.env.passthrough element must be a string");
379-
}
380-
Ok(vec.iter().map(|val| val.as_str().unwrap()).collect())
387+
vec.iter().map(|val| {
388+
val.as_str().ok_or_else(|| {
389+
format!("every target.{}.env.{} element must be a string", triple, key).into()
390+
})
391+
}).collect()
381392
},
382393
_ => Ok(Vec::new()),
383394
}
384395
}
385396

386-
/// Returns the `target.<triple>.env.passthrough` part of `Cross.toml` for `target`.
387-
fn target_env_passthrough(&self, target: &Target) -> Result<Vec<&str>> {
388-
let triple = target.triple();
389-
390-
let key = format!("target.{}.env.passthrough", triple);
391-
392-
match self.table.get("target").and_then(|t| t.get(triple)).and_then(|t| t.get("env")).and_then(|e| e.get("passthrough")) {
397+
fn build_env(&self, key: &str) -> Result<Vec<&str>> {
398+
match self.table.get("build").and_then(|b| b.get("env")).and_then(|e| e.get(key)) {
393399
Some(&Value::Array(ref vec)) => {
394-
if vec.iter().any(|val| val.as_str().is_none()) {
395-
bail!("every {} element must be a string", key);
396-
}
397-
Ok(vec.iter().map(|val| val.as_str().unwrap()).collect())
400+
vec.iter().map(|val| {
401+
val.as_str().ok_or_else(|| format!("every build.env.{} element must be a string", key).into())
402+
}).collect()
398403
},
399404
_ => Ok(Vec::new()),
400405
}

0 commit comments

Comments
 (0)