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)]
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<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) {
let working_set = StateWorkingSet::new(engine_state);
report_error(
@ -43,35 +60,31 @@ fn gather_env_vars(vars: impl Iterator<Item = (String, String)>, 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();

View File

@ -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")

View File

@ -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 {