From c5cb369d8d1e625682998868efb37edda31304c4 Mon Sep 17 00:00:00 2001 From: WindSoilder Date: Sat, 11 Jun 2022 02:01:08 +0800 Subject: [PATCH] While starting nu, force PWD to be current working directory (#5751) * fix current working directory during start * fix tests * always set PWD to current_dir --- crates/nu-cli/src/util.rs | 70 +++++++++++++++++----------- crates/nu-test-support/src/macros.rs | 3 +- src/main.rs | 2 +- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/crates/nu-cli/src/util.rs b/crates/nu-cli/src/util.rs index a79187d70c..f36a88b38d 100644 --- a/crates/nu-cli/src/util.rs +++ b/crates/nu-cli/src/util.rs @@ -9,18 +9,35 @@ use nu_protocol::{ }; #[cfg(windows)] use nu_utils::enable_vt_processing; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; // This will collect environment variables from std::env and adds them to a stack. // // In order to ensure the values have spans, it first creates a dummy file, writes the collected // env vars into it (in a "NAME"="value" format, quite similar to the output of the Unix 'env' // tool), then uses the file to get the spans. The file stays in memory, no filesystem IO is done. -pub fn gather_parent_env_vars(engine_state: &mut EngineState) { - gather_env_vars(std::env::vars(), engine_state); +// +// The "PWD" env value will be forced to `init_cwd`. +// The reason to use `init_cwd`: +// +// While gathering parent env vars, the parent `PWD` may not be the same as `current working directory`. +// Consider to the following command as the case (assume we execute command inside `/tmp`): +// +// tmux split-window -v -c "#{pane_current_path}" +// +// Here nu execute external command `tmux`, and tmux starts a new `nushell`, with `init_cwd` value "#{pane_current_path}". +// But at the same time `PWD` still remains to be `/tmp`. +// +// In this scenario, the new `nushell`'s PWD should be "#{pane_current_path}" rather init_cwd. +pub fn gather_parent_env_vars(engine_state: &mut EngineState, init_cwd: &Path) { + gather_env_vars(std::env::vars(), engine_state, init_cwd); } -fn gather_env_vars(vars: impl Iterator, engine_state: &mut EngineState) { +fn gather_env_vars( + vars: impl Iterator, + engine_state: &mut EngineState, + init_cwd: &Path, +) { fn report_capture_error(engine_state: &EngineState, env_str: &str, msg: &str) { let working_set = StateWorkingSet::new(engine_state); report_error( @@ -43,35 +60,31 @@ fn gather_env_vars(vars: impl Iterator, engine_state: & } let mut fake_env_file = String::new(); - let mut has_pwd = false; - // Write all the env vars into a fake file for (name, val) in vars { - if name == "PWD" { - has_pwd = true; - } put_env_to_fake_file(&name, &val, &mut fake_env_file); } - if !has_pwd { - match std::env::current_dir() { - Ok(cwd) => { - put_env_to_fake_file("PWD", &cwd.to_string_lossy(), &mut fake_env_file); - } - Err(e) => { - // Could not capture current working directory - let working_set = StateWorkingSet::new(engine_state); - report_error( - &working_set, - &ShellError::GenericError( - "Current directory not found".to_string(), - "".to_string(), - None, - Some(format!("Retrieving current directory failed: {:?}", e)), - Vec::new(), - ), - ); - } + match init_cwd.to_str() { + Some(cwd) => { + put_env_to_fake_file("PWD", cwd, &mut fake_env_file); + } + None => { + // Could not capture current working directory + let working_set = StateWorkingSet::new(engine_state); + report_error( + &working_set, + &ShellError::GenericError( + "Current directory is not a valid utf-8 path".to_string(), + "".to_string(), + None, + Some(format!( + "Retrieving current directory failed: {:?} not a valid utf-8 path", + init_cwd + )), + Vec::new(), + ), + ); } } @@ -314,6 +327,7 @@ mod test { ] .into_iter(), &mut engine_state, + Path::new("t"), ); let env = engine_state.render_env_vars(); diff --git a/crates/nu-test-support/src/macros.rs b/crates/nu-test-support/src/macros.rs index 1f8b75d8ce..4df7bda7f9 100644 --- a/crates/nu-test-support/src/macros.rs +++ b/crates/nu-test-support/src/macros.rs @@ -67,7 +67,8 @@ macro_rules! nu { let target_cwd = $crate::fs::in_directory(&$cwd); let mut process = match Command::new($crate::fs::executable_path()) - .env("PWD", &target_cwd) // setting PWD is enough to set cwd + .env("PWD", &target_cwd) + .current_dir(target_cwd) .env(NATIVE_PATH_ENV_VAR, paths_joined) // .arg("--skip-plugins") // .arg("--no-history") diff --git a/src/main.rs b/src/main.rs index 09c67d12da..5dc6660e8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -194,7 +194,7 @@ fn main() -> Result<()> { } // First, set up env vars as strings only - gather_parent_env_vars(&mut engine_state); + gather_parent_env_vars(&mut engine_state, &init_cwd); let mut stack = nu_protocol::engine::Stack::new(); if let Some(commands) = &binary_args.commands {