Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/bin/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down
2 changes: 2 additions & 0 deletions src/cargo/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think something more verbose like CARGO_EXECUTABLE would be a tiny bit better, but we already use plain RUSTC and RUSRDOC variables for similar purposes, and in this regard just CARGO is indeed the best name here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really have a strong feeling one way or another (hehe) but I guess, like you said, CARGO is good for consistency with RUSTC ...


macro_rules! bail {
($($fmt:tt)*) => (
return Err(::util::human(&format_args!($($fmt)*)))
Expand Down
3 changes: 3 additions & 0 deletions src/cargo/ops/cargo_rustc/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
11 changes: 11 additions & 0 deletions src/cargo/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand All @@ -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),
Expand Down Expand Up @@ -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())
}
Expand Down
13 changes: 11 additions & 2 deletions src/doc/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ 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");
```

`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.
Expand Down Expand Up @@ -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.
40 changes: 36 additions & 4 deletions tests/cargo.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
extern crate cargo;
extern crate cargotest;
extern crate hamcrest;

Expand All @@ -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> {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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(),
Expand Down
2 changes: 1 addition & 1 deletion tests/cargotest/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
6 changes: 5 additions & 1 deletion tests/cargotest/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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.
/*
Expand Down
4 changes: 2 additions & 2 deletions tests/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions tests/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
31 changes: 30 additions & 1 deletion tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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())));
}