1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

Implemented deno.env and refactored flags.rs

This commit is contained in:
Aaron Power 2018-08-31 12:51:12 +01:00 committed by Ryan Dahl
parent 45dafe15ee
commit f131445a46
8 changed files with 206 additions and 46 deletions

View file

@ -1,6 +1,7 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license. // Copyright 2018 the Deno authors. All rights reserved. MIT license.
// Public deno module. // Public deno module.
export { export {
env,
exit, exit,
FileInfo, FileInfo,
makeTempDirSync, makeTempDirSync,

View file

@ -128,6 +128,64 @@ export function readFileSync(filename: string): Uint8Array {
return new Uint8Array(dataArray!); return new Uint8Array(dataArray!);
} }
function createEnv(_msg: fbs.EnvironRes): { [index:string]: string } {
const env: { [index:string]: string } = {};
for (let i = 0; i < _msg.mapLength(); i++) {
const item = _msg.map(i)!;
env[item.key()!] = item.value()!;
}
return new Proxy(env, {
set(obj, prop: string, value: string | number) {
setEnv(prop, value.toString());
return Reflect.set(obj, prop, value);
}
});
}
function setEnv(key: string, value: string): void {
const builder = new flatbuffers.Builder();
const _key = builder.createString(key);
const _value = builder.createString(value);
fbs.SetEnv.startSetEnv(builder);
fbs.SetEnv.addKey(builder, _key);
fbs.SetEnv.addValue(builder, _value);
const msg = fbs.SetEnv.endSetEnv(builder);
send(builder, fbs.Any.SetEnv, msg);
}
/**
* 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 or `number`s
* as values.
* import { env } from "deno";
* const env = deno.env();
* console.log(env.SHELL)
* env.TEST_VAR = "HELLO";
*
* const newEnv = deno.env();
* console.log(env.TEST_VAR == newEnv.TEST_VAR);
*/
export function env(): { [index:string]: string } {
/* Ideally we could write
const res = send({
command: fbs.Command.ENV,
});
*/
const builder = new flatbuffers.Builder();
fbs.Environ.startEnviron(builder);
const msg = fbs.Environ.endEnviron(builder);
const baseRes = send(builder, fbs.Any.Environ, msg)!;
assert(fbs.Any.EnvironRes === baseRes.msgType());
const res = new fbs.EnvironRes();
assert(baseRes.msg(res) != null);
// TypeScript cannot track assertion above, therefore not null assertion
return createEnv(res);
}
export class FileInfo { export class FileInfo {
private _isFile: boolean; private _isFile: boolean;
private _isSymlink: boolean; private _isSymlink: boolean;

View file

@ -2,6 +2,27 @@
import { test, testPerm, assert, assertEqual } from "./test_util.ts"; import { test, testPerm, assert, assertEqual } from "./test_util.ts";
import * as deno from "deno"; import * as deno from "deno";
testPerm({ env: true }, async function envSuccess() {
const env = deno.env();
assert(env !== null);
env.test_var = "Hello World";
const newEnv = deno.env();
assertEqual(env.test_var, newEnv.test_var);
});
test(async function envFailure() {
let caughtError = false;
try {
const env = deno.env();
} catch (err) {
caughtError = true;
// TODO assert(err instanceof deno.PermissionDenied).
assertEqual(err.name, "deno.PermissionDenied");
}
assert(caughtError);
});
// TODO Add tests for modified, accessed, and created fields once there is a way // TODO Add tests for modified, accessed, and created fields once there is a way
// to create temp files. // to create temp files.
test(async function statSyncSuccess() { test(async function statSyncSuccess() {

View file

@ -17,23 +17,26 @@ testing.setFilter(deno.argv[1]);
interface DenoPermissions { interface DenoPermissions {
write?: boolean; write?: boolean;
net?: boolean; net?: boolean;
env?: boolean;
} }
function permToString(perms: DenoPermissions): string { function permToString(perms: DenoPermissions): string {
const w = perms.write ? 1 : 0; const w = perms.write ? 1 : 0;
const n = perms.net ? 1 : 0; const n = perms.net ? 1 : 0;
return `permW${w}N${n}`; const e = perms.env ? 1 : 0;
return `permW${w}N${n}E${e}`;
} }
function permFromString(s: string): DenoPermissions { function permFromString(s: string): DenoPermissions {
const re = /^permW([01])N([01])$/; const re = /^permW([01])N([01])E([01])$/;
const found = s.match(re); const found = s.match(re);
if (!found) { if (!found) {
throw Error("Not a permission string"); throw Error("Not a permission string");
} }
return { return {
write: Boolean(Number(found[1])), write: Boolean(Number(found[1])),
net: Boolean(Number(found[2])) net: Boolean(Number(found[2])),
env: Boolean(Number(found[3])),
}; };
} }
@ -43,14 +46,16 @@ export function testPerm(perms: DenoPermissions, fn: testing.TestFunction) {
} }
export function test(fn: testing.TestFunction) { export function test(fn: testing.TestFunction) {
testPerm({ write: false, net: false }, fn); testPerm({ write: false, net: false, env: false }, fn);
} }
test(function permSerialization() { test(function permSerialization() {
for (let write of [true, false]) { for (const write of [true, false]) {
for (let net of [true, false]) { for (const net of [true, false]) {
let perms: DenoPermissions = { write, net }; for (const env of [true, false]) {
testing.assertEqual(perms, permFromString(permToString(perms))); const perms: DenoPermissions = { write, net, env };
testing.assertEqual(perms, permFromString(permToString(perms)));
}
} }
} }
}); });

View file

@ -11,7 +11,7 @@ macro_rules! svec {
($($x:expr),*) => (vec![$($x.to_string()),*]); ($($x:expr),*) => (vec![$($x.to_string()),*]);
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Default)]
pub struct DenoFlags { pub struct DenoFlags {
pub help: bool, pub help: bool,
pub log_debug: bool, pub log_debug: bool,
@ -19,6 +19,7 @@ pub struct DenoFlags {
pub reload: bool, pub reload: bool,
pub allow_write: bool, pub allow_write: bool,
pub allow_net: bool, pub allow_net: bool,
pub allow_env: bool,
} }
pub fn print_usage() { pub fn print_usage() {
@ -27,6 +28,7 @@ pub fn print_usage() {
--allow-write Allow file system write access. --allow-write Allow file system write access.
--allow-net Allow network access. --allow-net Allow network access.
--allow-env Allow environment access.
-v or --version Print the version. -v or --version Print the version.
-r or --reload Reload cached remote resources. -r or --reload Reload cached remote resources.
-D or --log-debug Log debug output. -D or --log-debug Log debug output.
@ -37,14 +39,7 @@ pub fn print_usage() {
// Parses flags for deno. This does not do v8_set_flags() - call that separately. // Parses flags for deno. This does not do v8_set_flags() - call that separately.
pub fn set_flags(args: Vec<String>) -> (DenoFlags, Vec<String>) { pub fn set_flags(args: Vec<String>) -> (DenoFlags, Vec<String>) {
let mut flags = DenoFlags { let mut flags = DenoFlags::default();
help: false,
version: false,
reload: false,
log_debug: false,
allow_write: false,
allow_net: false,
};
let mut rest = Vec::new(); let mut rest = Vec::new();
for a in &args { for a in &args {
match a.as_str() { match a.as_str() {
@ -52,6 +47,7 @@ pub fn set_flags(args: Vec<String>) -> (DenoFlags, Vec<String>) {
"-D" | "--log-debug" => flags.log_debug = true, "-D" | "--log-debug" => flags.log_debug = true,
"-v" | "--version" => flags.version = true, "-v" | "--version" => flags.version = true,
"-r" | "--reload" => flags.reload = true, "-r" | "--reload" => flags.reload = true,
"--allow-env" => flags.allow_env = true,
"--allow-write" => flags.allow_write = true, "--allow-write" => flags.allow_write = true,
"--allow-net" => flags.allow_net = true, "--allow-net" => flags.allow_net = true,
_ => rest.push(a.clone()), _ => rest.push(a.clone()),
@ -64,15 +60,10 @@ pub fn set_flags(args: Vec<String>) -> (DenoFlags, Vec<String>) {
#[test] #[test]
fn test_set_flags_1() { fn test_set_flags_1() {
let (flags, rest) = set_flags(svec!["deno", "--version"]); let (flags, rest) = set_flags(svec!["deno", "--version"]);
assert!(rest == svec!["deno"]); assert_eq!(rest, svec!["deno"]);
assert!( assert_eq!(flags, DenoFlags {
flags == DenoFlags {
help: false,
log_debug: false,
version: true, version: true,
reload: false, ..DenoFlags::default()
allow_write: false,
allow_net: false,
} }
); );
} }
@ -80,15 +71,11 @@ fn test_set_flags_1() {
#[test] #[test]
fn test_set_flags_2() { fn test_set_flags_2() {
let (flags, rest) = set_flags(svec!["deno", "-r", "-D", "script.ts"]); let (flags, rest) = set_flags(svec!["deno", "-r", "-D", "script.ts"]);
assert!(rest == svec!["deno", "script.ts"]); assert_eq!(rest, svec!["deno", "script.ts"]);
assert!( assert_eq!(flags, DenoFlags {
flags == DenoFlags {
help: false,
log_debug: true, log_debug: true,
version: false,
reload: true, reload: true,
allow_write: false, ..DenoFlags::default()
allow_net: false,
} }
); );
} }
@ -97,15 +84,11 @@ fn test_set_flags_2() {
fn test_set_flags_3() { fn test_set_flags_3() {
let (flags, rest) = let (flags, rest) =
set_flags(svec!["deno", "-r", "script.ts", "--allow-write"]); set_flags(svec!["deno", "-r", "script.ts", "--allow-write"]);
assert!(rest == svec!["deno", "script.ts"]); assert_eq!(rest, svec!["deno", "script.ts"]);
assert!( assert_eq!(flags, DenoFlags {
flags == DenoFlags {
help: false,
log_debug: false,
version: false,
reload: true, reload: true,
allow_write: true, allow_write: true,
allow_net: false, ..DenoFlags::default()
} }
); );
} }
@ -142,13 +125,13 @@ fn parse_core_args(args: Vec<String>) -> (Vec<String>, Vec<String>) {
fn test_parse_core_args_1() { fn test_parse_core_args_1() {
let js_args = let js_args =
parse_core_args(vec!["deno".to_string(), "--v8-options".to_string()]); parse_core_args(vec!["deno".to_string(), "--v8-options".to_string()]);
assert!(js_args == (vec!["deno".to_string(), "--help".to_string()], vec![])); assert_eq!(js_args, (vec!["deno".to_string(), "--help".to_string()], vec![]));
} }
#[test] #[test]
fn test_parse_core_args_2() { fn test_parse_core_args_2() {
let js_args = parse_core_args(vec!["deno".to_string(), "--help".to_string()]); let js_args = parse_core_args(vec!["deno".to_string(), "--help".to_string()]);
assert!(js_args == (vec!["deno".to_string()], vec!["--help".to_string()])); assert_eq!(js_args, (vec!["deno".to_string()], vec!["--help".to_string()]));
} }
// Pass the command line arguments to v8. // Pass the command line arguments to v8.

View file

@ -45,6 +45,7 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) {
let output_code = msg.output_code().unwrap(); let output_code = msg.output_code().unwrap();
handle_code_cache(d, &mut builder, filename, source_code, output_code) handle_code_cache(d, &mut builder, filename, source_code, output_code)
} }
msg::Any::Environ => handle_env(d, &mut builder),
msg::Any::FetchReq => { msg::Any::FetchReq => {
// TODO base.msg_as_FetchReq(); // TODO base.msg_as_FetchReq();
let msg = msg::FetchReq::init_from_table(base.msg().unwrap()); let msg = msg::FetchReq::init_from_table(base.msg().unwrap());
@ -79,6 +80,13 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) {
let filename = msg.filename().unwrap(); let filename = msg.filename().unwrap();
handle_read_file_sync(d, &mut builder, filename) handle_read_file_sync(d, &mut builder, filename)
} }
msg::Any::SetEnv => {
// TODO base.msg_as_SetEnv();
let msg = msg::SetEnv::init_from_table(base.msg().unwrap());
let key = msg.key().unwrap();
let value = msg.value().unwrap();
handle_set_env(d, &mut builder, key, value)
}
msg::Any::StatSync => { msg::Any::StatSync => {
// TODO base.msg_as_StatSync(); // TODO base.msg_as_StatSync();
let msg = msg::StatSync::init_from_table(base.msg().unwrap()); let msg = msg::StatSync::init_from_table(base.msg().unwrap());
@ -244,6 +252,69 @@ fn handle_code_cache(
Ok(null_buf()) // null response indicates success. Ok(null_buf()) // null response indicates success.
} }
fn handle_set_env(
d: *const DenoC,
_builder: &mut FlatBufferBuilder,
key: &str,
value: &str,
) -> HandlerResult {
let deno = from_c(d);
if !deno.flags.allow_env {
let err = std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"allow_env is off.",
);
return Err(err.into());
}
std::env::set_var(key, value);
Ok(null_buf())
}
fn handle_env(
d: *const DenoC,
builder: &mut FlatBufferBuilder,
) -> HandlerResult {
let deno = from_c(d);
if !deno.flags.allow_env {
let err = std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"allow_env is off.",
);
return Err(err.into());
}
let vars: Vec<_> = std::env::vars().map(|(key, value)| {
let key = builder.create_string(&key);
let value = builder.create_string(&value);
msg::EnvPair::create(builder, &msg::EnvPairArgs {
key: Some(key),
value: Some(value),
..Default::default()
})
}).collect();
let tables = builder.create_vector_of_reverse_offsets(&vars);
let msg = msg::EnvironRes::create(
builder,
&msg::EnvironResArgs {
map: Some(tables),
..Default::default()
},
);
Ok(create_msg(
builder,
&msg::BaseArgs {
msg: Some(flatbuffers::Offset::new(msg.value())),
msg_type: msg::Any::EnvironRes,
..Default::default()
},
))
}
fn handle_fetch_req( fn handle_fetch_req(
d: *const DenoC, d: *const DenoC,
_builder: &mut FlatBufferBuilder, _builder: &mut FlatBufferBuilder,

View file

@ -10,6 +10,8 @@ union Any {
TimerStart, TimerStart,
TimerReady, TimerReady,
TimerClear, TimerClear,
Environ,
EnvironRes,
FetchReq, FetchReq,
FetchRes, FetchRes,
MakeTempDir, MakeTempDir,
@ -18,6 +20,7 @@ union Any {
ReadFileSyncRes, ReadFileSyncRes,
StatSync, StatSync,
StatSyncRes, StatSyncRes,
SetEnv,
WriteFileSync, WriteFileSync,
} }
@ -124,6 +127,22 @@ table TimerClear {
id: uint; id: uint;
} }
table Environ {}
table SetEnv {
key: string;
value: string;
}
table EnvironRes {
map: [EnvPair];
}
table EnvPair {
key: string;
value: string;
}
table FetchReq { table FetchReq {
id: uint; id: uint;
url: string; url: string;

View file

@ -10,12 +10,14 @@ import sys
# tests by the special string. permW0N0 means allow-write but not allow-net. # tests by the special string. permW0N0 means allow-write but not allow-net.
# See js/test_util.ts for more details. # See js/test_util.ts for more details.
def unit_tests(deno_exe): def unit_tests(deno_exe):
run([deno_exe, "js/unit_tests.ts", "permW0N0"]) run([deno_exe, "js/unit_tests.ts", "permW0N0E0"])
run([deno_exe, "js/unit_tests.ts", "permW1N0", "--allow-write"]) run([deno_exe, "js/unit_tests.ts", "permW1N0E0", "--allow-write"])
run([deno_exe, "js/unit_tests.ts", "permW0N1", "--allow-net"]) run([deno_exe, "js/unit_tests.ts", "permW0N1E0", "--allow-net"])
run([deno_exe, "js/unit_tests.ts", "permW0N0E1", "--allow-env"])
run([ run([
deno_exe, "js/unit_tests.ts", "permW1N1", "--allow-write", deno_exe, "js/unit_tests.ts", "permW1N1E1", "--allow-write",
"--allow-net" "--allow-net",
"--allow-env",
]) ])