diff options
Diffstat (limited to 'src/deno_dir.rs')
-rw-r--r-- | src/deno_dir.rs | 160 |
1 files changed, 117 insertions, 43 deletions
diff --git a/src/deno_dir.rs b/src/deno_dir.rs index 72e75bf5b..b8573a018 100644 --- a/src/deno_dir.rs +++ b/src/deno_dir.rs @@ -1,6 +1,8 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. use errors::DenoError; +use errors::DenoResult; use fs; +use net; use sha1; use std; use std::fs::File; @@ -25,12 +27,17 @@ pub struct DenoDir { // This is where we cache compilation outputs. Example: // /Users/rld/.deno/gen/f39a473452321cacd7c346a870efb0e3e1264b43.js pub deps: PathBuf, + // If remote resources should be reloaded. + reload: bool, } impl DenoDir { // Must be called before using any function from this module. // https://github.com/denoland/deno/blob/golang/deno_dir.go#L99-L111 - pub fn new(custom_root: Option<&Path>) -> std::io::Result<DenoDir> { + pub fn new( + reload: bool, + custom_root: Option<&Path>, + ) -> std::io::Result<DenoDir> { // Only setup once. let home_dir = std::env::home_dir().expect("Could not get home directory."); let default = home_dir.join(".deno"); @@ -42,7 +49,12 @@ impl DenoDir { let gen = root.as_path().join("gen"); let deps = root.as_path().join("deps"); - let deno_dir = DenoDir { root, gen, deps }; + let deno_dir = DenoDir { + root, + gen, + deps, + reload, + }; fs::mkdir(deno_dir.gen.as_ref())?; fs::mkdir(deno_dir.deps.as_ref())?; @@ -93,6 +105,50 @@ impl DenoDir { } } + // Prototype https://github.com/denoland/deno/blob/golang/deno_dir.go#L37-L73 + fn fetch_remote_source( + self: &DenoDir, + module_name: &str, + filename: &str, + ) -> DenoResult<String> { + let p = Path::new(filename); + + let src = if self.reload || !p.exists() { + println!("Downloading {}", module_name); + let source = net::fetch_sync_string(module_name)?; + match p.parent() { + Some(ref parent) => std::fs::create_dir_all(parent), + None => Ok(()), + }?; + fs::write_file_sync(&p, source.as_bytes())?; + source + } else { + let source = fs::read_file_sync_string(&p)?; + source + }; + Ok(src) + } + + // Prototype: https://github.com/denoland/deno/blob/golang/os.go#L122-L138 + fn get_source_code( + self: &DenoDir, + module_name: &str, + filename: &str, + ) -> DenoResult<String> { + if is_remote(module_name) { + self.fetch_remote_source(module_name, filename) + } else if module_name.starts_with(ASSET_PREFIX) { + panic!("Asset resolution should be done in JS, not Rust."); + } else { + assert!( + module_name == filename, + "if a module isn't remote, it should have the same filename" + ); + let src = fs::read_file_sync_string(Path::new(filename))?; + Ok(src) + } + } + pub fn code_fetch( self: &DenoDir, module_specifier: &str, @@ -106,7 +162,8 @@ impl DenoDir { module_name, module_specifier, containing_file, filename ); - let out = get_source_code(module_name.as_str(), filename.as_str()) + let out = self + .get_source_code(module_name.as_str(), filename.as_str()) .and_then(|source_code| { Ok(CodeFetchOutput { module_name, @@ -154,6 +211,9 @@ impl DenoDir { module_specifier: &str, containing_file: &str, ) -> Result<(String, String), url::ParseError> { + let module_name; + let filename; + debug!( "resolve_module before module_specifier {} containing_file {}", module_specifier, containing_file @@ -165,12 +225,11 @@ impl DenoDir { let j: Url = if containing_file == "." || Path::new(module_specifier).is_absolute() { - let r = Url::from_file_path(module_specifier); - // TODO(ry) Properly handle error. - if r.is_err() { - error!("Url::from_file_path error {}", module_specifier); + if module_specifier.starts_with("http://") { + Url::parse(module_specifier)? + } else { + Url::from_file_path(module_specifier).unwrap() } - r.unwrap() } else if containing_file.ends_with("/") { let r = Url::from_directory_path(&containing_file); // TODO(ry) Properly handle error. @@ -189,27 +248,59 @@ impl DenoDir { base.join(module_specifier)? }; - let mut p = j - .to_file_path() - .unwrap() - .into_os_string() - .into_string() - .unwrap(); + match j.scheme() { + "file" => { + let mut p = j + .to_file_path() + .unwrap() + .into_os_string() + .into_string() + .unwrap(); + + if cfg!(target_os = "windows") { + // On windows, replace backward slashes to forward slashes. + // TODO(piscisaureus): This may not me be right, I just did it to make + // the tests pass. + p = p.replace("\\", "/"); + } - if cfg!(target_os = "windows") { - // On windows, replace backward slashes to forward slashes. - // TODO(piscisaureus): This may not me be right, I just did it to make - // the tests pass. - p = p.replace("\\", "/"); + module_name = p.to_string(); + filename = p.to_string(); + } + _ => { + module_name = module_specifier.to_string(); + filename = get_cache_filename(self.deps.as_path(), j) + .to_str() + .unwrap() + .to_string(); + } } - let module_name = p.to_string(); - let filename = p.to_string(); - + debug!("module_name: {}, filename: {}", module_name, filename); Ok((module_name, filename)) } } +fn get_cache_filename(basedir: &Path, url: Url) -> PathBuf { + let mut out = basedir.to_path_buf(); + out.push(url.host_str().unwrap()); + for path_seg in url.path_segments().unwrap() { + out.push(path_seg); + } + out +} + +#[test] +fn test_get_cache_filename() { + let url = Url::parse("http://example.com:1234/path/to/file.ts").unwrap(); + let basedir = Path::new("/cache/dir/"); + let cache_file = get_cache_filename(&basedir, url); + assert_eq!( + cache_file, + Path::new("/cache/dir/example.com/path/to/file.ts") + ); +} + #[derive(Debug)] pub struct CodeFetchOutput { pub module_name: String, @@ -221,7 +312,8 @@ pub struct CodeFetchOutput { #[cfg(test)] pub fn test_setup() -> (TempDir, DenoDir) { let temp_dir = TempDir::new().expect("tempdir fail"); - let deno_dir = DenoDir::new(Some(temp_dir.path())).expect("setup fail"); + let deno_dir = + DenoDir::new(false, Some(temp_dir.path())).expect("setup fail"); (temp_dir, deno_dir) } @@ -395,24 +487,6 @@ fn test_resolve_module() { const ASSET_PREFIX: &str = "/$asset$/"; -fn is_remote(_module_name: &str) -> bool { - false -} - -fn get_source_code( - module_name: &str, - filename: &str, -) -> std::io::Result<String> { - if is_remote(module_name) { - unimplemented!(); - } else if module_name.starts_with(ASSET_PREFIX) { - assert!(false, "Asset resolution should be done in JS, not Rust."); - unimplemented!(); - } else { - assert!( - module_name == filename, - "if a module isn't remote, it should have the same filename" - ); - fs::read_file_sync_string(Path::new(filename)) - } +fn is_remote(module_name: &str) -> bool { + module_name.starts_with("http") } |