diff options
author | Jed Fox <git@twopointzero.us> | 2019-10-02 11:55:28 -0400 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2019-10-02 11:55:28 -0400 |
commit | 99eec73b4b8813c6db7cae83f5415b031de0c2c7 (patch) | |
tree | 2a64e8dd3a7ae7fc097e14bba432d71193c39c6f /js | |
parent | c920c5f62aba7eee0f6fa70f68f701e204ac1a9c (diff) |
feat: Add support for passing a key to Deno.env() (#2952)
This adds a new op to get a single env var.
Diffstat (limited to 'js')
-rw-r--r-- | js/dispatch.ts | 1 | ||||
-rw-r--r-- | js/lib.deno_runtime.d.ts | 10 | ||||
-rw-r--r-- | js/os.ts | 14 | ||||
-rw-r--r-- | js/os_test.ts | 91 |
4 files changed, 108 insertions, 8 deletions
diff --git a/js/dispatch.ts b/js/dispatch.ts index 67c831e09..7f30707a7 100644 --- a/js/dispatch.ts +++ b/js/dispatch.ts @@ -11,6 +11,7 @@ export let OP_ENV: number; export let OP_EXEC_PATH: number; export let OP_UTIME: number; export let OP_SET_ENV: number; +export let OP_GET_ENV: number; export let OP_HOME_DIR: number; export let OP_START: number; export let OP_APPLY_SOURCE_MAP: number; diff --git a/js/lib.deno_runtime.d.ts b/js/lib.deno_runtime.d.ts index d0a720769..780503106 100644 --- a/js/lib.deno_runtime.d.ts +++ b/js/lib.deno_runtime.d.ts @@ -44,6 +44,16 @@ declare namespace Deno { export function env(): { [index: string]: string; }; + /** Returns the value of an environment variable at invocation. + * If the variable is not present, `undefined` will be returned. + * + * const myEnv = Deno.env(); + * console.log(myEnv.SHELL); + * myEnv.TEST_VAR = "HELLO"; + * const newEnv = Deno.env(); + * console.log(myEnv.TEST_VAR == newEnv.TEST_VAR); + */ + export function env(key: string): string | undefined; /** * Returns the current user's home directory. * Requires the `--allow-env` flag. @@ -37,18 +37,30 @@ function setEnv(key: string, value: string): void { sendSync(dispatch.OP_SET_ENV, { key, value }); } +function getEnv(key: string): string | undefined { + return sendSync(dispatch.OP_GET_ENV, { key })[0]; +} + /** Returns a snapshot of the environment variables at invocation. Mutating a * property in the object will set that variable in the environment for * the process. The environment object will only accept `string`s * as values. * + * console.log(Deno.env("SHELL")); * const myEnv = Deno.env(); * console.log(myEnv.SHELL); * myEnv.TEST_VAR = "HELLO"; * const newEnv = Deno.env(); * console.log(myEnv.TEST_VAR == newEnv.TEST_VAR); */ -export function env(): { [index: string]: string } { +export function env(): { [index: string]: string }; +export function env(key: string): string | undefined; +export function env( + key?: string +): { [index: string]: string } | string | undefined { + if (key) { + return getEnv(key); + } const env = sendSync(dispatch.OP_ENV); return new Proxy(env, { set(obj, prop: string, value: string): boolean { diff --git a/js/os_test.ts b/js/os_test.ts index ad3772631..0d07df1b4 100644 --- a/js/os_test.ts +++ b/js/os_test.ts @@ -14,21 +14,98 @@ testPerm({ env: true }, function envSuccess(): void { env.test_var = "Hello World"; const newEnv = Deno.env(); assertEquals(env.test_var, newEnv.test_var); + assertEquals(Deno.env("test_var"), env.test_var); }); -test(function envFailure(): void { - let caughtError = false; +testPerm({ env: true }, function envNotFound(): void { + const r = Deno.env("env_var_does_not_exist!"); + assertEquals(r, undefined); +}); + +test(function envPermissionDenied1(): void { + let err; try { Deno.env(); - } catch (err) { - caughtError = true; - assertEquals(err.kind, Deno.ErrorKind.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); + } catch (e) { + err = e; } + assertNotEquals(err, undefined); + assertEquals(err.kind, Deno.ErrorKind.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); - assert(caughtError); +test(function envPermissionDenied2(): void { + let err; + try { + Deno.env("PATH"); + } catch (e) { + err = e; + } + assertNotEquals(err, undefined); + assertEquals(err.kind, Deno.ErrorKind.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); }); +if (Deno.build.os === "win") { + // This test verifies that on Windows, environment variables are + // case-insensitive. Case normalization needs be done using the collation + // that Windows uses, rather than naively using String.toLowerCase(). + testPerm({ env: true, run: true }, async function envCaseInsensitive() { + // Utility function that runs a Deno subprocess with the environment + // specified in `inputEnv`. The subprocess reads the environment variables + // which are in the keys of `expectedEnv` and writes them to stdout as JSON. + // It is then verified that these match with the values of `expectedEnv`. + const checkChildEnv = async (inputEnv, expectedEnv): Promise<void> => { + const src = ` + console.log( + ${JSON.stringify(Object.keys(expectedEnv))}.map(k => Deno.env(k)) + )`; + const proc = Deno.run({ + args: [Deno.execPath(), "eval", src], + env: inputEnv, + stdout: "piped" + }); + const status = await proc.status(); + assertEquals(status.success, true); + const expectedValues = Object.values(expectedEnv); + const actualValues = JSON.parse( + new TextDecoder().decode(await proc.output()) + ); + assertEquals(actualValues, expectedValues); + }; + + assertEquals(Deno.env("path"), Deno.env("PATH")); + assertEquals(Deno.env("Path"), Deno.env("PATH")); + + // Check 'foo', 'Foo' and 'Foo' are case folded. + await checkChildEnv({ foo: "X" }, { foo: "X", Foo: "X", FOO: "X" }); + + // Check that 'µ' and 'Μ' are not case folded. + const lc1 = "µ"; + const uc1 = lc1.toUpperCase(); + assertNotEquals(lc1, uc1); + await checkChildEnv( + { [lc1]: "mu", [uc1]: "MU" }, + { [lc1]: "mu", [uc1]: "MU" } + ); + + // Check that 'dž' and 'DŽ' are folded, but 'Dž' is preserved. + const c2 = "Dž"; + const lc2 = c2.toLowerCase(); + const uc2 = c2.toUpperCase(); + assertNotEquals(c2, lc2); + assertNotEquals(c2, uc2); + await checkChildEnv( + { [c2]: "Dz", [lc2]: "dz" }, + { [c2]: "Dz", [lc2]: "dz", [uc2]: "dz" } + ); + await checkChildEnv( + { [c2]: "Dz", [uc2]: "DZ" }, + { [c2]: "Dz", [uc2]: "DZ", [lc2]: "DZ" } + ); + }); +} + test(function osPid(): void { console.log("pid", Deno.pid); assert(Deno.pid > 0); |