Fix #3231: Pick up nu-env if cd with shortcuts (#3344)

* Fix autoenv not set when using implied cd

* Fix wrong return value

* Fix windows no value returned err
This commit is contained in:
Leonhard Kipp 2021-04-28 07:31:22 +02:00 committed by GitHub
parent 36cc5eb933
commit d05c48a1d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 131 additions and 36 deletions

View File

@ -1,4 +1,7 @@
use crate::{maybe_print_errors, path::canonicalize, run_block}; use crate::{
evaluate::internal::InternalIterator, maybe_print_errors, path::canonicalize, run_block,
shell::CdArgs,
};
use crate::{BufCodecReader, MaybeTextCodec, StringOrBinary}; use crate::{BufCodecReader, MaybeTextCodec, StringOrBinary};
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::hir::{ use nu_protocol::hir::{
@ -10,8 +13,8 @@ use nu_stream::{InputStream, ToInputStream};
use crate::EvaluationContext; use crate::EvaluationContext;
use log::{debug, trace}; use log::{debug, trace};
use nu_source::{Span, Tag, Text}; use nu_source::{AnchorLocation, Span, Tag, Tagged, Text};
use std::path::Path; use std::path::{Path, PathBuf};
use std::{error::Error, sync::atomic::Ordering}; use std::{error::Error, sync::atomic::Ordering};
use std::{io::BufReader, iter::Iterator}; use std::{io::BufReader, iter::Iterator};
@ -83,7 +86,9 @@ pub fn process_script(
&& block.block[0].pipelines[0].list.len() == 1 && block.block[0].pipelines[0].list.len() == 1
{ {
if let ClassifiedCommand::Internal(InternalCommand { if let ClassifiedCommand::Internal(InternalCommand {
ref name, ref args, .. ref name,
ref args,
name_span,
}) = block.block[0].pipelines[0].list[0] }) = block.block[0].pipelines[0].list[0]
{ {
let internal_name = name; let internal_name = name;
@ -117,44 +122,67 @@ pub fn process_script(
&& Path::new(&name).is_dir() && Path::new(&name).is_dir()
&& !ctx.host.lock().is_external_cmd(&name) && !ctx.host.lock().is_external_cmd(&name)
{ {
// Here we work differently if we're in Windows because of the expected Windows behavior let tag = Tag {
#[cfg(windows)] anchor: Some(AnchorLocation::Source(line.into())),
{ span: name_span,
if name.ends_with(':') { };
// This looks like a drive shortcut. We need to a) switch drives and b) go back to the previous directory we were viewing on that drive let path = {
// But first, we need to save where we are now // Here we work differently if we're in Windows because of the expected Windows behavior
let current_path = ctx.shell_manager.path(); #[cfg(windows)]
{
if name.ends_with(':') {
// This looks like a drive shortcut. We need to a) switch drives and b) go back to the previous directory we were viewing on that drive
// But first, we need to save where we are now
let current_path = ctx.shell_manager.path();
let split_path: Vec<_> = current_path.split(':').collect(); let split_path: Vec<_> = current_path.split(':').collect();
if split_path.len() > 1 { if split_path.len() > 1 {
ctx.windows_drives_previous_cwd ctx.windows_drives_previous_cwd
.lock() .lock()
.insert(split_path[0].to_string(), current_path); .insert(split_path[0].to_string(), current_path);
} }
let name = name.to_uppercase(); let name = name.to_uppercase();
let new_drive: Vec<_> = name.split(':').collect(); let new_drive: Vec<_> = name.split(':').collect();
if let Some(val) = if let Some(val) =
ctx.windows_drives_previous_cwd.lock().get(new_drive[0]) ctx.windows_drives_previous_cwd.lock().get(new_drive[0])
{ {
ctx.shell_manager.set_path(val.to_string()); val.to_string()
return LineResult::Success(line.to_string()); } else {
format!("{}\\", name.to_string())
}
} else { } else {
ctx.shell_manager name.to_string()
.set_path(format!("{}\\", name.to_string()));
return LineResult::Success(line.to_string());
} }
} else {
ctx.shell_manager.set_path(name.to_string());
return LineResult::Success(line.to_string());
} }
} #[cfg(not(windows))]
#[cfg(not(windows))] {
{ name.to_string()
ctx.shell_manager.set_path(name.to_string()); }
return LineResult::Success(line.to_string()); };
}
let cd_args = CdArgs {
path: Some(Tagged {
item: PathBuf::from(path),
tag: tag.clone(),
}),
};
return match ctx.shell_manager.cd(cd_args, tag) {
Err(e) => LineResult::Error(line.to_string(), e),
Ok(stream) => {
let iter = InternalIterator {
context: ctx.clone(),
leftovers: InputStream::empty(),
input: stream,
};
for _ in iter {
//nullopt, commands are run by iterating over iter
}
LineResult::Success(line.to_string())
}
};
} }
} }
} }

View File

@ -35,6 +35,73 @@ fn picks_up_env_keys_when_entering_trusted_directory() {
}) })
} }
#[cfg(feature = "directories-support")]
#[cfg(feature = "which-support")]
#[test]
#[serial]
fn picks_up_and_lets_go_env_keys_when_entering_trusted_directory_with_implied_cd() {
use nu_test_support::fs::Stub::FileWithContent;
Playground::setup("autoenv_test", |dirs, sandbox| {
sandbox.mkdir("foo");
sandbox.mkdir("foo/bar");
sandbox.with_files(vec![
FileWithContent(
"foo/.nu-env",
r#"[env]
testkey = "testvalue"
"#,
),
FileWithContent(
"foo/bar/.nu-env",
r#"
[env]
bar = "true"
"#,
),
]);
let actual = nu!(
cwd: dirs.test(),
r#"
do {autoenv trust foo ; = $nothing }
foo
echo $nu.env.testkey"#
);
assert_eq!(actual.out, "testvalue");
//Assert testkey is gone when leaving foo
let actual = nu!(
cwd: dirs.test(),
r#"
do {autoenv trust foo; = $nothing } ;
foo
..
echo $nu.env.testkey
"#
);
assert!(actual.err.contains("Unknown"));
//Assert testkey is present also when jumping over foo
let actual = nu!(
cwd: dirs.test(),
r#"
do {autoenv trust foo; = $nothing } ;
do {autoenv trust foo/bar; = $nothing } ;
foo/bar
echo $nu.env.testkey
echo $nu.env.bar
"#
);
assert_eq!(actual.out, "testvaluetrue");
//Assert bar removed after leaving bar
let actual = nu!(
cwd: dirs.test(),
r#"autoenv trust foo;
foo/bar
../..
echo $nu.env.bar"#
);
assert!(actual.err.contains("Unknown"));
});
}
#[test] #[test]
#[serial] #[serial]
#[ignore] #[ignore]