]> git.proxmox.com Git - cargo.git/commitdiff
Tell subprocesses the path to self in an env variable #3778
authorVojtech Kral <vojtech@kral.hk>
Thu, 2 Mar 2017 06:38:54 +0000 (07:38 +0100)
committerVojtech Kral <vojtech@kral.hk>
Tue, 7 Mar 2017 22:29:50 +0000 (23:29 +0100)
src/bin/cargo.rs
src/cargo/lib.rs
src/cargo/ops/cargo_rustc/compilation.rs
src/cargo/util/config.rs
src/doc/environment-variables.md
tests/cargo.rs
tests/cargotest/lib.rs
tests/cargotest/support/mod.rs
tests/init.rs
tests/package.rs
tests/test.rs

index 0d0171ad2e8b1a5be85eaba0a3881682d78231f4..187db436fcbc76a73b948b87b5dd509261510388 100644 (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,
     };
index 1d13a50332377a91de3a3436f5c94b51d01a49aa..019a7a19dff5181e65492ad08387226a69d55955 100755 (executable)
@@ -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)*)))
index 60f62eada544ef8449c21e1b637a202d8cddf21c..9f9b1c52ebba774df673bd963c9a64732e399dfe 100644 (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())
index 08af70451c87fadfa5585fc8fd2f65883abe9a89..a715306637c94d436f8c860ecbb5f0292e5e8ad2 100644 (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())
     }
index 7cb67b6c19e9c451f75d2d1003221e953c5876c2..97bdb38cb51640a4166c1006773eb8b6a221edfd 100644 (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.
index b8f87325ba4c6ac319b37abecd1a7e2709258334..43e76c6ec153ed4d6b8a11e07939ae9c347cb298 100644 (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(),
index 11df25fdd1363c26d996b60929a418cd86dd4cf3..c6a4dc4f48e2694ac79404bfc1a2cecfae702329 100644 (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) {
index 88b5c39643781e3c2296c730608340438b93c42a..2e3e6d21c8c1c2828cac1ee1825c1ca715df2572 100644 (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.
 /*
index c13d57d73406c4731da21e3d52d4ef53a11ac300..47efa3b97c907c2724a30efd0e9df08851bf18ce 100644 (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
 }
index c40da6f5391a7efb9d0c7da6e59901ff1d956dcd..fab868061d59839ea019353f46a708b5b416926c 100644 (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
index 6e3e5c4646cb5882c6d74dcc0390d756a8a87d81..2f0d3e6332e6a4ce531a8a9c7b16df5fc508191a 100644 (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())));
+}