diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs index 9e5eb70ceb88..d838b7fec016 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::{features, CliUnstable}; use cargo::{self, drop_print, drop_println, CliResult, Config}; use clap::{ @@ -55,6 +55,13 @@ pub fn main(config: &mut Config) -> CliResult { } }; + if let Some(new_cwd) = args.get_one::("directory") { + // Change the configured directory to work in, before any config files are read + config.set_cwd(new_cwd.as_path()) + .with_context(|| "could not change to requested directory")?; + } + + // Global args need to be extracted before expanding aliases because the // clap code for extracting a subcommand discards global options // (appearing before the subcommand). @@ -473,6 +480,14 @@ 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()) + .global(true), + ) .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/src/cargo/util/config/mod.rs b/src/cargo/util/config/mod.rs index dd3f6ae933ea..453ba5f19469 100644 --- a/src/cargo/util/config/mod.rs +++ b/src/cargo/util/config/mod.rs @@ -483,6 +483,24 @@ impl Config { Ok(()) } + /// Updates the application's notion of current working directory, both in + /// the process environment as well as the configuration data + pub fn set_cwd(&mut self, new_cwd: &Path) -> CargoResult<()> { + // Update the process-level notion of cwd + std::env::set_current_dir(&new_cwd)?; + // Update struct members derived from the process-wide cwd + // processing occurs + self.cwd = new_cwd.to_path_buf(); + self.home_path = Filesystem::new(homedir(new_cwd) + .ok_or_else(|| { + anyhow!( + "Cargo couldn't find your home directory. \ + This probably means that $HOME was not set." + ) + })?); + Ok(()) + } + /// The current working directory. pub fn cwd(&self) -> &Path { &self.cwd