Skip to content

Commit 4535b6b

Browse files
bors[bot]ostrosco
andauthored
Merge #344
344: Adding support for Podman r=reitermarkus a=ostrosco - Via the new container_engine parameter in Cross.toml, the user can now specify whether they want to use Podman or Docker. - Several changes to src/docker.rs to pass in different options based on whether docker or podman is being used. This also mandates the use of `--userns host` which does require bumping the minimum Docker version. - Updates to the code base based on rustfmt and clippy recommendations. Co-authored-by: ostrosco <[email protected]>
2 parents f29f612 + 243e21a commit 4535b6b

File tree

5 files changed

+76
-69
lines changed

5 files changed

+76
-69
lines changed

Cargo.lock

Lines changed: 17 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ libc = "0.2.18"
1919
rustc_version = "0.2"
2020
semver = "0.9"
2121
toml = "0.5"
22+
which = { version = "3.1.0", default_features = false }
2223

2324
[target.'cfg(not(windows))'.dependencies]
2425
nix = "0.15"

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,20 @@ This project is developed and maintained by the [Tools team][team].
3636

3737
- [rustup](https://rustup.rs/)
3838

39+
- A Linux kernel with [binfmt_misc] support is required for cross testing.
40+
41+
[binfmt_misc]: https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html
42+
43+
One of these container engines is required. If both are installed, `cross` will
44+
default to `docker`.
45+
3946
- [Docker](https://www.docker.com/). Note that on Linux non-sudo users need to be in the
40-
`docker` group. Read the official [post-installation steps][post].
47+
`docker` group. Read the official [post-installation steps][post]. Requires version
48+
1.24 or later.
4149

4250
[post]: https://docs.docker.com/install/linux/linux-postinstall/
4351

44-
- A Linux kernel with [binfmt_misc] support is required for cross testing.
45-
46-
[binfmt_misc]: https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html
52+
- [Podman](https://podman.io). Requires version 1.6.3 or later.
4753

4854
## Installation
4955

src/docker.rs

Lines changed: 47 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ use std::{env, fs};
44

55
use atty::Stream;
66
use error_chain::bail;
7-
use lazy_static::lazy_static;
8-
use semver::{Version, VersionReq};
97

108
use crate::{Target, Toml};
119
use crate::cargo::Root;
@@ -14,41 +12,22 @@ use crate::extensions::CommandExt;
1412
use crate::id;
1513

1614
const DOCKER_IMAGES: &[&str] = &include!(concat!(env!("OUT_DIR"), "/docker-images.rs"));
15+
const DOCKER: &str = "docker";
16+
const PODMAN: &str = "podman";
1717

18-
lazy_static! {
19-
/// Retrieve the Docker Daemon version.
20-
///
21-
/// # Panics
22-
/// Panics if the version cannot be retrieved or parsed
23-
static ref DOCKER_VERSION: Version = {
24-
let version_string = Command::new("docker")
25-
.arg("version")
26-
.arg("--format={{.Server.APIVersion}}")
27-
.run_and_get_stdout(false)
28-
.expect("Unable to obtain Docker version");
29-
// API versions don't have "patch" version
30-
Version::parse(&format!("{}.0", version_string.trim()))
31-
.expect("Cannot parse Docker engine version")
32-
};
33-
34-
/// Version requirements for user namespace.
35-
///
36-
/// # Panics
37-
/// Panics if the parsing fails
38-
static ref USERNS_REQUIREMENT: VersionReq = {
39-
VersionReq::parse(">= 1.24")
40-
.expect("Unable to parse version requirements")
41-
};
18+
fn get_container_engine() -> Result<std::path::PathBuf> {
19+
which::which(DOCKER).or_else(|_| which::which(PODMAN)).map_err(|e| e.into())
4220
}
4321

44-
/// Add the `userns` flag, if needed
45-
pub fn docker_command(subcommand: &str) -> Command {
46-
let mut docker = Command::new("docker");
47-
docker.arg(subcommand);
48-
if USERNS_REQUIREMENT.matches(&DOCKER_VERSION) {
49-
docker.args(&["--userns", "host"]);
22+
pub fn docker_command(subcommand: &str) -> Result<Command> {
23+
if let Ok(ce) = get_container_engine() {
24+
let mut command = Command::new(ce);
25+
command.arg(subcommand);
26+
command.args(&["--userns", "host"]);
27+
Ok(command)
28+
} else {
29+
Err("no container engine found; install docker or podman".into())
5030
}
51-
docker
5231
}
5332

5433
/// Register binfmt interpreters
@@ -61,7 +40,8 @@ pub fn register(target: &Target, verbose: bool) -> Result<()> {
6140
"apt-get update && apt-get install --no-install-recommends -y \
6241
binfmt-support qemu-user-static"
6342
};
64-
docker_command("run")
43+
44+
docker_command("run")?
6545
.arg("--privileged")
6646
.arg("--rm")
6747
.arg("ubuntu:16.04")
@@ -101,17 +81,45 @@ pub fn run(target: &Target,
10181
// We create/regenerate the lockfile on the host system because the Docker
10282
// container doesn't have write access to the root of the Cargo project
10383
let cargo_toml = root.join("Cargo.toml");
84+
85+
let runner = None;
86+
10487
Command::new("cargo").args(&["fetch",
10588
"--manifest-path",
10689
&cargo_toml.display().to_string()])
10790
.run(verbose)
10891
.chain_err(|| "couldn't generate Cargo.lock")?;
10992

110-
let mut docker = docker_command("run");
93+
let mut docker = docker_command("run")?;
94+
95+
if let Some(toml) = toml {
96+
for var in toml.env_passthrough(target)? {
97+
if var.contains('=') {
98+
bail!("environment variable names must not contain the '=' character");
99+
}
100+
101+
if var == "CROSS_RUNNER" {
102+
bail!(
103+
"CROSS_RUNNER environment variable name is reserved and cannot be pass through"
104+
);
105+
}
106+
107+
// Only specifying the environment variable name in the "-e"
108+
// flag forwards the value from the parent shell
109+
docker.args(&["-e", var]);
110+
}
111+
}
112+
113+
docker.arg("--rm");
114+
115+
// We need to specify the user for Docker, but not for Podman.
116+
if let Ok(ce) = get_container_engine() {
117+
if ce.ends_with(DOCKER) {
118+
docker.args(&["--user", &format!("{}:{}", id::user(), id::group())]);
119+
}
120+
}
111121

112122
docker
113-
.arg("--rm")
114-
.args(&["--user", &format!("{}:{}", id::user(), id::group())])
115123
.args(&["-e", "XARGO_HOME=/xargo"])
116124
.args(&["-e", "CARGO_HOME=/cargo"])
117125
.args(&["-e", "CARGO_TARGET_DIR=/target"])
@@ -130,31 +138,12 @@ pub fn run(target: &Target,
130138
docker.args(&opts);
131139
}
132140

133-
let mut runner = None;
134-
135-
if let Some(toml) = toml {
136-
for var in toml.env_passthrough(target)? {
137-
if var.contains("=") {
138-
bail!("environment variable names must not contain the '=' character");
139-
}
140-
141-
if var == "CROSS_RUNNER" {
142-
bail!("CROSS_RUNNER environment variable name is reserved and cannot be pass through");
143-
}
144-
145-
// Only specifying the environment variable name in the "-e"
146-
// flag forwards the value from the parent shell
147-
docker.args(&["-e", var]);
148-
}
149-
150-
runner = toml.runner(target)?;
151-
}
152-
153141
docker
154142
.args(&["-e", &format!("CROSS_RUNNER={}", runner.unwrap_or_else(|| String::new()))])
155143
.args(&["-v", &format!("{}:/xargo:Z", xargo_dir.display())])
156144
.args(&["-v", &format!("{}:/cargo:Z", cargo_dir.display())])
157-
.args(&["-v", "/cargo/bin"]) // Prevent `bin` from being mounted inside the Docker container.
145+
// Prevent `bin` from being mounted inside the Docker container.
146+
.args(&["-v", "/cargo/bin"])
158147
.args(&["-v", &format!("{}:/project:Z,ro", root.display())])
159148
.args(&["-v", &format!("{}:/rust:Z,ro", sysroot.display())])
160149
.args(&["-v", &format!("{}:/target:Z", target_dir.display())])

src/errors.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ use error_chain::error_chain;
55
error_chain! {
66
foreign_links {
77
Io(std::io::Error);
8+
Which(which::Error);
89
}
910
}

0 commit comments

Comments
 (0)