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
This commit is contained in:
WindSoilder 2022-06-11 02:01:08 +08:00 committed by GitHub
parent b6959197bf
commit c5cb369d8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 30 deletions

View file

@ -9,18 +9,35 @@ use nu_protocol::{
}; };
#[cfg(windows)] #[cfg(windows)]
use nu_utils::enable_vt_processing; 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. // 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 // 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' // 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. // 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<Item = (String, String)>, engine_state: &mut EngineState) { fn gather_env_vars(
vars: impl Iterator<Item = (String, String)>,
engine_state: &mut EngineState,
init_cwd: &Path,
) {
fn report_capture_error(engine_state: &EngineState, env_str: &str, msg: &str) { fn report_capture_error(engine_state: &EngineState, env_str: &str, msg: &str) {
let working_set = StateWorkingSet::new(engine_state); let working_set = StateWorkingSet::new(engine_state);
report_error( report_error(
@ -43,37 +60,33 @@ fn gather_env_vars(vars: impl Iterator<Item = (String, String)>, engine_state: &
} }
let mut fake_env_file = String::new(); let mut fake_env_file = String::new();
let mut has_pwd = false;
// Write all the env vars into a fake file // Write all the env vars into a fake file
for (name, val) in vars { for (name, val) in vars {
if name == "PWD" {
has_pwd = true;
}
put_env_to_fake_file(&name, &val, &mut fake_env_file); put_env_to_fake_file(&name, &val, &mut fake_env_file);
} }
if !has_pwd { match init_cwd.to_str() {
match std::env::current_dir() { Some(cwd) => {
Ok(cwd) => { put_env_to_fake_file("PWD", cwd, &mut fake_env_file);
put_env_to_fake_file("PWD", &cwd.to_string_lossy(), &mut fake_env_file);
} }
Err(e) => { None => {
// Could not capture current working directory // Could not capture current working directory
let working_set = StateWorkingSet::new(engine_state); let working_set = StateWorkingSet::new(engine_state);
report_error( report_error(
&working_set, &working_set,
&ShellError::GenericError( &ShellError::GenericError(
"Current directory not found".to_string(), "Current directory is not a valid utf-8 path".to_string(),
"".to_string(), "".to_string(),
None, None,
Some(format!("Retrieving current directory failed: {:?}", e)), Some(format!(
"Retrieving current directory failed: {:?} not a valid utf-8 path",
init_cwd
)),
Vec::new(), Vec::new(),
), ),
); );
} }
} }
}
// Lex the fake file, assign spans to all environment variables and add them // Lex the fake file, assign spans to all environment variables and add them
// to stack // to stack
@ -314,6 +327,7 @@ mod test {
] ]
.into_iter(), .into_iter(),
&mut engine_state, &mut engine_state,
Path::new("t"),
); );
let env = engine_state.render_env_vars(); let env = engine_state.render_env_vars();

View file

@ -67,7 +67,8 @@ macro_rules! nu {
let target_cwd = $crate::fs::in_directory(&$cwd); let target_cwd = $crate::fs::in_directory(&$cwd);
let mut process = match Command::new($crate::fs::executable_path()) 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) .env(NATIVE_PATH_ENV_VAR, paths_joined)
// .arg("--skip-plugins") // .arg("--skip-plugins")
// .arg("--no-history") // .arg("--no-history")

View file

@ -194,7 +194,7 @@ fn main() -> Result<()> {
} }
// First, set up env vars as strings only // 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(); let mut stack = nu_protocol::engine::Stack::new();
if let Some(commands) = &binary_args.commands { if let Some(commands) = &binary_args.commands {