Skip to content

Commit

Permalink
Allow specifying volumes in Cross.toml.
Browse files Browse the repository at this point in the history
  • Loading branch information
reitermarkus committed Jul 2, 2020
1 parent acf83a5 commit 24e4bf7
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 24 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

- Added support for mounting volumes.

## [v0.2.1] - 2020-06-30

- Disabled `powerpc64-unknown-linux-gnu` image.
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,18 @@ passthrough = [
]
```

### Mounting volumes into the build environment

In addition to passing environment variables, you can also specify environment
variables pointing to paths which should be mounted into the container:

```toml
[target.aarch64-unknown-linux-gnu.env]
volumes = [
"BUILD_DIR",
]
```

### Use Xargo instead of Cargo

By default, `cross` uses `xargo` to build your Cargo project only for all
Expand Down
24 changes: 21 additions & 3 deletions src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,15 @@ pub fn run(target: &Target,
} else {
SafeCommand::new("cargo")
};

cmd.args(args);

let runner = None;

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

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

Ok(())
};

for var in toml.env_passthrough(target)? {
validate_env_var(var)?;

// Only specifying the environment variable name in the "-e"
// flag forwards the value from the parent shell
docker.args(&["-e", var]);
}

for var in toml.env_volumes(target)? {
validate_env_var(var)?;

if let Ok(val) = env::var(var) {
let host_path = Path::new(&val).canonicalize()?;
let mount_path = &host_path;
docker.args(&["-v", &format!("{}:{}", host_path.display(), mount_path.display())]);
docker.args(&["-e", &format!("{}={}", var, mount_path.display())]);
}
}
}

docker.args(&["-e", "PKG_CONFIG_ALLOW_CROSS=1"]);
Expand Down Expand Up @@ -152,10 +170,10 @@ pub fn run(target: &Target,
.args(&["-v", &format!("{}:/cargo:Z", cargo_dir.display())])
// Prevent `bin` from being mounted inside the Docker container.
.args(&["-v", "/cargo/bin"])
.args(&["-v", &format!("{}:/project:Z", mount_root.display())])
.args(&["-v", &format!("{}:/{}:Z", mount_root.display(), mount_root.display())])
.args(&["-v", &format!("{}:/rust:Z,ro", sysroot.display())])
.args(&["-v", &format!("{}:/target:Z", target_dir.display())])
.args(&["-w", "/project"]);
.args(&["-w", &mount_root.display().to_string()]);

if atty::is(Stream::Stdin) {
docker.arg("-i");
Expand Down
47 changes: 26 additions & 21 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use std::io::Write;
use std::process::ExitStatus;
use std::{env, io, process};

use error_chain::bail;
use toml::{Value, value::Table};

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

Ok(bwl)
}

/// Returns the `build.env.passthrough` part of `Cross.toml`
fn build_env_passthrough(&self) -> Result<Vec<&str>> {
match self.table.get("build").and_then(|b| b.get("env")).and_then(|e| e.get("passthrough")) {
/// Returns the list of volumes to pass through for `target`,
/// including volumes specified under `build` and under `target`.
pub fn env_volumes(&self, target: &Target) -> Result<Vec<&str>> {
let mut bwl = self.build_env("volumes")?;
let mut twl = self.target_env(target, "volumes")?;
bwl.extend(twl.drain(..));

Ok(bwl)
}

fn target_env(&self, target: &Target, key: &str) -> Result<Vec<&str>> {
let triple = target.triple();

match self.table.get("target").and_then(|t| t.get(triple)).and_then(|t| t.get("env")).and_then(|e| e.get(key)) {
Some(&Value::Array(ref vec)) => {
if vec.iter().any(|val| val.as_str().is_none()) {
bail!("every build.env.passthrough element must be a string");
}
Ok(vec.iter().map(|val| val.as_str().unwrap()).collect())
vec.iter().map(|val| {
val.as_str().ok_or_else(|| {
format!("every target.{}.env.{} element must be a string", triple, key).into()
})
}).collect()
},
_ => Ok(Vec::new()),
}
}

/// Returns the `target.<triple>.env.passthrough` part of `Cross.toml` for `target`.
fn target_env_passthrough(&self, target: &Target) -> Result<Vec<&str>> {
let triple = target.triple();

let key = format!("target.{}.env.passthrough", triple);

match self.table.get("target").and_then(|t| t.get(triple)).and_then(|t| t.get("env")).and_then(|e| e.get("passthrough")) {
fn build_env(&self, key: &str) -> Result<Vec<&str>> {
match self.table.get("build").and_then(|b| b.get("env")).and_then(|e| e.get(key)) {
Some(&Value::Array(ref vec)) => {
if vec.iter().any(|val| val.as_str().is_none()) {
bail!("every {} element must be a string", key);
}
Ok(vec.iter().map(|val| val.as_str().unwrap()).collect())
vec.iter().map(|val| {
val.as_str().ok_or_else(|| format!("every build.env.{} element must be a string", key).into())
}).collect()
},
_ => Ok(Vec::new()),
}
Expand Down

0 comments on commit 24e4bf7

Please sign in to comment.