Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 9 commits into from
Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions libdeno/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand All @@ -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) {
Expand Down
7 changes: 6 additions & 1 deletion libdeno/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only modified part of this PR: module->Evaluate is not run and short circuited by is_prefetch


if (result.IsEmpty()) {
Expand Down
5 changes: 4 additions & 1 deletion libdeno/deno.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Expand Down
2 changes: 1 addition & 1 deletion libdeno/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
32 changes: 27 additions & 5 deletions libdeno/libdeno_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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));
ry marked this conversation as resolved.
Show resolved Hide resolved
deno_buf test_snapshot = deno_get_snapshot(d1);
deno_delete(d1);

Expand All @@ -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,
Expand All @@ -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);
}
5 changes: 5 additions & 0 deletions src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();

Expand Down
11 changes: 9 additions & 2 deletions src/isolate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -271,6 +275,7 @@ impl Isolate {
self.as_raw_ptr(),
filename_ptr,
js_source_ptr,
if is_prefetch { 1 } else { 0 },
)
};
if r == 0 {
Expand Down Expand Up @@ -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();
});
}
Expand Down
1 change: 1 addition & 0 deletions src/libdeno.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,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);
Expand All @@ -114,7 +116,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);
}

Expand Down
5 changes: 1 addition & 4 deletions tools/integration_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
35 changes: 35 additions & 0 deletions tools/prefetch_test.py
Original file line number Diff line number Diff line change
@@ -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])
3 changes: 3 additions & 0 deletions tools/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions tools/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down