diff --git a/crates/nu-cli/src/env/directory_specific_environment.rs b/crates/nu-cli/src/env/directory_specific_environment.rs index 3adbd947c0..ead0a2cc87 100644 --- a/crates/nu-cli/src/env/directory_specific_environment.rs +++ b/crates/nu-cli/src/env/directory_specific_environment.rs @@ -3,9 +3,11 @@ use commands::autoenv; use indexmap::{IndexMap, IndexSet}; use nu_errors::ShellError; use sha2::{Digest, Sha256}; +use std::io::Write; use std::{ ffi::OsString, fmt::Debug, + fs::OpenOptions, path::{Path, PathBuf}, }; @@ -14,7 +16,7 @@ type EnvVal = OsString; #[derive(Debug, Default)] pub struct DirectorySpecificEnvironment { trusted: Option, - + last_seen_directory: PathBuf, //Directory -> Env key. If an environment var has been added from a .nu in a directory, we track it here so we can remove it when the user leaves the directory. added_env_vars: IndexMap>, } @@ -27,6 +29,7 @@ impl DirectorySpecificEnvironment { }; DirectorySpecificEnvironment { trusted, + last_seen_directory: PathBuf::from("/"), added_env_vars: IndexMap::new(), } } @@ -54,13 +57,35 @@ impl DirectorySpecificEnvironment { Err(ShellError::untagged_runtime_error("No trusted directories")) } + fn is_parent_or_same(&self, parent: &PathBuf, child: &PathBuf) -> bool { + let mut child = Some(child.as_path()); + while let Some(c) = child { + if c == parent { + return true; + } + child = child.expect("Can't be none").parent(); + } + return false; + } + pub fn env_vars_to_add(&mut self) -> Result, ShellError> { let current_dir = std::env::current_dir()?; let mut working_dir = Some(current_dir.as_path()); let mut vars_to_add = IndexMap::new(); + //If we are in the last seen directory, do nothing + //If we are in a parent directory to last_seen_directory, just return without applying .nu-env in the parent directory - they were already applied earlier. + if self.is_parent_or_same(¤t_dir, &self.last_seen_directory) { + return Ok(vars_to_add); + } + //Start in the current directory, then traverse towards the root with working_dir to see if we are in a subdirectory of a valid directory. while let Some(wdir) = working_dir { + //If we are in a subdirectory to last_seen_directory, we should apply all .nu-envs up until last_seen_directory + if wdir == self.last_seen_directory { + self.last_seen_directory = current_dir; + return Ok(vars_to_add); + } let wdirenv = wdir.join(".nu-env"); if wdirenv.exists() { let toml_doc = self.toml_if_directory_is_trusted(&wdirenv)?; @@ -99,6 +124,7 @@ impl DirectorySpecificEnvironment { .parent(); } + self.last_seen_directory = current_dir; Ok(vars_to_add) }