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

refactor(cli): refactor file_fetcher (#8245)

This commit is contained in:
Kitson Kelly 2020-11-06 11:38:21 +11:00 committed by GitHub
parent 1112be7dc0
commit 96e03e0b93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 1195 additions and 1736 deletions

File diff suppressed because it is too large Load diff

View file

@ -56,8 +56,8 @@ mod worker;
use crate::coverage::CoverageCollector; use crate::coverage::CoverageCollector;
use crate::coverage::PrettyCoverageReporter; use crate::coverage::PrettyCoverageReporter;
use crate::file_fetcher::SourceFile; use crate::file_fetcher::File;
use crate::file_fetcher::SourceFileFetcher; use crate::file_fetcher::FileFetcher;
use crate::fs as deno_fs; use crate::fs as deno_fs;
use crate::media_type::MediaType; use crate::media_type::MediaType;
use crate::permissions::Permissions; use crate::permissions::Permissions;
@ -117,7 +117,7 @@ fn print_cache_info(
json: bool, json: bool,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let deno_dir = &state.dir.root; let deno_dir = &state.dir.root;
let modules_cache = &state.file_fetcher.http_cache.location; let modules_cache = &state.file_fetcher.get_http_cache_location();
let typescript_cache = &state.dir.gen_cache.location; let typescript_cache = &state.dir.gen_cache.location;
if json { if json {
let output = json!({ let output = json!({
@ -286,22 +286,21 @@ async fn eval_command(
} }
.into_bytes(); .into_bytes();
let source_file = SourceFile { let file = File {
filename: main_module_url.to_file_path().unwrap(), local: main_module_url.to_file_path().unwrap(),
url: main_module_url, maybe_types: None,
types_header: None,
media_type: if as_typescript { media_type: if as_typescript {
MediaType::TypeScript MediaType::TypeScript
} else { } else {
MediaType::JavaScript MediaType::JavaScript
}, },
source_code: String::from_utf8(source_code)?, source: String::from_utf8(source_code)?,
specifier: ModuleSpecifier::from(main_module_url),
}; };
// Save our fake file into file fetcher cache // Save our fake file into file fetcher cache
// to allow module access by TS compiler. // to allow module access by TS compiler.
program_state program_state.file_fetcher.insert_cached(file);
.file_fetcher
.save_source_file_in_cache(&main_module, source_file);
debug!("main_module {}", &main_module); debug!("main_module {}", &main_module);
worker.execute_module(&main_module).await?; worker.execute_module(&main_module).await?;
worker.execute("window.dispatchEvent(new Event('load'))")?; worker.execute("window.dispatchEvent(new Event('load'))")?;
@ -397,7 +396,7 @@ async fn bundle_command(
} }
struct DocLoader { struct DocLoader {
fetcher: SourceFileFetcher, fetcher: FileFetcher,
maybe_import_map: Option<ImportMap>, maybe_import_map: Option<ImportMap>,
} }
@ -435,7 +434,7 @@ impl DocFileLoader for DocLoader {
.expect("Expected valid specifier"); .expect("Expected valid specifier");
async move { async move {
let source_file = fetcher let source_file = fetcher
.fetch_source_file(&specifier, None, Permissions::allow_all()) .fetch(&specifier, &Permissions::allow_all())
.await .await
.map_err(|e| { .map_err(|e| {
doc::DocError::Io(std::io::Error::new( doc::DocError::Io(std::io::Error::new(
@ -443,7 +442,7 @@ impl DocFileLoader for DocLoader {
e.to_string(), e.to_string(),
)) ))
})?; })?;
Ok(source_file.source_code) Ok(source_file.source)
} }
.boxed_local() .boxed_local()
} }
@ -541,18 +540,16 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> {
std::io::stdin().read_to_end(&mut source)?; std::io::stdin().read_to_end(&mut source)?;
let main_module_url = main_module.as_url().to_owned(); let main_module_url = main_module.as_url().to_owned();
// Create a dummy source file. // Create a dummy source file.
let source_file = SourceFile { let source_file = File {
filename: main_module_url.to_file_path().unwrap(), local: main_module_url.to_file_path().unwrap(),
url: main_module_url, maybe_types: None,
types_header: None,
media_type: MediaType::TypeScript, media_type: MediaType::TypeScript,
source_code: String::from_utf8(source)?, source: String::from_utf8(source)?,
specifier: main_module.clone(),
}; };
// Save our fake file into file fetcher cache // Save our fake file into file fetcher cache
// to allow module access by TS compiler // to allow module access by TS compiler
program_state program_state.file_fetcher.insert_cached(source_file);
.file_fetcher
.save_source_file_in_cache(&main_module, source_file);
debug!("main_module {}", main_module); debug!("main_module {}", main_module);
worker.execute_module(&main_module).await?; worker.execute_module(&main_module).await?;
@ -671,18 +668,16 @@ async fn test_command(
let mut worker = let mut worker =
MainWorker::new(&program_state, main_module.clone(), permissions); MainWorker::new(&program_state, main_module.clone(), permissions);
// Create a dummy source file. // Create a dummy source file.
let source_file = SourceFile { let source_file = File {
filename: test_file_url.to_file_path().unwrap(), local: test_file_url.to_file_path().unwrap(),
url: test_file_url.clone(), maybe_types: None,
types_header: None,
media_type: MediaType::TypeScript, media_type: MediaType::TypeScript,
source_code: test_file.clone(), source: test_file.clone(),
specifier: ModuleSpecifier::from(test_file_url.clone()),
}; };
// Save our fake file into file fetcher cache // Save our fake file into file fetcher cache
// to allow module access by TS compiler // to allow module access by TS compiler
program_state program_state.file_fetcher.insert_cached(source_file);
.file_fetcher
.save_source_file_in_cache(&main_module, source_file);
let mut maybe_coverage_collector = if flags.coverage { let mut maybe_coverage_collector = if flags.coverage {
let session = worker.create_inspector_session(); let session = worker.create_inspector_session();

View file

@ -236,6 +236,23 @@ mod tests {
assert_eq!(MediaType::from(Path::new("foo/bar")), MediaType::Unknown); assert_eq!(MediaType::from(Path::new("foo/bar")), MediaType::Unknown);
} }
#[test]
fn test_from_specifier() {
let fixtures = vec![
("file:///a/b/c.ts", MediaType::TypeScript),
("file:///a/b/c.js", MediaType::JavaScript),
("file:///a/b/c.txt", MediaType::Unknown),
("https://deno.land/x/mod.ts", MediaType::TypeScript),
("https://deno.land/x/mod.js", MediaType::JavaScript),
("https://deno.land/x/mod.txt", MediaType::Unknown),
];
for (specifier, expected) in fixtures {
let actual = ModuleSpecifier::resolve_url_or_path(specifier).unwrap();
assert_eq!(MediaType::from(&actual), expected);
}
}
#[test] #[test]
fn test_serialization() { fn test_serialization() {
assert_eq!(json!(MediaType::JavaScript), json!(0)); assert_eq!(json!(MediaType::JavaScript), json!(0));

View file

@ -1,7 +1,8 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::deno_dir; use crate::deno_dir;
use crate::file_fetcher::SourceFileFetcher; use crate::file_fetcher::CacheSetting;
use crate::file_fetcher::FileFetcher;
use crate::flags; use crate::flags;
use crate::http_cache; use crate::http_cache;
use crate::import_map::ImportMap; use crate::import_map::ImportMap;
@ -47,7 +48,7 @@ pub struct ProgramState {
/// Flags parsed from `argv` contents. /// Flags parsed from `argv` contents.
pub flags: flags::Flags, pub flags: flags::Flags,
pub dir: deno_dir::DenoDir, pub dir: deno_dir::DenoDir,
pub file_fetcher: SourceFileFetcher, pub file_fetcher: FileFetcher,
pub lockfile: Option<Arc<Mutex<Lockfile>>>, pub lockfile: Option<Arc<Mutex<Lockfile>>>,
pub maybe_import_map: Option<ImportMap>, pub maybe_import_map: Option<ImportMap>,
pub maybe_inspector_server: Option<Arc<InspectorServer>>, pub maybe_inspector_server: Option<Arc<InspectorServer>>,
@ -61,12 +62,20 @@ impl ProgramState {
let http_cache = http_cache::HttpCache::new(&deps_cache_location); let http_cache = http_cache::HttpCache::new(&deps_cache_location);
let ca_file = flags.ca_file.clone().or_else(|| env::var("DENO_CERT").ok()); let ca_file = flags.ca_file.clone().or_else(|| env::var("DENO_CERT").ok());
let file_fetcher = SourceFileFetcher::new( let cache_usage = if flags.cached_only {
CacheSetting::Only
} else if !flags.cache_blocklist.is_empty() {
CacheSetting::ReloadSome(flags.cache_blocklist.clone())
} else if flags.reload {
CacheSetting::ReloadAll
} else {
CacheSetting::Use
};
let file_fetcher = FileFetcher::new(
http_cache, http_cache,
!flags.reload, cache_usage,
flags.cache_blocklist.clone(), !flags.no_remote,
flags.no_remote,
flags.cached_only,
ca_file.as_deref(), ca_file.as_deref(),
)?; )?;
@ -175,16 +184,20 @@ impl ProgramState {
module_specifier: ModuleSpecifier, module_specifier: ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>, maybe_referrer: Option<ModuleSpecifier>,
) -> Result<CompiledModule, AnyError> { ) -> Result<CompiledModule, AnyError> {
// TODO(@kitsonk) this really needs to be avoided and refactored out, as we
// really should just be getting this from the module graph.
let out = self let out = self
.file_fetcher .file_fetcher
.fetch_cached_source_file(&module_specifier, Permissions::allow_all()) .get_cached(&module_specifier)
.expect("Cached source file doesn't exist"); .expect("Cached source file doesn't exist");
let url = out.url.clone(); let specifier = out.specifier.clone();
let compiled_module = if let Some((code, _)) = self.get_emit(&url) { let compiled_module = if let Some((code, _)) =
self.get_emit(&specifier.as_url())
{
CompiledModule { CompiledModule {
code: String::from_utf8(code).unwrap(), code: String::from_utf8(code).unwrap(),
name: out.url.to_string(), name: specifier.as_url().to_string(),
} }
// We expect a compiled source for any non-JavaScript files, except for // We expect a compiled source for any non-JavaScript files, except for
// local files that have an unknown media type and no referrer (root modules // local files that have an unknown media type and no referrer (root modules
@ -192,7 +205,7 @@ impl ProgramState {
} else if out.media_type != MediaType::JavaScript } else if out.media_type != MediaType::JavaScript
&& !(out.media_type == MediaType::Unknown && !(out.media_type == MediaType::Unknown
&& maybe_referrer.is_none() && maybe_referrer.is_none()
&& url.scheme() == "file") && specifier.as_url().scheme() == "file")
{ {
let message = if let Some(referrer) = maybe_referrer { let message = if let Some(referrer) = maybe_referrer {
format!("Compiled module not found \"{}\"\n From: {}\n If the source module contains only types, use `import type` and `export type` to import it instead.", module_specifier, referrer) format!("Compiled module not found \"{}\"\n From: {}\n If the source module contains only types, use `import type` and `export type` to import it instead.", module_specifier, referrer)
@ -202,12 +215,12 @@ impl ProgramState {
info!("{}: {}", crate::colors::yellow("warning"), message); info!("{}: {}", crate::colors::yellow("warning"), message);
CompiledModule { CompiledModule {
code: "".to_string(), code: "".to_string(),
name: out.url.to_string(), name: specifier.as_url().to_string(),
} }
} else { } else {
CompiledModule { CompiledModule {
code: out.source_code, code: out.source,
name: out.url.to_string(), name: specifier.as_url().to_string(),
} }
}; };
@ -310,16 +323,13 @@ impl SourceMapGetter for ProgramState {
line_number: usize, line_number: usize,
) -> Option<String> { ) -> Option<String> {
if let Ok(specifier) = ModuleSpecifier::resolve_url(file_name) { if let Ok(specifier) = ModuleSpecifier::resolve_url(file_name) {
self self.file_fetcher.get_cached(&specifier).map(|out| {
.file_fetcher // Do NOT use .lines(): it skips the terminating empty line.
.fetch_cached_source_file(&specifier, Permissions::allow_all()) // (due to internally using .split_terminator() instead of .split())
.map(|out| { let lines: Vec<&str> = out.source.split('\n').collect();
// Do NOT use .lines(): it skips the terminating empty line. assert!(lines.len() > line_number);
// (due to internally using .split_terminator() instead of .split()) lines[line_number].to_string()
let lines: Vec<&str> = out.source_code.split('\n').collect(); })
assert!(lines.len() > line_number);
lines[line_number].to_string()
})
} else { } else {
None None
} }

View file

@ -3,7 +3,7 @@
use crate::ast::Location; use crate::ast::Location;
use crate::deno_dir::DenoDir; use crate::deno_dir::DenoDir;
use crate::disk_cache::DiskCache; use crate::disk_cache::DiskCache;
use crate::file_fetcher::SourceFileFetcher; use crate::file_fetcher::FileFetcher;
use crate::media_type::MediaType; use crate::media_type::MediaType;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::program_state::ProgramState; use crate::program_state::ProgramState;
@ -220,7 +220,7 @@ pub struct FetchHandler {
/// dynamic imports. /// dynamic imports.
runtime_permissions: Permissions, runtime_permissions: Permissions,
/// A clone of the `program_state` file fetcher. /// A clone of the `program_state` file fetcher.
file_fetcher: SourceFileFetcher, file_fetcher: FileFetcher,
} }
impl FetchHandler { impl FetchHandler {
@ -258,20 +258,35 @@ impl SpecifierHandler for FetchHandler {
}; };
let file_fetcher = self.file_fetcher.clone(); let file_fetcher = self.file_fetcher.clone();
let disk_cache = self.disk_cache.clone(); let disk_cache = self.disk_cache.clone();
let maybe_referrer: Option<ModuleSpecifier> =
if let Some(location) = &maybe_location {
Some(location.clone().into())
} else {
None
};
async move { async move {
let source_file = file_fetcher let source_file = file_fetcher
.fetch_source_file(&requested_specifier, maybe_referrer, permissions) .fetch(&requested_specifier, &permissions)
.await .await
.map_err(|err| { .map_err(|err| {
let err = if let Some(e) = err.downcast_ref::<std::io::Error>() {
if e.kind() == std::io::ErrorKind::NotFound {
let message = if let Some(location) = &maybe_location {
format!(
"Cannot resolve module \"{}\" from \"{}\".",
requested_specifier, location.filename
)
} else {
format!("Cannot resolve module \"{}\".", requested_specifier)
};
custom_error("NotFound", message)
} else {
err
}
} else {
err
};
if let Some(location) = maybe_location { if let Some(location) = maybe_location {
if !is_dynamic { // Injected modules (like test and eval) come with locations, but
// they are confusing to the user to print out the location because
// they cannot actually get to the source code that is quoted, as
// it only exists in the runtime memory of Deno.
if !location.filename.contains("$deno$") {
HandlerError::FetchErrorWithLocation(err.to_string(), location) HandlerError::FetchErrorWithLocation(err.to_string(), location)
.into() .into()
} else { } else {
@ -281,9 +296,9 @@ impl SpecifierHandler for FetchHandler {
err err
} }
})?; })?;
let url = source_file.url.clone(); let url = source_file.specifier.as_url();
let is_remote = url.scheme() != "file"; let is_remote = url.scheme() != "file";
let filename = disk_cache.get_cache_filename_with_extension(&url, "meta"); let filename = disk_cache.get_cache_filename_with_extension(url, "meta");
let maybe_version = if let Ok(bytes) = disk_cache.get(&filename) { let maybe_version = if let Ok(bytes) = disk_cache.get(&filename) {
if let Ok(compiled_file_metadata) = if let Ok(compiled_file_metadata) =
CompiledFileMetadata::from_bytes(&bytes) CompiledFileMetadata::from_bytes(&bytes)
@ -313,20 +328,19 @@ impl SpecifierHandler for FetchHandler {
maybe_emit_path = maybe_emit_path =
Some((disk_cache.location.join(emit_path), maybe_map_path)); Some((disk_cache.location.join(emit_path), maybe_map_path));
}; };
let specifier = ModuleSpecifier::from(url);
Ok(CachedModule { Ok(CachedModule {
is_remote, is_remote,
maybe_dependencies: None, maybe_dependencies: None,
maybe_emit, maybe_emit,
maybe_emit_path, maybe_emit_path,
maybe_types: source_file.types_header, maybe_types: source_file.maybe_types,
maybe_version, maybe_version,
media_type: source_file.media_type, media_type: source_file.media_type,
requested_specifier, requested_specifier,
source: source_file.source_code, source: source_file.source,
source_path: source_file.filename, source_path: source_file.local,
specifier, specifier: source_file.specifier,
}) })
} }
.boxed_local() .boxed_local()
@ -521,6 +535,7 @@ impl SpecifierHandler for MemoryHandler {
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use super::*; use super::*;
use crate::file_fetcher::CacheSetting;
use crate::http_cache::HttpCache; use crate::http_cache::HttpCache;
use tempfile::TempDir; use tempfile::TempDir;
@ -541,12 +556,10 @@ pub mod tests {
let deno_dir = DenoDir::new(Some(temp_dir.path().to_path_buf())) let deno_dir = DenoDir::new(Some(temp_dir.path().to_path_buf()))
.expect("could not setup"); .expect("could not setup");
let file_fetcher = SourceFileFetcher::new( let file_fetcher = FileFetcher::new(
HttpCache::new(&temp_dir.path().to_path_buf().join("deps")), HttpCache::new(&temp_dir.path().to_path_buf().join("deps")),
CacheSetting::Use,
true, true,
Vec::new(),
false,
false,
None, None,
) )
.expect("could not setup"); .expect("could not setup");

View file

@ -1 +1 @@
error: Cannot find module "http://127.0.0.1:4545/cli/tests/019_media_types.ts" in cache, --cached-only is specified error: Specifier not found in cache: "http://127.0.0.1:4545/cli/tests/019_media_types.ts", --cached-only is specified.

View file

@ -1 +1 @@
error: Cannot resolve module "http://127.0.0.1:4545/cli/tests/019_media_types.ts" error: A remote specifier was requested: "http://127.0.0.1:4545/cli/tests/019_media_types.ts", but --no-remote is specified.

View file

@ -1,2 +1,2 @@
[WILDCARD]error: Cannot resolve module "file:///[WILDCARD]cli/tests/bad-module.ts" from "file:///[WILDCARD]cli/tests/error_004_missing_module.ts" [WILDCARD]error: Cannot resolve module "file:///[WILDCARD]cli/tests/bad-module.ts" from "file:///[WILDCARD]cli/tests/error_004_missing_module.ts".
at file:///[WILDCARD]cli/tests/error_004_missing_module.ts:2:0 at file:///[WILDCARD]cli/tests/error_004_missing_module.ts:2:0

View file

@ -1 +1,2 @@
error: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]/error_005_missing_dynamic_import.ts" error: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]/error_005_missing_dynamic_import.ts".
at file:///[WILDCARD]/error_005_missing_dynamic_import.ts:3:26

View file

@ -1,2 +1,2 @@
[WILDCARD]error: Cannot resolve module "[WILDCARD]/non-existent" from "[WILDCARD]/error_006_import_ext_failure.ts" [WILDCARD]error: Cannot resolve module "[WILDCARD]/non-existent" from "[WILDCARD]/error_006_import_ext_failure.ts".
at file:///[WILDCARD]cli/tests/error_006_import_ext_failure.ts:1:0 at file:///[WILDCARD]cli/tests/error_006_import_ext_failure.ts:1:0

View file

@ -1 +1 @@
error: Cannot resolve module "[WILDCARD]missing_file_name" error: Cannot resolve module "[WILDCARD]missing_file_name".

View file

@ -1 +1,2 @@
error: network access to "http://localhost:4545/cli/tests/subdir/mod4.js", run again with the --allow-net flag error: network access to "http://localhost:4545/cli/tests/subdir/mod4.js", run again with the --allow-net flag
at file:///[WILDCARD]cli/tests/error_015_dynamic_import_permissions.js:[WILDCARD]

View file

@ -1,3 +1,3 @@
[WILDCARD] [WILDCARD]
DEBUG RS - [WILDCARD] - fetch_source_file specifier: file:[WILDCARD]cli/tests/subdir/type_reference.d.ts [WILDCARD] DEBUG RS - [WILDCARD] - FileFetcher::fetch() - specifier: file:///[WILDCARD]cli/tests/subdir/type_reference.d.ts
[WILDCARD] [WILDCARD]