1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 15:24:46 -05:00

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

This commit is contained in:
Kevin (Kun) "Kassimo" Qian 2019-01-15 09:19:58 -08:00 committed by Ryan Dahl
parent ac6ac5037f
commit c870cf4082
13 changed files with 99 additions and 17 deletions

View file

@ -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) {

View file

@ -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()) {

View file

@ -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.
//

View file

@ -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

View file

@ -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);
}

View file

@ -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();

View file

@ -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();
});
}

View file

@ -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,

View file

@ -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);
}

View file

@ -11,10 +11,7 @@ import os
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):

35
tools/prefetch_test.py Executable file
View file

@ -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])

View file

@ -12,6 +12,7 @@ from unit_tests import unit_tests
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.

View file

@ -12,6 +12,7 @@ FG_GREEN = "\x1b[32m"
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):