Tell subprocesses the path to self in an env variable #3778

This commit is contained in:
Vojtech Kral 2017-03-02 07:38:54 +01:00
parent ef8fa8fc1c
commit 015a08a0c4
11 changed files with 109 additions and 14 deletions

View File

@ -320,7 +320,12 @@ fn execute_external_subcommand(config: &Config, cmd: &str, args: &[String]) -> C
.into())
}
};
let err = match util::process(&command).args(&args[1..]).exec() {
let cargo_exe = config.cargo_exe()?;
let err = match util::process(&command)
.env(cargo::CARGO_ENV, cargo_exe)
.args(&args[1..])
.exec() {
Ok(()) => return Ok(()),
Err(e) => e,
};

View File

@ -41,6 +41,8 @@ use term::color::{BLACK};
pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};
pub const CARGO_ENV: &'static str = "CARGO";
macro_rules! bail {
($($fmt:tt)*) => (
return Err(::util::human(&format_args!($($fmt)*)))

View File

@ -143,6 +143,9 @@ impl<'cfg> Compilation<'cfg> {
let metadata = pkg.manifest().metadata();
let cargo_exe = self.config.cargo_exe()?;
cmd.env(::CARGO_ENV, cargo_exe);
cmd.env("CARGO_MANIFEST_DIR", pkg.root())
.env("CARGO_PKG_VERSION_MAJOR", &pkg.version().major.to_string())
.env("CARGO_PKG_VERSION_MINOR", &pkg.version().minor.to_string())

View File

@ -28,6 +28,7 @@ pub struct Config {
rustc: LazyCell<Rustc>,
values: LazyCell<HashMap<String, ConfigValue>>,
cwd: PathBuf,
cargo_exe: LazyCell<PathBuf>,
rustdoc: LazyCell<PathBuf>,
extra_verbose: Cell<bool>,
frozen: Cell<bool>,
@ -44,6 +45,7 @@ impl Config {
rustc: LazyCell::new(),
cwd: cwd,
values: LazyCell::new(),
cargo_exe: LazyCell::new(),
rustdoc: LazyCell::new(),
extra_verbose: Cell::new(false),
frozen: Cell::new(false),
@ -93,6 +95,15 @@ impl Config {
self.rustc.get_or_try_init(|| Rustc::new(self.get_tool("rustc")?))
}
pub fn cargo_exe(&self) -> CargoResult<&Path> {
self.cargo_exe.get_or_try_init(||
env::current_exe().and_then(|path| path.canonicalize())
.chain_error(|| {
human("couldn't get the path to cargo executable")
})
).map(AsRef::as_ref)
}
pub fn values(&self) -> CargoResult<&HashMap<String, ConfigValue>> {
self.values.get_or_try_init(|| self.load_values())
}

View File

@ -30,8 +30,9 @@ configuration values, as described in [that documentation][config-env]
# Environment variables Cargo sets for crates
Cargo exposes these environment variables to your crate when it is compiled. To get the
value of any of these variables in a Rust program, do this:
Cargo exposes these environment variables to your crate when it is compiled.
Note that this applies for test binaries as well.
To get the value of any of these variables in a Rust program, do this:
```
let version = env!("CARGO_PKG_VERSION");
@ -39,6 +40,7 @@ let version = env!("CARGO_PKG_VERSION");
`version` will now contain the value of `CARGO_PKG_VERSION`.
* `CARGO` - Path to the `cargo` binary performing the build.
* `CARGO_MANIFEST_DIR` - The directory containing the manifest of your package.
* `CARGO_PKG_VERSION` - The full version of your package.
* `CARGO_PKG_VERSION_MAJOR` - The major version of your package.
@ -96,3 +98,10 @@ let out_dir = env::var("OUT_DIR").unwrap();
[links]: build-script.html#the-links-manifest-key
[profile]: manifest.html#the-profile-sections
[clang]:http://clang.llvm.org/docs/CrossCompilation.html#target-triple
# Environment variables Cargo sets for 3rd party subcommands
Cargo exposes this environment variable to 3rd party subcommands
(ie. programs named `cargo-foobar` placed in `$PATH`):
* `CARGO` - Path to the `cargo` binary performing the build.

View File

@ -1,3 +1,4 @@
extern crate cargo;
extern crate cargotest;
extern crate hamcrest;
@ -10,8 +11,8 @@ use std::str;
use cargotest::cargo_process;
use cargotest::support::paths::{self, CargoPathExt};
use cargotest::support::{execs, project, ProjectBuilder};
use hamcrest::{assert_that};
use cargotest::support::{execs, project, ProjectBuilder, basic_bin_manifest};
use hamcrest::{assert_that, existing_file};
#[cfg_attr(windows,allow(dead_code))]
enum FakeKind<'a> {
@ -81,11 +82,11 @@ fn list_command_looks_at_path() {
#[cfg(unix)]
#[test]
fn list_command_resolves_symlinks() {
use cargotest::support::cargo_dir;
use cargotest::support::cargo_exe;
let proj = project("list-non-overlapping");
let proj = fake_file(proj, Path::new("path-test"), "cargo-2",
FakeKind::Symlink{target:&cargo_dir().join("cargo")});
FakeKind::Symlink{target:&cargo_exe()});
let mut pr = cargo_process();
let mut path = path();
@ -161,6 +162,37 @@ fn override_cargo_home() {
assert!(contents.contains(r#"authors = ["foo <bar>"]"#));
}
#[test]
fn cargo_subcommand_env() {
use cargotest::support::cargo_exe;
let src = format!(r#"
use std::env;
fn main() {{
println!("{{}}", env::var("{}").unwrap());
}}
"#, cargo::CARGO_ENV);
let p = project("cargo-envtest")
.file("Cargo.toml", &basic_bin_manifest("cargo-envtest"))
.file("src/main.rs", &src);
let target_dir = p.target_debug_dir();
assert_that(p.cargo_process("build"), execs().with_status(0));
assert_that(&p.bin("cargo-envtest"), existing_file());
let mut pr = cargo_process();
let cargo = cargo_exe().canonicalize().unwrap();
let mut path = path();
path.push(target_dir);
let path = env::join_paths(path.iter()).unwrap();
assert_that(pr.arg("envtest").env("PATH", &path),
execs().with_status(0).with_stdout(cargo.to_str().unwrap()));
}
#[test]
fn cargo_help() {
assert_that(cargo_process(),

View File

@ -90,7 +90,7 @@ fn _process(t: &OsStr) -> cargo::util::ProcessBuilder {
}
pub fn cargo_process() -> cargo::util::ProcessBuilder {
process(&support::cargo_dir().join("cargo"))
process(&support::cargo_exe())
}
pub fn sleep_ms(ms: u64) {

View File

@ -165,7 +165,7 @@ impl ProjectBuilder {
assert!(self.is_build.get(),
"call `.build()` before calling `.cargo()`, \
or use `.cargo_process()`");
let mut p = self.process(&cargo_dir().join("cargo"));
let mut p = self.process(&cargo_exe());
p.arg(cmd);
return p;
}
@ -317,6 +317,10 @@ pub fn cargo_dir() -> PathBuf {
})
}
pub fn cargo_exe() -> PathBuf {
cargo_dir().join(format!("cargo{}", env::consts::EXE_SUFFIX))
}
/// Returns an absolute path in the filesystem that `path` points to. The
/// returned path does not contain any symlinks in its hierarchy.
/*

View File

@ -8,12 +8,12 @@ use std::io::prelude::*;
use std::env;
use cargo::util::ProcessBuilder;
use cargotest::support::{execs, paths, cargo_dir};
use cargotest::support::{execs, paths, cargo_exe};
use hamcrest::{assert_that, existing_file, existing_dir, is_not};
use tempdir::TempDir;
fn cargo_process(s: &str) -> ProcessBuilder {
let mut p = cargotest::process(&cargo_dir().join("cargo"));
let mut p = cargotest::process(&cargo_exe());
p.arg(s).cwd(&paths::root()).env("HOME", &paths::home());
p
}

View File

@ -11,7 +11,7 @@ use std::io::prelude::*;
use std::path::{Path, PathBuf};
use cargotest::{cargo_process, process};
use cargotest::support::{project, execs, paths, git, path2url, cargo_dir};
use cargotest::support::{project, execs, paths, git, path2url, cargo_exe};
use flate2::read::GzDecoder;
use hamcrest::{assert_that, existing_file, contains};
use tar::Archive;
@ -481,7 +481,7 @@ fn repackage_on_source_change() {
"#).unwrap();
std::mem::drop(file);
let mut pro = process(&cargo_dir().join("cargo"));
let mut pro = process(&cargo_exe());
pro.arg("package").cwd(p.root());
// Check that cargo rebuilds the tarball

View File

@ -7,7 +7,7 @@ use std::io::prelude::*;
use std::str;
use cargotest::{sleep_ms, is_nightly};
use cargotest::support::{project, execs, basic_bin_manifest, basic_lib_manifest};
use cargotest::support::{project, execs, basic_bin_manifest, basic_lib_manifest, cargo_exe};
use cargotest::support::paths::CargoPathExt;
use cargotest::support::registry::Package;
use hamcrest::{assert_that, existing_file, is_not};
@ -2666,3 +2666,32 @@ fn doctest_and_registry() {
assert_that(p.cargo_process("test").arg("--all").arg("-v"),
execs().with_status(0));
}
#[test]
fn cargo_test_env() {
let src = format!(r#"
#![crate_type = "rlib"]
#[test]
fn env_test() {{
use std::env;
println!("{{}}", env::var("{}").unwrap());
}}
"#, cargo::CARGO_ENV);
let p = project("env_test")
.file("Cargo.toml", &basic_lib_manifest("env_test"))
.file("src/lib.rs", &src);
let mut pr = p.cargo_process("test");
let cargo = cargo_exe().canonicalize().unwrap();
assert_that(pr.args(&["--lib", "--", "--nocapture"]),
execs().with_status(0).with_stdout(format!("
running 1 test
{}
test env_test ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
", cargo.to_str().unwrap())));
}