From e11b400a752ae956f755d8c3803fdbcb9f649f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Thu, 19 Aug 2021 10:06:18 +0300 Subject: [PATCH] Allow `source` to accept paths with emojis (#3939) * Allow sourcing paths with emojis * Add source command tests for emoji paths * Fmt * Disable source tests on Windows with illegal paths * Test sourcing also ASCII and single-quoted paths --- crates/nu-command/tests/commands/mod.rs | 1 + crates/nu-command/tests/commands/source.rs | 95 ++++++++++++++++++++++ crates/nu-parser/src/parse.rs | 17 +++- 3 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 crates/nu-command/tests/commands/source.rs diff --git a/crates/nu-command/tests/commands/mod.rs b/crates/nu-command/tests/commands/mod.rs index 4f7a604fa6..6952da7645 100644 --- a/crates/nu-command/tests/commands/mod.rs +++ b/crates/nu-command/tests/commands/mod.rs @@ -52,6 +52,7 @@ mod select; mod semicolon; mod skip; mod sort_by; +mod source; mod split_by; mod split_column; mod split_row; diff --git a/crates/nu-command/tests/commands/source.rs b/crates/nu-command/tests/commands/source.rs new file mode 100644 index 0000000000..d67d3aae80 --- /dev/null +++ b/crates/nu-command/tests/commands/source.rs @@ -0,0 +1,95 @@ +use nu_test_support::fs::Stub::FileWithContent; +use nu_test_support::nu; +use nu_test_support::playground::Playground; + +fn try_source_foo_with_double_quotes_in(testdir: &str, playdir: &str) { + Playground::setup(playdir, |dirs, sandbox| { + let testdir = String::from(testdir); + let mut foo_file = testdir.clone(); + foo_file.push_str("/foo.nu"); + + sandbox.mkdir(&testdir); + sandbox.with_files(vec![FileWithContent(&foo_file, "echo foo")]); + + let cmd = String::from("source ") + r#"""# + &foo_file + r#"""#; + + let actual = nu!(cwd: dirs.test(), &cmd); + + assert_eq!(actual.out, "foo"); + }); +} + +fn try_source_foo_with_single_quotes_in(testdir: &str, playdir: &str) { + Playground::setup(playdir, |dirs, sandbox| { + let testdir = String::from(testdir); + let mut foo_file = testdir.clone(); + foo_file.push_str("/foo.nu"); + + sandbox.mkdir(&testdir); + sandbox.with_files(vec![FileWithContent(&foo_file, "echo foo")]); + + let cmd = String::from("source ") + r#"'"# + &foo_file + r#"'"#; + + let actual = nu!(cwd: dirs.test(), &cmd); + + assert_eq!(actual.out, "foo"); + }); +} + +fn try_source_foo_without_quotes_in(testdir: &str, playdir: &str) { + Playground::setup(playdir, |dirs, sandbox| { + let testdir = String::from(testdir); + let mut foo_file = testdir.clone(); + foo_file.push_str("/foo.nu"); + + sandbox.mkdir(&testdir); + sandbox.with_files(vec![FileWithContent(&foo_file, "echo foo")]); + + let cmd = String::from("source ") + &foo_file; + + let actual = nu!(cwd: dirs.test(), &cmd); + + assert_eq!(actual.out, "foo"); + }); +} + +#[test] +fn sources_unicode_file_in_normal_dir() { + try_source_foo_with_single_quotes_in("foo", "source_test_1"); + try_source_foo_with_double_quotes_in("foo", "source_test_2"); + try_source_foo_without_quotes_in("foo", "source_test_3"); +} + +#[test] +fn sources_unicode_file_in_unicode_dir_without_spaces_1() { + try_source_foo_with_single_quotes_in("πŸš’", "source_test_4"); + try_source_foo_with_double_quotes_in("πŸš’", "source_test_5"); + try_source_foo_without_quotes_in("πŸš’", "source_test_6"); +} + +#[cfg(not(windows))] // ':' is not allowed in Windows paths +#[test] +fn sources_unicode_file_in_unicode_dir_without_spaces_2() { + try_source_foo_with_single_quotes_in(":fire_engine:", "source_test_7"); + try_source_foo_with_double_quotes_in(":fire_engine:", "source_test_8"); + try_source_foo_without_quotes_in(":fire_engine:", "source_test_9"); +} + +#[test] +fn sources_unicode_file_in_unicode_dir_with_spaces_1() { + try_source_foo_with_single_quotes_in("e-$ Γ¨Ρ€Ρ‚πŸš’β™žδΈ­η‰‡-j", "source_test_8"); + try_source_foo_with_double_quotes_in("e-$ Γ¨Ρ€Ρ‚πŸš’β™žδΈ­η‰‡-j", "source_test_9"); +} + +#[cfg(not(windows))] // ':' is not allowed in Windows paths +#[test] +fn sources_unicode_file_in_unicode_dir_with_spaces_2() { + try_source_foo_with_single_quotes_in("e-$ Γ¨Ρ€Ρ‚:fire_engine:β™žδΈ­η‰‡-j", "source_test_10"); + try_source_foo_with_double_quotes_in("e-$ Γ¨Ρ€Ρ‚:fire_engine:β™žδΈ­η‰‡-j", "source_test_11"); +} + +#[ignore] +#[test] +fn sources_unicode_file_in_non_utf8_dir() { + // How do I create non-UTF-8 path??? +} diff --git a/crates/nu-parser/src/parse.rs b/crates/nu-parser/src/parse.rs index f12340349e..ac3c2ec336 100644 --- a/crates/nu-parser/src/parse.rs +++ b/crates/nu-parser/src/parse.rs @@ -1889,9 +1889,20 @@ fn parse_call( )), ); } - if let Ok(contents) = std::fs::read_to_string(&expand_path(Cow::Borrowed(Path::new( - &lite_cmd.parts[1].item, - )))) { + + let script_path = if let Some(ref positional_args) = internal_command.args.positional { + if let Expression::FilePath(ref p) = positional_args[0].expr { + p + } else { + Path::new(&lite_cmd.parts[1].item) + } + } else { + Path::new(&lite_cmd.parts[1].item) + }; + + if let Ok(contents) = + std::fs::read_to_string(&expand_path(Cow::Borrowed(Path::new(script_path)))) + { let _ = parse(&contents, 0, scope); } else { return (