Permalink
Browse files

Add --prefetch flag for deps prefetch without running (#1475)

  • Loading branch information...
kevinkassimo authored and ry committed Jan 15, 2019
1 parent ac6ac50 commit c870cf40823a4900278f8ddf03489338c169878b
Showing with 99 additions and 17 deletions.
  1. +3 −2 libdeno/api.cc
  2. +6 −1 libdeno/binding.cc
  3. +4 −1 libdeno/deno.h
  4. +1 −1 libdeno/internal.h
  5. +27 −5 libdeno/libdeno_test.cc
  6. +5 −0 src/flags.rs
  7. +9 −2 src/isolate.rs
  8. +1 −0 src/libdeno.rs
  9. +3 −1 src/main.rs
  10. +1 −4 tools/integration_tests.py
  11. +35 −0 tools/prefetch_test.py
  12. +3 −0 tools/test.py
  13. +1 −0 tools/util.py
@@ -127,7 +127,7 @@ int deno_execute(Deno* d_, void* user_data, const char* js_filename,
}

int deno_execute_mod(Deno* d_, void* user_data, const char* js_filename,
const char* js_source) {
const char* js_source, int resolve_only) {
auto* d = unwrap(d_);
deno::UserDataScope user_data_scope(d, user_data);
auto* isolate = d->isolate_;
@@ -136,7 +136,8 @@ int deno_execute_mod(Deno* d_, void* user_data, const char* js_filename,
v8::HandleScope handle_scope(isolate);
auto context = d->context_.Get(d->isolate_);
CHECK(!context.IsEmpty());
return deno::ExecuteMod(context, js_filename, js_source) ? 1 : 0;
return deno::ExecuteMod(context, js_filename, js_source, resolve_only) ? 1
: 0;
}

int deno_respond(Deno* d_, void* user_data, int32_t req_id, deno_buf buf) {
@@ -590,7 +590,7 @@ void DenoIsolate::ResolveOk(const char* filename, const char* source) {
}

bool ExecuteMod(v8::Local<v8::Context> context, const char* js_filename,
const char* js_source) {
const char* js_source, bool resolve_only) {
auto* isolate = context->GetIsolate();
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
@@ -616,6 +616,11 @@ bool ExecuteMod(v8::Local<v8::Context> context, const char* js_filename,
}

CHECK_EQ(v8::Module::kInstantiated, module->GetStatus());

if (resolve_only) {
return true;
}

auto result = module->Evaluate(context);

if (result.IsEmpty()) {
@@ -75,8 +75,11 @@ int deno_execute(Deno* d, void* user_data, const char* js_filename,
// when instantiating the Deno object.
// Return value: 0 = fail, 1 = success
// Get error text with deno_last_exception().
// If resolve_only is 0, compile and evaluate the module.
// If resolve_only is 1, compile and collect dependencies of the module
// without running the code.
int deno_execute_mod(Deno* d, void* user_data, const char* js_filename,
const char* js_source);
const char* js_source, int resolve_only);

// deno_respond sends up to one message back for every deno_recv_cb made.
//
@@ -145,7 +145,7 @@ void DeleteDataRef(DenoIsolate* d, int32_t req_id);
bool Execute(v8::Local<v8::Context> context, const char* js_filename,
const char* js_source);
bool ExecuteMod(v8::Local<v8::Context> context, const char* js_filename,
const char* js_source);
const char* js_source, bool resolve_only);

} // namespace deno

@@ -284,7 +284,7 @@ TEST(LibDenoTest, ModuleResolution) {
deno_resolve_ok(d, "b.js", mod_b);
};
Deno* d = deno_new(deno_config{0, empty, empty, nullptr, resolve_cb});
EXPECT_TRUE(deno_execute_mod(d, d, "a.js", mod_a));
EXPECT_TRUE(deno_execute_mod(d, d, "a.js", mod_a, false));
EXPECT_EQ(count, 1);
deno_delete(d);
}
@@ -299,7 +299,7 @@ TEST(LibDenoTest, ModuleResolutionFail) {
// Do not call deno_resolve_ok();
};
Deno* d = deno_new(deno_config{0, empty, empty, nullptr, resolve_cb});
EXPECT_FALSE(deno_execute_mod(d, d, "a.js", mod_a));
EXPECT_FALSE(deno_execute_mod(d, d, "a.js", mod_a, false));
EXPECT_EQ(count, 1);
deno_delete(d);
}
@@ -309,7 +309,8 @@ TEST(LibDenoTest, ModuleSnapshot) {
EXPECT_TRUE(deno_execute_mod(d1, nullptr, "x.js",
"const globalEval = eval\n"
"const global = globalEval('this')\n"
"global.a = 1 + 2"));
"global.a = 1 + 2",
0));
deno_buf test_snapshot = deno_get_snapshot(d1);
deno_delete(d1);

@@ -321,12 +322,32 @@ TEST(LibDenoTest, ModuleSnapshot) {
deno_delete(d2);

Deno* d3 = deno_new(config);
EXPECT_TRUE(deno_execute_mod(d3, nullptr, "y.js", y_src));
EXPECT_TRUE(deno_execute_mod(d3, nullptr, "y.js", y_src, false));
deno_delete(d3);

delete[] test_snapshot.data_ptr;
}

TEST(LibDenoTest, ModuleResolveOnly) {
static int count = 0;
auto resolve_cb = [](void* user_data, const char* specifier,
const char* referrer) {
EXPECT_STREQ(specifier, "b.js");
EXPECT_STREQ(referrer, "a.js");
count++;
auto d = reinterpret_cast<Deno*>(user_data);
deno_resolve_ok(d, "b.js", mod_b);
};
Deno* d = deno_new(deno_config{0, empty, empty, nullptr, resolve_cb});
// Code should not execute. If executed, the error would be thrown
EXPECT_TRUE(deno_execute_mod(d, d, "a.js",
"import { retb } from 'b.js'\n"
"throw Error('unreachable');",
true));
EXPECT_EQ(count, 1);
deno_delete(d);
}

TEST(LibDenoTest, BuiltinModules) {
static int count = 0;
auto resolve_cb = [](void* user_data, const char* specifier,
@@ -347,7 +368,8 @@ TEST(LibDenoTest, BuiltinModules) {
"import * as deno from 'deno'\n"
"if (retb() != 'b') throw Error('retb');\n"
// " libdeno.print('deno ' + JSON.stringify(deno));\n"
"if (deno.foo != 'bar') throw Error('foo');\n"));
"if (deno.foo != 'bar') throw Error('foo');\n",
false));
EXPECT_EQ(count, 1);
deno_delete(d);
}
@@ -28,6 +28,7 @@ pub struct DenoFlags {
pub allow_env: bool,
pub allow_run: bool,
pub types: bool,
pub prefetch: bool,
}

pub fn get_usage(opts: &Options) -> String {
@@ -107,6 +108,9 @@ fn set_recognized_flags(
if matches.opt_present("types") {
flags.types = true;
}
if matches.opt_present("prefetch") {
flags.prefetch = true;
}

if !matches.free.is_empty() {
rest.extend(matches.free);
@@ -142,6 +146,7 @@ pub fn set_flags(
opts.optflag("r", "reload", "Reload cached remote resources.");
opts.optflag("", "v8-options", "Print V8 command line options.");
opts.optflag("", "types", "Print runtime TypeScript declarations.");
opts.optflag("", "prefetch", "Prefetch the dependencies.");

let mut flags = DenoFlags::default();

@@ -254,7 +254,11 @@ impl Isolate {
}

/// Executes the provided JavaScript module.
pub fn execute_mod(&self, js_filename: &str) -> Result<(), JSError> {
pub fn execute_mod(
&self,
js_filename: &str,
is_prefetch: bool,
) -> Result<(), JSError> {
let out =
code_fetch_and_maybe_compile(&self.state, js_filename, ".").unwrap();

@@ -271,6 +275,7 @@ impl Isolate {
self.as_raw_ptr(),
filename_ptr,
js_source_ptr,
if is_prefetch { 1 } else { 0 },
)
};
if r == 0 {
@@ -662,7 +667,9 @@ mod tests {
let snapshot = libdeno::deno_buf::empty();
let isolate = Isolate::new(snapshot, state, dispatch_sync);
tokio_util::init(|| {
isolate.execute_mod(filename).expect("execute_mod error");
isolate
.execute_mod(filename, false)
.expect("execute_mod error");
isolate.event_loop().ok();
});
}
@@ -151,6 +151,7 @@ extern "C" {
user_data: *const c_void,
js_filename: *const c_char,
js_source: *const c_char,
resolve_only: i32,
) -> c_int;
pub fn deno_resolve_ok(
i: *const isolate,
@@ -79,6 +79,8 @@ fn main() {
log::LevelFilter::Warn
});

let should_prefetch = flags.prefetch;

let state = Arc::new(isolate::IsolateState::new(flags, rest_argv, None));
let snapshot = snapshot::deno_snapshot();
let isolate = isolate::Isolate::new(snapshot, state, ops::dispatch);
@@ -93,7 +95,7 @@ fn main() {
if isolate.state.argv.len() > 1 {
let input_filename = &isolate.state.argv[1];
isolate
.execute_mod(input_filename)
.execute_mod(input_filename, should_prefetch)
.unwrap_or_else(print_err_and_exit);
}

@@ -11,10 +11,7 @@
import re
import sys
import subprocess
from util import pattern_match, green_ok, red_failed

root_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
tests_path = os.path.join(root_path, "tests")
from util import root_path, tests_path, pattern_match, green_ok, red_failed


def read_test(file_name):
@@ -0,0 +1,35 @@
#!/usr/bin/env python
# Copyright 2018 the Deno authors. All rights reserved. MIT license.
import os
import sys
from util import tests_path, run_output, build_path, executable_suffix, green_ok
import tempfile
import shutil


def prefetch_test(deno_exe):
sys.stdout.write("prefetch_test...")
sys.stdout.flush()

# On Windows, set the base directory that mkdtemp() uses explicitly. If not,
# it'll use the short (8.3) path to the temp dir, which triggers the error
# 'TS5009: Cannot find the common subdirectory path for the input files.'
temp_dir = os.environ["TEMP"] if os.name == 'nt' else None
deno_dir = tempfile.mkdtemp(dir=temp_dir)
try:
t = os.path.join(tests_path, "006_url_imports.ts")
output = run_output([deno_exe, "--prefetch", t],
merge_env={"DENO_DIR": deno_dir})
assert output == ""
# Check that we actually did the prefetch.
os.path.exists(
os.path.join(deno_dir,
"deps/http/localhost_PORT4545/tests/subdir/mod2.ts"))
finally:
shutil.rmtree(deno_dir)

print green_ok()


if __name__ == "__main__":
prefetch_test(sys.argv[1])
@@ -12,6 +12,7 @@
from util_test import util_test
from benchmark_test import benchmark_test
from repl_test import repl_tests
from prefetch_test import prefetch_test
import subprocess
import http_server

@@ -59,6 +60,8 @@ def main(argv):

unit_tests(deno_exe)

prefetch_test(deno_exe)

integration_tests(deno_exe)

# TODO We currently skip testing the prompt in Windows completely.
@@ -12,6 +12,7 @@

executable_suffix = ".exe" if os.name == "nt" else ""
root_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
tests_path = os.path.join(root_path, "tests")


def make_env(merge_env=None, env=None):

0 comments on commit c870cf4

Please sign in to comment.