diff --git a/cli/msg.fbs b/cli/msg.fbs index 438fa0cb901bb..8fb92fee9f01c 100644 --- a/cli/msg.fbs +++ b/cli/msg.fbs @@ -77,6 +77,8 @@ union Any { Truncate, HomeDir, HomeDirRes, + ExecPath, + ExecPathRes, Utime, WorkerGetMessage, WorkerGetMessageRes, @@ -181,7 +183,6 @@ table StartRes { cwd: string; pid: uint32; argv: [string]; - exec_path: string; main_module: string; // Absolute URL. debug_flag: bool; deps_flag: bool; @@ -468,6 +469,12 @@ table HomeDirRes { path: string; } +table ExecPath {} + +table ExecPathRes { + path: string; +} + table Utime { filename: string; atime: uint64; diff --git a/cli/ops.rs b/cli/ops.rs index 6f98c82bc0d9c..98528f9795253 100644 --- a/cli/ops.rs +++ b/cli/ops.rs @@ -212,6 +212,7 @@ pub fn op_selector_std(inner_type: msg::Any) -> Option { msg::Any::Cwd => Some(op_cwd), msg::Any::Dial => Some(op_dial), msg::Any::Environ => Some(op_env), + msg::Any::ExecPath => Some(op_exec_path), msg::Any::Exit => Some(op_exit), msg::Any::Fetch => Some(op_fetch), msg::Any::FetchSourceFile => Some(op_fetch_source_file), @@ -354,18 +355,6 @@ fn op_start( let cwd_off = builder.create_string(deno_fs::normalize_path(cwd_path.as_ref()).as_ref()); - // Use permissions.allows_env() to bypass env request prompt. - let exec_path = if state.permissions.allows_env() { - let current_exe = std::env::current_exe().unwrap(); - // Now apply URL parser to current exe to get fully resolved path, otherwise we might get - // `./` and `../` bits in `exec_path` - let exe_url = Url::from_file_path(current_exe).unwrap(); - exe_url.to_file_path().unwrap().to_str().unwrap().to_owned() - } else { - "".to_owned() - }; - let exec_path = builder.create_string(&exec_path); - let v8_version = version::v8(); let v8_version_off = builder.create_string(v8_version); @@ -399,7 +388,6 @@ fn op_start( v8_version: Some(v8_version_off), deno_version: Some(deno_version_off), no_color: !ansi::use_color(), - exec_path: Some(exec_path), xeval_delim, ..Default::default() }, @@ -1787,6 +1775,36 @@ fn op_home_dir( )) } +fn op_exec_path( + state: &ThreadSafeState, + base: &msg::Base<'_>, + data: Option, +) -> CliOpResult { + assert!(data.is_none()); + let cmd_id = base.cmd_id(); + + state.check_env()?; + + let builder = &mut FlatBufferBuilder::new(); + let current_exe = std::env::current_exe().unwrap(); + // Now apply URL parser to current exe to get fully resolved path, otherwise we might get + // `./` and `../` bits in `exec_path` + let exe_url = Url::from_file_path(current_exe).unwrap(); + let path = exe_url.to_file_path().unwrap().to_str().unwrap().to_owned(); + let path = Some(builder.create_string(&path)); + let inner = msg::ExecPathRes::create(builder, &msg::ExecPathResArgs { path }); + + ok_buf(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + inner: Some(inner.as_union_value()), + inner_type: msg::Any::ExecPathRes, + ..Default::default() + }, + )) +} + fn op_resources( _state: &ThreadSafeState, base: &msg::Base<'_>, diff --git a/js/os.ts b/js/os.ts index 551cb1ea6b053..11407cfb08ae8 100644 --- a/js/os.ts +++ b/js/os.ts @@ -13,16 +13,10 @@ export let pid: number; /** Reflects the NO_COLOR environment variable: https://no-color.org/ */ export let noColor: boolean; -/** Path to the current deno process's executable file. - * Requires the `--allow-env` flag, otherwise it'll be set to an empty `string`. - */ -export let execPath: string; - -function setGlobals(pid_: number, noColor_: boolean, execPath_: string): void { +function setGlobals(pid_: number, noColor_: boolean): void { assert(!pid); pid = pid_; noColor = noColor_; - execPath = execPath_; } /** Check if running in terminal. @@ -127,7 +121,7 @@ export function start( util.setLogDebug(startResMsg.debugFlag(), source); - setGlobals(startResMsg.pid(), startResMsg.noColor(), startResMsg.execPath()!); + setGlobals(startResMsg.pid(), startResMsg.noColor()); if (preserveDenoNamespace) { util.immutableDefine(window, "Deno", window.Deno); @@ -164,3 +158,19 @@ export function homeDir(): string { return path; } + +export function execPath(): string { + const builder = flatbuffers.createBuilder(); + const inner = msg.ExecPath.createExecPath(builder); + const baseRes = sendSync(builder, msg.Any.ExecPath, inner)!; + assert(msg.Any.ExecPathRes === baseRes.innerType()); + const res = new msg.ExecPathRes(); + assert(baseRes.inner(res) != null); + const path = res.path(); + + if (!path) { + throw new Error("Could not get home directory."); + } + + return path; +} diff --git a/js/os_test.ts b/js/os_test.ts index b2f511b5e55ae..28c8b6a0bec6c 100644 --- a/js/os_test.ts +++ b/js/os_test.ts @@ -56,9 +56,17 @@ testPerm({ env: false }, function homeDirPerm(): void { }); testPerm({ env: true }, function execPath(): void { - assertNotEquals(Deno.execPath, ""); + assertNotEquals(Deno.execPath(), ""); }); testPerm({ env: false }, function execPathPerm(): void { - assertEquals(Deno.execPath, ""); + let caughtError = false; + try { + Deno.execPath(); + } catch (err) { + caughtError = true; + assertEquals(err.kind, Deno.ErrorKind.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } + assert(caughtError); }); diff --git a/js/unit_test_runner.ts b/js/unit_test_runner.ts index 55ccd14bf7175..24dae7706eb87 100755 --- a/js/unit_test_runner.ts +++ b/js/unit_test_runner.ts @@ -53,7 +53,7 @@ async function main(): Promise { const cliPerms = permsToCliFlags(perms); // run subsequent tests using same deno executable const args = [ - Deno.execPath, + Deno.execPath(), "run", "--no-prompt", ...cliPerms, diff --git a/tests/exec_path.ts b/tests/exec_path.ts index f09663d7e4bcd..b70b232377b7a 100644 --- a/tests/exec_path.ts +++ b/tests/exec_path.ts @@ -1 +1 @@ -console.log(Deno.execPath); +console.log(Deno.execPath());