@@ -4,8 +4,6 @@ use std::{env, fs};
4
4
5
5
use atty:: Stream ;
6
6
use error_chain:: bail;
7
- use lazy_static:: lazy_static;
8
- use semver:: { Version , VersionReq } ;
9
7
10
8
use crate :: { Target , Toml } ;
11
9
use crate :: cargo:: Root ;
@@ -14,41 +12,22 @@ use crate::extensions::CommandExt;
14
12
use crate :: id;
15
13
16
14
const DOCKER_IMAGES : & [ & str ] = & include ! ( concat!( env!( "OUT_DIR" ) , "/docker-images.rs" ) ) ;
15
+ const DOCKER : & str = "docker" ;
16
+ const PODMAN : & str = "podman" ;
17
17
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 ( ) )
42
20
}
43
21
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 ( ) )
50
30
}
51
- docker
52
31
}
53
32
54
33
/// Register binfmt interpreters
@@ -61,7 +40,8 @@ pub fn register(target: &Target, verbose: bool) -> Result<()> {
61
40
"apt-get update && apt-get install --no-install-recommends -y \
62
41
binfmt-support qemu-user-static"
63
42
} ;
64
- docker_command ( "run" )
43
+
44
+ docker_command ( "run" ) ?
65
45
. arg ( "--privileged" )
66
46
. arg ( "--rm" )
67
47
. arg ( "ubuntu:16.04" )
@@ -101,17 +81,45 @@ pub fn run(target: &Target,
101
81
// We create/regenerate the lockfile on the host system because the Docker
102
82
// container doesn't have write access to the root of the Cargo project
103
83
let cargo_toml = root. join ( "Cargo.toml" ) ;
84
+
85
+ let runner = None ;
86
+
104
87
Command :: new ( "cargo" ) . args ( & [ "fetch" ,
105
88
"--manifest-path" ,
106
89
& cargo_toml. display ( ) . to_string ( ) ] )
107
90
. run ( verbose)
108
91
. chain_err ( || "couldn't generate Cargo.lock" ) ?;
109
92
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
+ }
111
121
112
122
docker
113
- . arg ( "--rm" )
114
- . args ( & [ "--user" , & format ! ( "{}:{}" , id:: user( ) , id:: group( ) ) ] )
115
123
. args ( & [ "-e" , "XARGO_HOME=/xargo" ] )
116
124
. args ( & [ "-e" , "CARGO_HOME=/cargo" ] )
117
125
. args ( & [ "-e" , "CARGO_TARGET_DIR=/target" ] )
@@ -130,31 +138,12 @@ pub fn run(target: &Target,
130
138
docker. args ( & opts) ;
131
139
}
132
140
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
-
153
141
docker
154
142
. args ( & [ "-e" , & format ! ( "CROSS_RUNNER={}" , runner. unwrap_or_else( || String :: new( ) ) ) ] )
155
143
. args ( & [ "-v" , & format ! ( "{}:/xargo:Z" , xargo_dir. display( ) ) ] )
156
144
. 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" ] )
158
147
. args ( & [ "-v" , & format ! ( "{}:/project:Z,ro" , root. display( ) ) ] )
159
148
. args ( & [ "-v" , & format ! ( "{}:/rust:Z,ro" , sysroot. display( ) ) ] )
160
149
. args ( & [ "-v" , & format ! ( "{}:/target:Z" , target_dir. display( ) ) ] )
0 commit comments