Skip to content

Commit 015a08a

Browse files
committed
Tell subprocesses the path to self in an env variable #3778
1 parent ef8fa8f commit 015a08a

File tree

11 files changed

+109
-14
lines changed

11 files changed

+109
-14
lines changed

src/bin/cargo.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,12 @@ fn execute_external_subcommand(config: &Config, cmd: &str, args: &[String]) -> C
320320
.into())
321321
}
322322
};
323-
let err = match util::process(&command).args(&args[1..]).exec() {
323+
324+
let cargo_exe = config.cargo_exe()?;
325+
let err = match util::process(&command)
326+
.env(cargo::CARGO_ENV, cargo_exe)
327+
.args(&args[1..])
328+
.exec() {
324329
Ok(()) => return Ok(()),
325330
Err(e) => e,
326331
};

src/cargo/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ use term::color::{BLACK};
4141

4242
pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};
4343

44+
pub const CARGO_ENV: &'static str = "CARGO";
45+
4446
macro_rules! bail {
4547
($($fmt:tt)*) => (
4648
return Err(::util::human(&format_args!($($fmt)*)))

src/cargo/ops/cargo_rustc/compilation.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ impl<'cfg> Compilation<'cfg> {
143143

144144
let metadata = pkg.manifest().metadata();
145145

146+
let cargo_exe = self.config.cargo_exe()?;
147+
cmd.env(::CARGO_ENV, cargo_exe);
148+
146149
cmd.env("CARGO_MANIFEST_DIR", pkg.root())
147150
.env("CARGO_PKG_VERSION_MAJOR", &pkg.version().major.to_string())
148151
.env("CARGO_PKG_VERSION_MINOR", &pkg.version().minor.to_string())

src/cargo/util/config.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub struct Config {
2828
rustc: LazyCell<Rustc>,
2929
values: LazyCell<HashMap<String, ConfigValue>>,
3030
cwd: PathBuf,
31+
cargo_exe: LazyCell<PathBuf>,
3132
rustdoc: LazyCell<PathBuf>,
3233
extra_verbose: Cell<bool>,
3334
frozen: Cell<bool>,
@@ -44,6 +45,7 @@ impl Config {
4445
rustc: LazyCell::new(),
4546
cwd: cwd,
4647
values: LazyCell::new(),
48+
cargo_exe: LazyCell::new(),
4749
rustdoc: LazyCell::new(),
4850
extra_verbose: Cell::new(false),
4951
frozen: Cell::new(false),
@@ -93,6 +95,15 @@ impl Config {
9395
self.rustc.get_or_try_init(|| Rustc::new(self.get_tool("rustc")?))
9496
}
9597

98+
pub fn cargo_exe(&self) -> CargoResult<&Path> {
99+
self.cargo_exe.get_or_try_init(||
100+
env::current_exe().and_then(|path| path.canonicalize())
101+
.chain_error(|| {
102+
human("couldn't get the path to cargo executable")
103+
})
104+
).map(AsRef::as_ref)
105+
}
106+
96107
pub fn values(&self) -> CargoResult<&HashMap<String, ConfigValue>> {
97108
self.values.get_or_try_init(|| self.load_values())
98109
}

src/doc/environment-variables.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,17 @@ configuration values, as described in [that documentation][config-env]
3030

3131
# Environment variables Cargo sets for crates
3232

33-
Cargo exposes these environment variables to your crate when it is compiled. To get the
34-
value of any of these variables in a Rust program, do this:
33+
Cargo exposes these environment variables to your crate when it is compiled.
34+
Note that this applies for test binaries as well.
35+
To get the value of any of these variables in a Rust program, do this:
3536

3637
```
3738
let version = env!("CARGO_PKG_VERSION");
3839
```
3940

4041
`version` will now contain the value of `CARGO_PKG_VERSION`.
4142

43+
* `CARGO` - Path to the `cargo` binary performing the build.
4244
* `CARGO_MANIFEST_DIR` - The directory containing the manifest of your package.
4345
* `CARGO_PKG_VERSION` - The full version of your package.
4446
* `CARGO_PKG_VERSION_MAJOR` - The major version of your package.
@@ -96,3 +98,10 @@ let out_dir = env::var("OUT_DIR").unwrap();
9698
[links]: build-script.html#the-links-manifest-key
9799
[profile]: manifest.html#the-profile-sections
98100
[clang]:http://clang.llvm.org/docs/CrossCompilation.html#target-triple
101+
102+
# Environment variables Cargo sets for 3rd party subcommands
103+
104+
Cargo exposes this environment variable to 3rd party subcommands
105+
(ie. programs named `cargo-foobar` placed in `$PATH`):
106+
107+
* `CARGO` - Path to the `cargo` binary performing the build.

tests/cargo.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
extern crate cargo;
12
extern crate cargotest;
23
extern crate hamcrest;
34

@@ -10,8 +11,8 @@ use std::str;
1011

1112
use cargotest::cargo_process;
1213
use cargotest::support::paths::{self, CargoPathExt};
13-
use cargotest::support::{execs, project, ProjectBuilder};
14-
use hamcrest::{assert_that};
14+
use cargotest::support::{execs, project, ProjectBuilder, basic_bin_manifest};
15+
use hamcrest::{assert_that, existing_file};
1516

1617
#[cfg_attr(windows,allow(dead_code))]
1718
enum FakeKind<'a> {
@@ -81,11 +82,11 @@ fn list_command_looks_at_path() {
8182
#[cfg(unix)]
8283
#[test]
8384
fn list_command_resolves_symlinks() {
84-
use cargotest::support::cargo_dir;
85+
use cargotest::support::cargo_exe;
8586

8687
let proj = project("list-non-overlapping");
8788
let proj = fake_file(proj, Path::new("path-test"), "cargo-2",
88-
FakeKind::Symlink{target:&cargo_dir().join("cargo")});
89+
FakeKind::Symlink{target:&cargo_exe()});
8990
let mut pr = cargo_process();
9091

9192
let mut path = path();
@@ -161,6 +162,37 @@ fn override_cargo_home() {
161162
assert!(contents.contains(r#"authors = ["foo <bar>"]"#));
162163
}
163164

165+
#[test]
166+
fn cargo_subcommand_env() {
167+
use cargotest::support::cargo_exe;
168+
169+
let src = format!(r#"
170+
use std::env;
171+
172+
fn main() {{
173+
println!("{{}}", env::var("{}").unwrap());
174+
}}
175+
"#, cargo::CARGO_ENV);
176+
177+
let p = project("cargo-envtest")
178+
.file("Cargo.toml", &basic_bin_manifest("cargo-envtest"))
179+
.file("src/main.rs", &src);
180+
181+
let target_dir = p.target_debug_dir();
182+
183+
assert_that(p.cargo_process("build"), execs().with_status(0));
184+
assert_that(&p.bin("cargo-envtest"), existing_file());
185+
186+
let mut pr = cargo_process();
187+
let cargo = cargo_exe().canonicalize().unwrap();
188+
let mut path = path();
189+
path.push(target_dir);
190+
let path = env::join_paths(path.iter()).unwrap();
191+
192+
assert_that(pr.arg("envtest").env("PATH", &path),
193+
execs().with_status(0).with_stdout(cargo.to_str().unwrap()));
194+
}
195+
164196
#[test]
165197
fn cargo_help() {
166198
assert_that(cargo_process(),

tests/cargotest/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ fn _process(t: &OsStr) -> cargo::util::ProcessBuilder {
9090
}
9191

9292
pub fn cargo_process() -> cargo::util::ProcessBuilder {
93-
process(&support::cargo_dir().join("cargo"))
93+
process(&support::cargo_exe())
9494
}
9595

9696
pub fn sleep_ms(ms: u64) {

tests/cargotest/support/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl ProjectBuilder {
165165
assert!(self.is_build.get(),
166166
"call `.build()` before calling `.cargo()`, \
167167
or use `.cargo_process()`");
168-
let mut p = self.process(&cargo_dir().join("cargo"));
168+
let mut p = self.process(&cargo_exe());
169169
p.arg(cmd);
170170
return p;
171171
}
@@ -317,6 +317,10 @@ pub fn cargo_dir() -> PathBuf {
317317
})
318318
}
319319

320+
pub fn cargo_exe() -> PathBuf {
321+
cargo_dir().join(format!("cargo{}", env::consts::EXE_SUFFIX))
322+
}
323+
320324
/// Returns an absolute path in the filesystem that `path` points to. The
321325
/// returned path does not contain any symlinks in its hierarchy.
322326
/*

tests/init.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ use std::io::prelude::*;
88
use std::env;
99

1010
use cargo::util::ProcessBuilder;
11-
use cargotest::support::{execs, paths, cargo_dir};
11+
use cargotest::support::{execs, paths, cargo_exe};
1212
use hamcrest::{assert_that, existing_file, existing_dir, is_not};
1313
use tempdir::TempDir;
1414

1515
fn cargo_process(s: &str) -> ProcessBuilder {
16-
let mut p = cargotest::process(&cargo_dir().join("cargo"));
16+
let mut p = cargotest::process(&cargo_exe());
1717
p.arg(s).cwd(&paths::root()).env("HOME", &paths::home());
1818
p
1919
}

tests/package.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::io::prelude::*;
1111
use std::path::{Path, PathBuf};
1212

1313
use cargotest::{cargo_process, process};
14-
use cargotest::support::{project, execs, paths, git, path2url, cargo_dir};
14+
use cargotest::support::{project, execs, paths, git, path2url, cargo_exe};
1515
use flate2::read::GzDecoder;
1616
use hamcrest::{assert_that, existing_file, contains};
1717
use tar::Archive;
@@ -481,7 +481,7 @@ fn repackage_on_source_change() {
481481
"#).unwrap();
482482
std::mem::drop(file);
483483

484-
let mut pro = process(&cargo_dir().join("cargo"));
484+
let mut pro = process(&cargo_exe());
485485
pro.arg("package").cwd(p.root());
486486

487487
// Check that cargo rebuilds the tarball

0 commit comments

Comments
 (0)