From 5f445ce071d44d68557aab86dc7c2deb2c643cee Mon Sep 17 00:00:00 2001 From: William Page Date: Mon, 8 Aug 2022 14:40:57 -0700 Subject: [PATCH] Add '--directory,-C' flag for changing current dir before build This implements the suggestion in #10098 to make cargo change cwd before completing config processing and starting the build. It is also an alternative to --manifest-path that resolves the issue described in #2930. --- src/bin/cargo/cli.rs | 15 ++++++++++++++- tests/testsuite/build.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs index 3053854d4c7b..e4e136f7f450 100644 --- a/src/bin/cargo/cli.rs +++ b/src/bin/cargo/cli.rs @@ -1,4 +1,4 @@ -use anyhow::anyhow; +use anyhow::{anyhow, Context as _}; use cargo::core::shell::Shell; use cargo::core::{features, CliUnstable}; use cargo::{self, drop_print, drop_println, CliResult, Config}; @@ -27,6 +27,12 @@ lazy_static::lazy_static! { pub fn main(config: &mut LazyConfig) -> CliResult { let args = cli().try_get_matches()?; + // Update the process-level notion of cwd + if let Some(new_cwd) = args.get_one::("directory") { + std::env::set_current_dir(&new_cwd) + .with_context(|| "could not change to requested directory")?; + } + // CAUTION: Be careful with using `config` until it is configured below. // In general, try to avoid loading config values unless necessary (like // the [alias] table). @@ -467,6 +473,13 @@ See 'cargo help ' for more information on a specific command.\n", .value_name("WHEN") .global(true), ) + .arg( + opt("directory", "Change to DIRECTORY before doing anything") + .short('C') + .value_name("DIRECTORY") + .value_hint(clap::ValueHint::DirPath) + .value_parser(clap::builder::ValueParser::path_buf()), + ) .arg(flag("frozen", "Require Cargo.lock and cache are up to date").global(true)) .arg(flag("locked", "Require Cargo.lock is up to date").global(true)) .arg(flag("offline", "Run without accessing the network").global(true)) diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 8ad9f70ac526..22827a071f78 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -159,6 +159,44 @@ fn cargo_compile_manifest_path() { assert!(p.bin("foo").is_file()); } +#[cargo_test] +fn cargo_compile_directory_not_cwd() { + let p = project() + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .file(".cargo/config.toml", &"") + .build(); + + p.cargo("-C foo build") + .cwd(p.root().parent().unwrap()) + .run(); + assert!(p.bin("foo").is_file()); +} + +#[cargo_test] +fn cargo_compile_directory_not_cwd_with_invalid_config() { + let p = project() + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .file(".cargo/config.toml", &"!") + .build(); + + p.cargo("-C foo build") + .cwd(p.root().parent().unwrap()) + .with_status(101) + .with_stderr_contains( + "\ +Caused by: + TOML parse error at line 1, column 1 + | + 1 | ! + | ^ + Unexpected `!` + Expected key or end of input", + ) + .run(); +} + #[cargo_test] fn cargo_compile_with_invalid_manifest() { let p = project().file("Cargo.toml", "").build();