diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 83c7270350..a6772b55fe 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -986,7 +986,15 @@ pub fn build( // ManuallyDrop will leak the bytes because we don't drop manually let bytes = &ManuallyDrop::new(std::fs::read(&binary_path).unwrap()); - roc_run(&arena, opt_level, target, args, bytes, expect_metadata) + roc_run( + &arena, + path, + opt_level, + target, + args, + bytes, + expect_metadata, + ) } BuildAndRunIfNoErrors => { if problems.fatally_errored { @@ -1021,7 +1029,15 @@ pub fn build( // ManuallyDrop will leak the bytes because we don't drop manually let bytes = &ManuallyDrop::new(std::fs::read(&binary_path).unwrap()); - roc_run(&arena, opt_level, target, args, bytes, expect_metadata) + roc_run( + &arena, + path, + opt_level, + target, + args, + bytes, + expect_metadata, + ) } } } @@ -1034,6 +1050,7 @@ pub fn build( fn roc_run<'a, I: IntoIterator>( arena: &Bump, + script_path: &Path, opt_level: OptLevel, target: Target, args: I, @@ -1073,7 +1090,14 @@ fn roc_run<'a, I: IntoIterator>( Ok(0) } - _ => roc_run_native(arena, opt_level, args, binary_bytes, expect_metadata), + _ => roc_run_native( + arena, + script_path, + opt_level, + args, + binary_bytes, + expect_metadata, + ), } } @@ -1090,7 +1114,7 @@ fn os_str_as_utf8_bytes(os_str: &OsStr) -> &[u8] { fn make_argv_envp<'a, I: IntoIterator, S: AsRef>( arena: &'a Bump, - executable: &ExecutableFile, + script_path: &Path, args: I, ) -> ( bumpalo::collections::Vec<'a, CString>, @@ -1098,8 +1122,7 @@ fn make_argv_envp<'a, I: IntoIterator, S: AsRef>( ) { use bumpalo::collections::CollectIn; - let path = executable.as_path(); - let path_cstring = CString::new(os_str_as_utf8_bytes(path.as_os_str())).unwrap(); + let path_cstring = CString::new(os_str_as_utf8_bytes(script_path.as_os_str())).unwrap(); // argv is an array of pointers to strings passed to the new program // as its command-line arguments. By convention, the first of these @@ -1137,6 +1160,7 @@ fn make_argv_envp<'a, I: IntoIterator, S: AsRef>( #[cfg(target_family = "unix")] fn roc_run_native, S: AsRef>( arena: &Bump, + script_path: &Path, opt_level: OptLevel, args: I, binary_bytes: &[u8], @@ -1145,7 +1169,7 @@ fn roc_run_native, S: AsRef>( use bumpalo::collections::CollectIn; let executable = roc_run_executable_file_path(binary_bytes)?; - let (argv_cstrings, envp_cstrings) = make_argv_envp(arena, &executable, args); + let (argv_cstrings, envp_cstrings) = make_argv_envp(arena, script_path, args); let argv: bumpalo::collections::Vec<*const c_char> = argv_cstrings .iter() @@ -1400,6 +1424,7 @@ fn roc_run_executable_file_path(binary_bytes: &[u8]) -> std::io::Result, S: AsRef>( arena: &Bump, // This should be passed an owned value, not a reference, so we can usefully mem::forget it! + script_path: &Path, opt_level: OptLevel, args: I, binary_bytes: &[u8], @@ -1411,7 +1436,7 @@ fn roc_run_native, S: AsRef>( let executable = roc_run_executable_file_path(binary_bytes)?; // TODO forward the arguments - let (argv_cstrings, envp_cstrings) = make_argv_envp(&arena, &executable, args); + let (argv_cstrings, envp_cstrings) = make_argv_envp(&arena, script_path, args); let argv: bumpalo::collections::Vec<*const c_char> = argv_cstrings .iter() diff --git a/crates/cli/tests/cli/argv0.roc b/crates/cli/tests/cli/argv0.roc new file mode 100644 index 0000000000..7cf397352d --- /dev/null +++ b/crates/cli/tests/cli/argv0.roc @@ -0,0 +1,12 @@ +app [main] { + pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br", +} + +import pf.Stdout +import pf.Arg + +main = + args = Arg.list! {} + when List.first args is + Ok argv0 -> Stdout.line argv0 + Err ListWasEmpty -> Stdout.line "Failed: argv was empty" diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 80526c2c3a..6f440420ee 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -305,7 +305,7 @@ mod cli_run { } }; - let self_path = file.display().to_string(); + let self_path = file.parent().unwrap().display().to_string(); let actual_cmd_stdout = ignore_test_timings(&strip_colors(&cmd_output.stdout)) .replace(&self_path, ""); @@ -573,12 +573,12 @@ mod cli_run { words : List Str words = ["this", "will", "for", "sure", "be", "a", "large", "string", "so", "when", "we", "split", "it", "it", "will", "use", "seamless", "slices", "which", "affect", "printing"] - [:31] x = 42 - [:33] "Fjoer en ferdjer frieten oan dyn geve lea" = "Fjoer en ferdjer frieten oan dyn geve lea" - [:35] "this is line 24" = "this is line 24" - [:21] x = "abc" - [:21] x = 10 - [:21] x = (A (B C)) + [/expects.roc:31] x = 42 + [/expects.roc:33] "Fjoer en ferdjer frieten oan dyn geve lea" = "Fjoer en ferdjer frieten oan dyn geve lea" + [/expects.roc:35] "this is line 24" = "this is line 24" + [/expects.roc:21] x = "abc" + [/expects.roc:21] x = 10 + [/expects.roc:21] x = (A (B C)) Program finished! "# ), @@ -1203,6 +1203,22 @@ mod cli_run { ) } + #[test] + #[serial(cli_platform)] + #[cfg_attr(windows, ignore)] + fn argv0() { + test_roc_app( + "crates/cli/tests/cli", + "argv0.roc", + &[], + &[], + &[], + "/argv0.roc\n", + UseValgrind::No, + TestCliCommands::Run, + ) + } + #[test] #[serial(cli_platform)] #[cfg_attr(windows, ignore)]