From 3689e310f31ea2cd90c34ec5a8c1059bb85d3579 Mon Sep 17 00:00:00 2001 From: futurist <26634873@qq.com> Date: Tue, 26 May 2020 00:56:17 +0800 Subject: [PATCH] feat(cli): allow import maps from url --- cli/import_map.rs | 67 ++++++++++++++++++++++++++++++++--------------- cli/main.rs | 35 ++++++++++++++----------- cli/state.rs | 8 +++--- cli/tsc.rs | 8 +++--- cli/worker.rs | 19 +++++++++++--- 5 files changed, 90 insertions(+), 47 deletions(-) diff --git a/cli/import_map.rs b/cli/import_map.rs index 51c03a4e12d803..f776ccc91f08f8 100644 --- a/cli/import_map.rs +++ b/cli/import_map.rs @@ -1,3 +1,4 @@ +use crate::global_state::GlobalState; use deno_core::ErrBox; use deno_core::ModuleSpecifier; use indexmap::IndexMap; @@ -46,26 +47,46 @@ pub struct ImportMap { } impl ImportMap { - pub fn load(file_path: &str) -> Result { - let file_url = ModuleSpecifier::resolve_url_or_path(file_path)?.to_string(); - let resolved_path = std::env::current_dir().unwrap().join(file_path); - debug!( - "Attempt to load import map: {}", - resolved_path.to_str().unwrap() - ); - - // Load the contents of import map - let json_string = fs::read_to_string(&resolved_path).map_err(|err| { - io::Error::new( - io::ErrorKind::InvalidInput, - format!( - "Error retrieving import map file at \"{}\": {}", - resolved_path.to_str().unwrap(), - err.to_string() - ) - .as_str(), - ) - })?; + pub async fn load( + file_path: &str, + state: &GlobalState, + ) -> Result { + let specifier = ModuleSpecifier::resolve_url_or_path(file_path)?; + let file_url = specifier.to_string(); + + // the json_string can from a url or a file + let json_string = + if SUPPORTED_FETCH_SCHEMES[..2].contains(&specifier.as_url().scheme()) { + // for url: only support http / https schema + debug!( + "Attempt to load import map from url: {}", + &specifier.as_url().as_str() + ); + let map_file = state + .file_fetcher + .fetch_source_file(&specifier, None, state.permissions.clone()) + .await?; + String::from_utf8(map_file.source_code)? + } else { + let resolved_path = std::env::current_dir().unwrap().join(file_path); + debug!( + "Attempt to load import map: {}", + resolved_path.to_str().unwrap() + ); + + // Load the contents of import map + fs::read_to_string(&resolved_path).map_err(|err| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!( + "Error retrieving import map file at \"{}\": {}", + resolved_path.to_str().unwrap(), + err.to_string() + ) + .as_str(), + ) + })? + }; // The URL of the import map is the base URL for its values. ImportMap::from_json(&file_url, &json_string).map_err(ErrBox::from) } @@ -475,7 +496,11 @@ mod tests { #[test] fn load_nonexistent() { let file_path = "nonexistent_import_map.json"; - assert!(ImportMap::load(file_path).is_err()); + assert!(futures::executor::block_on(ImportMap::load( + file_path, + &GlobalState::new(crate::flags::Flags::default()).unwrap() + )) + .is_err()); } #[test] diff --git a/cli/main.rs b/cli/main.rs index 68ba5e7763c5c3..2574aa73d9e87a 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -139,11 +139,11 @@ fn write_to_stdout_ignore_sigpipe(bytes: &[u8]) -> Result<(), std::io::Error> { } } -fn create_main_worker( +async fn create_main_worker( global_state: GlobalState, main_module: ModuleSpecifier, ) -> Result { - let state = State::new(global_state, None, main_module, false)?; + let state = State::new(global_state, None, main_module, false).await?; let mut worker = MainWorker::new( "main".to_string(), @@ -294,7 +294,8 @@ async fn info_command( } let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())?; - let mut worker = create_main_worker(global_state, main_module.clone())?; + let mut worker = + create_main_worker(global_state, main_module.clone()).await?; worker.preload_module(&main_module).await?; print_file_info(&worker, main_module.clone()).await } @@ -312,7 +313,8 @@ async fn install_command( fetch_flags.reload = true; let global_state = GlobalState::new(fetch_flags)?; let main_module = ModuleSpecifier::resolve_url_or_path(&module_url)?; - let mut worker = create_main_worker(global_state, main_module.clone())?; + let mut worker = + create_main_worker(global_state, main_module.clone()).await?; worker.preload_module(&main_module).await?; installer::install(flags, &module_url, args, name, root, force) .map_err(ErrBox::from) @@ -323,7 +325,7 @@ async fn cache_command(flags: Flags, files: Vec) -> Result<(), ErrBox> { ModuleSpecifier::resolve_url_or_path("./__$deno$fetch.ts").unwrap(); let global_state = GlobalState::new(flags)?; let mut worker = - create_main_worker(global_state.clone(), main_module.clone())?; + create_main_worker(global_state.clone(), main_module.clone()).await?; for file in files { let specifier = ModuleSpecifier::resolve_url_or_path(&file)?; @@ -352,7 +354,8 @@ async fn eval_command( let main_module = ModuleSpecifier::resolve_url_or_path("./__$deno$eval.ts").unwrap(); let global_state = GlobalState::new(flags)?; - let mut worker = create_main_worker(global_state, main_module.clone())?; + let mut worker = + create_main_worker(global_state, main_module.clone()).await?; let main_module_url = main_module.as_url().to_owned(); // Create a dummy source file. let source_file = SourceFile { @@ -401,25 +404,27 @@ async fn bundle_command( debug!(">>>>> bundle START"); let compiler_config = tsc::CompilerConfig::load(flags.config_path.clone())?; - let maybe_import_map = match flags.import_map_path.as_ref() { + // save unstable flag to prevent flags borrow + let unstable_flag = flags.unstable; + let global_state = GlobalState::new(flags)?; + + let maybe_import_map = match global_state.flags.import_map_path.as_ref() { None => None, Some(file_path) => { - if !flags.unstable { + if !unstable_flag { exit_unstable("--importmap") } - Some(ImportMap::load(file_path)?) + Some(ImportMap::load(file_path, &global_state).await?) } }; - let global_state = GlobalState::new(flags)?; - let bundle_result = tsc::bundle( &global_state, compiler_config, module_name, maybe_import_map, out_file, - global_state.flags.unstable, + unstable_flag, ) .await; @@ -501,7 +506,7 @@ async fn run_repl(flags: Flags) -> Result<(), ErrBox> { let main_module = ModuleSpecifier::resolve_url_or_path("./__$deno$repl.ts").unwrap(); let global_state = GlobalState::new(flags)?; - let mut worker = create_main_worker(global_state, main_module)?; + let mut worker = create_main_worker(global_state, main_module).await?; loop { (&mut *worker).await?; } @@ -511,7 +516,7 @@ async fn run_command(flags: Flags, script: String) -> Result<(), ErrBox> { let global_state = GlobalState::new(flags.clone())?; let main_module = ModuleSpecifier::resolve_url_or_path(&script).unwrap(); let mut worker = - create_main_worker(global_state.clone(), main_module.clone())?; + create_main_worker(global_state.clone(), main_module.clone()).await?; debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; @@ -558,7 +563,7 @@ async fn test_command( let main_module = ModuleSpecifier::resolve_url(&test_file_url.to_string()).unwrap(); let mut worker = - create_main_worker(global_state.clone(), main_module.clone())?; + create_main_worker(global_state.clone(), main_module.clone()).await?; // Create a dummy source file. let source_file = SourceFile { filename: test_file_url.to_file_path().unwrap(), diff --git a/cli/state.rs b/cli/state.rs index baac89216ff87c..5f0b37f4c2d612 100644 --- a/cli/state.rs +++ b/cli/state.rs @@ -375,7 +375,7 @@ impl ModuleLoader for State { impl State { /// If `shared_permission` is None then permissions from globa state are used. - pub fn new( + pub async fn new( global_state: GlobalState, shared_permissions: Option, main_module: ModuleSpecifier, @@ -388,7 +388,7 @@ impl State { if !global_state.flags.unstable { exit_unstable("--importmap") } - Some(ImportMap::load(file_path)?) + Some(ImportMap::load(file_path, &global_state).await?) } }; @@ -525,12 +525,12 @@ impl State { pub fn mock(main_module: &str) -> State { let module_specifier = ModuleSpecifier::resolve_url_or_path(main_module) .expect("Invalid entry module"); - State::new( + futures::executor::block_on(State::new( GlobalState::mock(vec!["deno".to_string()]), None, module_specifier, false, - ) + )) .unwrap() } } diff --git a/cli/tsc.rs b/cli/tsc.rs index 664721bc15135b..d04deafdc2425c 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -167,7 +167,7 @@ lazy_static! { /// Create a new worker with snapshot of TS compiler and setup compiler's /// runtime. -fn create_compiler_worker( +async fn create_compiler_worker( global_state: GlobalState, permissions: Permissions, ) -> CompilerWorker { @@ -177,6 +177,7 @@ fn create_compiler_worker( ModuleSpecifier::resolve_url_or_path("./__$deno$ts_compiler.ts").unwrap(); let worker_state = State::new(global_state.clone(), Some(permissions), entry_point, true) + .await .expect("Unable to create worker state"); // TODO(bartlomieju): this metric is never used anywhere @@ -451,7 +452,7 @@ impl TsCompiler { if !global_state.flags.unstable { exit_unstable("--importmap") } - Some(ImportMap::load(file_path)?) + Some(ImportMap::load(file_path, &global_state).await?) } }; let mut module_graph_loader = ModuleGraphLoader::new( @@ -820,7 +821,8 @@ async fn execute_in_same_thread( permissions: Permissions, req: Buf, ) -> Result { - let mut worker = create_compiler_worker(global_state.clone(), permissions); + let mut worker = + create_compiler_worker(global_state.clone(), permissions).await; let handle = worker.thread_safe_handle(); handle.post_message(req)?; diff --git a/cli/worker.rs b/cli/worker.rs index 66aa98e6021c9e..00e487c27cea68 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -305,8 +305,13 @@ mod tests { let module_specifier = ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap(); let global_state = GlobalState::new(flags::Flags::default()).unwrap(); - let state = - State::new(global_state, None, module_specifier.clone(), false).unwrap(); + let state = futures::executor::block_on(State::new( + global_state, + None, + module_specifier.clone(), + false, + )) + .unwrap(); let state_ = state.clone(); tokio_util::run_basic(async move { let mut worker = @@ -334,8 +339,13 @@ mod tests { let module_specifier = ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap(); let global_state = GlobalState::new(flags::Flags::default()).unwrap(); - let state = - State::new(global_state, None, module_specifier.clone(), false).unwrap(); + let state = futures::executor::block_on(State::new( + global_state, + None, + module_specifier.clone(), + false, + )) + .unwrap(); let state_ = state.clone(); tokio_util::run_basic(async move { let mut worker = @@ -374,6 +384,7 @@ mod tests { let global_state = GlobalState::new(flags).unwrap(); let state = State::new(global_state.clone(), None, module_specifier.clone(), false) + .await .unwrap(); let mut worker = MainWorker::new( "TEST".to_string(),