diff --git a/crates/nu-cli/src/env.rs b/crates/nu-cli/src/env.rs index 3f1dd1c311..74ae277ab5 100644 --- a/crates/nu-cli/src/env.rs +++ b/crates/nu-cli/src/env.rs @@ -1,3 +1,4 @@ +pub(crate) mod directory_specific_environment; pub(crate) mod environment; pub(crate) mod environment_syncer; pub(crate) mod host; diff --git a/crates/nu-cli/src/env/directory_specific_environment.rs b/crates/nu-cli/src/env/directory_specific_environment.rs new file mode 100644 index 0000000000..0705bb064e --- /dev/null +++ b/crates/nu-cli/src/env/directory_specific_environment.rs @@ -0,0 +1,90 @@ +use indexmap::indexmap; +use std::{ + collections::HashMap, + fmt::Debug, + path::PathBuf, +}; + + +#[derive(Debug, Default)] +pub struct DirectorySpecificEnvironment { + pub whitelisted_directories: Vec, + + //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. + pub added_env_vars: HashMap>, + + //Directory -> (env_key, value). If a .nu overwrites some existing environment variables, they are added here so that they can be restored later. + pub overwritten_env_values: HashMap>, +} + +impl DirectorySpecificEnvironment { + pub fn new(whitelisted_directories: Vec) -> DirectorySpecificEnvironment { + DirectorySpecificEnvironment { + whitelisted_directories, + added_env_vars: HashMap::new(), + overwritten_env_values: HashMap::new(), + } + } + + pub fn env_vars_to_add(&mut self) -> std::io::Result> { + let current_dir = std::env::current_dir()?; + + let mut vars_to_add = HashMap::new(); + for dir in &self.whitelisted_directories { + //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. + let mut working_dir = Some(current_dir.as_path()); + + while let Some(wdir) = working_dir { + if wdir == dir.as_path() { + + //Read the .nu file and parse it into a nice map + let toml_doc = std::fs::read_to_string(wdir.join(".nu").as_path())? + .parse::() + .unwrap(); + let vars_in_current_file = toml_doc.get("env").unwrap().as_table().unwrap(); + + let keys_in_file = vars_in_current_file + .iter() + .map(|(k, v)| { + vars_to_add.insert(k.clone(), v.as_str().unwrap().to_string()); //This is to add the keys and values to the environment + k.clone() //We add them all to a list to keep track of which keys we have added + }) + .collect(); + + self.added_env_vars.insert(wdir.to_path_buf(), keys_in_file); + break; + } else { + working_dir = working_dir.unwrap().parent(); + } + } + } + Ok(vars_to_add) + } + + //If the user has left directories which added env vars through .nu, we clear those vars + pub fn env_vars_to_delete(&mut self) -> std::io::Result> { + let current_dir = std::env::current_dir()?; + + //Gather up all environment variables that should be deleted. + //If we are not in a directory or one of its subdirectories, mark the env_vals it maps to for removal. + let vars_to_delete = self.added_env_vars.iter().fold( + Vec::new(), + |mut vars_to_delete, (directory, env_vars)| { + let mut working_dir = Some(current_dir.as_path()); + + while let Some(wdir) = working_dir { + if &wdir == directory { + return vars_to_delete; + } else { + working_dir = working_dir.unwrap().parent(); + } + } + //only delete vars from directories we are not in + vars_to_delete.extend(env_vars.clone()); + vars_to_delete + }, + ); + + Ok(vars_to_delete) + } +} \ No newline at end of file diff --git a/crates/nu-cli/src/env/environment.rs b/crates/nu-cli/src/env/environment.rs index aaf451513a..8106f0e518 100644 --- a/crates/nu-cli/src/env/environment.rs +++ b/crates/nu-cli/src/env/environment.rs @@ -1,12 +1,9 @@ use crate::data::config::Conf; +use crate::env::directory_specific_environment::*; use indexmap::{indexmap, IndexSet}; use nu_protocol::{Primitive, UntaggedValue, Value}; use std::ffi::OsString; -use std::{ - collections::HashMap, - fmt::Debug, - path::PathBuf, -}; +use std::{fmt::Debug, path::PathBuf}; pub trait Env: Debug + Send { fn env(&self) -> Option; @@ -34,89 +31,6 @@ impl Env for Box { } } -#[derive(Debug, Default)] -struct DirectorySpecificEnvironment { - pub whitelisted_directories: Vec, - - //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. - pub added_env_vars: HashMap>, - - //Directory -> (env_key, value). If a .nu overwrites some existing environment variables, they are added here so that they can be restored later. - pub overwritten_env_values: HashMap>, -} - -impl DirectorySpecificEnvironment { - pub fn new(whitelisted_directories: Vec) -> DirectorySpecificEnvironment { - DirectorySpecificEnvironment { - whitelisted_directories, - added_env_vars: HashMap::new(), - overwritten_env_values: HashMap::new(), - } - } - - pub fn env_vars_to_add(&mut self) -> std::io::Result> { - let current_dir = std::env::current_dir()?; - - let mut vars_to_add = HashMap::new(); - for dir in &self.whitelisted_directories { - //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. - let mut working_dir = Some(current_dir.as_path()); - - while let Some(wdir) = working_dir { - if wdir == dir.as_path() { - - //Read the .nu file and parse it into a nice map - let toml_doc = std::fs::read_to_string(wdir.join(".nu").as_path())? - .parse::() - .unwrap(); - let vars_in_current_file = toml_doc.get("env").unwrap().as_table().unwrap(); - - let keys_in_file = vars_in_current_file - .iter() - .map(|(k, v)| { - vars_to_add.insert(k.clone(), v.as_str().unwrap().to_string()); //This is to add the keys and values to the environment - k.clone() //We add them all to a list to keep track of which keys we have added - }) - .collect(); - - self.added_env_vars.insert(wdir.to_path_buf(), keys_in_file); - break; - } else { - working_dir = working_dir.unwrap().parent(); - } - } - } - Ok(vars_to_add) - } - - //If the user has left directories which added env vars through .nu, we clear those vars - pub fn env_vars_to_delete(&mut self) -> std::io::Result> { - let current_dir = std::env::current_dir()?; - - //Gather up all environment variables that should be deleted. - //If we are not in a directory or one of its subdirectories, mark the env_vals it maps to for removal. - let vars_to_delete = self.added_env_vars.iter().fold( - Vec::new(), - |mut vars_to_delete, (directory, env_vars)| { - let mut working_dir = Some(current_dir.as_path()); - - while let Some(wdir) = working_dir { - if &wdir == directory { - return vars_to_delete; - } else { - working_dir = working_dir.unwrap().parent(); - } - } - //only delete vars from directories we are not in - vars_to_delete.extend(env_vars.clone()); - vars_to_delete - }, - ); - - Ok(vars_to_delete) - } -} - #[derive(Debug, Default)] pub struct Environment { environment_vars: Option,