mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 09:25:38 +02:00
Fix autoenv executing scripts multiple times (#2171)
* Fix autoenv executing scripts multiple times Previously, if the user had only specified entry or exitscripts the scripts would execute many times. This should be fixed now * Add tests * Run exitscripts * More tests and fixes to existing tests * Test solution with visited dirs * Track visited directories * Comments and fmt
This commit is contained in:
@ -20,6 +20,9 @@ pub struct DirectorySpecificEnvironment {
|
||||
//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.
|
||||
//If setting the var overwrote some value, we save the old value in an option so we can restore it later.
|
||||
added_vars: IndexMap<PathBuf, IndexMap<EnvKey, Option<EnvVal>>>,
|
||||
|
||||
//We track directories that we have read .nu-env from. This is different from the keys in added_vars since sometimes a file only wants to run scripts.
|
||||
visited_dirs: IndexSet<PathBuf>,
|
||||
exitscripts: IndexMap<PathBuf, Vec<String>>,
|
||||
}
|
||||
|
||||
@ -42,6 +45,7 @@ impl DirectorySpecificEnvironment {
|
||||
DirectorySpecificEnvironment {
|
||||
last_seen_directory: root_dir,
|
||||
added_vars: IndexMap::new(),
|
||||
visited_dirs: IndexSet::new(),
|
||||
exitscripts: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
@ -75,13 +79,15 @@ impl DirectorySpecificEnvironment {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
//We track which keys we set as we go up the directory hierarchy, so that we don't overwrite a value we set in a subdir.
|
||||
let mut added_keys = IndexSet::new();
|
||||
|
||||
//We note which directories we pass so we can clear unvisited dirs later.
|
||||
let mut seen_directories = IndexSet::new();
|
||||
|
||||
//Add all .nu-envs until we reach a dir which we have already added, or we reached the root.
|
||||
let mut popped = true;
|
||||
while !self.added_vars.contains_key(&dir) && popped {
|
||||
while popped && !self.visited_dirs.contains(&dir) {
|
||||
let nu_env_file = dir.join(".nu-env");
|
||||
if nu_env_file.exists() {
|
||||
let nu_env_doc = self.toml_if_trusted(&nu_env_file)?;
|
||||
@ -92,6 +98,7 @@ impl DirectorySpecificEnvironment {
|
||||
self.maybe_add_key(&mut added_keys, &dir, &env_key, &env_val);
|
||||
}
|
||||
}
|
||||
self.visited_dirs.insert(dir.clone());
|
||||
|
||||
//Add variables that need to evaluate scripts to run, from [scriptvars] section
|
||||
if let Some(sv) = nu_env_doc.scriptvars {
|
||||
@ -132,13 +139,30 @@ impl DirectorySpecificEnvironment {
|
||||
std::env::remove_var(k);
|
||||
}
|
||||
}
|
||||
if let Some(es) = self.exitscripts.get(&dir) {
|
||||
for s in es {
|
||||
run(s.as_str())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_visited = IndexSet::new();
|
||||
for dir in self.visited_dirs.drain(..) {
|
||||
if seen_directories.contains(&dir) {
|
||||
new_visited.insert(dir);
|
||||
}
|
||||
}
|
||||
|
||||
//Run exitscripts, can not be done in same loop as new vars as some files can contain only exitscripts
|
||||
let mut new_exitscripts = IndexMap::new();
|
||||
for (dir, scripts) in self.exitscripts.drain(..) {
|
||||
if seen_directories.contains(&dir) {
|
||||
new_exitscripts.insert(dir, scripts);
|
||||
} else {
|
||||
for s in scripts {
|
||||
run(s.as_str())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.visited_dirs = new_visited;
|
||||
self.exitscripts = new_exitscripts;
|
||||
self.added_vars = new_vars;
|
||||
self.last_seen_directory = current_dir()?;
|
||||
Ok(())
|
||||
|
Reference in New Issue
Block a user