mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
Refactor error to use dynamic dispatch and traits
This is in preperation for dynamic import (#1789), which is more easily implemented when errors are dynamic.
This commit is contained in:
parent
db5c66a638
commit
abe8a113ad
28 changed files with 926 additions and 1082 deletions
|
@ -1,6 +1,4 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::deno_error::err_check;
|
|
||||||
use crate::deno_error::DenoError;
|
|
||||||
use crate::diagnostics::Diagnostic;
|
use crate::diagnostics::Diagnostic;
|
||||||
use crate::msg;
|
use crate::msg;
|
||||||
use crate::resources;
|
use crate::resources;
|
||||||
|
@ -9,6 +7,7 @@ use crate::state::*;
|
||||||
use crate::tokio_util;
|
use crate::tokio_util;
|
||||||
use crate::worker::Worker;
|
use crate::worker::Worker;
|
||||||
use deno::Buf;
|
use deno::Buf;
|
||||||
|
use deno::ErrBox;
|
||||||
use deno::ModuleSpecifier;
|
use deno::ModuleSpecifier;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
|
@ -96,7 +95,7 @@ pub fn bundle_async(
|
||||||
state: ThreadSafeState,
|
state: ThreadSafeState,
|
||||||
module_name: String,
|
module_name: String,
|
||||||
out_file: String,
|
out_file: String,
|
||||||
) -> impl Future<Item = (), Error = DenoError> {
|
) -> impl Future<Item = (), Error = ErrBox> {
|
||||||
debug!(
|
debug!(
|
||||||
"Invoking the compiler to bundle. module_name: {}",
|
"Invoking the compiler to bundle. module_name: {}",
|
||||||
module_name
|
module_name
|
||||||
|
@ -116,9 +115,9 @@ pub fn bundle_async(
|
||||||
// as was done previously.
|
// as was done previously.
|
||||||
state.clone(),
|
state.clone(),
|
||||||
);
|
);
|
||||||
err_check(worker.execute("denoMain()"));
|
worker.execute("denoMain()").unwrap();
|
||||||
err_check(worker.execute("workerMain()"));
|
worker.execute("workerMain()").unwrap();
|
||||||
err_check(worker.execute("compilerMain()"));
|
worker.execute("compilerMain()").unwrap();
|
||||||
|
|
||||||
let resource = worker.state.resource.clone();
|
let resource = worker.state.resource.clone();
|
||||||
let compiler_rid = resource.rid;
|
let compiler_rid = resource.rid;
|
||||||
|
@ -144,7 +143,7 @@ pub fn bundle_async(
|
||||||
let json_str = std::str::from_utf8(&msg).unwrap();
|
let json_str = std::str::from_utf8(&msg).unwrap();
|
||||||
debug!("Message: {}", json_str);
|
debug!("Message: {}", json_str);
|
||||||
if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) {
|
if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) {
|
||||||
return Err(DenoError::from(diagnostics));
|
return Err(ErrBox::from(diagnostics));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +155,7 @@ pub fn bundle_async(
|
||||||
pub fn compile_async(
|
pub fn compile_async(
|
||||||
state: ThreadSafeState,
|
state: ThreadSafeState,
|
||||||
module_meta_data: &ModuleMetaData,
|
module_meta_data: &ModuleMetaData,
|
||||||
) -> impl Future<Item = ModuleMetaData, Error = DenoError> {
|
) -> impl Future<Item = ModuleMetaData, Error = ErrBox> {
|
||||||
let module_name = module_meta_data.module_name.clone();
|
let module_name = module_meta_data.module_name.clone();
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -178,9 +177,9 @@ pub fn compile_async(
|
||||||
// as was done previously.
|
// as was done previously.
|
||||||
state.clone(),
|
state.clone(),
|
||||||
);
|
);
|
||||||
err_check(worker.execute("denoMain()"));
|
worker.execute("denoMain()").unwrap();
|
||||||
err_check(worker.execute("workerMain()"));
|
worker.execute("workerMain()").unwrap();
|
||||||
err_check(worker.execute("compilerMain()"));
|
worker.execute("compilerMain()").unwrap();
|
||||||
|
|
||||||
let compiling_job = state.progress.add("Compile", &module_name);
|
let compiling_job = state.progress.add("Compile", &module_name);
|
||||||
|
|
||||||
|
@ -211,7 +210,7 @@ pub fn compile_async(
|
||||||
let json_str = std::str::from_utf8(&msg).unwrap();
|
let json_str = std::str::from_utf8(&msg).unwrap();
|
||||||
debug!("Message: {}", json_str);
|
debug!("Message: {}", json_str);
|
||||||
if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) {
|
if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) {
|
||||||
return Err(DenoError::from(diagnostics));
|
return Err(ErrBox::from(diagnostics));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +241,7 @@ pub fn compile_async(
|
||||||
pub fn compile_sync(
|
pub fn compile_sync(
|
||||||
state: ThreadSafeState,
|
state: ThreadSafeState,
|
||||||
module_meta_data: &ModuleMetaData,
|
module_meta_data: &ModuleMetaData,
|
||||||
) -> Result<ModuleMetaData, DenoError> {
|
) -> Result<ModuleMetaData, ErrBox> {
|
||||||
tokio_util::block_on(compile_async(state, module_meta_data))
|
tokio_util::block_on(compile_async(state, module_meta_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
220
cli/deno_dir.rs
220
cli/deno_dir.rs
|
@ -1,9 +1,8 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::compiler::ModuleMetaData;
|
use crate::compiler::ModuleMetaData;
|
||||||
use crate::deno_error;
|
|
||||||
use crate::deno_error::DenoError;
|
use crate::deno_error::DenoError;
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
use crate::deno_error::ErrorKind;
|
use crate::deno_error::ErrorKind;
|
||||||
|
use crate::deno_error::GetErrorKind;
|
||||||
use crate::fs as deno_fs;
|
use crate::fs as deno_fs;
|
||||||
use crate::http_util;
|
use crate::http_util;
|
||||||
use crate::msg;
|
use crate::msg;
|
||||||
|
@ -11,6 +10,7 @@ use crate::progress::Progress;
|
||||||
use crate::source_maps::SourceMapGetter;
|
use crate::source_maps::SourceMapGetter;
|
||||||
use crate::tokio_util;
|
use crate::tokio_util;
|
||||||
use crate::version;
|
use crate::version;
|
||||||
|
use deno::ErrBox;
|
||||||
use deno::ModuleSpecifier;
|
use deno::ModuleSpecifier;
|
||||||
use dirs;
|
use dirs;
|
||||||
use futures::future::{loop_fn, Either, Loop};
|
use futures::future::{loop_fn, Either, Loop};
|
||||||
|
@ -20,8 +20,6 @@ use ring;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std;
|
use std;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
|
||||||
use std::fmt::Display;
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -34,36 +32,6 @@ use std::sync::Mutex;
|
||||||
use url;
|
use url;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
// TODO: DenoDirError is temporary solution, should be upgraded during rewrite
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum DenoDirErrorKind {
|
|
||||||
UnsupportedFetchScheme,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DenoDirError {
|
|
||||||
pub message: String,
|
|
||||||
pub kind: DenoDirErrorKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DenoDirError {
|
|
||||||
pub fn new(message: String, kind: DenoDirErrorKind) -> Self {
|
|
||||||
DenoDirError { message, kind }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for DenoDirError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
&*self.message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for DenoDirError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
writeln!(f, "{}", self.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SUPPORTED_URL_SCHEMES: [&str; 3] = ["http", "https", "file"];
|
const SUPPORTED_URL_SCHEMES: [&str; 3] = ["http", "https", "file"];
|
||||||
|
|
||||||
fn normalize_path(path: &Path) -> PathBuf {
|
fn normalize_path(path: &Path) -> PathBuf {
|
||||||
|
@ -198,13 +166,13 @@ impl DenoDir {
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
use_cache: bool,
|
use_cache: bool,
|
||||||
no_fetch: bool,
|
no_fetch: bool,
|
||||||
) -> impl Future<Item = ModuleMetaData, Error = deno_error::DenoError> {
|
) -> impl Future<Item = ModuleMetaData, Error = ErrBox> {
|
||||||
let module_url = specifier.as_url().to_owned();
|
let module_url = specifier.as_url().to_owned();
|
||||||
debug!("fetch_module_meta_data. specifier {} ", &module_url);
|
debug!("fetch_module_meta_data. specifier {} ", &module_url);
|
||||||
|
|
||||||
let result = self.url_to_deps_path(&module_url);
|
let result = self.url_to_deps_path(&module_url);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
return Either::A(futures::future::err(DenoError::from(err)));
|
return Either::A(futures::future::err(err));
|
||||||
}
|
}
|
||||||
let deps_filepath = result.unwrap();
|
let deps_filepath = result.unwrap();
|
||||||
|
|
||||||
|
@ -223,20 +191,17 @@ impl DenoDir {
|
||||||
use_cache,
|
use_cache,
|
||||||
no_fetch,
|
no_fetch,
|
||||||
).then(move |result| {
|
).then(move |result| {
|
||||||
let mut out = match result {
|
let mut out = result.map_err(|err| {
|
||||||
Ok(out) => out,
|
if err.kind() == ErrorKind::NotFound {
|
||||||
Err(err) => {
|
// For NotFound, change the message to something better.
|
||||||
if err.kind() == ErrorKind::NotFound {
|
DenoError::new(
|
||||||
// For NotFound, change the message to something better.
|
ErrorKind::NotFound,
|
||||||
return Err(deno_error::new(
|
format!("Cannot resolve module \"{}\"", module_url.to_string()),
|
||||||
ErrorKind::NotFound,
|
).into()
|
||||||
format!("Cannot resolve module \"{}\"", module_url.to_string()),
|
} else {
|
||||||
));
|
err
|
||||||
} else {
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
})?;
|
||||||
|
|
||||||
if out.source_code.starts_with(b"#!") {
|
if out.source_code.starts_with(b"#!") {
|
||||||
out.source_code = filter_shebang(out.source_code);
|
out.source_code = filter_shebang(out.source_code);
|
||||||
|
@ -290,7 +255,7 @@ impl DenoDir {
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
use_cache: bool,
|
use_cache: bool,
|
||||||
no_fetch: bool,
|
no_fetch: bool,
|
||||||
) -> Result<ModuleMetaData, deno_error::DenoError> {
|
) -> Result<ModuleMetaData, ErrBox> {
|
||||||
tokio_util::block_on(
|
tokio_util::block_on(
|
||||||
self.fetch_module_meta_data_async(specifier, use_cache, no_fetch),
|
self.fetch_module_meta_data_async(specifier, use_cache, no_fetch),
|
||||||
)
|
)
|
||||||
|
@ -303,20 +268,17 @@ impl DenoDir {
|
||||||
///
|
///
|
||||||
/// For specifier starting with `http://` and `https://` it returns
|
/// For specifier starting with `http://` and `https://` it returns
|
||||||
/// path to DenoDir dependency directory.
|
/// path to DenoDir dependency directory.
|
||||||
pub fn url_to_deps_path(
|
pub fn url_to_deps_path(self: &Self, url: &Url) -> Result<PathBuf, ErrBox> {
|
||||||
self: &Self,
|
|
||||||
url: &Url,
|
|
||||||
) -> Result<PathBuf, DenoDirError> {
|
|
||||||
let filename = match url.scheme() {
|
let filename = match url.scheme() {
|
||||||
"file" => url.to_file_path().unwrap(),
|
"file" => url.to_file_path().unwrap(),
|
||||||
"https" => get_cache_filename(self.deps_https.as_path(), &url),
|
"https" => get_cache_filename(self.deps_https.as_path(), &url),
|
||||||
"http" => get_cache_filename(self.deps_http.as_path(), &url),
|
"http" => get_cache_filename(self.deps_http.as_path(), &url),
|
||||||
scheme => {
|
scheme => {
|
||||||
return Err(
|
return Err(
|
||||||
DenoDirError::new(
|
DenoError::new(
|
||||||
|
ErrorKind::UnsupportedFetchScheme,
|
||||||
format!("Unsupported scheme \"{}\" for module \"{}\". Supported schemes: {:#?}", scheme, url, SUPPORTED_URL_SCHEMES),
|
format!("Unsupported scheme \"{}\" for module \"{}\". Supported schemes: {:#?}", scheme, url, SUPPORTED_URL_SCHEMES),
|
||||||
DenoDirErrorKind::UnsupportedFetchScheme
|
).into()
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -389,7 +351,7 @@ fn get_source_code_async(
|
||||||
filepath: PathBuf,
|
filepath: PathBuf,
|
||||||
use_cache: bool,
|
use_cache: bool,
|
||||||
no_fetch: bool,
|
no_fetch: bool,
|
||||||
) -> impl Future<Item = ModuleMetaData, Error = DenoError> {
|
) -> impl Future<Item = ModuleMetaData, Error = ErrBox> {
|
||||||
let filename = filepath.to_str().unwrap().to_string();
|
let filename = filepath.to_str().unwrap().to_string();
|
||||||
let module_name = module_url.to_string();
|
let module_name = module_url.to_string();
|
||||||
let url_scheme = module_url.scheme();
|
let url_scheme = module_url.scheme();
|
||||||
|
@ -425,23 +387,23 @@ fn get_source_code_async(
|
||||||
// If not remote file stop here!
|
// If not remote file stop here!
|
||||||
if !is_module_remote {
|
if !is_module_remote {
|
||||||
debug!("not remote file stop here");
|
debug!("not remote file stop here");
|
||||||
return Either::A(futures::future::err(DenoError::from(
|
return Either::A(futures::future::err(
|
||||||
std::io::Error::new(
|
std::io::Error::new(
|
||||||
std::io::ErrorKind::NotFound,
|
std::io::ErrorKind::NotFound,
|
||||||
format!("cannot find local file '{}'", filename),
|
format!("cannot find local file '{}'", filename),
|
||||||
),
|
).into(),
|
||||||
)));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If remote downloads are not allowed stop here!
|
// If remote downloads are not allowed stop here!
|
||||||
if no_fetch {
|
if no_fetch {
|
||||||
debug!("remote file with no_fetch stop here");
|
debug!("remote file with no_fetch stop here");
|
||||||
return Either::A(futures::future::err(DenoError::from(
|
return Either::A(futures::future::err(
|
||||||
std::io::Error::new(
|
std::io::Error::new(
|
||||||
std::io::ErrorKind::NotFound,
|
std::io::ErrorKind::NotFound,
|
||||||
format!("cannot find remote file '{}' in cache", filename),
|
format!("cannot find remote file '{}' in cache", filename),
|
||||||
),
|
).into(),
|
||||||
)));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("is remote but didn't find module");
|
debug!("is remote but didn't find module");
|
||||||
|
@ -456,10 +418,12 @@ fn get_source_code_async(
|
||||||
download_cache.mark(&module_name);
|
download_cache.mark(&module_name);
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
None => Err(DenoError::from(std::io::Error::new(
|
None => Err(
|
||||||
std::io::ErrorKind::NotFound,
|
std::io::Error::new(
|
||||||
format!("cannot find remote file '{}'", filename),
|
std::io::ErrorKind::NotFound,
|
||||||
))),
|
format!("cannot find remote file '{}'", filename),
|
||||||
|
).into(),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -474,7 +438,7 @@ fn get_source_code(
|
||||||
filepath: PathBuf,
|
filepath: PathBuf,
|
||||||
use_cache: bool,
|
use_cache: bool,
|
||||||
no_fetch: bool,
|
no_fetch: bool,
|
||||||
) -> DenoResult<ModuleMetaData> {
|
) -> Result<ModuleMetaData, ErrBox> {
|
||||||
tokio_util::block_on(get_source_code_async(
|
tokio_util::block_on(get_source_code_async(
|
||||||
deno_dir, module_url, filepath, use_cache, no_fetch,
|
deno_dir, module_url, filepath, use_cache, no_fetch,
|
||||||
))
|
))
|
||||||
|
@ -595,7 +559,7 @@ fn save_module_code_and_headers(
|
||||||
source: &str,
|
source: &str,
|
||||||
maybe_content_type: Option<String>,
|
maybe_content_type: Option<String>,
|
||||||
maybe_initial_filepath: Option<PathBuf>,
|
maybe_initial_filepath: Option<PathBuf>,
|
||||||
) -> DenoResult<()> {
|
) -> Result<(), ErrBox> {
|
||||||
match filepath.parent() {
|
match filepath.parent() {
|
||||||
Some(ref parent) => fs::create_dir_all(parent),
|
Some(ref parent) => fs::create_dir_all(parent),
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
|
@ -636,7 +600,7 @@ fn fetch_remote_source_async(
|
||||||
deno_dir: &DenoDir,
|
deno_dir: &DenoDir,
|
||||||
module_url: &Url,
|
module_url: &Url,
|
||||||
filepath: &Path,
|
filepath: &Path,
|
||||||
) -> impl Future<Item = Option<ModuleMetaData>, Error = DenoError> {
|
) -> impl Future<Item = Option<ModuleMetaData>, Error = ErrBox> {
|
||||||
use crate::http_util::FetchOnceResult;
|
use crate::http_util::FetchOnceResult;
|
||||||
|
|
||||||
let download_job = deno_dir.progress.add("Download", &module_url.to_string());
|
let download_job = deno_dir.progress.add("Download", &module_url.to_string());
|
||||||
|
@ -664,61 +628,65 @@ fn fetch_remote_source_async(
|
||||||
)| {
|
)| {
|
||||||
let module_uri = url_into_uri(&module_url);
|
let module_uri = url_into_uri(&module_url);
|
||||||
// Single pass fetch, either yields code or yields redirect.
|
// Single pass fetch, either yields code or yields redirect.
|
||||||
http_util::fetch_string_once(module_uri).and_then(move |fetch_once_result| {
|
http_util::fetch_string_once(module_uri).and_then(
|
||||||
match fetch_once_result {
|
move |fetch_once_result| {
|
||||||
FetchOnceResult::Redirect(uri) => {
|
match fetch_once_result {
|
||||||
// If redirects, update module_name and filename for next looped call.
|
FetchOnceResult::Redirect(uri) => {
|
||||||
let new_module_url = Url::parse(&uri.to_string()).expect("http::uri::Uri should be parseable as Url");
|
// If redirects, update module_name and filename for next looped call.
|
||||||
let new_filepath = dir.url_to_deps_path(&new_module_url)?;
|
let new_module_url = Url::parse(&uri.to_string())
|
||||||
|
.expect("http::uri::Uri should be parseable as Url");
|
||||||
|
let new_filepath = dir.url_to_deps_path(&new_module_url)?;
|
||||||
|
|
||||||
if maybe_initial_module_name.is_none() {
|
if maybe_initial_module_name.is_none() {
|
||||||
maybe_initial_module_name = Some(module_url.to_string());
|
maybe_initial_module_name = Some(module_url.to_string());
|
||||||
maybe_initial_filepath = Some(filepath.clone());
|
maybe_initial_filepath = Some(filepath.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not yet completed. Follow the redirect and loop.
|
||||||
|
Ok(Loop::Continue((
|
||||||
|
dir,
|
||||||
|
maybe_initial_module_name,
|
||||||
|
maybe_initial_filepath,
|
||||||
|
new_module_url,
|
||||||
|
new_filepath,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
FetchOnceResult::Code(source, maybe_content_type) => {
|
||||||
|
// We land on the code.
|
||||||
|
save_module_code_and_headers(
|
||||||
|
filepath.clone(),
|
||||||
|
&module_url,
|
||||||
|
&source,
|
||||||
|
maybe_content_type.clone(),
|
||||||
|
maybe_initial_filepath,
|
||||||
|
)?;
|
||||||
|
|
||||||
// Not yet completed. Follow the redirect and loop.
|
let media_type = map_content_type(
|
||||||
Ok(Loop::Continue((
|
&filepath,
|
||||||
dir,
|
maybe_content_type.as_ref().map(String::as_str),
|
||||||
maybe_initial_module_name,
|
);
|
||||||
maybe_initial_filepath,
|
|
||||||
new_module_url,
|
// TODO: module_name should be renamed to URL
|
||||||
new_filepath,
|
let module_meta_data = ModuleMetaData {
|
||||||
)))
|
module_name: module_url.to_string(),
|
||||||
|
module_redirect_source_name: maybe_initial_module_name,
|
||||||
|
filename: filepath.clone(),
|
||||||
|
media_type,
|
||||||
|
source_code: source.as_bytes().to_owned(),
|
||||||
|
maybe_output_code_filename: None,
|
||||||
|
maybe_output_code: None,
|
||||||
|
maybe_source_map_filename: None,
|
||||||
|
maybe_source_map: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Loop::Break(Some(module_meta_data)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FetchOnceResult::Code(source, maybe_content_type) => {
|
},
|
||||||
// We land on the code.
|
)
|
||||||
save_module_code_and_headers(
|
|
||||||
filepath.clone(),
|
|
||||||
&module_url,
|
|
||||||
&source,
|
|
||||||
maybe_content_type.clone(),
|
|
||||||
maybe_initial_filepath,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let media_type = map_content_type(
|
|
||||||
&filepath,
|
|
||||||
maybe_content_type.as_ref().map(String::as_str),
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: module_name should be renamed to URL
|
|
||||||
let module_meta_data = ModuleMetaData {
|
|
||||||
module_name: module_url.to_string(),
|
|
||||||
module_redirect_source_name: maybe_initial_module_name,
|
|
||||||
filename: filepath.clone(),
|
|
||||||
media_type,
|
|
||||||
source_code: source.as_bytes().to_owned(),
|
|
||||||
maybe_output_code_filename: None,
|
|
||||||
maybe_output_code: None,
|
|
||||||
maybe_source_map_filename: None,
|
|
||||||
maybe_source_map: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Loop::Break(Some(module_meta_data)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
).then(move |r| {
|
)
|
||||||
|
.then(move |r| {
|
||||||
// Explicit drop to keep reference alive until future completes.
|
// Explicit drop to keep reference alive until future completes.
|
||||||
drop(download_job);
|
drop(download_job);
|
||||||
r
|
r
|
||||||
|
@ -731,7 +699,7 @@ fn fetch_remote_source(
|
||||||
deno_dir: &DenoDir,
|
deno_dir: &DenoDir,
|
||||||
module_url: &Url,
|
module_url: &Url,
|
||||||
filepath: &Path,
|
filepath: &Path,
|
||||||
) -> DenoResult<Option<ModuleMetaData>> {
|
) -> Result<Option<ModuleMetaData>, ErrBox> {
|
||||||
tokio_util::block_on(fetch_remote_source_async(
|
tokio_util::block_on(fetch_remote_source_async(
|
||||||
deno_dir, module_url, filepath,
|
deno_dir, module_url, filepath,
|
||||||
))
|
))
|
||||||
|
@ -751,7 +719,7 @@ fn fetch_local_source(
|
||||||
module_url: &Url,
|
module_url: &Url,
|
||||||
filepath: &Path,
|
filepath: &Path,
|
||||||
module_initial_source_name: Option<String>,
|
module_initial_source_name: Option<String>,
|
||||||
) -> DenoResult<Option<ModuleMetaData>> {
|
) -> Result<Option<ModuleMetaData>, ErrBox> {
|
||||||
let source_code_headers = get_source_code_headers(&filepath);
|
let source_code_headers = get_source_code_headers(&filepath);
|
||||||
// If source code headers says that it would redirect elsewhere,
|
// If source code headers says that it would redirect elsewhere,
|
||||||
// (meaning that the source file might not exist; only .headers.json is present)
|
// (meaning that the source file might not exist; only .headers.json is present)
|
||||||
|
@ -907,7 +875,7 @@ fn save_source_code_headers(
|
||||||
|
|
||||||
// TODO(bartlomieju): this method should be moved, it doesn't belong to deno_dir.rs
|
// TODO(bartlomieju): this method should be moved, it doesn't belong to deno_dir.rs
|
||||||
// it's a general utility
|
// it's a general utility
|
||||||
pub fn resolve_from_cwd(path: &str) -> Result<(PathBuf, String), DenoError> {
|
pub fn resolve_from_cwd(path: &str) -> Result<(PathBuf, String), ErrBox> {
|
||||||
let candidate_path = Path::new(path);
|
let candidate_path = Path::new(path);
|
||||||
|
|
||||||
let resolved_path = if candidate_path.is_absolute() {
|
let resolved_path = if candidate_path.is_absolute() {
|
||||||
|
@ -1669,8 +1637,8 @@ mod tests {
|
||||||
for &test in test_cases.iter() {
|
for &test in test_cases.iter() {
|
||||||
let url = Url::parse(test).unwrap();
|
let url = Url::parse(test).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
deno_dir.url_to_deps_path(&url).unwrap_err().kind,
|
deno_dir.url_to_deps_path(&url).unwrap_err().kind(),
|
||||||
DenoDirErrorKind::UnsupportedFetchScheme
|
ErrorKind::UnsupportedFetchScheme
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,346 +1,239 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::deno_dir;
|
use crate::diagnostics::Diagnostic;
|
||||||
use crate::diagnostics;
|
use crate::fmt_errors::JSError;
|
||||||
use crate::fmt_errors::JSErrorColor;
|
use crate::import_map::ImportMapError;
|
||||||
use crate::import_map;
|
|
||||||
pub use crate::msg::ErrorKind;
|
pub use crate::msg::ErrorKind;
|
||||||
use crate::resolve_addr::ResolveAddrError;
|
use deno::AnyError;
|
||||||
use crate::source_maps::apply_source_map;
|
use deno::ErrBox;
|
||||||
use crate::source_maps::SourceMapGetter;
|
|
||||||
use deno::JSError;
|
|
||||||
use deno::ModuleResolutionError;
|
use deno::ModuleResolutionError;
|
||||||
|
use http::uri;
|
||||||
use hyper;
|
use hyper;
|
||||||
#[cfg(unix)]
|
|
||||||
use nix::{errno::Errno, Error as UnixError};
|
|
||||||
use std;
|
use std;
|
||||||
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::str;
|
|
||||||
use url;
|
use url;
|
||||||
|
|
||||||
pub type DenoResult<T> = std::result::Result<T, DenoError>;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DenoError {
|
pub struct DenoError {
|
||||||
repr: Repr,
|
kind: ErrorKind,
|
||||||
}
|
msg: String,
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Repr {
|
|
||||||
Simple(ErrorKind, String),
|
|
||||||
IoErr(io::Error),
|
|
||||||
UrlErr(url::ParseError),
|
|
||||||
HyperErr(hyper::Error),
|
|
||||||
ImportMapErr(import_map::ImportMapError),
|
|
||||||
ModuleResolutionErr(ModuleResolutionError),
|
|
||||||
Diagnostic(diagnostics::Diagnostic),
|
|
||||||
JSError(JSError),
|
|
||||||
DenoDirErr(deno_dir::DenoDirError),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new simple DenoError.
|
|
||||||
pub fn new(kind: ErrorKind, msg: String) -> DenoError {
|
|
||||||
DenoError {
|
|
||||||
repr: Repr::Simple(kind, msg),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DenoError {
|
impl DenoError {
|
||||||
fn url_error_kind(err: url::ParseError) -> ErrorKind {
|
pub fn new(kind: ErrorKind, msg: String) -> Self {
|
||||||
use url::ParseError::*;
|
Self { kind, msg }
|
||||||
match err {
|
|
||||||
EmptyHost => ErrorKind::EmptyHost,
|
|
||||||
IdnaError => ErrorKind::IdnaError,
|
|
||||||
InvalidPort => ErrorKind::InvalidPort,
|
|
||||||
InvalidIpv4Address => ErrorKind::InvalidIpv4Address,
|
|
||||||
InvalidIpv6Address => ErrorKind::InvalidIpv6Address,
|
|
||||||
InvalidDomainCharacter => ErrorKind::InvalidDomainCharacter,
|
|
||||||
RelativeUrlWithoutBase => ErrorKind::RelativeUrlWithoutBase,
|
|
||||||
RelativeUrlWithCannotBeABaseBase => {
|
|
||||||
ErrorKind::RelativeUrlWithCannotBeABaseBase
|
|
||||||
}
|
|
||||||
SetHostOnCannotBeABaseUrl => ErrorKind::SetHostOnCannotBeABaseUrl,
|
|
||||||
Overflow => ErrorKind::Overflow,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> ErrorKind {
|
|
||||||
match self.repr {
|
|
||||||
Repr::Simple(kind, ref _msg) => kind,
|
|
||||||
// Repr::Simple(kind) => kind,
|
|
||||||
Repr::IoErr(ref err) => {
|
|
||||||
use std::io::ErrorKind::*;
|
|
||||||
match err.kind() {
|
|
||||||
NotFound => ErrorKind::NotFound,
|
|
||||||
PermissionDenied => ErrorKind::PermissionDenied,
|
|
||||||
ConnectionRefused => ErrorKind::ConnectionRefused,
|
|
||||||
ConnectionReset => ErrorKind::ConnectionReset,
|
|
||||||
ConnectionAborted => ErrorKind::ConnectionAborted,
|
|
||||||
NotConnected => ErrorKind::NotConnected,
|
|
||||||
AddrInUse => ErrorKind::AddrInUse,
|
|
||||||
AddrNotAvailable => ErrorKind::AddrNotAvailable,
|
|
||||||
BrokenPipe => ErrorKind::BrokenPipe,
|
|
||||||
AlreadyExists => ErrorKind::AlreadyExists,
|
|
||||||
WouldBlock => ErrorKind::WouldBlock,
|
|
||||||
InvalidInput => ErrorKind::InvalidInput,
|
|
||||||
InvalidData => ErrorKind::InvalidData,
|
|
||||||
TimedOut => ErrorKind::TimedOut,
|
|
||||||
Interrupted => ErrorKind::Interrupted,
|
|
||||||
WriteZero => ErrorKind::WriteZero,
|
|
||||||
Other => ErrorKind::Other,
|
|
||||||
UnexpectedEof => ErrorKind::UnexpectedEof,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Repr::UrlErr(err) => Self::url_error_kind(err),
|
|
||||||
Repr::HyperErr(ref err) => {
|
|
||||||
// For some reason hyper::errors::Kind is private.
|
|
||||||
if err.is_parse() {
|
|
||||||
ErrorKind::HttpParse
|
|
||||||
} else if err.is_user() {
|
|
||||||
ErrorKind::HttpUser
|
|
||||||
} else if err.is_canceled() {
|
|
||||||
ErrorKind::HttpCanceled
|
|
||||||
} else if err.is_closed() {
|
|
||||||
ErrorKind::HttpClosed
|
|
||||||
} else {
|
|
||||||
ErrorKind::HttpOther
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Repr::ImportMapErr(ref _err) => ErrorKind::ImportMapError,
|
|
||||||
Repr::ModuleResolutionErr(err) => {
|
|
||||||
use ModuleResolutionError::*;
|
|
||||||
match err {
|
|
||||||
InvalidUrl(err) | InvalidBaseUrl(err) => Self::url_error_kind(err),
|
|
||||||
InvalidPath => ErrorKind::InvalidPath,
|
|
||||||
ImportPrefixMissing => ErrorKind::ImportPrefixMissing,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Repr::Diagnostic(ref _err) => ErrorKind::Diagnostic,
|
|
||||||
Repr::JSError(ref _err) => ErrorKind::JSError,
|
|
||||||
Repr::DenoDirErr(ref _err) => ErrorKind::DenoDirError,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply_source_map<G: SourceMapGetter>(self, getter: &G) -> Self {
|
|
||||||
if let Repr::JSError(js_error) = self.repr {
|
|
||||||
return DenoError {
|
|
||||||
repr: Repr::JSError(apply_source_map(&js_error, getter)),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
panic!("attempt to apply source map an unremappable error")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Error for DenoError {}
|
||||||
|
|
||||||
impl fmt::Display for DenoError {
|
impl fmt::Display for DenoError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self.repr {
|
f.pad(self.msg.as_str())
|
||||||
Repr::Simple(_kind, ref err_str) => f.pad(err_str),
|
}
|
||||||
Repr::IoErr(ref err) => err.fmt(f),
|
}
|
||||||
Repr::UrlErr(ref err) => err.fmt(f),
|
|
||||||
Repr::HyperErr(ref err) => err.fmt(f),
|
#[derive(Debug)]
|
||||||
Repr::ImportMapErr(ref err) => f.pad(&err.msg),
|
struct StaticError(ErrorKind, &'static str);
|
||||||
Repr::ModuleResolutionErr(ref err) => err.fmt(f),
|
|
||||||
Repr::Diagnostic(ref err) => err.fmt(f),
|
impl Error for StaticError {}
|
||||||
Repr::JSError(ref err) => JSErrorColor(err).fmt(f),
|
|
||||||
Repr::DenoDirErr(ref err) => err.fmt(f),
|
impl fmt::Display for StaticError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.pad(self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bad_resource() -> ErrBox {
|
||||||
|
StaticError(ErrorKind::BadResource, "bad resource id").into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn permission_denied() -> ErrBox {
|
||||||
|
StaticError(ErrorKind::PermissionDenied, "permission denied").into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn op_not_implemented() -> ErrBox {
|
||||||
|
StaticError(ErrorKind::OpNotAvailable, "op not implemented").into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn no_buffer_specified() -> ErrBox {
|
||||||
|
StaticError(ErrorKind::InvalidInput, "no buffer specified").into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn no_async_support() -> ErrBox {
|
||||||
|
StaticError(ErrorKind::NoAsyncSupport, "op doesn't support async calls")
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn no_sync_support() -> ErrBox {
|
||||||
|
StaticError(ErrorKind::NoSyncSupport, "op doesn't support sync calls").into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalid_address_syntax() -> ErrBox {
|
||||||
|
StaticError(ErrorKind::InvalidInput, "invalid address syntax").into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GetErrorKind {
|
||||||
|
fn kind(&self) -> ErrorKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetErrorKind for DenoError {
|
||||||
|
fn kind(&self) -> ErrorKind {
|
||||||
|
self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetErrorKind for StaticError {
|
||||||
|
fn kind(&self) -> ErrorKind {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetErrorKind for JSError {
|
||||||
|
fn kind(&self) -> ErrorKind {
|
||||||
|
ErrorKind::JSError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetErrorKind for Diagnostic {
|
||||||
|
fn kind(&self) -> ErrorKind {
|
||||||
|
ErrorKind::Diagnostic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetErrorKind for ImportMapError {
|
||||||
|
fn kind(&self) -> ErrorKind {
|
||||||
|
ErrorKind::ImportMapError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetErrorKind for ModuleResolutionError {
|
||||||
|
fn kind(&self) -> ErrorKind {
|
||||||
|
use ModuleResolutionError::*;
|
||||||
|
match self {
|
||||||
|
InvalidUrl(ref err) | InvalidBaseUrl(ref err) => err.kind(),
|
||||||
|
InvalidPath => ErrorKind::InvalidPath,
|
||||||
|
ImportPrefixMissing => ErrorKind::ImportPrefixMissing,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for DenoError {
|
impl GetErrorKind for io::Error {
|
||||||
fn description(&self) -> &str {
|
fn kind(&self) -> ErrorKind {
|
||||||
match self.repr {
|
use io::ErrorKind::*;
|
||||||
Repr::Simple(_kind, ref msg) => msg.as_str(),
|
match self.kind() {
|
||||||
Repr::IoErr(ref err) => err.description(),
|
NotFound => ErrorKind::NotFound,
|
||||||
Repr::UrlErr(ref err) => err.description(),
|
PermissionDenied => ErrorKind::PermissionDenied,
|
||||||
Repr::HyperErr(ref err) => err.description(),
|
ConnectionRefused => ErrorKind::ConnectionRefused,
|
||||||
Repr::ImportMapErr(ref err) => &err.msg,
|
ConnectionReset => ErrorKind::ConnectionReset,
|
||||||
Repr::ModuleResolutionErr(ref err) => err.description(),
|
ConnectionAborted => ErrorKind::ConnectionAborted,
|
||||||
Repr::Diagnostic(ref err) => &err.items[0].message,
|
NotConnected => ErrorKind::NotConnected,
|
||||||
Repr::JSError(ref err) => &err.description(),
|
AddrInUse => ErrorKind::AddrInUse,
|
||||||
Repr::DenoDirErr(ref err) => err.description(),
|
AddrNotAvailable => ErrorKind::AddrNotAvailable,
|
||||||
}
|
BrokenPipe => ErrorKind::BrokenPipe,
|
||||||
}
|
AlreadyExists => ErrorKind::AlreadyExists,
|
||||||
|
WouldBlock => ErrorKind::WouldBlock,
|
||||||
fn cause(&self) -> Option<&dyn std::error::Error> {
|
InvalidInput => ErrorKind::InvalidInput,
|
||||||
match self.repr {
|
InvalidData => ErrorKind::InvalidData,
|
||||||
Repr::Simple(_kind, ref _msg) => None,
|
TimedOut => ErrorKind::TimedOut,
|
||||||
Repr::IoErr(ref err) => Some(err),
|
Interrupted => ErrorKind::Interrupted,
|
||||||
Repr::UrlErr(ref err) => Some(err),
|
WriteZero => ErrorKind::WriteZero,
|
||||||
Repr::HyperErr(ref err) => Some(err),
|
UnexpectedEof => ErrorKind::UnexpectedEof,
|
||||||
Repr::ImportMapErr(ref _err) => None,
|
_ => ErrorKind::Other,
|
||||||
Repr::ModuleResolutionErr(ref err) => err.source(),
|
|
||||||
Repr::Diagnostic(ref _err) => None,
|
|
||||||
Repr::JSError(ref err) => Some(err),
|
|
||||||
Repr::DenoDirErr(ref err) => Some(err),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for DenoError {
|
impl GetErrorKind for uri::InvalidUri {
|
||||||
#[inline]
|
fn kind(&self) -> ErrorKind {
|
||||||
fn from(err: io::Error) -> Self {
|
// The http::uri::ErrorKind exists and is similar to url::ParseError.
|
||||||
Self {
|
// However it is also private, so we can't get any details out.
|
||||||
repr: Repr::IoErr(err),
|
ErrorKind::InvalidUri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetErrorKind for url::ParseError {
|
||||||
|
fn kind(&self) -> ErrorKind {
|
||||||
|
use url::ParseError::*;
|
||||||
|
match self {
|
||||||
|
EmptyHost => ErrorKind::EmptyHost,
|
||||||
|
IdnaError => ErrorKind::IdnaError,
|
||||||
|
InvalidDomainCharacter => ErrorKind::InvalidDomainCharacter,
|
||||||
|
InvalidIpv4Address => ErrorKind::InvalidIpv4Address,
|
||||||
|
InvalidIpv6Address => ErrorKind::InvalidIpv6Address,
|
||||||
|
InvalidPort => ErrorKind::InvalidPort,
|
||||||
|
Overflow => ErrorKind::Overflow,
|
||||||
|
RelativeUrlWithCannotBeABaseBase => {
|
||||||
|
ErrorKind::RelativeUrlWithCannotBeABaseBase
|
||||||
|
}
|
||||||
|
RelativeUrlWithoutBase => ErrorKind::RelativeUrlWithoutBase,
|
||||||
|
SetHostOnCannotBeABaseUrl => ErrorKind::SetHostOnCannotBeABaseUrl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<url::ParseError> for DenoError {
|
impl GetErrorKind for hyper::Error {
|
||||||
#[inline]
|
fn kind(&self) -> ErrorKind {
|
||||||
fn from(err: url::ParseError) -> Self {
|
match self {
|
||||||
Self {
|
e if e.is_canceled() => ErrorKind::HttpCanceled,
|
||||||
repr: Repr::UrlErr(err),
|
e if e.is_closed() => ErrorKind::HttpClosed,
|
||||||
}
|
e if e.is_parse() => ErrorKind::HttpParse,
|
||||||
}
|
e if e.is_user() => ErrorKind::HttpUser,
|
||||||
}
|
_ => ErrorKind::HttpOther,
|
||||||
|
|
||||||
impl From<hyper::Error> for DenoError {
|
|
||||||
#[inline]
|
|
||||||
fn from(err: hyper::Error) -> Self {
|
|
||||||
Self {
|
|
||||||
repr: Repr::HyperErr(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ResolveAddrError> for DenoError {
|
|
||||||
fn from(e: ResolveAddrError) -> Self {
|
|
||||||
match e {
|
|
||||||
ResolveAddrError::Syntax => Self {
|
|
||||||
repr: Repr::Simple(
|
|
||||||
ErrorKind::InvalidInput,
|
|
||||||
"invalid address syntax".to_string(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
ResolveAddrError::Resolution(io_err) => Self {
|
|
||||||
repr: Repr::IoErr(io_err),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
impl From<UnixError> for DenoError {
|
mod unix {
|
||||||
fn from(e: UnixError) -> Self {
|
use super::{ErrorKind, GetErrorKind};
|
||||||
match e {
|
use nix::errno::Errno::*;
|
||||||
UnixError::Sys(Errno::EPERM) => Self {
|
pub use nix::Error;
|
||||||
repr: Repr::Simple(
|
use nix::Error::Sys;
|
||||||
ErrorKind::PermissionDenied,
|
|
||||||
Errno::EPERM.desc().to_owned(),
|
impl GetErrorKind for Error {
|
||||||
),
|
fn kind(&self) -> ErrorKind {
|
||||||
},
|
match self {
|
||||||
UnixError::Sys(Errno::EINVAL) => Self {
|
Sys(EPERM) => ErrorKind::PermissionDenied,
|
||||||
repr: Repr::Simple(
|
Sys(EINVAL) => ErrorKind::InvalidInput,
|
||||||
ErrorKind::InvalidInput,
|
Sys(ENOENT) => ErrorKind::NotFound,
|
||||||
Errno::EINVAL.desc().to_owned(),
|
Sys(_) => ErrorKind::UnixError,
|
||||||
),
|
_ => ErrorKind::Other,
|
||||||
},
|
}
|
||||||
UnixError::Sys(Errno::ENOENT) => Self {
|
|
||||||
repr: Repr::Simple(
|
|
||||||
ErrorKind::NotFound,
|
|
||||||
Errno::ENOENT.desc().to_owned(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
UnixError::Sys(err) => Self {
|
|
||||||
repr: Repr::Simple(ErrorKind::UnixError, err.desc().to_owned()),
|
|
||||||
},
|
|
||||||
_ => Self {
|
|
||||||
repr: Repr::Simple(ErrorKind::Other, format!("{}", e)),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<import_map::ImportMapError> for DenoError {
|
impl GetErrorKind for dyn AnyError {
|
||||||
fn from(err: import_map::ImportMapError) -> Self {
|
fn kind(&self) -> ErrorKind {
|
||||||
Self {
|
use self::GetErrorKind as Get;
|
||||||
repr: Repr::ImportMapErr(err),
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn unix_error_kind(err: &dyn AnyError) -> Option<ErrorKind> {
|
||||||
|
err.downcast_ref::<unix::Error>().map(Get::kind)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<deno_dir::DenoDirError> for DenoError {
|
#[cfg(not(unix))]
|
||||||
fn from(err: deno_dir::DenoDirError) -> Self {
|
fn unix_error_kind(_: &dyn AnyError) -> Option<ErrorKind> {
|
||||||
Self {
|
None
|
||||||
repr: Repr::DenoDirErr(err),
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ModuleResolutionError> for DenoError {
|
None
|
||||||
fn from(err: ModuleResolutionError) -> Self {
|
.or_else(|| self.downcast_ref::<DenoError>().map(Get::kind))
|
||||||
Self {
|
.or_else(|| self.downcast_ref::<Diagnostic>().map(Get::kind))
|
||||||
repr: Repr::ModuleResolutionErr(err),
|
.or_else(|| self.downcast_ref::<hyper::Error>().map(Get::kind))
|
||||||
}
|
.or_else(|| self.downcast_ref::<ImportMapError>().map(Get::kind))
|
||||||
}
|
.or_else(|| self.downcast_ref::<io::Error>().map(Get::kind))
|
||||||
}
|
.or_else(|| self.downcast_ref::<JSError>().map(Get::kind))
|
||||||
|
.or_else(|| self.downcast_ref::<ModuleResolutionError>().map(Get::kind))
|
||||||
impl From<diagnostics::Diagnostic> for DenoError {
|
.or_else(|| self.downcast_ref::<StaticError>().map(Get::kind))
|
||||||
fn from(diagnostic: diagnostics::Diagnostic) -> Self {
|
.or_else(|| self.downcast_ref::<uri::InvalidUri>().map(Get::kind))
|
||||||
Self {
|
.or_else(|| self.downcast_ref::<url::ParseError>().map(Get::kind))
|
||||||
repr: Repr::Diagnostic(diagnostic),
|
.or_else(|| unix_error_kind(self))
|
||||||
}
|
.unwrap_or_else(|| {
|
||||||
}
|
panic!("Can't get ErrorKind for {:?}", self);
|
||||||
}
|
})
|
||||||
|
|
||||||
impl From<JSError> for DenoError {
|
|
||||||
fn from(err: JSError) -> Self {
|
|
||||||
Self {
|
|
||||||
repr: Repr::JSError(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bad_resource() -> DenoError {
|
|
||||||
new(ErrorKind::BadResource, String::from("bad resource id"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn permission_denied() -> DenoError {
|
|
||||||
new(
|
|
||||||
ErrorKind::PermissionDenied,
|
|
||||||
String::from("permission denied"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn op_not_implemented() -> DenoError {
|
|
||||||
new(
|
|
||||||
ErrorKind::OpNotAvailable,
|
|
||||||
String::from("op not implemented"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn worker_init_failed() -> DenoError {
|
|
||||||
// TODO(afinch7) pass worker error data through here
|
|
||||||
new(
|
|
||||||
ErrorKind::WorkerInitFailed,
|
|
||||||
String::from("worker init failed"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn no_buffer_specified() -> DenoError {
|
|
||||||
new(ErrorKind::InvalidInput, String::from("no buffer specified"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn no_async_support() -> DenoError {
|
|
||||||
new(
|
|
||||||
ErrorKind::NoAsyncSupport,
|
|
||||||
String::from("op doesn't support async calls"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn no_sync_support() -> DenoError {
|
|
||||||
new(
|
|
||||||
ErrorKind::NoSyncSupport,
|
|
||||||
String::from("op doesn't support sync calls"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn err_check<R>(r: Result<R, DenoError>) {
|
|
||||||
if let Err(e) = r {
|
|
||||||
panic!(e.to_string());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,16 +241,15 @@ pub fn err_check<R>(r: Result<R, DenoError>) {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ansi::strip_ansi_codes;
|
use crate::ansi::strip_ansi_codes;
|
||||||
use crate::deno_dir::DenoDirError;
|
|
||||||
use crate::deno_dir::DenoDirErrorKind;
|
|
||||||
use crate::diagnostics::Diagnostic;
|
use crate::diagnostics::Diagnostic;
|
||||||
use crate::diagnostics::DiagnosticCategory;
|
use crate::diagnostics::DiagnosticCategory;
|
||||||
use crate::diagnostics::DiagnosticItem;
|
use crate::diagnostics::DiagnosticItem;
|
||||||
use crate::import_map::ImportMapError;
|
use deno::ErrBox;
|
||||||
use deno::StackFrame;
|
use deno::StackFrame;
|
||||||
|
use deno::V8Exception;
|
||||||
|
|
||||||
fn js_error() -> JSError {
|
fn js_error() -> JSError {
|
||||||
JSError {
|
JSError::new(V8Exception {
|
||||||
message: "Error: foo bar".to_string(),
|
message: "Error: foo bar".to_string(),
|
||||||
source_line: None,
|
source_line: None,
|
||||||
script_resource_name: None,
|
script_resource_name: None,
|
||||||
|
@ -396,7 +288,7 @@ mod tests {
|
||||||
is_wasm: false,
|
is_wasm: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diagnostic() -> Diagnostic {
|
fn diagnostic() -> Diagnostic {
|
||||||
|
@ -436,22 +328,6 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MockSourceMapGetter {}
|
|
||||||
|
|
||||||
impl SourceMapGetter for MockSourceMapGetter {
|
|
||||||
fn get_source_map(&self, _script_name: &str) -> Option<Vec<u8>> {
|
|
||||||
Some(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_source_line(
|
|
||||||
&self,
|
|
||||||
_script_name: &str,
|
|
||||||
_line: usize,
|
|
||||||
) -> Option<String> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn io_error() -> io::Error {
|
fn io_error() -> io::Error {
|
||||||
io::Error::from(io::ErrorKind::NotFound)
|
io::Error::from(io::ErrorKind::NotFound)
|
||||||
}
|
}
|
||||||
|
@ -466,30 +342,24 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deno_dir_error() -> DenoDirError {
|
|
||||||
DenoDirError::new(
|
|
||||||
"a deno dir error".to_string(),
|
|
||||||
DenoDirErrorKind::UnsupportedFetchScheme,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_simple_error() {
|
fn test_simple_error() {
|
||||||
let err = new(ErrorKind::NoError, "foo".to_string());
|
let err =
|
||||||
|
ErrBox::from(DenoError::new(ErrorKind::NoError, "foo".to_string()));
|
||||||
assert_eq!(err.kind(), ErrorKind::NoError);
|
assert_eq!(err.kind(), ErrorKind::NoError);
|
||||||
assert_eq!(err.to_string(), "foo");
|
assert_eq!(err.to_string(), "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_io_error() {
|
fn test_io_error() {
|
||||||
let err = DenoError::from(io_error());
|
let err = ErrBox::from(io_error());
|
||||||
assert_eq!(err.kind(), ErrorKind::NotFound);
|
assert_eq!(err.kind(), ErrorKind::NotFound);
|
||||||
assert_eq!(err.to_string(), "entity not found");
|
assert_eq!(err.to_string(), "entity not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_url_error() {
|
fn test_url_error() {
|
||||||
let err = DenoError::from(url_error());
|
let err = ErrBox::from(url_error());
|
||||||
assert_eq!(err.kind(), ErrorKind::EmptyHost);
|
assert_eq!(err.kind(), ErrorKind::EmptyHost);
|
||||||
assert_eq!(err.to_string(), "empty host");
|
assert_eq!(err.to_string(), "empty host");
|
||||||
}
|
}
|
||||||
|
@ -498,32 +368,25 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_diagnostic() {
|
fn test_diagnostic() {
|
||||||
let err = DenoError::from(diagnostic());
|
let err = ErrBox::from(diagnostic());
|
||||||
assert_eq!(err.kind(), ErrorKind::Diagnostic);
|
assert_eq!(err.kind(), ErrorKind::Diagnostic);
|
||||||
assert_eq!(strip_ansi_codes(&err.to_string()), "error TS2322: Example 1\n\n► deno/tests/complex_diagnostics.ts:19:3\n\n19 values: o => [\n ~~~~~~\n\nerror TS2000: Example 2\n\n► /foo/bar.ts:129:3\n\n129 values: undefined,\n ~~~~~~\n\n\nFound 2 errors.\n");
|
assert_eq!(strip_ansi_codes(&err.to_string()), "error TS2322: Example 1\n\n► deno/tests/complex_diagnostics.ts:19:3\n\n19 values: o => [\n ~~~~~~\n\nerror TS2000: Example 2\n\n► /foo/bar.ts:129:3\n\n129 values: undefined,\n ~~~~~~\n\n\nFound 2 errors.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_js_error() {
|
fn test_js_error() {
|
||||||
let err = DenoError::from(js_error());
|
let err = ErrBox::from(js_error());
|
||||||
assert_eq!(err.kind(), ErrorKind::JSError);
|
assert_eq!(err.kind(), ErrorKind::JSError);
|
||||||
assert_eq!(strip_ansi_codes(&err.to_string()), "error: Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2");
|
assert_eq!(strip_ansi_codes(&err.to_string()), "error: Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_import_map_error() {
|
fn test_import_map_error() {
|
||||||
let err = DenoError::from(import_map_error());
|
let err = ErrBox::from(import_map_error());
|
||||||
assert_eq!(err.kind(), ErrorKind::ImportMapError);
|
assert_eq!(err.kind(), ErrorKind::ImportMapError);
|
||||||
assert_eq!(err.to_string(), "an import map error");
|
assert_eq!(err.to_string(), "an import map error");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_deno_dir_error() {
|
|
||||||
let err = DenoError::from(deno_dir_error());
|
|
||||||
assert_eq!(err.kind(), ErrorKind::DenoDirError);
|
|
||||||
assert_eq!(err.to_string(), "a deno dir error\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bad_resource() {
|
fn test_bad_resource() {
|
||||||
let err = bad_resource();
|
let err = bad_resource();
|
||||||
|
@ -545,13 +408,6 @@ mod tests {
|
||||||
assert_eq!(err.to_string(), "op not implemented");
|
assert_eq!(err.to_string(), "op not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_worker_init_failed() {
|
|
||||||
let err = worker_init_failed();
|
|
||||||
assert_eq!(err.kind(), ErrorKind::WorkerInitFailed);
|
|
||||||
assert_eq!(err.to_string(), "worker init failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_no_buffer_specified() {
|
fn test_no_buffer_specified() {
|
||||||
let err = no_buffer_specified();
|
let err = no_buffer_specified();
|
||||||
|
@ -572,20 +428,4 @@ mod tests {
|
||||||
assert_eq!(err.kind(), ErrorKind::NoSyncSupport);
|
assert_eq!(err.kind(), ErrorKind::NoSyncSupport);
|
||||||
assert_eq!(err.to_string(), "op doesn't support sync calls");
|
assert_eq!(err.to_string(), "op doesn't support sync calls");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_apply_source_map_invalid() {
|
|
||||||
let getter = MockSourceMapGetter {};
|
|
||||||
let err = new(ErrorKind::NotFound, "not found".to_string());
|
|
||||||
err.apply_source_map(&getter);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_err_check() {
|
|
||||||
err_check(
|
|
||||||
Err(new(ErrorKind::NotFound, "foo".to_string())) as Result<(), DenoError>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::fmt_errors::format_maybe_source_name;
|
||||||
use crate::fmt_errors::DisplayFormatter;
|
use crate::fmt_errors::DisplayFormatter;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use serde_json::value::Value;
|
use serde_json::value::Value;
|
||||||
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -66,6 +67,12 @@ impl fmt::Display for Diagnostic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Error for Diagnostic {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
&self.items[0].message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct DiagnosticItem {
|
pub struct DiagnosticItem {
|
||||||
/// The top level message relating to the diagnostic item.
|
/// The top level message relating to the diagnostic item.
|
||||||
|
|
|
@ -127,10 +127,11 @@ mod ops {
|
||||||
use crate::deno_error;
|
use crate::deno_error;
|
||||||
use crate::resources;
|
use crate::resources;
|
||||||
use crate::tokio_write;
|
use crate::tokio_write;
|
||||||
|
use deno::ErrBox;
|
||||||
use deno::PinnedBuf;
|
use deno::PinnedBuf;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
|
||||||
type MinimalOp = dyn Future<Item = i32, Error = deno_error::DenoError> + Send;
|
type MinimalOp = dyn Future<Item = i32, Error = ErrBox> + Send;
|
||||||
|
|
||||||
pub fn read(rid: i32, zero_copy: Option<PinnedBuf>) -> Box<MinimalOp> {
|
pub fn read(rid: i32, zero_copy: Option<PinnedBuf>) -> Box<MinimalOp> {
|
||||||
debug!("read rid={}", rid);
|
debug!("read rid={}", rid);
|
||||||
|
@ -144,7 +145,7 @@ mod ops {
|
||||||
None => Box::new(futures::future::err(deno_error::bad_resource())),
|
None => Box::new(futures::future::err(deno_error::bad_resource())),
|
||||||
Some(resource) => Box::new(
|
Some(resource) => Box::new(
|
||||||
tokio::io::read(resource, zero_copy)
|
tokio::io::read(resource, zero_copy)
|
||||||
.map_err(deno_error::DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
.and_then(move |(_resource, _buf, nread)| Ok(nread as i32)),
|
.and_then(move |(_resource, _buf, nread)| Ok(nread as i32)),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -162,7 +163,7 @@ mod ops {
|
||||||
None => Box::new(futures::future::err(deno_error::bad_resource())),
|
None => Box::new(futures::future::err(deno_error::bad_resource())),
|
||||||
Some(resource) => Box::new(
|
Some(resource) => Box::new(
|
||||||
tokio_write::write(resource, zero_copy)
|
tokio_write::write(resource, zero_copy)
|
||||||
.map_err(deno_error::DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
.and_then(move |(_resource, _buf, nwritten)| Ok(nwritten as i32)),
|
.and_then(move |(_resource, _buf, nwritten)| Ok(nwritten as i32)),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
//! This mod provides DenoError to unify errors across Deno.
|
//! This mod provides DenoError to unify errors across Deno.
|
||||||
use crate::ansi;
|
use crate::ansi;
|
||||||
use deno::JSError;
|
use crate::source_maps::apply_source_map;
|
||||||
|
use crate::source_maps::SourceMapGetter;
|
||||||
|
use deno::ErrBox;
|
||||||
use deno::StackFrame;
|
use deno::StackFrame;
|
||||||
|
use deno::V8Exception;
|
||||||
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// A trait which specifies parts of a diagnostic like item needs to be able to
|
/// A trait which specifies parts of a diagnostic like item needs to be able to
|
||||||
|
@ -104,10 +108,50 @@ pub fn format_error_message(msg: String) -> String {
|
||||||
format!("{} {}", preamble, msg)
|
format!("{} {}", preamble, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around JSError which provides color to_string.
|
fn format_stack_frame(frame: &StackFrame) -> String {
|
||||||
pub struct JSErrorColor<'a>(pub &'a JSError);
|
// Note when we print to string, we change from 0-indexed to 1-indexed.
|
||||||
|
let function_name = ansi::italic_bold(frame.function_name.clone());
|
||||||
|
let source_loc =
|
||||||
|
format_source_name(frame.script_name.clone(), frame.line, frame.column);
|
||||||
|
|
||||||
impl<'a> DisplayFormatter for JSErrorColor<'a> {
|
if !frame.function_name.is_empty() {
|
||||||
|
format!(" at {} ({})", function_name, source_loc)
|
||||||
|
} else if frame.is_eval {
|
||||||
|
format!(" at eval ({})", source_loc)
|
||||||
|
} else {
|
||||||
|
format!(" at {}", source_loc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper around V8Exception which provides color to_string.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct JSError(V8Exception);
|
||||||
|
|
||||||
|
impl JSError {
|
||||||
|
pub fn new(v8_exception: V8Exception) -> Self {
|
||||||
|
Self(v8_exception)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_json(
|
||||||
|
json_str: &str,
|
||||||
|
source_map_getter: &impl SourceMapGetter,
|
||||||
|
) -> ErrBox {
|
||||||
|
let unmapped_exception = V8Exception::from_json(json_str).unwrap();
|
||||||
|
Self::from_v8_exception(unmapped_exception, source_map_getter)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_v8_exception(
|
||||||
|
unmapped_exception: V8Exception,
|
||||||
|
source_map_getter: &impl SourceMapGetter,
|
||||||
|
) -> ErrBox {
|
||||||
|
let mapped_exception =
|
||||||
|
apply_source_map(&unmapped_exception, source_map_getter);
|
||||||
|
let js_error = Self(mapped_exception);
|
||||||
|
ErrBox::from(js_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayFormatter for JSError {
|
||||||
fn format_category_and_code(&self) -> String {
|
fn format_category_and_code(&self) -> String {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
|
@ -136,7 +180,7 @@ impl<'a> DisplayFormatter for JSErrorColor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_source_name(&self) -> String {
|
fn format_source_name(&self) -> String {
|
||||||
let e = self.0;
|
let e = &self.0;
|
||||||
if e.script_resource_name.is_none() {
|
if e.script_resource_name.is_none() {
|
||||||
return "".to_string();
|
return "".to_string();
|
||||||
}
|
}
|
||||||
|
@ -152,7 +196,7 @@ impl<'a> DisplayFormatter for JSErrorColor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for JSErrorColor<'a> {
|
impl fmt::Display for JSError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
@ -163,39 +207,21 @@ impl<'a> fmt::Display for JSErrorColor<'a> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for frame in &self.0.frames {
|
for frame in &self.0.frames {
|
||||||
write!(f, "\n{}", StackFrameColor(&frame).to_string())?;
|
write!(f, "\n{}", format_stack_frame(&frame))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StackFrameColor<'a>(&'a StackFrame);
|
impl Error for JSError {}
|
||||||
|
|
||||||
impl<'a> fmt::Display for StackFrameColor<'a> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let frame = self.0;
|
|
||||||
// Note when we print to string, we change from 0-indexed to 1-indexed.
|
|
||||||
let function_name = ansi::italic_bold(frame.function_name.clone());
|
|
||||||
let script_line_column =
|
|
||||||
format_source_name(frame.script_name.clone(), frame.line, frame.column);
|
|
||||||
|
|
||||||
if !frame.function_name.is_empty() {
|
|
||||||
write!(f, " at {} ({})", function_name, script_line_column)
|
|
||||||
} else if frame.is_eval {
|
|
||||||
write!(f, " at eval ({})", script_line_column)
|
|
||||||
} else {
|
|
||||||
write!(f, " at {}", script_line_column)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ansi::strip_ansi_codes;
|
use crate::ansi::strip_ansi_codes;
|
||||||
|
|
||||||
fn error1() -> JSError {
|
fn error1() -> V8Exception {
|
||||||
JSError {
|
V8Exception {
|
||||||
message: "Error: foo bar".to_string(),
|
message: "Error: foo bar".to_string(),
|
||||||
source_line: None,
|
source_line: None,
|
||||||
script_resource_name: None,
|
script_resource_name: None,
|
||||||
|
@ -240,7 +266,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn js_error_to_string() {
|
fn js_error_to_string() {
|
||||||
let e = error1();
|
let e = error1();
|
||||||
assert_eq!("error: Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2", strip_ansi_codes(&JSErrorColor(&e).to_string()));
|
assert_eq!("error: Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2", strip_ansi_codes(&JSError(e).to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
13
cli/fs.rs
13
cli/fs.rs
|
@ -5,6 +5,7 @@ use std::io::ErrorKind;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use deno::ErrBox;
|
||||||
use rand;
|
use rand;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
@ -15,8 +16,6 @@ use std::os::unix::fs::DirBuilderExt;
|
||||||
#[cfg(any(unix))]
|
#[cfg(any(unix))]
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
|
|
||||||
pub fn write_file<T: AsRef<[u8]>>(
|
pub fn write_file<T: AsRef<[u8]>>(
|
||||||
filename: &Path,
|
filename: &Path,
|
||||||
data: T,
|
data: T,
|
||||||
|
@ -114,18 +113,16 @@ pub fn normalize_path(path: &Path) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn chown(path: &str, uid: u32, gid: u32) -> DenoResult<()> {
|
pub fn chown(path: &str, uid: u32, gid: u32) -> Result<(), ErrBox> {
|
||||||
use crate::deno_error::DenoError;
|
|
||||||
let nix_uid = Uid::from_raw(uid);
|
let nix_uid = Uid::from_raw(uid);
|
||||||
let nix_gid = Gid::from_raw(gid);
|
let nix_gid = Gid::from_raw(gid);
|
||||||
unix_chown(path, Option::Some(nix_uid), Option::Some(nix_gid))
|
unix_chown(path, Option::Some(nix_uid), Option::Some(nix_gid))
|
||||||
.map_err(DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
pub fn chown(_path: &str, _uid: u32, _gid: u32) -> DenoResult<()> {
|
pub fn chown(_path: &str, _uid: u32, _gid: u32) -> Result<(), ErrBox> {
|
||||||
// Noop
|
// Noop
|
||||||
// TODO: implement chown for Windows
|
// TODO: implement chown for Windows
|
||||||
use crate::deno_error;
|
Err(crate::deno_error::op_not_implemented())
|
||||||
Err(deno_error::op_not_implemented())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::deno_error;
|
use crate::deno_error;
|
||||||
use crate::deno_error::DenoError;
|
use crate::deno_error::DenoError;
|
||||||
|
use deno::ErrBox;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use futures::future::{loop_fn, Loop};
|
use futures::future::{loop_fn, Loop};
|
||||||
use futures::{future, Future, Stream};
|
use futures::{future, Future, Stream};
|
||||||
|
@ -57,13 +58,13 @@ fn resolve_uri_from_location(base_uri: &Uri, location: &str) -> Uri {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::tokio_util;
|
use crate::tokio_util;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// Synchronously fetchs the given HTTP URL. Returns (content, media_type).
|
/// Synchronously fetchs the given HTTP URL. Returns (content, media_type).
|
||||||
pub fn fetch_sync_string(module_name: &str) -> DenoResult<(String, String)> {
|
pub fn fetch_sync_string(
|
||||||
|
module_name: &str,
|
||||||
|
) -> Result<(String, String), ErrBox> {
|
||||||
tokio_util::block_on(fetch_string(module_name))
|
tokio_util::block_on(fetch_string(module_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,15 +81,15 @@ pub enum FetchOnceResult {
|
||||||
/// yields Redirect(url).
|
/// yields Redirect(url).
|
||||||
pub fn fetch_string_once(
|
pub fn fetch_string_once(
|
||||||
url: http::uri::Uri,
|
url: http::uri::Uri,
|
||||||
) -> impl Future<Item = FetchOnceResult, Error = DenoError> {
|
) -> impl Future<Item = FetchOnceResult, Error = ErrBox> {
|
||||||
type FetchAttempt = (Option<String>, Option<String>, Option<FetchOnceResult>);
|
type FetchAttempt = (Option<String>, Option<String>, Option<FetchOnceResult>);
|
||||||
let client = get_client();
|
let client = get_client();
|
||||||
client
|
client
|
||||||
.get(url.clone())
|
.get(url.clone())
|
||||||
.map_err(DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
.and_then(
|
.and_then(
|
||||||
move |response| -> Box<
|
move |response| -> Box<
|
||||||
dyn Future<Item = FetchAttempt, Error = DenoError> + Send,
|
dyn Future<Item = FetchAttempt, Error = ErrBox> + Send,
|
||||||
> {
|
> {
|
||||||
if response.status().is_redirection() {
|
if response.status().is_redirection() {
|
||||||
let location_string = response
|
let location_string = response
|
||||||
|
@ -108,10 +109,10 @@ pub fn fetch_string_once(
|
||||||
} else if response.status().is_client_error()
|
} else if response.status().is_client_error()
|
||||||
|| response.status().is_server_error()
|
|| response.status().is_server_error()
|
||||||
{
|
{
|
||||||
return Box::new(future::err(deno_error::new(
|
return Box::new(future::err(DenoError::new(
|
||||||
deno_error::ErrorKind::Other,
|
deno_error::ErrorKind::Other,
|
||||||
format!("Import '{}' failed: {}", &url, response.status()),
|
format!("Import '{}' failed: {}", &url, response.status()),
|
||||||
)));
|
).into()));
|
||||||
}
|
}
|
||||||
let content_type = response
|
let content_type = response
|
||||||
.headers()
|
.headers()
|
||||||
|
@ -121,7 +122,7 @@ pub fn fetch_string_once(
|
||||||
.into_body()
|
.into_body()
|
||||||
.concat2()
|
.concat2()
|
||||||
.map(|body| String::from_utf8(body.to_vec()).ok())
|
.map(|body| String::from_utf8(body.to_vec()).ok())
|
||||||
.map_err(DenoError::from);
|
.map_err(ErrBox::from);
|
||||||
Box::new(body.join3(future::ok(content_type), future::ok(None)))
|
Box::new(body.join3(future::ok(content_type), future::ok(None)))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -142,7 +143,7 @@ pub fn fetch_string_once(
|
||||||
/// Asynchronously fetchs the given HTTP URL. Returns (content, media_type).
|
/// Asynchronously fetchs the given HTTP URL. Returns (content, media_type).
|
||||||
pub fn fetch_string(
|
pub fn fetch_string(
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
) -> impl Future<Item = (String, String), Error = DenoError> {
|
) -> impl Future<Item = (String, String), Error = ErrBox> {
|
||||||
let url = module_name.parse::<Uri>().unwrap();
|
let url = module_name.parse::<Uri>().unwrap();
|
||||||
let client = get_client();
|
let client = get_client();
|
||||||
// TODO(kevinkassimo): consider set a max redirection counter
|
// TODO(kevinkassimo): consider set a max redirection counter
|
||||||
|
@ -150,7 +151,7 @@ pub fn fetch_string(
|
||||||
loop_fn((client, url), |(client, url)| {
|
loop_fn((client, url), |(client, url)| {
|
||||||
client
|
client
|
||||||
.get(url.clone())
|
.get(url.clone())
|
||||||
.map_err(DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
.and_then(move |response| {
|
.and_then(move |response| {
|
||||||
if response.status().is_redirection() {
|
if response.status().is_redirection() {
|
||||||
let location_string = response
|
let location_string = response
|
||||||
|
@ -165,10 +166,12 @@ pub fn fetch_string(
|
||||||
return Ok(Loop::Continue((client, new_url)));
|
return Ok(Loop::Continue((client, new_url)));
|
||||||
}
|
}
|
||||||
if !response.status().is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(deno_error::new(
|
return Err(
|
||||||
deno_error::ErrorKind::NotFound,
|
DenoError::new(
|
||||||
"module not found".to_string(),
|
deno_error::ErrorKind::NotFound,
|
||||||
));
|
"module not found".to_string(),
|
||||||
|
).into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Ok(Loop::Break(response))
|
Ok(Loop::Break(response))
|
||||||
})
|
})
|
||||||
|
@ -181,7 +184,7 @@ pub fn fetch_string(
|
||||||
.into_body()
|
.into_body()
|
||||||
.concat2()
|
.concat2()
|
||||||
.map(|body| String::from_utf8(body.to_vec()).unwrap())
|
.map(|body| String::from_utf8(body.to_vec()).unwrap())
|
||||||
.map_err(DenoError::from);
|
.map_err(ErrBox::from);
|
||||||
body.join(future::ok(content_type))
|
body.join(future::ok(content_type))
|
||||||
}).and_then(|(body_string, maybe_content_type)| {
|
}).and_then(|(body_string, maybe_content_type)| {
|
||||||
future::ok((body_string, maybe_content_type.unwrap()))
|
future::ok((body_string, maybe_content_type.unwrap()))
|
||||||
|
|
|
@ -3,6 +3,8 @@ use indexmap::IndexMap;
|
||||||
use serde_json::Map;
|
use serde_json::Map;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -19,6 +21,14 @@ impl ImportMapError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ImportMapError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.pad(&self.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for ImportMapError {}
|
||||||
|
|
||||||
// NOTE: here is difference between deno and reference implementation - deno currently
|
// NOTE: here is difference between deno and reference implementation - deno currently
|
||||||
// can't resolve URL with other schemes (eg. data:, about:, blob:)
|
// can't resolve URL with other schemes (eg. data:, about:, blob:)
|
||||||
const SUPPORTED_FETCH_SCHEMES: [&str; 3] = ["http", "https", "file"];
|
const SUPPORTED_FETCH_SCHEMES: [&str; 3] = ["http", "https", "file"];
|
||||||
|
|
21
cli/main.rs
21
cli/main.rs
|
@ -46,11 +46,11 @@ pub mod version;
|
||||||
pub mod worker;
|
pub mod worker;
|
||||||
|
|
||||||
use crate::compiler::bundle_async;
|
use crate::compiler::bundle_async;
|
||||||
use crate::deno_error::DenoError;
|
|
||||||
use crate::progress::Progress;
|
use crate::progress::Progress;
|
||||||
use crate::state::ThreadSafeState;
|
use crate::state::ThreadSafeState;
|
||||||
use crate::worker::Worker;
|
use crate::worker::Worker;
|
||||||
use deno::v8_set_flags;
|
use deno::v8_set_flags;
|
||||||
|
use deno::ErrBox;
|
||||||
use deno::ModuleSpecifier;
|
use deno::ModuleSpecifier;
|
||||||
use flags::DenoFlags;
|
use flags::DenoFlags;
|
||||||
use flags::DenoSubcommand;
|
use flags::DenoSubcommand;
|
||||||
|
@ -86,17 +86,14 @@ impl log::Log for Logger {
|
||||||
fn flush(&self) {}
|
fn flush(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_err_and_exit(err: DenoError) {
|
fn print_err_and_exit(err: ErrBox) {
|
||||||
eprintln!("{}", err.to_string());
|
eprintln!("{}", err.to_string());
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn js_check<E>(r: Result<(), E>)
|
fn js_check(r: Result<(), ErrBox>) {
|
||||||
where
|
|
||||||
E: Into<DenoError>,
|
|
||||||
{
|
|
||||||
if let Err(err) = r {
|
if let Err(err) = r {
|
||||||
print_err_and_exit(err.into());
|
print_err_and_exit(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +261,7 @@ fn xeval_command(flags: DenoFlags, argv: Vec<String>) {
|
||||||
.then(|result| {
|
.then(|result| {
|
||||||
js_check(result);
|
js_check(result);
|
||||||
Ok(())
|
Ok(())
|
||||||
}).map_err(|(err, _worker): (DenoError, Worker)| print_err_and_exit(err))
|
}).map_err(print_err_and_exit)
|
||||||
});
|
});
|
||||||
tokio_util::run(main_future);
|
tokio_util::run(main_future);
|
||||||
}
|
}
|
||||||
|
@ -277,10 +274,10 @@ fn bundle_command(flags: DenoFlags, argv: Vec<String>) {
|
||||||
let out_file = state.argv[2].clone();
|
let out_file = state.argv[2].clone();
|
||||||
debug!(">>>>> bundle_async START");
|
debug!(">>>>> bundle_async START");
|
||||||
let bundle_future = bundle_async(state, main_module.to_string(), out_file)
|
let bundle_future = bundle_async(state, main_module.to_string(), out_file)
|
||||||
.map_err(|e| {
|
.map_err(|err| {
|
||||||
debug!("diagnostics returned, exiting!");
|
debug!("diagnostics returned, exiting!");
|
||||||
eprintln!("\n{}", e.to_string());
|
eprintln!("");
|
||||||
std::process::exit(1);
|
print_err_and_exit(err);
|
||||||
}).and_then(move |_| {
|
}).and_then(move |_| {
|
||||||
debug!(">>>>> bundle_async END");
|
debug!(">>>>> bundle_async END");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -299,7 +296,7 @@ fn run_repl(flags: DenoFlags, argv: Vec<String>) {
|
||||||
.then(|result| {
|
.then(|result| {
|
||||||
js_check(result);
|
js_check(result);
|
||||||
Ok(())
|
Ok(())
|
||||||
}).map_err(|(err, _worker): (DenoError, Worker)| print_err_and_exit(err))
|
}).map_err(|(err, _worker): (ErrBox, Worker)| print_err_and_exit(err))
|
||||||
});
|
});
|
||||||
tokio_util::run(main_future);
|
tokio_util::run(main_future);
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,6 @@ enum ErrorKind: byte {
|
||||||
WouldBlock,
|
WouldBlock,
|
||||||
InvalidInput,
|
InvalidInput,
|
||||||
InvalidData,
|
InvalidData,
|
||||||
InvalidPath,
|
|
||||||
TimedOut,
|
TimedOut,
|
||||||
Interrupted,
|
Interrupted,
|
||||||
WriteZero,
|
WriteZero,
|
||||||
|
@ -142,8 +141,9 @@ enum ErrorKind: byte {
|
||||||
NoAsyncSupport,
|
NoAsyncSupport,
|
||||||
NoSyncSupport,
|
NoSyncSupport,
|
||||||
ImportMapError,
|
ImportMapError,
|
||||||
|
InvalidPath,
|
||||||
ImportPrefixMissing,
|
ImportPrefixMissing,
|
||||||
DenoDirError,
|
UnsupportedFetchScheme,
|
||||||
|
|
||||||
// other kinds
|
// other kinds
|
||||||
Diagnostic,
|
Diagnostic,
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
// Helpers for serialization.
|
// Helpers for serialization.
|
||||||
use crate::deno_error;
|
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
use crate::msg;
|
use crate::msg;
|
||||||
|
use deno::ErrBox;
|
||||||
use flatbuffers;
|
use flatbuffers;
|
||||||
use http::header::HeaderName;
|
use http::header::HeaderName;
|
||||||
use http::uri::Uri;
|
use http::uri::Uri;
|
||||||
|
@ -97,14 +95,13 @@ pub fn serialize_http_response<'bldr>(
|
||||||
pub fn deserialize_request(
|
pub fn deserialize_request(
|
||||||
header_msg: msg::HttpHeader<'_>,
|
header_msg: msg::HttpHeader<'_>,
|
||||||
body: Body,
|
body: Body,
|
||||||
) -> DenoResult<Request<Body>> {
|
) -> Result<Request<Body>, ErrBox> {
|
||||||
let mut r = Request::new(body);
|
let mut r = Request::new(body);
|
||||||
|
|
||||||
assert!(header_msg.is_request());
|
assert!(header_msg.is_request());
|
||||||
|
|
||||||
let u = header_msg.url().unwrap();
|
let u = header_msg.url().unwrap();
|
||||||
let u = Uri::from_str(u)
|
let u = Uri::from_str(u).map_err(ErrBox::from)?;
|
||||||
.map_err(|e| deno_error::new(msg::ErrorKind::InvalidUri, e.to_string()))?;
|
|
||||||
*r.uri_mut() = u;
|
*r.uri_mut() = u;
|
||||||
|
|
||||||
if let Some(method) = header_msg.method() {
|
if let Some(method) = header_msg.method() {
|
||||||
|
|
144
cli/ops.rs
144
cli/ops.rs
|
@ -3,12 +3,12 @@ use atty;
|
||||||
use crate::ansi;
|
use crate::ansi;
|
||||||
use crate::deno_dir::resolve_from_cwd;
|
use crate::deno_dir::resolve_from_cwd;
|
||||||
use crate::deno_error;
|
use crate::deno_error;
|
||||||
use crate::deno_error::err_check;
|
|
||||||
use crate::deno_error::DenoError;
|
use crate::deno_error::DenoError;
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
use crate::deno_error::ErrorKind;
|
use crate::deno_error::ErrorKind;
|
||||||
|
use crate::deno_error::GetErrorKind;
|
||||||
use crate::dispatch_minimal::dispatch_minimal;
|
use crate::dispatch_minimal::dispatch_minimal;
|
||||||
use crate::dispatch_minimal::parse_min_record;
|
use crate::dispatch_minimal::parse_min_record;
|
||||||
|
use crate::fmt_errors::JSError;
|
||||||
use crate::fs as deno_fs;
|
use crate::fs as deno_fs;
|
||||||
use crate::http_util;
|
use crate::http_util;
|
||||||
use crate::msg;
|
use crate::msg;
|
||||||
|
@ -28,7 +28,7 @@ use crate::version;
|
||||||
use crate::worker::Worker;
|
use crate::worker::Worker;
|
||||||
use deno::Buf;
|
use deno::Buf;
|
||||||
use deno::CoreOp;
|
use deno::CoreOp;
|
||||||
use deno::JSError;
|
use deno::ErrBox;
|
||||||
use deno::Loader;
|
use deno::Loader;
|
||||||
use deno::ModuleSpecifier;
|
use deno::ModuleSpecifier;
|
||||||
use deno::Op;
|
use deno::Op;
|
||||||
|
@ -65,7 +65,7 @@ use std::os::unix::fs::PermissionsExt;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::process::ExitStatusExt;
|
use std::os::unix::process::ExitStatusExt;
|
||||||
|
|
||||||
type CliOpResult = OpResult<DenoError>;
|
type CliOpResult = OpResult<ErrBox>;
|
||||||
|
|
||||||
type CliDispatchFn =
|
type CliDispatchFn =
|
||||||
fn(state: &ThreadSafeState, base: &msg::Base<'_>, data: Option<PinnedBuf>)
|
fn(state: &ThreadSafeState, base: &msg::Base<'_>, data: Option<PinnedBuf>)
|
||||||
|
@ -132,7 +132,7 @@ pub fn dispatch_all_legacy(
|
||||||
}
|
}
|
||||||
Ok(Op::Async(fut)) => {
|
Ok(Op::Async(fut)) => {
|
||||||
let result_fut = Box::new(
|
let result_fut = Box::new(
|
||||||
fut.or_else(move |err: DenoError| -> Result<Buf, ()> {
|
fut.or_else(move |err: ErrBox| -> Result<Buf, ()> {
|
||||||
debug!("op err {}", err);
|
debug!("op err {}", err);
|
||||||
// No matter whether we got an Err or Ok, we want a serialized message to
|
// No matter whether we got an Err or Ok, we want a serialized message to
|
||||||
// send back. So transform the DenoError into a Buf.
|
// send back. So transform the DenoError into a Buf.
|
||||||
|
@ -410,11 +410,9 @@ fn op_format_error(
|
||||||
) -> CliOpResult {
|
) -> CliOpResult {
|
||||||
assert!(data.is_none());
|
assert!(data.is_none());
|
||||||
let inner = base.inner_as_format_error().unwrap();
|
let inner = base.inner_as_format_error().unwrap();
|
||||||
let orig_error = String::from(inner.error().unwrap());
|
let json_str = inner.error().unwrap();
|
||||||
|
let error = JSError::from_json(json_str, &state.dir);
|
||||||
let js_error = JSError::from_v8_exception(&orig_error).unwrap();
|
let error_string = error.to_string();
|
||||||
let error_mapped = DenoError::from(js_error).apply_source_map(&state.dir);
|
|
||||||
let error_string = error_mapped.to_string();
|
|
||||||
|
|
||||||
let mut builder = FlatBufferBuilder::new();
|
let mut builder = FlatBufferBuilder::new();
|
||||||
let new_error = builder.create_string(&error_string);
|
let new_error = builder.create_string(&error_string);
|
||||||
|
@ -495,10 +493,10 @@ fn op_cache(
|
||||||
|
|
||||||
if extension == ".map" {
|
if extension == ".map" {
|
||||||
debug!("cache {:?}", source_map_path);
|
debug!("cache {:?}", source_map_path);
|
||||||
fs::write(source_map_path, contents).map_err(DenoError::from)?;
|
fs::write(source_map_path, contents).map_err(ErrBox::from)?;
|
||||||
} else if extension == ".js" {
|
} else if extension == ".js" {
|
||||||
debug!("cache {:?}", js_cache_path);
|
debug!("cache {:?}", js_cache_path);
|
||||||
fs::write(js_cache_path, contents).map_err(DenoError::from)?;
|
fs::write(js_cache_path, contents).map_err(ErrBox::from)?;
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
@ -735,39 +733,38 @@ fn op_fetch(
|
||||||
|
|
||||||
let req = msg_util::deserialize_request(header, body)?;
|
let req = msg_util::deserialize_request(header, body)?;
|
||||||
|
|
||||||
let url_ = url::Url::parse(url).map_err(DenoError::from)?;
|
let url_ = url::Url::parse(url).map_err(ErrBox::from)?;
|
||||||
state.check_net_url(url_)?;
|
state.check_net_url(url_)?;
|
||||||
|
|
||||||
let client = http_util::get_client();
|
let client = http_util::get_client();
|
||||||
|
|
||||||
debug!("Before fetch {}", url);
|
debug!("Before fetch {}", url);
|
||||||
let future =
|
let future = client
|
||||||
client
|
.request(req)
|
||||||
.request(req)
|
.map_err(ErrBox::from)
|
||||||
.map_err(DenoError::from)
|
.and_then(move |res| {
|
||||||
.and_then(move |res| {
|
let builder = &mut FlatBufferBuilder::new();
|
||||||
let builder = &mut FlatBufferBuilder::new();
|
let header_off = msg_util::serialize_http_response(builder, &res);
|
||||||
let header_off = msg_util::serialize_http_response(builder, &res);
|
let body = res.into_body();
|
||||||
let body = res.into_body();
|
let body_resource = resources::add_hyper_body(body);
|
||||||
let body_resource = resources::add_hyper_body(body);
|
let inner = msg::FetchRes::create(
|
||||||
let inner = msg::FetchRes::create(
|
builder,
|
||||||
builder,
|
&msg::FetchResArgs {
|
||||||
&msg::FetchResArgs {
|
header: Some(header_off),
|
||||||
header: Some(header_off),
|
body_rid: body_resource.rid,
|
||||||
body_rid: body_resource.rid,
|
},
|
||||||
},
|
);
|
||||||
);
|
|
||||||
|
|
||||||
Ok(serialize_response(
|
Ok(serialize_response(
|
||||||
cmd_id,
|
cmd_id,
|
||||||
builder,
|
builder,
|
||||||
msg::BaseArgs {
|
msg::BaseArgs {
|
||||||
inner: Some(inner.as_union_value()),
|
inner: Some(inner.as_union_value()),
|
||||||
inner_type: msg::Any::FetchRes,
|
inner_type: msg::Any::FetchRes,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
if base.sync() {
|
if base.sync() {
|
||||||
let result_buf = future.wait()?;
|
let result_buf = future.wait()?;
|
||||||
Ok(Op::Sync(result_buf))
|
Ok(Op::Sync(result_buf))
|
||||||
|
@ -778,9 +775,9 @@ fn op_fetch(
|
||||||
|
|
||||||
// This is just type conversion. Implement From trait?
|
// This is just type conversion. Implement From trait?
|
||||||
// See https://github.com/tokio-rs/tokio/blob/ffd73a64e7ec497622b7f939e38017afe7124dc4/tokio-fs/src/lib.rs#L76-L85
|
// See https://github.com/tokio-rs/tokio/blob/ffd73a64e7ec497622b7f939e38017afe7124dc4/tokio-fs/src/lib.rs#L76-L85
|
||||||
fn convert_blocking<F>(f: F) -> Poll<Buf, DenoError>
|
fn convert_blocking<F>(f: F) -> Poll<Buf, ErrBox>
|
||||||
where
|
where
|
||||||
F: FnOnce() -> DenoResult<Buf>,
|
F: FnOnce() -> Result<Buf, ErrBox>,
|
||||||
{
|
{
|
||||||
use futures::Async::*;
|
use futures::Async::*;
|
||||||
match tokio_threadpool::blocking(f) {
|
match tokio_threadpool::blocking(f) {
|
||||||
|
@ -793,7 +790,7 @@ where
|
||||||
|
|
||||||
fn blocking<F>(is_sync: bool, f: F) -> CliOpResult
|
fn blocking<F>(is_sync: bool, f: F) -> CliOpResult
|
||||||
where
|
where
|
||||||
F: 'static + Send + FnOnce() -> DenoResult<Buf>,
|
F: 'static + Send + FnOnce() -> Result<Buf, ErrBox>,
|
||||||
{
|
{
|
||||||
if is_sync {
|
if is_sync {
|
||||||
let result_buf = f()?;
|
let result_buf = f()?;
|
||||||
|
@ -981,10 +978,8 @@ fn op_open(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let op = open_options
|
let op = open_options.open(filename).map_err(ErrBox::from).and_then(
|
||||||
.open(filename)
|
move |fs_file| {
|
||||||
.map_err(DenoError::from)
|
|
||||||
.and_then(move |fs_file| {
|
|
||||||
let resource = resources::add_fs_file(fs_file);
|
let resource = resources::add_fs_file(fs_file);
|
||||||
let builder = &mut FlatBufferBuilder::new();
|
let builder = &mut FlatBufferBuilder::new();
|
||||||
let inner =
|
let inner =
|
||||||
|
@ -998,7 +993,8 @@ fn op_open(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
});
|
},
|
||||||
|
);
|
||||||
if base.sync() {
|
if base.sync() {
|
||||||
let buf = op.wait()?;
|
let buf = op.wait()?;
|
||||||
Ok(Op::Sync(buf))
|
Ok(Op::Sync(buf))
|
||||||
|
@ -1076,7 +1072,7 @@ fn op_read(
|
||||||
None => Err(deno_error::bad_resource()),
|
None => Err(deno_error::bad_resource()),
|
||||||
Some(resource) => {
|
Some(resource) => {
|
||||||
let op = tokio::io::read(resource, data.unwrap())
|
let op = tokio::io::read(resource, data.unwrap())
|
||||||
.map_err(DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
.and_then(move |(_resource, _buf, nread)| {
|
.and_then(move |(_resource, _buf, nread)| {
|
||||||
let builder = &mut FlatBufferBuilder::new();
|
let builder = &mut FlatBufferBuilder::new();
|
||||||
let inner = msg::ReadRes::create(
|
let inner = msg::ReadRes::create(
|
||||||
|
@ -1119,7 +1115,7 @@ fn op_write(
|
||||||
None => Err(deno_error::bad_resource()),
|
None => Err(deno_error::bad_resource()),
|
||||||
Some(resource) => {
|
Some(resource) => {
|
||||||
let op = tokio_write::write(resource, data.unwrap())
|
let op = tokio_write::write(resource, data.unwrap())
|
||||||
.map_err(DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
.and_then(move |(_resource, _buf, nwritten)| {
|
.and_then(move |(_resource, _buf, nwritten)| {
|
||||||
let builder = &mut FlatBufferBuilder::new();
|
let builder = &mut FlatBufferBuilder::new();
|
||||||
let inner = msg::WriteRes::create(
|
let inner = msg::WriteRes::create(
|
||||||
|
@ -1219,10 +1215,10 @@ fn op_copy_file(
|
||||||
// See https://github.com/rust-lang/rust/issues/54800
|
// See https://github.com/rust-lang/rust/issues/54800
|
||||||
// Once the issue is reolved, we should remove this workaround.
|
// Once the issue is reolved, we should remove this workaround.
|
||||||
if cfg!(unix) && !from.is_file() {
|
if cfg!(unix) && !from.is_file() {
|
||||||
return Err(deno_error::new(
|
return Err(
|
||||||
ErrorKind::NotFound,
|
DenoError::new(ErrorKind::NotFound, "File not found".to_string())
|
||||||
"File not found".to_string(),
|
.into(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::copy(&from, &to)?;
|
fs::copy(&from, &to)?;
|
||||||
|
@ -1431,10 +1427,9 @@ fn op_symlink(
|
||||||
state.check_write(&newname_)?;
|
state.check_write(&newname_)?;
|
||||||
// TODO Use type for Windows.
|
// TODO Use type for Windows.
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
return Err(deno_error::new(
|
return Err(
|
||||||
ErrorKind::Other,
|
DenoError::new(ErrorKind::Other, "Not implemented".to_string()).into(),
|
||||||
"Not implemented".to_string(),
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
blocking(base.sync(), move || {
|
blocking(base.sync(), move || {
|
||||||
debug!("op_symlink {} {}", oldname.display(), newname.display());
|
debug!("op_symlink {} {}", oldname.display(), newname.display());
|
||||||
|
@ -1621,7 +1616,7 @@ fn op_listen(
|
||||||
ok_buf(response_buf)
|
ok_buf(response_buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_conn(cmd_id: u32, tcp_stream: TcpStream) -> DenoResult<Buf> {
|
fn new_conn(cmd_id: u32, tcp_stream: TcpStream) -> Result<Buf, ErrBox> {
|
||||||
let tcp_stream_resource = resources::add_tcp_stream(tcp_stream);
|
let tcp_stream_resource = resources::add_tcp_stream(tcp_stream);
|
||||||
// TODO forward socket_addr to client.
|
// TODO forward socket_addr to client.
|
||||||
|
|
||||||
|
@ -1658,7 +1653,7 @@ fn op_accept(
|
||||||
None => Err(deno_error::bad_resource()),
|
None => Err(deno_error::bad_resource()),
|
||||||
Some(server_resource) => {
|
Some(server_resource) => {
|
||||||
let op = tokio_util::accept(server_resource)
|
let op = tokio_util::accept(server_resource)
|
||||||
.map_err(DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
.and_then(move |(tcp_stream, _socket_addr)| {
|
.and_then(move |(tcp_stream, _socket_addr)| {
|
||||||
new_conn(cmd_id, tcp_stream)
|
new_conn(cmd_id, tcp_stream)
|
||||||
});
|
});
|
||||||
|
@ -1686,14 +1681,11 @@ fn op_dial(
|
||||||
|
|
||||||
state.check_net(&address)?;
|
state.check_net(&address)?;
|
||||||
|
|
||||||
let op =
|
let op = resolve_addr(address).and_then(move |addr| {
|
||||||
resolve_addr(address)
|
TcpStream::connect(&addr)
|
||||||
.map_err(DenoError::from)
|
.map_err(ErrBox::from)
|
||||||
.and_then(move |addr| {
|
.and_then(move |tcp_stream| new_conn(cmd_id, tcp_stream))
|
||||||
TcpStream::connect(&addr)
|
});
|
||||||
.map_err(DenoError::from)
|
|
||||||
.and_then(move |tcp_stream| new_conn(cmd_id, tcp_stream))
|
|
||||||
});
|
|
||||||
if base.sync() {
|
if base.sync() {
|
||||||
let buf = op.wait()?;
|
let buf = op.wait()?;
|
||||||
Ok(Op::Sync(buf))
|
Ok(Op::Sync(buf))
|
||||||
|
@ -1858,7 +1850,7 @@ fn op_run(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn the command.
|
// Spawn the command.
|
||||||
let child = c.spawn_async().map_err(DenoError::from)?;
|
let child = c.spawn_async().map_err(ErrBox::from)?;
|
||||||
|
|
||||||
let pid = child.id();
|
let pid = child.id();
|
||||||
let resources = resources::add_child(child);
|
let resources = resources::add_child(child);
|
||||||
|
@ -1977,8 +1969,8 @@ fn op_worker_get_message(
|
||||||
let op = GetMessageFuture {
|
let op = GetMessageFuture {
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
};
|
};
|
||||||
let op = op.map_err(move |_| -> DenoError { unimplemented!() });
|
let op = op.map_err(move |_| -> ErrBox { unimplemented!() });
|
||||||
let op = op.and_then(move |maybe_buf| -> DenoResult<Buf> {
|
let op = op.and_then(move |maybe_buf| -> Result<Buf, ErrBox> {
|
||||||
debug!("op_worker_get_message");
|
debug!("op_worker_get_message");
|
||||||
let builder = &mut FlatBufferBuilder::new();
|
let builder = &mut FlatBufferBuilder::new();
|
||||||
|
|
||||||
|
@ -2015,7 +2007,7 @@ fn op_worker_post_message(
|
||||||
};
|
};
|
||||||
tx.send(d)
|
tx.send(d)
|
||||||
.wait()
|
.wait()
|
||||||
.map_err(|e| deno_error::new(ErrorKind::Other, e.to_string()))?;
|
.map_err(|e| DenoError::new(ErrorKind::Other, e.to_string()))?;
|
||||||
let builder = &mut FlatBufferBuilder::new();
|
let builder = &mut FlatBufferBuilder::new();
|
||||||
|
|
||||||
ok_buf(serialize_response(
|
ok_buf(serialize_response(
|
||||||
|
@ -2051,8 +2043,8 @@ fn op_create_worker(
|
||||||
|
|
||||||
let mut worker =
|
let mut worker =
|
||||||
Worker::new(name, startup_data::deno_isolate_init(), child_state);
|
Worker::new(name, startup_data::deno_isolate_init(), child_state);
|
||||||
err_check(worker.execute("denoMain()"));
|
worker.execute("denoMain()").unwrap();
|
||||||
err_check(worker.execute("workerMain()"));
|
worker.execute("workerMain()").unwrap();
|
||||||
|
|
||||||
let module_specifier = ModuleSpecifier::resolve_url_or_path(specifier)?;
|
let module_specifier = ModuleSpecifier::resolve_url_or_path(specifier)?;
|
||||||
|
|
||||||
|
@ -2132,8 +2124,8 @@ fn op_host_get_message(
|
||||||
let rid = inner.rid();
|
let rid = inner.rid();
|
||||||
|
|
||||||
let op = resources::get_message_from_worker(rid);
|
let op = resources::get_message_from_worker(rid);
|
||||||
let op = op.map_err(move |_| -> DenoError { unimplemented!() });
|
let op = op.map_err(move |_| -> ErrBox { unimplemented!() });
|
||||||
let op = op.and_then(move |maybe_buf| -> DenoResult<Buf> {
|
let op = op.and_then(move |maybe_buf| -> Result<Buf, ErrBox> {
|
||||||
let builder = &mut FlatBufferBuilder::new();
|
let builder = &mut FlatBufferBuilder::new();
|
||||||
|
|
||||||
let data = maybe_buf.as_ref().map(|buf| builder.create_vector(buf));
|
let data = maybe_buf.as_ref().map(|buf| builder.create_vector(buf));
|
||||||
|
@ -2168,7 +2160,7 @@ fn op_host_post_message(
|
||||||
|
|
||||||
resources::post_message_to_worker(rid, d)
|
resources::post_message_to_worker(rid, d)
|
||||||
.wait()
|
.wait()
|
||||||
.map_err(|e| deno_error::new(ErrorKind::Other, e.to_string()))?;
|
.map_err(|e| DenoError::new(ErrorKind::Other, e.to_string()))?;
|
||||||
let builder = &mut FlatBufferBuilder::new();
|
let builder = &mut FlatBufferBuilder::new();
|
||||||
|
|
||||||
ok_buf(serialize_response(
|
ok_buf(serialize_response(
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
use atty;
|
|
||||||
|
|
||||||
use crate::flags::DenoFlags;
|
|
||||||
|
|
||||||
use ansi_term::Style;
|
use ansi_term::Style;
|
||||||
|
use atty;
|
||||||
use crate::deno_error::permission_denied;
|
use crate::deno_error::permission_denied;
|
||||||
use crate::deno_error::DenoResult;
|
use crate::flags::DenoFlags;
|
||||||
|
use deno::ErrBox;
|
||||||
use log;
|
use log;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -160,7 +158,7 @@ impl DenoPermissions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_run(&self) -> DenoResult<()> {
|
pub fn check_run(&self) -> Result<(), ErrBox> {
|
||||||
let msg = "access to run a subprocess";
|
let msg = "access to run a subprocess";
|
||||||
|
|
||||||
match self.allow_run.get_state() {
|
match self.allow_run.get_state() {
|
||||||
|
@ -181,7 +179,7 @@ impl DenoPermissions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_read(&self, filename: &str) -> DenoResult<()> {
|
pub fn check_read(&self, filename: &str) -> Result<(), ErrBox> {
|
||||||
let msg = &format!("read access to \"{}\"", filename);
|
let msg = &format!("read access to \"{}\"", filename);
|
||||||
match self.allow_read.get_state() {
|
match self.allow_read.get_state() {
|
||||||
PermissionAccessorState::Allow => {
|
PermissionAccessorState::Allow => {
|
||||||
|
@ -213,7 +211,7 @@ impl DenoPermissions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_write(&self, filename: &str) -> DenoResult<()> {
|
pub fn check_write(&self, filename: &str) -> Result<(), ErrBox> {
|
||||||
let msg = &format!("write access to \"{}\"", filename);
|
let msg = &format!("write access to \"{}\"", filename);
|
||||||
match self.allow_write.get_state() {
|
match self.allow_write.get_state() {
|
||||||
PermissionAccessorState::Allow => {
|
PermissionAccessorState::Allow => {
|
||||||
|
@ -245,7 +243,7 @@ impl DenoPermissions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_net(&self, host_and_port: &str) -> DenoResult<()> {
|
pub fn check_net(&self, host_and_port: &str) -> Result<(), ErrBox> {
|
||||||
let msg = &format!("network access to \"{}\"", host_and_port);
|
let msg = &format!("network access to \"{}\"", host_and_port);
|
||||||
match self.allow_net.get_state() {
|
match self.allow_net.get_state() {
|
||||||
PermissionAccessorState::Allow => {
|
PermissionAccessorState::Allow => {
|
||||||
|
@ -276,7 +274,7 @@ impl DenoPermissions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_net_url(&self, url: url::Url) -> DenoResult<()> {
|
pub fn check_net_url(&self, url: url::Url) -> Result<(), ErrBox> {
|
||||||
let msg = &format!("network access to \"{}\"", url);
|
let msg = &format!("network access to \"{}\"", url);
|
||||||
match self.allow_net.get_state() {
|
match self.allow_net.get_state() {
|
||||||
PermissionAccessorState::Allow => {
|
PermissionAccessorState::Allow => {
|
||||||
|
@ -311,7 +309,7 @@ impl DenoPermissions {
|
||||||
&self,
|
&self,
|
||||||
state: PermissionAccessorState,
|
state: PermissionAccessorState,
|
||||||
prompt_str: &str,
|
prompt_str: &str,
|
||||||
) -> DenoResult<()> {
|
) -> Result<(), ErrBox> {
|
||||||
match state {
|
match state {
|
||||||
PermissionAccessorState::Ask => {
|
PermissionAccessorState::Ask => {
|
||||||
match self.try_permissions_prompt(prompt_str) {
|
match self.try_permissions_prompt(prompt_str) {
|
||||||
|
@ -329,7 +327,7 @@ impl DenoPermissions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_env(&self) -> DenoResult<()> {
|
pub fn check_env(&self) -> Result<(), ErrBox> {
|
||||||
let msg = "access to environment variables";
|
let msg = "access to environment variables";
|
||||||
match self.allow_env.get_state() {
|
match self.allow_env.get_state() {
|
||||||
PermissionAccessorState::Allow => {
|
PermissionAccessorState::Allow => {
|
||||||
|
@ -351,7 +349,10 @@ impl DenoPermissions {
|
||||||
|
|
||||||
/// Try to present the user with a permission prompt
|
/// Try to present the user with a permission prompt
|
||||||
/// will error with permission_denied if no_prompts is enabled
|
/// will error with permission_denied if no_prompts is enabled
|
||||||
fn try_permissions_prompt(&self, message: &str) -> DenoResult<PromptResult> {
|
fn try_permissions_prompt(
|
||||||
|
&self,
|
||||||
|
message: &str,
|
||||||
|
) -> Result<PromptResult, ErrBox> {
|
||||||
if self.no_prompts.load(Ordering::SeqCst) {
|
if self.no_prompts.load(Ordering::SeqCst) {
|
||||||
return Err(permission_denied());
|
return Err(permission_denied());
|
||||||
}
|
}
|
||||||
|
@ -396,31 +397,31 @@ impl DenoPermissions {
|
||||||
self.allow_hrtime.is_allow()
|
self.allow_hrtime.is_allow()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revoke_run(&self) -> DenoResult<()> {
|
pub fn revoke_run(&self) -> Result<(), ErrBox> {
|
||||||
self.allow_run.revoke();
|
self.allow_run.revoke();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revoke_read(&self) -> DenoResult<()> {
|
pub fn revoke_read(&self) -> Result<(), ErrBox> {
|
||||||
self.allow_read.revoke();
|
self.allow_read.revoke();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revoke_write(&self) -> DenoResult<()> {
|
pub fn revoke_write(&self) -> Result<(), ErrBox> {
|
||||||
self.allow_write.revoke();
|
self.allow_write.revoke();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revoke_net(&self) -> DenoResult<()> {
|
pub fn revoke_net(&self) -> Result<(), ErrBox> {
|
||||||
self.allow_net.revoke();
|
self.allow_net.revoke();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revoke_env(&self) -> DenoResult<()> {
|
pub fn revoke_env(&self) -> Result<(), ErrBox> {
|
||||||
self.allow_env.revoke();
|
self.allow_env.revoke();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn revoke_hrtime(&self) -> DenoResult<()> {
|
pub fn revoke_hrtime(&self) -> Result<(), ErrBox> {
|
||||||
self.allow_hrtime.revoke();
|
self.allow_hrtime.revoke();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -437,7 +438,7 @@ pub enum PromptResult {
|
||||||
|
|
||||||
impl PromptResult {
|
impl PromptResult {
|
||||||
/// If value is any form of deny this will error with permission_denied
|
/// If value is any form of deny this will error with permission_denied
|
||||||
pub fn check(&self) -> DenoResult<()> {
|
pub fn check(&self) -> Result<(), ErrBox> {
|
||||||
match self {
|
match self {
|
||||||
PromptResult::DenyOnce => Err(permission_denied()),
|
PromptResult::DenyOnce => Err(permission_denied()),
|
||||||
PromptResult::DenyAlways => Err(permission_denied()),
|
PromptResult::DenyAlways => Err(permission_denied()),
|
||||||
|
@ -457,7 +458,7 @@ impl fmt::Display for PromptResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn permission_prompt(message: &str) -> DenoResult<PromptResult> {
|
fn permission_prompt(message: &str) -> Result<PromptResult, ErrBox> {
|
||||||
let msg = format!("️{} Deno requests {}. Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)] ", PERMISSION_EMOJI, message);
|
let msg = format!("️{} Deno requests {}. Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)] ", PERMISSION_EMOJI, message);
|
||||||
// print to stderr so that if deno is > to a file this is still displayed.
|
// print to stderr so that if deno is > to a file this is still displayed.
|
||||||
eprint!("{}", Style::new().bold().paint(msg));
|
eprint!("{}", Style::new().bold().paint(msg));
|
||||||
|
|
17
cli/repl.rs
17
cli/repl.rs
|
@ -1,12 +1,7 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
use rustyline;
|
|
||||||
|
|
||||||
use crate::msg::ErrorKind;
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
use crate::deno_dir::DenoDir;
|
use crate::deno_dir::DenoDir;
|
||||||
use crate::deno_error::new as deno_error;
|
use deno::ErrBox;
|
||||||
use crate::deno_error::DenoResult;
|
use rustyline;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
|
@ -78,25 +73,25 @@ impl Repl {
|
||||||
.unwrap_or(())
|
.unwrap_or(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_history(&mut self) -> DenoResult<()> {
|
fn save_history(&mut self) -> Result<(), ErrBox> {
|
||||||
self
|
self
|
||||||
.editor
|
.editor
|
||||||
.save_history(&self.history_file.to_str().unwrap())
|
.save_history(&self.history_file.to_str().unwrap())
|
||||||
.map(|_| debug!("Saved REPL history to: {:?}", self.history_file))
|
.map(|_| debug!("Saved REPL history to: {:?}", self.history_file))
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
eprintln!("Unable to save REPL history: {:?} {}", self.history_file, e);
|
eprintln!("Unable to save REPL history: {:?} {}", self.history_file, e);
|
||||||
deno_error(ErrorKind::Other, e.description().to_string())
|
ErrBox::from(e)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn readline(&mut self, prompt: &str) -> DenoResult<String> {
|
pub fn readline(&mut self, prompt: &str) -> Result<String, ErrBox> {
|
||||||
self
|
self
|
||||||
.editor
|
.editor
|
||||||
.readline(&prompt)
|
.readline(&prompt)
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
self.editor.add_history_entry(line.clone());
|
self.editor.add_history_entry(line.clone());
|
||||||
line
|
line
|
||||||
}).map_err(|e| deno_error(ErrorKind::Other, e.description().to_string()))
|
}).map_err(ErrBox::from)
|
||||||
// Forward error to TS side for processing
|
// Forward error to TS side for processing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
|
use crate::deno_error;
|
||||||
|
use deno::ErrBox;
|
||||||
use futures::Async;
|
use futures::Async;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use futures::Poll;
|
use futures::Poll;
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
|
|
||||||
|
@ -21,46 +20,23 @@ pub fn resolve_addr(address: &str) -> ResolveAddrFuture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ResolveAddrError {
|
|
||||||
Syntax,
|
|
||||||
Resolution(std::io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ResolveAddrError {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt.write_str(self.description())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for ResolveAddrError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
ResolveAddrError::Syntax => "invalid address syntax",
|
|
||||||
ResolveAddrError::Resolution(e) => e.description(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ResolveAddrFuture {
|
pub struct ResolveAddrFuture {
|
||||||
address: String,
|
address: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for ResolveAddrFuture {
|
impl Future for ResolveAddrFuture {
|
||||||
type Item = SocketAddr;
|
type Item = SocketAddr;
|
||||||
type Error = ResolveAddrError;
|
type Error = ErrBox;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
// The implementation of this is not actually async at the moment,
|
// The implementation of this is not actually async at the moment,
|
||||||
// however we intend to use async DNS resolution in the future and
|
// however we intend to use async DNS resolution in the future and
|
||||||
// so we expose this as a future instead of Result.
|
// so we expose this as a future instead of Result.
|
||||||
match split(&self.address) {
|
match split(&self.address) {
|
||||||
None => Err(ResolveAddrError::Syntax),
|
None => Err(deno_error::invalid_address_syntax()),
|
||||||
Some(addr_port_pair) => {
|
Some(addr_port_pair) => {
|
||||||
// I absolutely despise the .to_socket_addrs() API.
|
// I absolutely despise the .to_socket_addrs() API.
|
||||||
let r = addr_port_pair
|
let r = addr_port_pair.to_socket_addrs().map_err(ErrBox::from);
|
||||||
.to_socket_addrs()
|
|
||||||
.map_err(ResolveAddrError::Resolution);
|
|
||||||
|
|
||||||
r.and_then(|mut iter| match iter.next() {
|
r.and_then(|mut iter| match iter.next() {
|
||||||
Some(a) => Ok(Async::Ready(a)),
|
Some(a) => Ok(Async::Ready(a)),
|
||||||
|
|
|
@ -10,13 +10,12 @@
|
||||||
|
|
||||||
use crate::deno_error;
|
use crate::deno_error;
|
||||||
use crate::deno_error::bad_resource;
|
use crate::deno_error::bad_resource;
|
||||||
use crate::deno_error::DenoError;
|
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
use crate::http_body::HttpBody;
|
use crate::http_body::HttpBody;
|
||||||
use crate::repl::Repl;
|
use crate::repl::Repl;
|
||||||
use crate::state::WorkerChannels;
|
use crate::state::WorkerChannels;
|
||||||
|
|
||||||
use deno::Buf;
|
use deno::Buf;
|
||||||
|
use deno::ErrBox;
|
||||||
|
|
||||||
use futures;
|
use futures;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
@ -216,14 +215,14 @@ impl Resource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown(&mut self, how: Shutdown) -> Result<(), DenoError> {
|
pub fn shutdown(&mut self, how: Shutdown) -> Result<(), ErrBox> {
|
||||||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||||
let maybe_repr = table.get_mut(&self.rid);
|
let maybe_repr = table.get_mut(&self.rid);
|
||||||
match maybe_repr {
|
match maybe_repr {
|
||||||
None => panic!("bad rid"),
|
None => panic!("bad rid"),
|
||||||
Some(repr) => match repr {
|
Some(repr) => match repr {
|
||||||
Repr::TcpStream(ref mut f) => {
|
Repr::TcpStream(ref mut f) => {
|
||||||
TcpStream::shutdown(f, how).map_err(DenoError::from)
|
TcpStream::shutdown(f, how).map_err(ErrBox::from)
|
||||||
}
|
}
|
||||||
_ => panic!("Cannot shutdown"),
|
_ => panic!("Cannot shutdown"),
|
||||||
},
|
},
|
||||||
|
@ -366,15 +365,13 @@ pub struct WorkerReceiver {
|
||||||
// Invert the dumbness that tokio_process causes by making Child itself a future.
|
// Invert the dumbness that tokio_process causes by making Child itself a future.
|
||||||
impl Future for WorkerReceiver {
|
impl Future for WorkerReceiver {
|
||||||
type Item = Option<Buf>;
|
type Item = Option<Buf>;
|
||||||
type Error = DenoError;
|
type Error = ErrBox;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Option<Buf>, DenoError> {
|
fn poll(&mut self) -> Poll<Option<Buf>, ErrBox> {
|
||||||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||||
let maybe_repr = table.get_mut(&self.rid);
|
let maybe_repr = table.get_mut(&self.rid);
|
||||||
match maybe_repr {
|
match maybe_repr {
|
||||||
Some(Repr::Worker(ref mut wc)) => wc.1.poll().map_err(|err| {
|
Some(Repr::Worker(ref mut wc)) => wc.1.poll().map_err(ErrBox::from),
|
||||||
deno_error::new(deno_error::ErrorKind::Other, err.to_string())
|
|
||||||
}),
|
|
||||||
_ => Err(bad_resource()),
|
_ => Err(bad_resource()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,15 +388,13 @@ pub struct WorkerReceiverStream {
|
||||||
// Invert the dumbness that tokio_process causes by making Child itself a future.
|
// Invert the dumbness that tokio_process causes by making Child itself a future.
|
||||||
impl Stream for WorkerReceiverStream {
|
impl Stream for WorkerReceiverStream {
|
||||||
type Item = Buf;
|
type Item = Buf;
|
||||||
type Error = DenoError;
|
type Error = ErrBox;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Option<Buf>, DenoError> {
|
fn poll(&mut self) -> Poll<Option<Buf>, ErrBox> {
|
||||||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||||
let maybe_repr = table.get_mut(&self.rid);
|
let maybe_repr = table.get_mut(&self.rid);
|
||||||
match maybe_repr {
|
match maybe_repr {
|
||||||
Some(Repr::Worker(ref mut wc)) => wc.1.poll().map_err(|err| {
|
Some(Repr::Worker(ref mut wc)) => wc.1.poll().map_err(ErrBox::from),
|
||||||
deno_error::new(deno_error::ErrorKind::Other, err.to_string())
|
|
||||||
}),
|
|
||||||
_ => Err(bad_resource()),
|
_ => Err(bad_resource()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -462,19 +457,19 @@ pub struct ChildStatus {
|
||||||
// Invert the dumbness that tokio_process causes by making Child itself a future.
|
// Invert the dumbness that tokio_process causes by making Child itself a future.
|
||||||
impl Future for ChildStatus {
|
impl Future for ChildStatus {
|
||||||
type Item = ExitStatus;
|
type Item = ExitStatus;
|
||||||
type Error = DenoError;
|
type Error = ErrBox;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<ExitStatus, DenoError> {
|
fn poll(&mut self) -> Poll<ExitStatus, ErrBox> {
|
||||||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||||
let maybe_repr = table.get_mut(&self.rid);
|
let maybe_repr = table.get_mut(&self.rid);
|
||||||
match maybe_repr {
|
match maybe_repr {
|
||||||
Some(Repr::Child(ref mut child)) => child.poll().map_err(DenoError::from),
|
Some(Repr::Child(ref mut child)) => child.poll().map_err(ErrBox::from),
|
||||||
_ => Err(bad_resource()),
|
_ => Err(bad_resource()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn child_status(rid: ResourceId) -> DenoResult<ChildStatus> {
|
pub fn child_status(rid: ResourceId) -> Result<ChildStatus, ErrBox> {
|
||||||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||||
let maybe_repr = table.get_mut(&rid);
|
let maybe_repr = table.get_mut(&rid);
|
||||||
match maybe_repr {
|
match maybe_repr {
|
||||||
|
@ -483,7 +478,7 @@ pub fn child_status(rid: ResourceId) -> DenoResult<ChildStatus> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_repl(rid: ResourceId) -> DenoResult<Arc<Mutex<Repl>>> {
|
pub fn get_repl(rid: ResourceId) -> Result<Arc<Mutex<Repl>>, ErrBox> {
|
||||||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||||
let maybe_repr = table.get_mut(&rid);
|
let maybe_repr = table.get_mut(&rid);
|
||||||
match maybe_repr {
|
match maybe_repr {
|
||||||
|
@ -494,7 +489,7 @@ pub fn get_repl(rid: ResourceId) -> DenoResult<Arc<Mutex<Repl>>> {
|
||||||
|
|
||||||
// TODO: revamp this after the following lands:
|
// TODO: revamp this after the following lands:
|
||||||
// https://github.com/tokio-rs/tokio/pull/785
|
// https://github.com/tokio-rs/tokio/pull/785
|
||||||
pub fn get_file(rid: ResourceId) -> DenoResult<std::fs::File> {
|
pub fn get_file(rid: ResourceId) -> Result<std::fs::File, ErrBox> {
|
||||||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||||
// We take ownership of File here.
|
// We take ownership of File here.
|
||||||
// It is put back below while still holding the lock.
|
// It is put back below while still holding the lock.
|
||||||
|
@ -516,7 +511,7 @@ pub fn get_file(rid: ResourceId) -> DenoResult<std::fs::File> {
|
||||||
table.insert(rid, Repr::FsFile(tokio_fs::File::from_std(std_file)));
|
table.insert(rid, Repr::FsFile(tokio_fs::File::from_std(std_file)));
|
||||||
|
|
||||||
if maybe_std_file_copy.is_err() {
|
if maybe_std_file_copy.is_err() {
|
||||||
return Err(DenoError::from(maybe_std_file_copy.unwrap_err()));
|
return Err(ErrBox::from(maybe_std_file_copy.unwrap_err()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let std_file_copy = maybe_std_file_copy.unwrap();
|
let std_file_copy = maybe_std_file_copy.unwrap();
|
||||||
|
@ -537,23 +532,25 @@ pub fn seek(
|
||||||
resource: Resource,
|
resource: Resource,
|
||||||
offset: i32,
|
offset: i32,
|
||||||
whence: u32,
|
whence: u32,
|
||||||
) -> Box<dyn Future<Item = (), Error = DenoError> + Send> {
|
) -> Box<dyn Future<Item = (), Error = ErrBox> + Send> {
|
||||||
// Translate seek mode to Rust repr.
|
// Translate seek mode to Rust repr.
|
||||||
let seek_from = match whence {
|
let seek_from = match whence {
|
||||||
0 => SeekFrom::Start(offset as u64),
|
0 => SeekFrom::Start(offset as u64),
|
||||||
1 => SeekFrom::Current(i64::from(offset)),
|
1 => SeekFrom::Current(i64::from(offset)),
|
||||||
2 => SeekFrom::End(i64::from(offset)),
|
2 => SeekFrom::End(i64::from(offset)),
|
||||||
_ => {
|
_ => {
|
||||||
return Box::new(futures::future::err(deno_error::new(
|
return Box::new(futures::future::err(
|
||||||
deno_error::ErrorKind::InvalidSeekMode,
|
deno_error::DenoError::new(
|
||||||
format!("Invalid seek mode: {}", whence),
|
deno_error::ErrorKind::InvalidSeekMode,
|
||||||
)));
|
format!("Invalid seek mode: {}", whence),
|
||||||
|
).into(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match get_file(resource.rid) {
|
match get_file(resource.rid) {
|
||||||
Ok(mut file) => Box::new(futures::future::lazy(move || {
|
Ok(mut file) => Box::new(futures::future::lazy(move || {
|
||||||
let result = file.seek(seek_from).map(|_| {}).map_err(DenoError::from);
|
let result = file.seek(seek_from).map(|_| {}).map_err(ErrBox::from);
|
||||||
futures::future::result(result)
|
futures::future::result(result)
|
||||||
})),
|
})),
|
||||||
Err(err) => Box::new(futures::future::err(err)),
|
Err(err) => Box::new(futures::future::err(err)),
|
||||||
|
|
32
cli/shell.rs
32
cli/shell.rs
|
@ -10,11 +10,10 @@ use std::fmt;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
||||||
use atty;
|
use atty;
|
||||||
|
use deno::ErrBox;
|
||||||
use termcolor::Color::{Cyan, Green, Red, Yellow};
|
use termcolor::Color::{Cyan, Green, Red, Yellow};
|
||||||
use termcolor::{self, Color, ColorSpec, StandardStream, WriteColor};
|
use termcolor::{self, Color, ColorSpec, StandardStream, WriteColor};
|
||||||
|
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
|
|
||||||
/// The requested verbosity of output.
|
/// The requested verbosity of output.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum Verbosity {
|
pub enum Verbosity {
|
||||||
|
@ -116,7 +115,7 @@ impl Shell {
|
||||||
message: Option<&dyn fmt::Display>,
|
message: Option<&dyn fmt::Display>,
|
||||||
color: Color,
|
color: Color,
|
||||||
justified: bool,
|
justified: bool,
|
||||||
) -> DenoResult<()> {
|
) -> Result<(), ErrBox> {
|
||||||
match self.verbosity {
|
match self.verbosity {
|
||||||
Verbosity::Quiet => Ok(()),
|
Verbosity::Quiet => Ok(()),
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -171,7 +170,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shortcut to right-align and color green a status message.
|
/// Shortcut to right-align and color green a status message.
|
||||||
pub fn status<T, U>(&mut self, status: T, message: U) -> DenoResult<()>
|
pub fn status<T, U>(&mut self, status: T, message: U) -> Result<(), ErrBox>
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
U: fmt::Display,
|
U: fmt::Display,
|
||||||
|
@ -179,7 +178,7 @@ impl Shell {
|
||||||
self.print(&status, Some(&message), Green, false)
|
self.print(&status, Some(&message), Green, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status_header<T>(&mut self, status: T) -> DenoResult<()>
|
pub fn status_header<T>(&mut self, status: T) -> Result<(), ErrBox>
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
|
@ -192,7 +191,7 @@ impl Shell {
|
||||||
status: T,
|
status: T,
|
||||||
message: U,
|
message: U,
|
||||||
color: Color,
|
color: Color,
|
||||||
) -> DenoResult<()>
|
) -> Result<(), ErrBox>
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
U: fmt::Display,
|
U: fmt::Display,
|
||||||
|
@ -201,9 +200,9 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the callback only if we are in verbose mode.
|
/// Runs the callback only if we are in verbose mode.
|
||||||
pub fn verbose<F>(&mut self, mut callback: F) -> DenoResult<()>
|
pub fn verbose<F>(&mut self, mut callback: F) -> Result<(), ErrBox>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut Shell) -> DenoResult<()>,
|
F: FnMut(&mut Shell) -> Result<(), ErrBox>,
|
||||||
{
|
{
|
||||||
match self.verbosity {
|
match self.verbosity {
|
||||||
Verbosity::Verbose => callback(self),
|
Verbosity::Verbose => callback(self),
|
||||||
|
@ -212,9 +211,9 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the callback if we are not in verbose mode.
|
/// Runs the callback if we are not in verbose mode.
|
||||||
pub fn concise<F>(&mut self, mut callback: F) -> DenoResult<()>
|
pub fn concise<F>(&mut self, mut callback: F) -> Result<(), ErrBox>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut Shell) -> DenoResult<()>,
|
F: FnMut(&mut Shell) -> Result<(), ErrBox>,
|
||||||
{
|
{
|
||||||
match self.verbosity {
|
match self.verbosity {
|
||||||
Verbosity::Verbose => Ok(()),
|
Verbosity::Verbose => Ok(()),
|
||||||
|
@ -223,12 +222,12 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a red 'error' message.
|
/// Prints a red 'error' message.
|
||||||
pub fn error<T: fmt::Display>(&mut self, message: T) -> DenoResult<()> {
|
pub fn error<T: fmt::Display>(&mut self, message: T) -> Result<(), ErrBox> {
|
||||||
self.print(&"error:", Some(&message), Red, false)
|
self.print(&"error:", Some(&message), Red, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints an amber 'warning' message.
|
/// Prints an amber 'warning' message.
|
||||||
pub fn warn<T: fmt::Display>(&mut self, message: T) -> DenoResult<()> {
|
pub fn warn<T: fmt::Display>(&mut self, message: T) -> Result<(), ErrBox> {
|
||||||
match self.verbosity {
|
match self.verbosity {
|
||||||
Verbosity::Quiet => Ok(()),
|
Verbosity::Quiet => Ok(()),
|
||||||
_ => self.print(&"warning:", Some(&message), Yellow, false),
|
_ => self.print(&"warning:", Some(&message), Yellow, false),
|
||||||
|
@ -246,7 +245,10 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the color choice (always, never, or auto) from a string..
|
/// Updates the color choice (always, never, or auto) from a string..
|
||||||
pub fn set_color_choice(&mut self, color: Option<&str>) -> DenoResult<()> {
|
pub fn set_color_choice(
|
||||||
|
&mut self,
|
||||||
|
color: Option<&str>,
|
||||||
|
) -> Result<(), ErrBox> {
|
||||||
if let ShellOut::Stream {
|
if let ShellOut::Stream {
|
||||||
ref mut stream,
|
ref mut stream,
|
||||||
ref mut color_choice,
|
ref mut color_choice,
|
||||||
|
@ -291,7 +293,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a message and translates ANSI escape code into console colors.
|
/// Prints a message and translates ANSI escape code into console colors.
|
||||||
pub fn print_ansi(&mut self, message: &[u8]) -> DenoResult<()> {
|
pub fn print_ansi(&mut self, message: &[u8]) -> Result<(), ErrBox> {
|
||||||
if self.needs_clear {
|
if self.needs_clear {
|
||||||
self.err_erase_line();
|
self.err_erase_line();
|
||||||
}
|
}
|
||||||
|
@ -323,7 +325,7 @@ impl ShellOut {
|
||||||
message: Option<&dyn fmt::Display>,
|
message: Option<&dyn fmt::Display>,
|
||||||
color: Color,
|
color: Color,
|
||||||
justified: bool,
|
justified: bool,
|
||||||
) -> DenoResult<()> {
|
) -> Result<(), ErrBox> {
|
||||||
match *self {
|
match *self {
|
||||||
ShellOut::Stream { ref mut stream, .. } => {
|
ShellOut::Stream { ref mut stream, .. } => {
|
||||||
stream.reset()?;
|
stream.reset()?;
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
#[cfg(unix)]
|
use deno::ErrBox;
|
||||||
use nix::sys::signal::{kill as unix_kill, Signal};
|
|
||||||
#[cfg(unix)]
|
|
||||||
use nix::unistd::Pid;
|
|
||||||
|
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn kill(pid: i32, signo: i32) -> DenoResult<()> {
|
pub fn kill(pid: i32, signo: i32) -> Result<(), ErrBox> {
|
||||||
use crate::deno_error::DenoError;
|
use nix::sys::signal::{kill as unix_kill, Signal};
|
||||||
|
use nix::unistd::Pid;
|
||||||
let sig = Signal::from_c_int(signo)?;
|
let sig = Signal::from_c_int(signo)?;
|
||||||
unix_kill(Pid::from_raw(pid), Option::Some(sig)).map_err(DenoError::from)
|
unix_kill(Pid::from_raw(pid), Option::Some(sig)).map_err(ErrBox::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
pub fn kill(_pid: i32, _signal: i32) -> DenoResult<()> {
|
pub fn kill(_pid: i32, _signal: i32) -> Result<(), ErrBox> {
|
||||||
// NOOP
|
// NOOP
|
||||||
// TODO: implement this for windows
|
// TODO: implement this for windows
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
//! This mod provides functions to remap a deno::JSError based on a source map
|
//! This mod provides functions to remap a deno::V8Exception based on a source map
|
||||||
use deno::JSError;
|
|
||||||
use deno::StackFrame;
|
use deno::StackFrame;
|
||||||
|
use deno::V8Exception;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use source_map_mappings::parse_mappings;
|
use source_map_mappings::parse_mappings;
|
||||||
use source_map_mappings::Bias;
|
use source_map_mappings::Bias;
|
||||||
|
@ -90,36 +90,36 @@ fn builtin_source_map(script_name: &str) -> Option<Vec<u8>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a source map to a JSError, returning a JSError where the filenames,
|
/// Apply a source map to a V8Exception, returning a V8Exception where the filenames,
|
||||||
/// the lines and the columns point to their original source location, not their
|
/// the lines and the columns point to their original source location, not their
|
||||||
/// transpiled location if applicable.
|
/// transpiled location if applicable.
|
||||||
pub fn apply_source_map<G: SourceMapGetter>(
|
pub fn apply_source_map<G: SourceMapGetter>(
|
||||||
js_error: &JSError,
|
v8_exception: &V8Exception,
|
||||||
getter: &G,
|
getter: &G,
|
||||||
) -> JSError {
|
) -> V8Exception {
|
||||||
let mut mappings_map: CachedMaps = HashMap::new();
|
let mut mappings_map: CachedMaps = HashMap::new();
|
||||||
|
|
||||||
let mut frames = Vec::<StackFrame>::new();
|
let mut frames = Vec::<StackFrame>::new();
|
||||||
for frame in &js_error.frames {
|
for frame in &v8_exception.frames {
|
||||||
let f = frame_apply_source_map(&frame, &mut mappings_map, getter);
|
let f = frame_apply_source_map(&frame, &mut mappings_map, getter);
|
||||||
frames.push(f);
|
frames.push(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (script_resource_name, line_number, start_column) =
|
let (script_resource_name, line_number, start_column) =
|
||||||
get_maybe_orig_position(
|
get_maybe_orig_position(
|
||||||
js_error.script_resource_name.clone(),
|
v8_exception.script_resource_name.clone(),
|
||||||
js_error.line_number,
|
v8_exception.line_number,
|
||||||
js_error.start_column,
|
v8_exception.start_column,
|
||||||
&mut mappings_map,
|
&mut mappings_map,
|
||||||
getter,
|
getter,
|
||||||
);
|
);
|
||||||
// It is better to just move end_column to be the same distance away from
|
// It is better to just move end_column to be the same distance away from
|
||||||
// start column because sometimes the code point is not available in the
|
// start column because sometimes the code point is not available in the
|
||||||
// source file map.
|
// source file map.
|
||||||
let end_column = match js_error.end_column {
|
let end_column = match v8_exception.end_column {
|
||||||
Some(ec) => {
|
Some(ec) => {
|
||||||
if start_column.is_some() {
|
if start_column.is_some() {
|
||||||
Some(ec - (js_error.start_column.unwrap() - start_column.unwrap()))
|
Some(ec - (v8_exception.start_column.unwrap() - start_column.unwrap()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -128,22 +128,22 @@ pub fn apply_source_map<G: SourceMapGetter>(
|
||||||
};
|
};
|
||||||
// if there is a source line that we might be different in the source file, we
|
// if there is a source line that we might be different in the source file, we
|
||||||
// will go fetch it from the getter
|
// will go fetch it from the getter
|
||||||
let source_line = if js_error.source_line.is_some()
|
let source_line = if v8_exception.source_line.is_some()
|
||||||
&& script_resource_name.is_some()
|
&& script_resource_name.is_some()
|
||||||
&& line_number.is_some()
|
&& line_number.is_some()
|
||||||
{
|
{
|
||||||
getter.get_source_line(
|
getter.get_source_line(
|
||||||
&js_error.script_resource_name.clone().unwrap(),
|
&v8_exception.script_resource_name.clone().unwrap(),
|
||||||
line_number.unwrap() as usize,
|
line_number.unwrap() as usize,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
js_error.source_line.clone()
|
v8_exception.source_line.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
JSError {
|
V8Exception {
|
||||||
message: js_error.message.clone(),
|
message: v8_exception.message.clone(),
|
||||||
frames,
|
frames,
|
||||||
error_level: js_error.error_level,
|
error_level: v8_exception.error_level,
|
||||||
source_line,
|
source_line,
|
||||||
script_resource_name,
|
script_resource_name,
|
||||||
line_number,
|
line_number,
|
||||||
|
@ -151,8 +151,8 @@ pub fn apply_source_map<G: SourceMapGetter>(
|
||||||
end_column,
|
end_column,
|
||||||
// These are difficult to map to their original position and they are not
|
// These are difficult to map to their original position and they are not
|
||||||
// currently used in any output, so we don't remap them.
|
// currently used in any output, so we don't remap them.
|
||||||
start_position: js_error.start_position,
|
start_position: v8_exception.start_position,
|
||||||
end_position: js_error.end_position,
|
end_position: v8_exception.end_position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,8 +297,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error1() -> JSError {
|
fn error1() -> V8Exception {
|
||||||
JSError {
|
V8Exception {
|
||||||
message: "Error: foo bar".to_string(),
|
message: "Error: foo bar".to_string(),
|
||||||
source_line: None,
|
source_line: None,
|
||||||
script_resource_name: None,
|
script_resource_name: None,
|
||||||
|
@ -341,11 +341,11 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn js_error_apply_source_map_1() {
|
fn v8_exception_apply_source_map_1() {
|
||||||
let e = error1();
|
let e = error1();
|
||||||
let getter = MockSourceMapGetter {};
|
let getter = MockSourceMapGetter {};
|
||||||
let actual = apply_source_map(&e, &getter);
|
let actual = apply_source_map(&e, &getter);
|
||||||
let expected = JSError {
|
let expected = V8Exception {
|
||||||
message: "Error: foo bar".to_string(),
|
message: "Error: foo bar".to_string(),
|
||||||
source_line: None,
|
source_line: None,
|
||||||
script_resource_name: None,
|
script_resource_name: None,
|
||||||
|
@ -389,8 +389,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn js_error_apply_source_map_2() {
|
fn v8_exception_apply_source_map_2() {
|
||||||
let e = JSError {
|
let e = V8Exception {
|
||||||
message: "TypeError: baz".to_string(),
|
message: "TypeError: baz".to_string(),
|
||||||
source_line: None,
|
source_line: None,
|
||||||
script_resource_name: None,
|
script_resource_name: None,
|
||||||
|
@ -419,8 +419,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn js_error_apply_source_map_line() {
|
fn v8_exception_apply_source_map_line() {
|
||||||
let e = JSError {
|
let e = V8Exception {
|
||||||
message: "TypeError: baz".to_string(),
|
message: "TypeError: baz".to_string(),
|
||||||
source_line: Some("foo".to_string()),
|
source_line: Some("foo".to_string()),
|
||||||
script_resource_name: Some("foo_bar.ts".to_string()),
|
script_resource_name: Some("foo_bar.ts".to_string()),
|
||||||
|
|
26
cli/state.rs
26
cli/state.rs
|
@ -2,8 +2,6 @@
|
||||||
use crate::compiler::compile_async;
|
use crate::compiler::compile_async;
|
||||||
use crate::compiler::ModuleMetaData;
|
use crate::compiler::ModuleMetaData;
|
||||||
use crate::deno_dir;
|
use crate::deno_dir;
|
||||||
use crate::deno_error::DenoError;
|
|
||||||
use crate::deno_error::DenoResult;
|
|
||||||
use crate::flags;
|
use crate::flags;
|
||||||
use crate::global_timer::GlobalTimer;
|
use crate::global_timer::GlobalTimer;
|
||||||
use crate::import_map::ImportMap;
|
use crate::import_map::ImportMap;
|
||||||
|
@ -16,6 +14,7 @@ use crate::resources::ResourceId;
|
||||||
use crate::worker::Worker;
|
use crate::worker::Worker;
|
||||||
use deno::Buf;
|
use deno::Buf;
|
||||||
use deno::CoreOp;
|
use deno::CoreOp;
|
||||||
|
use deno::ErrBox;
|
||||||
use deno::Loader;
|
use deno::Loader;
|
||||||
use deno::ModuleSpecifier;
|
use deno::ModuleSpecifier;
|
||||||
use deno::PinnedBuf;
|
use deno::PinnedBuf;
|
||||||
|
@ -118,7 +117,7 @@ impl ThreadSafeState {
|
||||||
pub fn fetch_module_meta_data_and_maybe_compile_async(
|
pub fn fetch_module_meta_data_and_maybe_compile_async(
|
||||||
state: &ThreadSafeState,
|
state: &ThreadSafeState,
|
||||||
module_specifier: &ModuleSpecifier,
|
module_specifier: &ModuleSpecifier,
|
||||||
) -> impl Future<Item = ModuleMetaData, Error = DenoError> {
|
) -> impl Future<Item = ModuleMetaData, Error = ErrBox> {
|
||||||
let state_ = state.clone();
|
let state_ = state.clone();
|
||||||
let use_cache =
|
let use_cache =
|
||||||
!state_.flags.reload || state_.has_compiled(&module_specifier.to_string());
|
!state_.flags.reload || state_.has_compiled(&module_specifier.to_string());
|
||||||
|
@ -150,14 +149,12 @@ pub fn fetch_module_meta_data_and_maybe_compile_async(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Loader for ThreadSafeState {
|
impl Loader for ThreadSafeState {
|
||||||
type Error = DenoError;
|
|
||||||
|
|
||||||
fn resolve(
|
fn resolve(
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
referrer: &str,
|
referrer: &str,
|
||||||
is_root: bool,
|
is_root: bool,
|
||||||
) -> Result<ModuleSpecifier, Self::Error> {
|
) -> Result<ModuleSpecifier, ErrBox> {
|
||||||
if !is_root {
|
if !is_root {
|
||||||
if let Some(import_map) = &self.import_map {
|
if let Some(import_map) = &self.import_map {
|
||||||
let result = import_map.resolve(specifier, referrer)?;
|
let result = import_map.resolve(specifier, referrer)?;
|
||||||
|
@ -167,15 +164,14 @@ impl Loader for ThreadSafeState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleSpecifier::resolve_import(specifier, referrer)
|
ModuleSpecifier::resolve_import(specifier, referrer).map_err(ErrBox::from)
|
||||||
.map_err(DenoError::from)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given an absolute url, load its source code.
|
/// Given an absolute url, load its source code.
|
||||||
fn load(
|
fn load(
|
||||||
&self,
|
&self,
|
||||||
module_specifier: &ModuleSpecifier,
|
module_specifier: &ModuleSpecifier,
|
||||||
) -> Box<deno::SourceCodeInfoFuture<Self::Error>> {
|
) -> Box<deno::SourceCodeInfoFuture> {
|
||||||
self.metrics.resolve_count.fetch_add(1, Ordering::SeqCst);
|
self.metrics.resolve_count.fetch_add(1, Ordering::SeqCst);
|
||||||
Box::new(
|
Box::new(
|
||||||
fetch_module_meta_data_and_maybe_compile_async(self, module_specifier)
|
fetch_module_meta_data_and_maybe_compile_async(self, module_specifier)
|
||||||
|
@ -324,32 +320,32 @@ impl ThreadSafeState {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn check_read(&self, filename: &str) -> DenoResult<()> {
|
pub fn check_read(&self, filename: &str) -> Result<(), ErrBox> {
|
||||||
self.permissions.check_read(filename)
|
self.permissions.check_read(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn check_write(&self, filename: &str) -> DenoResult<()> {
|
pub fn check_write(&self, filename: &str) -> Result<(), ErrBox> {
|
||||||
self.permissions.check_write(filename)
|
self.permissions.check_write(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn check_env(&self) -> DenoResult<()> {
|
pub fn check_env(&self) -> Result<(), ErrBox> {
|
||||||
self.permissions.check_env()
|
self.permissions.check_env()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn check_net(&self, host_and_port: &str) -> DenoResult<()> {
|
pub fn check_net(&self, host_and_port: &str) -> Result<(), ErrBox> {
|
||||||
self.permissions.check_net(host_and_port)
|
self.permissions.check_net(host_and_port)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn check_net_url(&self, url: url::Url) -> DenoResult<()> {
|
pub fn check_net_url(&self, url: url::Url) -> Result<(), ErrBox> {
|
||||||
self.permissions.check_net_url(url)
|
self.permissions.check_net_url(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn check_run(&self) -> DenoResult<()> {
|
pub fn check_run(&self) -> Result<(), ErrBox> {
|
||||||
self.permissions.check_run()
|
self.permissions.check_run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::deno_error::DenoError;
|
use crate::fmt_errors::JSError;
|
||||||
use crate::state::ThreadSafeState;
|
use crate::state::ThreadSafeState;
|
||||||
use crate::tokio_util;
|
use crate::tokio_util;
|
||||||
use deno;
|
use deno;
|
||||||
|
use deno::ErrBox;
|
||||||
use deno::ModuleSpecifier;
|
use deno::ModuleSpecifier;
|
||||||
use deno::StartupData;
|
use deno::StartupData;
|
||||||
use futures::Async;
|
use futures::Async;
|
||||||
|
@ -24,19 +25,23 @@ impl Worker {
|
||||||
startup_data: StartupData,
|
startup_data: StartupData,
|
||||||
state: ThreadSafeState,
|
state: ThreadSafeState,
|
||||||
) -> Worker {
|
) -> Worker {
|
||||||
let state_ = state.clone();
|
|
||||||
let isolate = Arc::new(Mutex::new(deno::Isolate::new(startup_data, false)));
|
let isolate = Arc::new(Mutex::new(deno::Isolate::new(startup_data, false)));
|
||||||
{
|
{
|
||||||
let mut i = isolate.lock().unwrap();
|
let mut i = isolate.lock().unwrap();
|
||||||
|
let state_ = state.clone();
|
||||||
i.set_dispatch(move |control_buf, zero_copy_buf| {
|
i.set_dispatch(move |control_buf, zero_copy_buf| {
|
||||||
state_.dispatch(control_buf, zero_copy_buf)
|
state_.dispatch(control_buf, zero_copy_buf)
|
||||||
});
|
});
|
||||||
|
let state_ = state.clone();
|
||||||
|
i.set_js_error_create(move |v8_exception| {
|
||||||
|
JSError::from_v8_exception(v8_exception, &state_.dir)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Self { isolate, state }
|
Self { isolate, state }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as execute2() but the filename defaults to "<anonymous>".
|
/// Same as execute2() but the filename defaults to "<anonymous>".
|
||||||
pub fn execute(&mut self, js_source: &str) -> Result<(), DenoError> {
|
pub fn execute(&mut self, js_source: &str) -> Result<(), ErrBox> {
|
||||||
self.execute2("<anonymous>", js_source)
|
self.execute2("<anonymous>", js_source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,12 +51,9 @@ impl Worker {
|
||||||
&mut self,
|
&mut self,
|
||||||
js_filename: &str,
|
js_filename: &str,
|
||||||
js_source: &str,
|
js_source: &str,
|
||||||
) -> Result<(), DenoError> {
|
) -> Result<(), ErrBox> {
|
||||||
let mut isolate = self.isolate.lock().unwrap();
|
let mut isolate = self.isolate.lock().unwrap();
|
||||||
match isolate.execute(js_filename, js_source) {
|
isolate.execute(js_filename, js_source)
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(err) => Err(DenoError::from(err)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the provided JavaScript module.
|
/// Executes the provided JavaScript module.
|
||||||
|
@ -59,9 +61,8 @@ impl Worker {
|
||||||
&mut self,
|
&mut self,
|
||||||
module_specifier: &ModuleSpecifier,
|
module_specifier: &ModuleSpecifier,
|
||||||
is_prefetch: bool,
|
is_prefetch: bool,
|
||||||
) -> impl Future<Item = (), Error = DenoError> {
|
) -> impl Future<Item = (), Error = ErrBox> {
|
||||||
let worker = self.clone();
|
let worker = self.clone();
|
||||||
let worker_ = worker.clone();
|
|
||||||
let loader = self.state.clone();
|
let loader = self.state.clone();
|
||||||
let isolate = self.isolate.clone();
|
let isolate = self.isolate.clone();
|
||||||
let modules = self.state.modules.clone();
|
let modules = self.state.modules.clone();
|
||||||
|
@ -71,30 +72,15 @@ impl Worker {
|
||||||
isolate,
|
isolate,
|
||||||
modules,
|
modules,
|
||||||
);
|
);
|
||||||
recursive_load
|
recursive_load.and_then(move |id| -> Result<(), ErrBox> {
|
||||||
.and_then(move |id| -> Result<(), deno::JSErrorOr<DenoError>> {
|
worker.state.progress.done();
|
||||||
worker.state.progress.done();
|
if is_prefetch {
|
||||||
if is_prefetch {
|
Ok(())
|
||||||
Ok(())
|
} else {
|
||||||
} else {
|
let mut isolate = worker.isolate.lock().unwrap();
|
||||||
let mut isolate = worker.isolate.lock().unwrap();
|
isolate.mod_evaluate(id)
|
||||||
let result = isolate.mod_evaluate(id);
|
}
|
||||||
if let Err(err) = result {
|
})
|
||||||
Err(deno::JSErrorOr::JSError(err))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).map_err(move |err| {
|
|
||||||
worker_.state.progress.done();
|
|
||||||
// Convert to DenoError AND apply_source_map.
|
|
||||||
match err {
|
|
||||||
deno::JSErrorOr::JSError(err) => {
|
|
||||||
worker_.apply_source_map(DenoError::from(err))
|
|
||||||
}
|
|
||||||
deno::JSErrorOr::Other(err) => err,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the provided JavaScript module.
|
/// Executes the provided JavaScript module.
|
||||||
|
@ -102,32 +88,24 @@ impl Worker {
|
||||||
&mut self,
|
&mut self,
|
||||||
module_specifier: &ModuleSpecifier,
|
module_specifier: &ModuleSpecifier,
|
||||||
is_prefetch: bool,
|
is_prefetch: bool,
|
||||||
) -> Result<(), DenoError> {
|
) -> Result<(), ErrBox> {
|
||||||
tokio_util::block_on(self.execute_mod_async(module_specifier, is_prefetch))
|
tokio_util::block_on(self.execute_mod_async(module_specifier, is_prefetch))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies source map to the error.
|
|
||||||
fn apply_source_map(&self, err: DenoError) -> DenoError {
|
|
||||||
err.apply_source_map(&self.state.dir)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for Worker {
|
impl Future for Worker {
|
||||||
type Item = ();
|
type Item = ();
|
||||||
type Error = DenoError;
|
type Error = ErrBox;
|
||||||
|
|
||||||
fn poll(&mut self) -> Result<Async<()>, Self::Error> {
|
fn poll(&mut self) -> Result<Async<()>, ErrBox> {
|
||||||
let mut isolate = self.isolate.lock().unwrap();
|
let mut isolate = self.isolate.lock().unwrap();
|
||||||
isolate
|
isolate.poll()
|
||||||
.poll()
|
|
||||||
.map_err(|err| self.apply_source_map(DenoError::from(err)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::deno_error::err_check;
|
|
||||||
use crate::flags;
|
use crate::flags;
|
||||||
use crate::ops::op_selector_std;
|
use crate::ops::op_selector_std;
|
||||||
use crate::progress::Progress;
|
use crate::progress::Progress;
|
||||||
|
@ -210,7 +188,7 @@ mod tests {
|
||||||
startup_data::deno_isolate_init(),
|
startup_data::deno_isolate_init(),
|
||||||
state,
|
state,
|
||||||
);
|
);
|
||||||
err_check(worker.execute("denoMain()"));
|
worker.execute("denoMain()").unwrap();
|
||||||
let result = worker.execute_mod(&module_specifier, false);
|
let result = worker.execute_mod(&module_specifier, false);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
eprintln!("execute_mod err {:?}", err);
|
eprintln!("execute_mod err {:?}", err);
|
||||||
|
@ -231,8 +209,8 @@ mod tests {
|
||||||
]);
|
]);
|
||||||
let mut worker =
|
let mut worker =
|
||||||
Worker::new("TEST".to_string(), startup_data::deno_isolate_init(), state);
|
Worker::new("TEST".to_string(), startup_data::deno_isolate_init(), state);
|
||||||
err_check(worker.execute("denoMain()"));
|
worker.execute("denoMain()").unwrap();
|
||||||
err_check(worker.execute("workerMain()"));
|
worker.execute("workerMain()").unwrap();
|
||||||
worker
|
worker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +231,7 @@ mod tests {
|
||||||
console.log("after postMessage");
|
console.log("after postMessage");
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
err_check(worker.execute(source));
|
worker.execute(source).unwrap();
|
||||||
|
|
||||||
let resource = worker.state.resource.clone();
|
let resource = worker.state.resource.clone();
|
||||||
let resource_ = resource.clone();
|
let resource_ = resource.clone();
|
||||||
|
@ -261,7 +239,7 @@ mod tests {
|
||||||
tokio::spawn(lazy(move || {
|
tokio::spawn(lazy(move || {
|
||||||
worker.then(move |r| -> Result<(), ()> {
|
worker.then(move |r| -> Result<(), ()> {
|
||||||
resource_.close();
|
resource_.close();
|
||||||
err_check(r);
|
r.unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
@ -291,9 +269,9 @@ mod tests {
|
||||||
fn removed_from_resource_table_on_close() {
|
fn removed_from_resource_table_on_close() {
|
||||||
tokio_util::init(|| {
|
tokio_util::init(|| {
|
||||||
let mut worker = create_test_worker();
|
let mut worker = create_test_worker();
|
||||||
err_check(
|
worker
|
||||||
worker.execute("onmessage = () => { delete window.onmessage; }"),
|
.execute("onmessage = () => { delete window.onmessage; }")
|
||||||
);
|
.unwrap();
|
||||||
|
|
||||||
let resource = worker.state.resource.clone();
|
let resource = worker.state.resource.clone();
|
||||||
let rid = resource.rid;
|
let rid = resource.rid;
|
||||||
|
@ -302,7 +280,7 @@ mod tests {
|
||||||
.then(move |r| -> Result<(), ()> {
|
.then(move |r| -> Result<(), ()> {
|
||||||
resource.close();
|
resource.close();
|
||||||
println!("workers.rs after resource close");
|
println!("workers.rs after resource close");
|
||||||
err_check(r);
|
r.unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}).shared();
|
}).shared();
|
||||||
|
|
||||||
|
|
68
core/any_error.rs
Normal file
68
core/any_error.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
use std::any::{Any, TypeId};
|
||||||
|
use std::convert::From;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
// The Send and Sync traits are required because deno is multithreaded and we
|
||||||
|
// need to beable to handle errors across threads.
|
||||||
|
pub trait AnyError: Any + Error + Send + Sync + 'static {}
|
||||||
|
impl<T> AnyError for T where T: Any + Error + Send + Sync + Sized + 'static {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ErrBox(Box<dyn AnyError>);
|
||||||
|
|
||||||
|
impl dyn AnyError {
|
||||||
|
pub fn downcast_ref<T: AnyError>(&self) -> Option<&T> {
|
||||||
|
if Any::type_id(self) == TypeId::of::<T>() {
|
||||||
|
let target = self as *const Self as *const T;
|
||||||
|
let target = unsafe { &*target };
|
||||||
|
Some(target)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrBox {
|
||||||
|
pub fn downcast<T: AnyError>(self) -> Result<T, Self> {
|
||||||
|
if Any::type_id(&*self.0) == TypeId::of::<T>() {
|
||||||
|
let target = Box::into_raw(self.0) as *mut T;
|
||||||
|
let target = unsafe { Box::from_raw(target) };
|
||||||
|
Ok(*target)
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<dyn AnyError> for ErrBox {
|
||||||
|
fn as_ref(&self) -> &dyn AnyError {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for ErrBox {
|
||||||
|
type Target = Box<AnyError>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AnyError> From<T> for ErrBox {
|
||||||
|
fn from(error: T) -> Self {
|
||||||
|
Self(Box::new(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<dyn AnyError>> for ErrBox {
|
||||||
|
fn from(boxed: Box<dyn AnyError>) -> Self {
|
||||||
|
Self(boxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ErrBox {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
|
@ -310,7 +310,7 @@ fn op_write(rid: i32, zero_copy_buf: Option<PinnedBuf>) -> Box<HttpBenchOp> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn js_check(r: Result<(), JSError>) {
|
fn js_check(r: Result<(), ErrBox>) {
|
||||||
if let Err(e) = r {
|
if let Err(e) = r {
|
||||||
panic!(e.to_string());
|
panic!(e.to_string());
|
||||||
}
|
}
|
||||||
|
|
148
core/isolate.rs
148
core/isolate.rs
|
@ -4,7 +4,9 @@
|
||||||
// isolate to keep the Isolate struct from becoming too bloating for users who
|
// isolate to keep the Isolate struct from becoming too bloating for users who
|
||||||
// do not need asynchronous module loading.
|
// do not need asynchronous module loading.
|
||||||
|
|
||||||
use crate::js_errors::JSError;
|
use crate::any_error::ErrBox;
|
||||||
|
use crate::js_errors::CoreJSError;
|
||||||
|
use crate::js_errors::V8Exception;
|
||||||
use crate::libdeno;
|
use crate::libdeno;
|
||||||
use crate::libdeno::deno_buf;
|
use crate::libdeno::deno_buf;
|
||||||
use crate::libdeno::deno_dyn_import_id;
|
use crate::libdeno::deno_dyn_import_id;
|
||||||
|
@ -81,6 +83,8 @@ type CoreDispatchFn = dyn Fn(&[u8], Option<PinnedBuf>) -> CoreOp;
|
||||||
pub type DynImportFuture = Box<dyn Future<Item = deno_mod, Error = ()> + Send>;
|
pub type DynImportFuture = Box<dyn Future<Item = deno_mod, Error = ()> + Send>;
|
||||||
type DynImportFn = dyn Fn(&str, &str) -> DynImportFuture;
|
type DynImportFn = dyn Fn(&str, &str) -> DynImportFuture;
|
||||||
|
|
||||||
|
type JSErrorCreateFn = dyn Fn(V8Exception) -> ErrBox;
|
||||||
|
|
||||||
/// Wraps DynImportFuture to include the deno_dyn_import_id, so that it doesn't
|
/// Wraps DynImportFuture to include the deno_dyn_import_id, so that it doesn't
|
||||||
/// need to be exposed.
|
/// need to be exposed.
|
||||||
struct DynImport {
|
struct DynImport {
|
||||||
|
@ -114,6 +118,7 @@ pub struct Isolate {
|
||||||
shared_libdeno_isolate: Arc<Mutex<Option<*const libdeno::isolate>>>,
|
shared_libdeno_isolate: Arc<Mutex<Option<*const libdeno::isolate>>>,
|
||||||
dispatch: Option<Arc<CoreDispatchFn>>,
|
dispatch: Option<Arc<CoreDispatchFn>>,
|
||||||
dyn_import: Option<Arc<DynImportFn>>,
|
dyn_import: Option<Arc<DynImportFn>>,
|
||||||
|
js_error_create: Arc<JSErrorCreateFn>,
|
||||||
needs_init: bool,
|
needs_init: bool,
|
||||||
shared: SharedQueue,
|
shared: SharedQueue,
|
||||||
pending_ops: FuturesUnordered<CoreOpAsyncFuture>,
|
pending_ops: FuturesUnordered<CoreOpAsyncFuture>,
|
||||||
|
@ -178,6 +183,7 @@ impl Isolate {
|
||||||
shared_libdeno_isolate: Arc::new(Mutex::new(Some(libdeno_isolate))),
|
shared_libdeno_isolate: Arc::new(Mutex::new(Some(libdeno_isolate))),
|
||||||
dispatch: None,
|
dispatch: None,
|
||||||
dyn_import: None,
|
dyn_import: None,
|
||||||
|
js_error_create: Arc::new(CoreJSError::from_v8_exception),
|
||||||
shared,
|
shared,
|
||||||
needs_init,
|
needs_init,
|
||||||
pending_ops: FuturesUnordered::new(),
|
pending_ops: FuturesUnordered::new(),
|
||||||
|
@ -204,6 +210,16 @@ impl Isolate {
|
||||||
self.dyn_import = Some(Arc::new(f));
|
self.dyn_import = Some(Arc::new(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allows a callback to be set whenever a V8 exception is made. This allows
|
||||||
|
/// the caller to wrap the V8Exception into an error. By default this callback
|
||||||
|
/// is set to CoreJSError::from_v8_exception.
|
||||||
|
pub fn set_js_error_create<F>(&mut self, f: F)
|
||||||
|
where
|
||||||
|
F: Fn(V8Exception) -> ErrBox + 'static,
|
||||||
|
{
|
||||||
|
self.js_error_create = Arc::new(f);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a thread safe handle on the isolate.
|
/// Get a thread safe handle on the isolate.
|
||||||
pub fn shared_isolate_handle(&mut self) -> IsolateHandle {
|
pub fn shared_isolate_handle(&mut self) -> IsolateHandle {
|
||||||
IsolateHandle {
|
IsolateHandle {
|
||||||
|
@ -307,11 +323,16 @@ impl Isolate {
|
||||||
self as *const _ as *const c_void
|
self as *const _ as *const c_void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes traditional JavaScript code (traditional = not ES modules)
|
||||||
|
///
|
||||||
|
/// ErrBox can be downcast to a type that exposes additional information about
|
||||||
|
/// the V8 exception. By default this type is CoreJSError, however it may be a
|
||||||
|
/// different type if Isolate::set_js_error_create() has been used.
|
||||||
pub fn execute(
|
pub fn execute(
|
||||||
&mut self,
|
&mut self,
|
||||||
js_filename: &str,
|
js_filename: &str,
|
||||||
js_source: &str,
|
js_source: &str,
|
||||||
) -> Result<(), JSError> {
|
) -> Result<(), ErrBox> {
|
||||||
self.shared_init();
|
self.shared_init();
|
||||||
let filename = CString::new(js_filename).unwrap();
|
let filename = CString::new(js_filename).unwrap();
|
||||||
let source = CString::new(js_source).unwrap();
|
let source = CString::new(js_source).unwrap();
|
||||||
|
@ -323,22 +344,20 @@ impl Isolate {
|
||||||
source.as_ptr(),
|
source.as_ptr(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if let Some(err) = self.last_exception() {
|
self.check_last_exception()
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_exception(&self) -> Option<JSError> {
|
fn check_last_exception(&self) -> Result<(), ErrBox> {
|
||||||
let ptr = unsafe { libdeno::deno_last_exception(self.libdeno_isolate) };
|
let ptr = unsafe { libdeno::deno_last_exception(self.libdeno_isolate) };
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
None
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
let js_error_create = &*self.js_error_create;
|
||||||
let cstr = unsafe { CStr::from_ptr(ptr) };
|
let cstr = unsafe { CStr::from_ptr(ptr) };
|
||||||
let v8_exception = cstr.to_str().unwrap();
|
let json_str = cstr.to_str().unwrap();
|
||||||
debug!("v8_exception\n{}\n", v8_exception);
|
let v8_exception = V8Exception::from_json(json_str).unwrap();
|
||||||
let js_error = JSError::from_v8_exception(v8_exception).unwrap();
|
let js_error = js_error_create(v8_exception);
|
||||||
Some(js_error)
|
Err(js_error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +367,7 @@ impl Isolate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn respond(&mut self, maybe_buf: Option<&[u8]>) -> Result<(), JSError> {
|
fn respond(&mut self, maybe_buf: Option<&[u8]>) -> Result<(), ErrBox> {
|
||||||
let buf = match maybe_buf {
|
let buf = match maybe_buf {
|
||||||
None => deno_buf::empty(),
|
None => deno_buf::empty(),
|
||||||
Some(r) => deno_buf::from(r),
|
Some(r) => deno_buf::from(r),
|
||||||
|
@ -356,11 +375,7 @@ impl Isolate {
|
||||||
unsafe {
|
unsafe {
|
||||||
libdeno::deno_respond(self.libdeno_isolate, self.as_raw_ptr(), buf)
|
libdeno::deno_respond(self.libdeno_isolate, self.as_raw_ptr(), buf)
|
||||||
}
|
}
|
||||||
if let Some(err) = self.last_exception() {
|
self.check_last_exception()
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Low-level module creation.
|
/// Low-level module creation.
|
||||||
|
@ -369,7 +384,7 @@ impl Isolate {
|
||||||
main: bool,
|
main: bool,
|
||||||
name: &str,
|
name: &str,
|
||||||
source: &str,
|
source: &str,
|
||||||
) -> Result<deno_mod, JSError> {
|
) -> Result<deno_mod, ErrBox> {
|
||||||
let name_ = CString::new(name.to_string()).unwrap();
|
let name_ = CString::new(name.to_string()).unwrap();
|
||||||
let name_ptr = name_.as_ptr() as *const libc::c_char;
|
let name_ptr = name_.as_ptr() as *const libc::c_char;
|
||||||
|
|
||||||
|
@ -379,12 +394,11 @@ impl Isolate {
|
||||||
let id = unsafe {
|
let id = unsafe {
|
||||||
libdeno::deno_mod_new(self.libdeno_isolate, main, name_ptr, source_ptr)
|
libdeno::deno_mod_new(self.libdeno_isolate, main, name_ptr, source_ptr)
|
||||||
};
|
};
|
||||||
if let Some(js_error) = self.last_exception() {
|
|
||||||
assert_eq!(id, 0);
|
|
||||||
return Err(js_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(id)
|
self.check_last_exception().map(|_| id).map_err(|err| {
|
||||||
|
assert_eq!(id, 0);
|
||||||
|
err
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mod_get_imports(&self, id: deno_mod) -> Vec<String> {
|
pub fn mod_get_imports(&self, id: deno_mod) -> Vec<String> {
|
||||||
|
@ -402,23 +416,29 @@ impl Isolate {
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot(&self) -> Result<Snapshot1<'static>, JSError> {
|
/// Takes a snapshot. The isolate should have been created with will_snapshot
|
||||||
|
/// set to true.
|
||||||
|
///
|
||||||
|
/// ErrBox can be downcast to a type that exposes additional information about
|
||||||
|
/// the V8 exception. By default this type is CoreJSError, however it may be a
|
||||||
|
/// different type if Isolate::set_js_error_create() has been used.
|
||||||
|
pub fn snapshot(&self) -> Result<Snapshot1<'static>, ErrBox> {
|
||||||
let snapshot = unsafe { libdeno::deno_snapshot_new(self.libdeno_isolate) };
|
let snapshot = unsafe { libdeno::deno_snapshot_new(self.libdeno_isolate) };
|
||||||
if let Some(js_error) = self.last_exception() {
|
match self.check_last_exception() {
|
||||||
assert_eq!(snapshot.data_ptr, null());
|
Ok(..) => Ok(snapshot),
|
||||||
assert_eq!(snapshot.data_len, 0);
|
Err(err) => {
|
||||||
return Err(js_error);
|
assert_eq!(snapshot.data_ptr, null());
|
||||||
|
assert_eq!(snapshot.data_len, 0);
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assert_ne!(snapshot.data_ptr, null());
|
|
||||||
assert_ne!(snapshot.data_len, 0);
|
|
||||||
Ok(snapshot)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dyn_import_done(
|
fn dyn_import_done(
|
||||||
&self,
|
&self,
|
||||||
id: libdeno::deno_dyn_import_id,
|
id: libdeno::deno_dyn_import_id,
|
||||||
mod_id: deno_mod,
|
mod_id: deno_mod,
|
||||||
) -> Result<(), JSError> {
|
) -> Result<(), ErrBox> {
|
||||||
debug!("dyn_import_done {} {}", id, mod_id);
|
debug!("dyn_import_done {} {}", id, mod_id);
|
||||||
unsafe {
|
unsafe {
|
||||||
libdeno::deno_dyn_import(
|
libdeno::deno_dyn_import(
|
||||||
|
@ -428,11 +448,10 @@ impl Isolate {
|
||||||
mod_id,
|
mod_id,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if let Some(js_error) = self.last_exception() {
|
self.check_last_exception().map_err(|err| {
|
||||||
assert_eq!(id, 0);
|
assert_eq!(id, 0);
|
||||||
return Err(js_error);
|
err
|
||||||
}
|
})
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,11 +477,16 @@ impl<'a> ResolveContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Isolate {
|
impl Isolate {
|
||||||
|
/// Instanciates a ES module
|
||||||
|
///
|
||||||
|
/// ErrBox can be downcast to a type that exposes additional information about
|
||||||
|
/// the V8 exception. By default this type is CoreJSError, however it may be a
|
||||||
|
/// different type if Isolate::set_js_error_create() has been used.
|
||||||
pub fn mod_instantiate(
|
pub fn mod_instantiate(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: deno_mod,
|
id: deno_mod,
|
||||||
resolve_fn: &mut ResolveFn,
|
resolve_fn: &mut ResolveFn,
|
||||||
) -> Result<(), JSError> {
|
) -> Result<(), ErrBox> {
|
||||||
let libdeno_isolate = self.libdeno_isolate;
|
let libdeno_isolate = self.libdeno_isolate;
|
||||||
let mut ctx = ResolveContext { resolve_fn };
|
let mut ctx = ResolveContext { resolve_fn };
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -473,11 +497,7 @@ impl Isolate {
|
||||||
Self::resolve_cb,
|
Self::resolve_cb,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
self.check_last_exception()
|
||||||
if let Some(js_error) = self.last_exception() {
|
|
||||||
return Err(js_error);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called during mod_instantiate() only.
|
/// Called during mod_instantiate() only.
|
||||||
|
@ -494,15 +514,17 @@ impl Isolate {
|
||||||
resolve_fn(specifier, referrer)
|
resolve_fn(specifier, referrer)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mod_evaluate(&mut self, id: deno_mod) -> Result<(), JSError> {
|
/// Evaluates an already instantiated ES module.
|
||||||
|
///
|
||||||
|
/// ErrBox can be downcast to a type that exposes additional information about
|
||||||
|
/// the V8 exception. By default this type is CoreJSError, however it may be a
|
||||||
|
/// different type if Isolate::set_js_error_create() has been used.
|
||||||
|
pub fn mod_evaluate(&mut self, id: deno_mod) -> Result<(), ErrBox> {
|
||||||
self.shared_init();
|
self.shared_init();
|
||||||
unsafe {
|
unsafe {
|
||||||
libdeno::deno_mod_evaluate(self.libdeno_isolate, self.as_raw_ptr(), id)
|
libdeno::deno_mod_evaluate(self.libdeno_isolate, self.as_raw_ptr(), id)
|
||||||
};
|
};
|
||||||
if let Some(js_error) = self.last_exception() {
|
self.check_last_exception()
|
||||||
return Err(js_error);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,9 +547,9 @@ impl Drop for LockerScope {
|
||||||
|
|
||||||
impl Future for Isolate {
|
impl Future for Isolate {
|
||||||
type Item = ();
|
type Item = ();
|
||||||
type Error = JSError;
|
type Error = ErrBox;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<(), JSError> {
|
fn poll(&mut self) -> Poll<(), ErrBox> {
|
||||||
// Lock the current thread for V8.
|
// Lock the current thread for V8.
|
||||||
let _locker = LockerScope::new(self.libdeno_isolate);
|
let _locker = LockerScope::new(self.libdeno_isolate);
|
||||||
|
|
||||||
|
@ -579,9 +601,7 @@ impl Future for Isolate {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_promise_errors();
|
self.check_promise_errors();
|
||||||
if let Some(err) = self.last_exception() {
|
self.check_last_exception()?;
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're idle if pending_ops is empty.
|
// We're idle if pending_ops is empty.
|
||||||
if self.pending_ops.is_empty() {
|
if self.pending_ops.is_empty() {
|
||||||
|
@ -616,7 +636,7 @@ impl IsolateHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn js_check(r: Result<(), JSError>) {
|
pub fn js_check(r: Result<(), ErrBox>) {
|
||||||
if let Err(e) = r {
|
if let Err(e) = r {
|
||||||
panic!(e.to_string());
|
panic!(e.to_string());
|
||||||
}
|
}
|
||||||
|
@ -814,7 +834,7 @@ pub mod tests {
|
||||||
"#,
|
"#,
|
||||||
));
|
));
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
|
||||||
assert_eq!(Ok(Async::Ready(())), isolate.poll());
|
assert_eq!(Async::Ready(()), isolate.poll().unwrap());
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
|
||||||
js_check(isolate.execute(
|
js_check(isolate.execute(
|
||||||
"check2.js",
|
"check2.js",
|
||||||
|
@ -825,11 +845,11 @@ pub mod tests {
|
||||||
"#,
|
"#,
|
||||||
));
|
));
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
|
||||||
assert_eq!(Ok(Async::Ready(())), isolate.poll());
|
assert_eq!(Async::Ready(()), isolate.poll().unwrap());
|
||||||
js_check(isolate.execute("check3.js", "assert(nrecv == 2)"));
|
js_check(isolate.execute("check3.js", "assert(nrecv == 2)"));
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
|
||||||
// We are idle, so the next poll should be the last.
|
// We are idle, so the next poll should be the last.
|
||||||
assert_eq!(Ok(Async::Ready(())), isolate.poll());
|
assert_eq!(Async::Ready(()), isolate.poll().unwrap());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,7 +885,7 @@ pub mod tests {
|
||||||
"#,
|
"#,
|
||||||
));
|
));
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
|
||||||
assert_eq!(Ok(Async::Ready(())), isolate.poll());
|
assert_eq!(Async::Ready(()), isolate.poll().unwrap());
|
||||||
js_check(isolate.execute("send1.js", "assert(nrecv === 2);"));
|
js_check(isolate.execute("send1.js", "assert(nrecv === 2);"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -949,9 +969,9 @@ pub mod tests {
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(count.load(Ordering::Relaxed), 1);
|
assert_eq!(count.load(Ordering::Relaxed), 1);
|
||||||
assert_eq!(Ok(Ready(())), isolate.poll());
|
assert_eq!(Ready(()), isolate.poll().unwrap());
|
||||||
assert_eq!(count.load(Ordering::Relaxed), 2);
|
assert_eq!(count.load(Ordering::Relaxed), 2);
|
||||||
assert_eq!(Ok(Ready(())), isolate.poll());
|
assert_eq!(Ready(()), isolate.poll().unwrap());
|
||||||
assert_eq!(count.load(Ordering::Relaxed), 2);
|
assert_eq!(count.load(Ordering::Relaxed), 2);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1090,7 +1110,7 @@ pub mod tests {
|
||||||
"#,
|
"#,
|
||||||
));
|
));
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
|
||||||
assert_eq!(Ok(Async::Ready(())), isolate.poll());
|
assert_eq!(Async::Ready(()), isolate.poll().unwrap());
|
||||||
js_check(isolate.execute("check.js", "assert(asyncRecv == 1);"));
|
js_check(isolate.execute("check.js", "assert(asyncRecv == 1);"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1118,7 +1138,7 @@ pub mod tests {
|
||||||
"#,
|
"#,
|
||||||
));
|
));
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
|
||||||
assert_eq!(Ok(()), poll_until_ready(&mut isolate, 3));
|
poll_until_ready(&mut isolate, 3).unwrap();
|
||||||
js_check(isolate.execute("check.js", "assert(asyncRecv == 1);"));
|
js_check(isolate.execute("check.js", "assert(asyncRecv == 1);"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1149,7 +1169,7 @@ pub mod tests {
|
||||||
"#,
|
"#,
|
||||||
));
|
));
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
|
||||||
assert_eq!(Ok(()), poll_until_ready(&mut isolate, 3));
|
poll_until_ready(&mut isolate, 3).unwrap();
|
||||||
js_check(isolate.execute("check.js", "assert(asyncRecv == 2);"));
|
js_check(isolate.execute("check.js", "assert(asyncRecv == 2);"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1164,7 +1184,7 @@ pub mod tests {
|
||||||
include_str!("shared_queue_test.js"),
|
include_str!("shared_queue_test.js"),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
assert_eq!(Ok(Async::Ready(())), isolate.poll());
|
assert_eq!(Async::Ready(()), isolate.poll().unwrap());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
// console.log(err.stack);
|
// console.log(err.stack);
|
||||||
// It would require calling into Rust from Error.prototype.prepareStackTrace.
|
// It would require calling into Rust from Error.prototype.prepareStackTrace.
|
||||||
|
|
||||||
|
use crate::any_error::ErrBox;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use serde_json::value::Value;
|
use serde_json::value::Value;
|
||||||
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
@ -26,7 +28,7 @@ pub struct StackFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct JSError {
|
pub struct V8Exception {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
|
|
||||||
pub source_line: Option<String>,
|
pub source_line: Option<String>,
|
||||||
|
@ -41,77 +43,8 @@ pub struct JSError {
|
||||||
pub frames: Vec<StackFrame>,
|
pub frames: Vec<StackFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for JSError {
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
pub struct CoreJSError(V8Exception);
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for StackFrame {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
// Note when we print to string, we change from 0-indexed to 1-indexed.
|
|
||||||
let function_name = self.function_name.clone();
|
|
||||||
let script_line_column =
|
|
||||||
format_script_line_column(&self.script_name, self.line, self.column);
|
|
||||||
|
|
||||||
if !self.function_name.is_empty() {
|
|
||||||
write!(f, " at {} ({})", function_name, script_line_column)
|
|
||||||
} else if self.is_eval {
|
|
||||||
write!(f, " at eval ({})", script_line_column)
|
|
||||||
} else {
|
|
||||||
write!(f, " at {}", script_line_column)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_script_line_column(
|
|
||||||
script_name: &str,
|
|
||||||
line: i64,
|
|
||||||
column: i64,
|
|
||||||
) -> String {
|
|
||||||
// TODO match this style with how typescript displays errors.
|
|
||||||
let line = (1 + line).to_string();
|
|
||||||
let column = (1 + column).to_string();
|
|
||||||
let script_name = script_name.to_string();
|
|
||||||
format!("{}:{}:{}", script_name, line, column)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for JSError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
if self.script_resource_name.is_some() {
|
|
||||||
let script_resource_name = self.script_resource_name.as_ref().unwrap();
|
|
||||||
if self.line_number.is_some() && self.start_column.is_some() {
|
|
||||||
assert!(self.line_number.is_some());
|
|
||||||
assert!(self.start_column.is_some());
|
|
||||||
let script_line_column = format_script_line_column(
|
|
||||||
script_resource_name,
|
|
||||||
self.line_number.unwrap() - 1,
|
|
||||||
self.start_column.unwrap() - 1,
|
|
||||||
);
|
|
||||||
write!(f, "{}", script_line_column)?;
|
|
||||||
}
|
|
||||||
if self.source_line.is_some() {
|
|
||||||
write!(f, "\n{}\n", self.source_line.as_ref().unwrap())?;
|
|
||||||
let mut s = String::new();
|
|
||||||
for i in 0..self.end_column.unwrap() {
|
|
||||||
if i >= self.start_column.unwrap() {
|
|
||||||
s.push('^');
|
|
||||||
} else {
|
|
||||||
s.push(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writeln!(f, "{}", s)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(f, "{}", self.message.clone())?;
|
|
||||||
|
|
||||||
for frame in &self.frames {
|
|
||||||
write!(f, "\n{}", &frame.to_string())?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StackFrame {
|
impl StackFrame {
|
||||||
// TODO Maybe use serde_derive?
|
// TODO Maybe use serde_derive?
|
||||||
|
@ -186,9 +119,9 @@ impl StackFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JSError {
|
impl V8Exception {
|
||||||
/// Creates a new JSError by parsing the raw exception JSON string from V8.
|
/// Creates a new V8Exception by parsing the raw exception JSON string from V8.
|
||||||
pub fn from_v8_exception(json_str: &str) -> Option<Self> {
|
pub fn from_json(json_str: &str) -> Option<Self> {
|
||||||
let v = serde_json::from_str::<serde_json::Value>(json_str);
|
let v = serde_json::from_str::<serde_json::Value>(json_str);
|
||||||
if v.is_err() {
|
if v.is_err() {
|
||||||
return None;
|
return None;
|
||||||
|
@ -236,7 +169,7 @@ impl JSError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(JSError {
|
Some(V8Exception {
|
||||||
message,
|
message,
|
||||||
source_line,
|
source_line,
|
||||||
script_resource_name,
|
script_resource_name,
|
||||||
|
@ -251,12 +184,79 @@ impl JSError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CoreJSError {
|
||||||
|
pub fn from_v8_exception(v8_exception: V8Exception) -> ErrBox {
|
||||||
|
let error = Self(v8_exception);
|
||||||
|
ErrBox::from(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_source_loc(script_name: &str, line: i64, column: i64) -> String {
|
||||||
|
// TODO match this style with how typescript displays errors.
|
||||||
|
let line = line + 1;
|
||||||
|
let column = column + 1;
|
||||||
|
format!("{}:{}:{}", script_name, line, column)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_stack_frame(frame: &StackFrame) -> String {
|
||||||
|
// Note when we print to string, we change from 0-indexed to 1-indexed.
|
||||||
|
let source_loc =
|
||||||
|
format_source_loc(&frame.script_name, frame.line, frame.column);
|
||||||
|
|
||||||
|
if !frame.function_name.is_empty() {
|
||||||
|
format!(" at {} ({})", frame.function_name, source_loc)
|
||||||
|
} else if frame.is_eval {
|
||||||
|
format!(" at eval ({})", source_loc)
|
||||||
|
} else {
|
||||||
|
format!(" at {}", source_loc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CoreJSError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.0.script_resource_name.is_some() {
|
||||||
|
let script_resource_name = self.0.script_resource_name.as_ref().unwrap();
|
||||||
|
if self.0.line_number.is_some() && self.0.start_column.is_some() {
|
||||||
|
assert!(self.0.line_number.is_some());
|
||||||
|
assert!(self.0.start_column.is_some());
|
||||||
|
let source_loc = format_source_loc(
|
||||||
|
script_resource_name,
|
||||||
|
self.0.line_number.unwrap() - 1,
|
||||||
|
self.0.start_column.unwrap() - 1,
|
||||||
|
);
|
||||||
|
write!(f, "{}", source_loc)?;
|
||||||
|
}
|
||||||
|
if self.0.source_line.is_some() {
|
||||||
|
write!(f, "\n{}\n", self.0.source_line.as_ref().unwrap())?;
|
||||||
|
let mut s = String::new();
|
||||||
|
for i in 0..self.0.end_column.unwrap() {
|
||||||
|
if i >= self.0.start_column.unwrap() {
|
||||||
|
s.push('^');
|
||||||
|
} else {
|
||||||
|
s.push(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(f, "{}", s)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "{}", self.0.message)?;
|
||||||
|
|
||||||
|
for frame in &self.0.frames {
|
||||||
|
write!(f, "\n{}", format_stack_frame(frame))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for CoreJSError {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn error1() -> JSError {
|
fn error1() -> V8Exception {
|
||||||
JSError {
|
V8Exception {
|
||||||
message: "Error: foo bar".to_string(),
|
message: "Error: foo bar".to_string(),
|
||||||
source_line: None,
|
source_line: None,
|
||||||
script_resource_name: None,
|
script_resource_name: None,
|
||||||
|
@ -344,8 +344,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn js_error_from_v8_exception() {
|
fn v8_exception_from_json() {
|
||||||
let r = JSError::from_v8_exception(
|
let r = V8Exception::from_json(
|
||||||
r#"{
|
r#"{
|
||||||
"message":"Uncaught Error: bad",
|
"message":"Uncaught Error: bad",
|
||||||
"frames":[
|
"frames":[
|
||||||
|
@ -387,8 +387,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn js_error_from_v8_exception2() {
|
fn v8_exception_from_json_2() {
|
||||||
let r = JSError::from_v8_exception(
|
let r = V8Exception::from_json(
|
||||||
"{\"message\":\"Error: boo\",\"sourceLine\":\"throw Error('boo');\",\"scriptResourceName\":\"a.js\",\"lineNumber\":3,\"startPosition\":8,\"endPosition\":9,\"errorLevel\":8,\"startColumn\":6,\"endColumn\":7,\"isSharedCrossOrigin\":false,\"isOpaque\":false,\"frames\":[{\"line\":3,\"column\":7,\"functionName\":\"\",\"scriptName\":\"a.js\",\"isEval\":false,\"isConstructor\":false,\"isWasm\":false}]}"
|
"{\"message\":\"Error: boo\",\"sourceLine\":\"throw Error('boo');\",\"scriptResourceName\":\"a.js\",\"lineNumber\":3,\"startPosition\":8,\"endPosition\":9,\"errorLevel\":8,\"startColumn\":6,\"endColumn\":7,\"isSharedCrossOrigin\":false,\"isOpaque\":false,\"frames\":[{\"line\":3,\"column\":7,\"functionName\":\"\",\"scriptName\":\"a.js\",\"isEval\":false,\"isConstructor\":false,\"isWasm\":false}]}"
|
||||||
);
|
);
|
||||||
assert!(r.is_some());
|
assert!(r.is_some());
|
||||||
|
@ -405,16 +405,9 @@ mod tests {
|
||||||
assert_eq!(e.frames.len(), 1);
|
assert_eq!(e.frames.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn stack_frame_to_string() {
|
|
||||||
let e = error1();
|
|
||||||
assert_eq!(" at foo (foo_bar.ts:5:17)", &e.frames[0].to_string());
|
|
||||||
assert_eq!(" at qat (bar_baz.ts:6:21)", &e.frames[1].to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn js_error_to_string() {
|
fn js_error_to_string() {
|
||||||
let e = error1();
|
let e = CoreJSError(error1());
|
||||||
let expected = "Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2";
|
let expected = "Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2";
|
||||||
assert_eq!(expected, &e.to_string());
|
assert_eq!(expected, &e.to_string());
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ extern crate log;
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
mod any_error;
|
||||||
mod flags;
|
mod flags;
|
||||||
mod isolate;
|
mod isolate;
|
||||||
mod js_errors;
|
mod js_errors;
|
||||||
|
@ -12,6 +13,7 @@ mod module_specifier;
|
||||||
mod modules;
|
mod modules;
|
||||||
mod shared_queue;
|
mod shared_queue;
|
||||||
|
|
||||||
|
pub use crate::any_error::*;
|
||||||
pub use crate::flags::v8_set_flags;
|
pub use crate::flags::v8_set_flags;
|
||||||
pub use crate::isolate::*;
|
pub use crate::isolate::*;
|
||||||
pub use crate::js_errors::*;
|
pub use crate::js_errors::*;
|
||||||
|
|
109
core/modules.rs
109
core/modules.rs
|
@ -6,8 +6,8 @@
|
||||||
// small and simple for users who do not use modules or if they do can load them
|
// small and simple for users who do not use modules or if they do can load them
|
||||||
// synchronously. The isolate.rs module should never depend on this module.
|
// synchronously. The isolate.rs module should never depend on this module.
|
||||||
|
|
||||||
|
use crate::any_error::ErrBox;
|
||||||
use crate::isolate::Isolate;
|
use crate::isolate::Isolate;
|
||||||
use crate::js_errors::JSError;
|
|
||||||
use crate::libdeno::deno_mod;
|
use crate::libdeno::deno_mod;
|
||||||
use crate::module_specifier::ModuleSpecifier;
|
use crate::module_specifier::ModuleSpecifier;
|
||||||
use futures::Async;
|
use futures::Async;
|
||||||
|
@ -15,7 +15,6 @@ use futures::Future;
|
||||||
use futures::Poll;
|
use futures::Poll;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -34,12 +33,10 @@ pub struct SourceCodeInfo {
|
||||||
pub code: String,
|
pub code: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type SourceCodeInfoFuture<E> =
|
pub type SourceCodeInfoFuture =
|
||||||
dyn Future<Item = SourceCodeInfo, Error = E> + Send;
|
dyn Future<Item = SourceCodeInfo, Error = ErrBox> + Send;
|
||||||
|
|
||||||
pub trait Loader: Send + Sync {
|
pub trait Loader: Send + Sync {
|
||||||
type Error: std::error::Error + 'static;
|
|
||||||
|
|
||||||
/// Returns an absolute URL.
|
/// Returns an absolute URL.
|
||||||
/// When implementing an spec-complaint VM, this should be exactly the
|
/// When implementing an spec-complaint VM, this should be exactly the
|
||||||
/// algorithm described here:
|
/// algorithm described here:
|
||||||
|
@ -49,19 +46,19 @@ pub trait Loader: Send + Sync {
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
referrer: &str,
|
referrer: &str,
|
||||||
is_root: bool,
|
is_root: bool,
|
||||||
) -> Result<ModuleSpecifier, Self::Error>;
|
) -> Result<ModuleSpecifier, ErrBox>;
|
||||||
|
|
||||||
/// Given ModuleSpecifier, load its source code.
|
/// Given ModuleSpecifier, load its source code.
|
||||||
fn load(
|
fn load(
|
||||||
&self,
|
&self,
|
||||||
module_specifier: &ModuleSpecifier,
|
module_specifier: &ModuleSpecifier,
|
||||||
) -> Box<SourceCodeInfoFuture<Self::Error>>;
|
) -> Box<SourceCodeInfoFuture>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PendingLoad<E: Error> {
|
struct PendingLoad {
|
||||||
url: String,
|
url: String,
|
||||||
is_root: bool,
|
is_root: bool,
|
||||||
source_code_info_future: Box<SourceCodeInfoFuture<E>>,
|
source_code_info_future: Box<SourceCodeInfoFuture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This future is used to implement parallel async module loading without
|
/// This future is used to implement parallel async module loading without
|
||||||
|
@ -71,7 +68,7 @@ pub struct RecursiveLoad<L: Loader> {
|
||||||
loader: L,
|
loader: L,
|
||||||
isolate: Arc<Mutex<Isolate>>,
|
isolate: Arc<Mutex<Isolate>>,
|
||||||
modules: Arc<Mutex<Modules>>,
|
modules: Arc<Mutex<Modules>>,
|
||||||
pending: Vec<PendingLoad<L::Error>>,
|
pending: Vec<PendingLoad>,
|
||||||
is_pending: HashSet<String>,
|
is_pending: HashSet<String>,
|
||||||
phantom: PhantomData<L>,
|
phantom: PhantomData<L>,
|
||||||
// TODO(ry) The following can all be combined into a single enum State type.
|
// TODO(ry) The following can all be combined into a single enum State type.
|
||||||
|
@ -106,7 +103,7 @@ impl<L: Loader> RecursiveLoad<L> {
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
referrer: &str,
|
referrer: &str,
|
||||||
parent_id: Option<deno_mod>,
|
parent_id: Option<deno_mod>,
|
||||||
) -> Result<String, L::Error> {
|
) -> Result<String, ErrBox> {
|
||||||
let is_root = parent_id.is_none();
|
let is_root = parent_id.is_none();
|
||||||
let module_specifier = self.loader.resolve(specifier, referrer, is_root)?;
|
let module_specifier = self.loader.resolve(specifier, referrer, is_root)?;
|
||||||
let module_name = module_specifier.to_string();
|
let module_name = module_specifier.to_string();
|
||||||
|
@ -142,22 +139,16 @@ impl<L: Loader> RecursiveLoad<L> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum JSErrorOr<E> {
|
|
||||||
JSError(JSError),
|
|
||||||
Other(E),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<L: Loader> Future for RecursiveLoad<L> {
|
impl<L: Loader> Future for RecursiveLoad<L> {
|
||||||
type Item = deno_mod;
|
type Item = deno_mod;
|
||||||
type Error = JSErrorOr<L::Error>;
|
type Error = ErrBox;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
if self.root.is_none() && self.root_specifier.is_some() {
|
if self.root.is_none() && self.root_specifier.is_some() {
|
||||||
let s = self.root_specifier.take().unwrap();
|
let s = self.root_specifier.take().unwrap();
|
||||||
match self.add(&s, ".", None) {
|
match self.add(&s, ".", None) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(JSErrorOr::Other(err));
|
return Err(err);
|
||||||
}
|
}
|
||||||
Ok(root) => {
|
Ok(root) => {
|
||||||
self.root = Some(root);
|
self.root = Some(root);
|
||||||
|
@ -172,7 +163,7 @@ impl<L: Loader> Future for RecursiveLoad<L> {
|
||||||
let pending = &mut self.pending[i];
|
let pending = &mut self.pending[i];
|
||||||
match pending.source_code_info_future.poll() {
|
match pending.source_code_info_future.poll() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(JSErrorOr::Other(err));
|
return Err(err);
|
||||||
}
|
}
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
i += 1;
|
i += 1;
|
||||||
|
@ -200,18 +191,15 @@ impl<L: Loader> Future for RecursiveLoad<L> {
|
||||||
if !is_module_registered {
|
if !is_module_registered {
|
||||||
let module_name = &source_code_info.module_name;
|
let module_name = &source_code_info.module_name;
|
||||||
|
|
||||||
let result = {
|
let mod_id = {
|
||||||
let isolate = self.isolate.lock().unwrap();
|
let isolate = self.isolate.lock().unwrap();
|
||||||
isolate.mod_new(
|
isolate.mod_new(
|
||||||
completed.is_root,
|
completed.is_root,
|
||||||
module_name,
|
module_name,
|
||||||
&source_code_info.code,
|
&source_code_info.code,
|
||||||
)
|
)
|
||||||
};
|
}?;
|
||||||
if let Err(err) = result {
|
|
||||||
return Err(JSErrorOr::JSError(err));
|
|
||||||
}
|
|
||||||
let mod_id = result.unwrap();
|
|
||||||
if completed.is_root {
|
if completed.is_root {
|
||||||
assert!(self.root_id.is_none());
|
assert!(self.root_id.is_none());
|
||||||
self.root_id = Some(mod_id);
|
self.root_id = Some(mod_id);
|
||||||
|
@ -235,9 +223,7 @@ impl<L: Loader> Future for RecursiveLoad<L> {
|
||||||
};
|
};
|
||||||
let referrer = module_name;
|
let referrer = module_name;
|
||||||
for specifier in imports {
|
for specifier in imports {
|
||||||
self
|
self.add(&specifier, referrer, Some(mod_id))?;
|
||||||
.add(&specifier, referrer, Some(mod_id))
|
|
||||||
.map_err(JSErrorOr::Other)?;
|
|
||||||
}
|
}
|
||||||
} else if need_alias {
|
} else if need_alias {
|
||||||
let mut modules = self.modules.lock().unwrap();
|
let mut modules = self.modules.lock().unwrap();
|
||||||
|
@ -252,31 +238,26 @@ impl<L: Loader> Future for RecursiveLoad<L> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let root_id = self.root_id.unwrap();
|
let root_id = self.root_id.unwrap();
|
||||||
let result = {
|
|
||||||
let mut resolve_cb =
|
|
||||||
|specifier: &str, referrer_id: deno_mod| -> deno_mod {
|
|
||||||
let modules = self.modules.lock().unwrap();
|
|
||||||
let referrer = modules.get_name(referrer_id).unwrap();
|
|
||||||
// this callback is only called for non-root modules
|
|
||||||
match self.loader.resolve(specifier, &referrer, false) {
|
|
||||||
Ok(specifier) => match modules.get_id(&specifier.to_string()) {
|
|
||||||
Some(id) => id,
|
|
||||||
None => 0,
|
|
||||||
},
|
|
||||||
// We should have already resolved and loaded this module, so
|
|
||||||
// resolve() will not fail this time.
|
|
||||||
Err(_err) => unreachable!(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut isolate = self.isolate.lock().unwrap();
|
let mut resolve_cb = |specifier: &str, referrer_id: deno_mod| -> deno_mod {
|
||||||
isolate.mod_instantiate(root_id, &mut resolve_cb)
|
let modules = self.modules.lock().unwrap();
|
||||||
|
let referrer = modules.get_name(referrer_id).unwrap();
|
||||||
|
// this callback is only called for non-root modules
|
||||||
|
match self.loader.resolve(specifier, &referrer, false) {
|
||||||
|
Ok(specifier) => match modules.get_id(&specifier.to_string()) {
|
||||||
|
Some(id) => id,
|
||||||
|
None => 0,
|
||||||
|
},
|
||||||
|
// We should have already resolved and loaded this module, so
|
||||||
|
// resolve() will not fail this time.
|
||||||
|
Err(_err) => unreachable!(),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
let mut isolate = self.isolate.lock().unwrap();
|
||||||
Err(err) => Err(JSErrorOr::JSError(err)),
|
isolate
|
||||||
Ok(()) => Ok(Async::Ready(root_id)),
|
.mod_instantiate(root_id, &mut resolve_cb)
|
||||||
}
|
.map(|_| Async::Ready(root_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,6 +518,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::isolate::js_check;
|
use crate::isolate::js_check;
|
||||||
use crate::isolate::tests::*;
|
use crate::isolate::tests::*;
|
||||||
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
struct MockLoader {
|
struct MockLoader {
|
||||||
|
@ -607,9 +589,9 @@ mod tests {
|
||||||
|
|
||||||
impl Future for DelayedSourceCodeFuture {
|
impl Future for DelayedSourceCodeFuture {
|
||||||
type Item = SourceCodeInfo;
|
type Item = SourceCodeInfo;
|
||||||
type Error = MockError;
|
type Error = ErrBox;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, ErrBox> {
|
||||||
self.counter += 1;
|
self.counter += 1;
|
||||||
if self.url == "file:///never_ready.js"
|
if self.url == "file:///never_ready.js"
|
||||||
|| (self.url == "file:///slow.js" && self.counter < 2)
|
|| (self.url == "file:///slow.js" && self.counter < 2)
|
||||||
|
@ -621,20 +603,18 @@ mod tests {
|
||||||
code: src.0.to_owned(),
|
code: src.0.to_owned(),
|
||||||
module_name: src.1.to_owned(),
|
module_name: src.1.to_owned(),
|
||||||
})),
|
})),
|
||||||
None => Err(MockError::LoadErr),
|
None => Err(MockError::LoadErr.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Loader for MockLoader {
|
impl Loader for MockLoader {
|
||||||
type Error = MockError;
|
|
||||||
|
|
||||||
fn resolve(
|
fn resolve(
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
referrer: &str,
|
referrer: &str,
|
||||||
_is_root: bool,
|
_is_root: bool,
|
||||||
) -> Result<ModuleSpecifier, Self::Error> {
|
) -> Result<ModuleSpecifier, ErrBox> {
|
||||||
let referrer = if referrer == "." {
|
let referrer = if referrer == "." {
|
||||||
"file:///"
|
"file:///"
|
||||||
} else {
|
} else {
|
||||||
|
@ -646,20 +626,20 @@ mod tests {
|
||||||
let output_specifier =
|
let output_specifier =
|
||||||
match ModuleSpecifier::resolve_import(specifier, referrer) {
|
match ModuleSpecifier::resolve_import(specifier, referrer) {
|
||||||
Ok(specifier) => specifier,
|
Ok(specifier) => specifier,
|
||||||
Err(..) => return Err(MockError::ResolveErr),
|
Err(..) => return Err(MockError::ResolveErr.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if mock_source_code(&output_specifier.to_string()).is_some() {
|
if mock_source_code(&output_specifier.to_string()).is_some() {
|
||||||
Ok(output_specifier)
|
Ok(output_specifier)
|
||||||
} else {
|
} else {
|
||||||
Err(MockError::ResolveErr)
|
Err(MockError::ResolveErr.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(
|
fn load(
|
||||||
&self,
|
&self,
|
||||||
module_specifier: &ModuleSpecifier,
|
module_specifier: &ModuleSpecifier,
|
||||||
) -> Box<SourceCodeInfoFuture<Self::Error>> {
|
) -> Box<SourceCodeInfoFuture> {
|
||||||
let mut loads = self.loads.lock().unwrap();
|
let mut loads = self.loads.lock().unwrap();
|
||||||
loads.push(module_specifier.to_string());
|
loads.push(module_specifier.to_string());
|
||||||
let url = module_specifier.to_string();
|
let url = module_specifier.to_string();
|
||||||
|
@ -962,8 +942,11 @@ mod tests {
|
||||||
RecursiveLoad::new("/bad_import.js", loader, isolate, modules);
|
RecursiveLoad::new("/bad_import.js", loader, isolate, modules);
|
||||||
let result = recursive_load.poll();
|
let result = recursive_load.poll();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
let either_err = result.err().unwrap();
|
let err = result.err().unwrap();
|
||||||
assert_eq!(either_err, JSErrorOr::Other(MockError::ResolveErr));
|
assert_eq!(
|
||||||
|
err.downcast_ref::<MockError>().unwrap(),
|
||||||
|
&MockError::ResolveErr
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue