diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2018-07-26 17:54:22 -0400 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2018-07-29 00:22:39 -0400 |
commit | 4d386e9e1c79d557cae6af58e6df85eb470c1e0c (patch) | |
tree | 2a5bda6620b2d68ea5f06e4c49c9b9a3ad4c76f2 /src | |
parent | 1f093c12f84d269cb68370262d68ff6d515aef2e (diff) |
Implement CodeCache
Diffstat (limited to 'src')
-rw-r--r-- | src/deno_dir.rs | 402 | ||||
-rw-r--r-- | src/fs.rs | 25 | ||||
-rw-r--r-- | src/handlers.h | 2 | ||||
-rw-r--r-- | src/handlers.rs | 311 | ||||
-rw-r--r-- | src/main.rs | 18 | ||||
-rw-r--r-- | src/reply.cc | 9 |
6 files changed, 506 insertions, 261 deletions
diff --git a/src/deno_dir.rs b/src/deno_dir.rs new file mode 100644 index 000000000..ba25c1d8e --- /dev/null +++ b/src/deno_dir.rs @@ -0,0 +1,402 @@ +// Copyright 2018 the Deno authors. All rights reserved. MIT license. +use fs; +use sha1; +use std; +use std::error::Error; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use std::path::PathBuf; +use std::result::Result; +use url; +use url::Url; + +#[cfg(test)] +use tempfile::TempDir; + +pub struct DenoDir { + // Example: /Users/rld/.deno/ + pub root: PathBuf, + // In the Go code this was called SrcDir. + // This is where we cache http resources. Example: + // /Users/rld/.deno/deps/github.com/ry/blah.js + pub gen: PathBuf, + // In the Go code this was called CacheDir. + // This is where we cache compilation outputs. Example: + // /Users/rld/.deno/gen/f39a473452321cacd7c346a870efb0e3e1264b43.js + pub deps: PathBuf, +} + +impl DenoDir { + // Must be called before using any function from this module. + // https://github.com/ry/deno/blob/golang/deno_dir.go#L99-L111 + pub fn new(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"); + + let root: PathBuf = match custom_root { + None => default, + Some(path) => path.to_path_buf(), + }; + let gen = root.as_path().join("gen"); + let deps = root.as_path().join("deps"); + + let deno_dir = DenoDir { root, gen, deps }; + fs::mkdir(deno_dir.gen.as_ref())?; + fs::mkdir(deno_dir.deps.as_ref())?; + + debug!("root {}", deno_dir.root.display()); + debug!("gen {}", deno_dir.gen.display()); + debug!("deps {}", deno_dir.deps.display()); + + Ok(deno_dir) + } + + // https://github.com/ry/deno/blob/golang/deno_dir.go#L32-L35 + pub fn cache_path( + self: &DenoDir, + filename: &str, + source_code: &str, + ) -> PathBuf { + let cache_key = source_code_hash(filename, source_code); + self.gen.join(cache_key + ".js") + } + + fn load_cache( + self: &DenoDir, + filename: &str, + source_code: &str, + ) -> std::io::Result<String> { + let path = self.cache_path(filename, source_code); + debug!("load_cache {}", path.display()); + fs::read_file_sync(&path) + } + + pub fn code_cache( + self: &DenoDir, + filename: &str, + source_code: &str, + output_code: &str, + ) -> std::io::Result<()> { + let cache_path = self.cache_path(filename, source_code); + // TODO(ry) This is a race condition w.r.t to exists() -- probably should + // create the file in exclusive mode. A worry is what might happen is there + // are two processes and one reads the cache file while the other is in the + // midst of writing it. + if cache_path.exists() { + Ok(()) + } else { + let mut file = File::create(cache_path)?; + file.write_all(output_code.as_bytes())?; + Ok(()) + } + } + + pub fn code_fetch( + self: &DenoDir, + module_specifier: &str, + containing_file: &str, + ) -> Result<CodeFetchOutput, Box<Error>> { + let (module_name, filename) = + self.resolve_module(module_specifier, containing_file)?; + + debug!( + "code_fetch. module_name = {} module_specifier = {} containing_file = {} filename = {}", + module_name, module_specifier, containing_file, filename + ); + + let out = get_source_code(module_name.as_str(), filename.as_str()) + .and_then(|source_code| { + Ok(CodeFetchOutput { + module_name, + filename, + source_code, + maybe_output_code: None, + }) + })?; + + let result = + self.load_cache(out.filename.as_str(), out.source_code.as_str()); + match result { + Err(err) => { + if err.kind() == std::io::ErrorKind::NotFound { + Ok(out) + } else { + Err(err.into()) + } + } + Ok(output_code) => Ok(CodeFetchOutput { + module_name: out.module_name, + filename: out.filename, + source_code: out.source_code, + maybe_output_code: Some(output_code), + }), + } + } + + // Prototype: https://github.com/ry/deno/blob/golang/os.go#L56-L68 + #[allow(dead_code)] + fn src_file_to_url<P: AsRef<Path>>(self: &DenoDir, filename: P) -> String { + let filename = filename.as_ref().to_path_buf(); + if filename.starts_with(&self.deps) { + let rest = filename.strip_prefix(&self.deps).unwrap(); + "http://".to_string() + rest.to_str().unwrap() + } else { + String::from(filename.to_str().unwrap()) + } + } + + // Prototype: https://github.com/ry/deno/blob/golang/os.go#L70-L98 + // Returns (module name, local filename) + fn resolve_module( + self: &DenoDir, + module_specifier: &str, + containing_file: &str, + ) -> Result<(String, String), url::ParseError> { + debug!( + "resolve_module before module_specifier {} containing_file {}", + module_specifier, containing_file + ); + + //let module_specifier = src_file_to_url(module_specifier); + //let containing_file = src_file_to_url(containing_file); + //let base_url = Url::parse(&containing_file)?; + + let j: Url = + if containing_file == "." || Path::new(module_specifier).is_absolute() { + Url::from_file_path(module_specifier).unwrap() + } else if containing_file.ends_with("/") { + let base = Url::from_directory_path(&containing_file).unwrap(); + base.join(module_specifier)? + } else { + let base = Url::from_file_path(&containing_file).unwrap(); + base.join(module_specifier)? + }; + + 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("\\", "/"); + } + + let module_name = p.to_string(); + let filename = p.to_string(); + + Ok((module_name, filename)) + } +} + +#[derive(Debug)] +pub struct CodeFetchOutput { + pub module_name: String, + pub filename: String, + pub source_code: String, + pub maybe_output_code: Option<String>, +} + +#[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"); + (temp_dir, deno_dir) +} + +#[test] +fn test_cache_path() { + let (temp_dir, deno_dir) = test_setup(); + assert_eq!( + temp_dir + .path() + .join("gen/a3e29aece8d35a19bf9da2bb1c086af71fb36ed5.js"), + deno_dir.cache_path("hello.ts", "1+2") + ); +} + +#[test] +fn test_code_cache() { + let (_temp_dir, deno_dir) = test_setup(); + + let filename = "hello.js"; + let source_code = "1+2"; + let output_code = "1+2 // output code"; + let cache_path = deno_dir.cache_path(filename, source_code); + assert!( + cache_path.ends_with("gen/e8e3ee6bee4aef2ec63f6ec3db7fc5fdfae910ae.js") + ); + + let r = deno_dir.code_cache(filename, source_code, output_code); + r.expect("code_cache error"); + assert!(cache_path.exists()); + assert_eq!(output_code, fs::read_file_sync(&cache_path).unwrap()); +} + +// https://github.com/ry/deno/blob/golang/deno_dir.go#L25-L30 +fn source_code_hash(filename: &str, source_code: &str) -> String { + let mut m = sha1::Sha1::new(); + m.update(filename.as_bytes()); + m.update(source_code.as_bytes()); + m.digest().to_string() +} + +#[test] +fn test_source_code_hash() { + assert_eq!( + "a3e29aece8d35a19bf9da2bb1c086af71fb36ed5", + source_code_hash("hello.ts", "1+2") + ); + // Different source_code should result in different hash. + assert_eq!( + "914352911fc9c85170908ede3df1128d690dda41", + source_code_hash("hello.ts", "1") + ); + // Different filename should result in different hash. + assert_eq!( + "2e396bc66101ecc642db27507048376d972b1b70", + source_code_hash("hi.ts", "1+2") + ); +} + +// The `add_root` macro prepends "C:" to a string if on windows; on posix +// systems it returns the input string untouched. This is necessary because +// `Url::from_file_path()` fails if the input path isn't an absolute path. +#[cfg(test)] +macro_rules! add_root { + ($path:expr) => { + if cfg!(target_os = "windows") { + concat!("C:", $path) + } else { + $path + } + }; +} + +#[test] +fn test_code_fetch() { + let (_temp_dir, deno_dir) = test_setup(); + + let cwd = std::env::current_dir().unwrap(); + let cwd_string = String::from(cwd.to_str().unwrap()) + "/"; + + // Test failure case. + let module_specifier = "hello.ts"; + let containing_file = add_root!("/baddir/badfile.ts"); + let r = deno_dir.code_fetch(module_specifier, containing_file); + assert!(r.is_err()); + + // Assuming cwd is the deno repo root. + let module_specifier = "./js/main.ts"; + let containing_file = cwd_string.as_str(); + let r = deno_dir.code_fetch(module_specifier, containing_file); + assert!(r.is_ok()); + //let code_fetch_output = r.unwrap(); + //println!("code_fetch_output {:?}", code_fetch_output); +} + +#[test] +fn test_src_file_to_url() { + let (_temp_dir, deno_dir) = test_setup(); + assert_eq!("hello", deno_dir.src_file_to_url("hello")); + assert_eq!("/hello", deno_dir.src_file_to_url("/hello")); + let x = String::from(deno_dir.deps.join("hello/world.txt").to_str().unwrap()); + assert_eq!("http://hello/world.txt", deno_dir.src_file_to_url(x)); +} + +// https://github.com/ry/deno/blob/golang/os_test.go#L16-L87 +#[test] +fn test_resolve_module() { + let (_temp_dir, deno_dir) = test_setup(); + + let test_cases = [ + ( + "./subdir/print_hello.ts", + add_root!( + "/Users/rld/go/src/github.com/ry/deno/testdata/006_url_imports.ts" + ), + add_root!( + "/Users/rld/go/src/github.com/ry/deno/testdata/subdir/print_hello.ts" + ), + add_root!( + "/Users/rld/go/src/github.com/ry/deno/testdata/subdir/print_hello.ts" + ), + ), + ( + "testdata/001_hello.js", + add_root!("/Users/rld/go/src/github.com/ry/deno/"), + add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/001_hello.js"), + add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/001_hello.js"), + ), + ( + add_root!("/Users/rld/src/deno/hello.js"), + ".", + add_root!("/Users/rld/src/deno/hello.js"), + add_root!("/Users/rld/src/deno/hello.js"), + ), + ( + add_root!("/this/module/got/imported.js"), + add_root!("/that/module/did/it.js"), + add_root!("/this/module/got/imported.js"), + add_root!("/this/module/got/imported.js"), + ), + /* + ( + "http://localhost:4545/testdata/subdir/print_hello.ts", + add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/006_url_imports.ts"), + "http://localhost:4545/testdata/subdir/print_hello.ts", + path.Join(SrcDir, "localhost:4545/testdata/subdir/print_hello.ts"), + ), + ( + path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"), + ".", + "http://unpkg.com/liltest@0.0.5/index.ts", + path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"), + ), + ( + "./util", + path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"), + "http://unpkg.com/liltest@0.0.5/util", + path.Join(SrcDir, "unpkg.com/liltest@0.0.5/util"), + ), + */ + ]; + for &test in test_cases.iter() { + let module_specifier = String::from(test.0); + let containing_file = String::from(test.1); + let (module_name, filename) = deno_dir + .resolve_module(&module_specifier, &containing_file) + .unwrap(); + assert_eq!(module_name, test.2); + assert_eq!(filename, test.3); + } +} + +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(Path::new(filename)) + } +} diff --git a/src/fs.rs b/src/fs.rs new file mode 100644 index 000000000..4ec9611ae --- /dev/null +++ b/src/fs.rs @@ -0,0 +1,25 @@ +use std; +use std::fs::File; +use std::io::Read; +use std::path::Path; + +#[allow(dead_code)] +pub fn read_file_sync(path: &Path) -> std::io::Result<String> { + File::open(path).and_then(|mut f| { + let mut contents = String::new(); + f.read_to_string(&mut contents)?; + Ok(contents) + }) +} + +pub fn mkdir(path: &Path) -> std::io::Result<()> { + debug!("mkdir -p {}", path.display()); + assert!(path.has_root(), "non-has_root not yet implemented"); + std::fs::create_dir_all(path).or_else(|err| { + if err.kind() == std::io::ErrorKind::AlreadyExists { + Ok(()) + } else { + Err(err) + } + }) +} diff --git a/src/handlers.h b/src/handlers.h index 04aed25ef..067819529 100644 --- a/src/handlers.h +++ b/src/handlers.h @@ -8,5 +8,7 @@ extern "C" { void handle_code_fetch(Deno* d, uint32_t cmd_id, const char* module_specifier, const char* containing_file); +void handle_code_cache(Deno* d, uint32_t cmd_id, const char* filename, + const char* source_code, const char* output_code); } // extern "C" #endif // HANDLERS_H_ diff --git a/src/handlers.rs b/src/handlers.rs index 6dc08f919..4cb3afd5b 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -1,29 +1,18 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. use binding::{deno_buf, deno_set_response, DenoC}; use flatbuffers; +use from_c; use libc::c_char; -use libc::uint32_t; use msg_generated::deno as msg; use std::ffi::CStr; -use std::fs::File; -use std::io::Read; -use std::path::Path; -use url; -use url::Url; -// TODO(ry) SRC_DIR is just a placeholder for future caching functionality. -static SRC_DIR: &str = "/Users/rld/.deno/src/"; -const ASSET_PREFIX: &str = "/$asset$/"; - -#[test] -fn test_url() { - let issue_list_url = Url::parse("https://github.com/rust-lang").unwrap(); - assert!(issue_list_url.scheme() == "https"); -} - -fn string_from_ptr(ptr: *const c_char) -> String { - let cstr = unsafe { CStr::from_ptr(ptr as *const i8) }; - String::from(cstr.to_str().unwrap()) +// Help. Is there a way to do this without macros? +// Want: fn str_from_ptr(*const c_char) -> &str +macro_rules! str_from_ptr { + ($ptr:expr) => {{ + let cstr = unsafe { CStr::from_ptr($ptr as *const i8) }; + cstr.to_str().unwrap() + }}; } /* @@ -35,182 +24,6 @@ pub fn deno_handle_msg_from_js(d: *const DenoC, buf: deno_buf) { } */ -// Prototype: https://github.com/ry/deno/blob/golang/os.go#L56-L68 -#[allow(dead_code)] -fn src_file_to_url<P: AsRef<Path>>(filename: P) -> String { - assert!(SRC_DIR.len() > 0, "SRC_DIR shouldn't be empty"); - - let filename = filename.as_ref().to_path_buf(); - let src = (SRC_DIR.as_ref() as &Path).to_path_buf(); - - if filename.starts_with(&src) { - let rest = filename.strip_prefix(&src).unwrap(); - "http://".to_string() + rest.to_str().unwrap() - } else { - String::from(filename.to_str().unwrap()) - } -} - -#[test] -fn test_src_file_to_url() { - assert_eq!("hello", src_file_to_url("hello")); - assert_eq!("/hello", src_file_to_url("/hello")); - let x = SRC_DIR.to_string() + "hello"; - assert_eq!("http://hello", src_file_to_url(&x)); - let x = SRC_DIR.to_string() + "/hello"; - assert_eq!("http://hello", src_file_to_url(&x)); -} - -// Prototype: https://github.com/ry/deno/blob/golang/os.go#L70-L98 -// Returns (module name, local filename) -fn resolve_module( - module_specifier: &String, - containing_file: &String, -) -> Result<(String, String), url::ParseError> { - debug!( - "resolve_module before module_specifier {} containing_file {}", - module_specifier, containing_file - ); - - //let module_specifier = src_file_to_url(module_specifier); - //let containing_file = src_file_to_url(containing_file); - //let base_url = Url::parse(&containing_file)?; - - let j: Url = - if containing_file == "." || Path::new(module_specifier).is_absolute() { - Url::from_file_path(module_specifier).unwrap() - } else if containing_file.as_str().ends_with("/") { - let base = Url::from_directory_path(&containing_file).unwrap(); - base.join(module_specifier)? - } else { - let base = Url::from_file_path(&containing_file).unwrap(); - base.join(module_specifier)? - }; - - 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("\\", "/"); - } - - let module_name = p.to_string(); - let filename = p.to_string(); - - Ok((module_name, filename)) -} - -// https://github.com/ry/deno/blob/golang/os_test.go#L16-L87 -#[test] -fn test_resolve_module() { - // The `add_root` macro prepends "C:" to a string if on windows; on posix - // systems it returns the input string untouched. This is necessary because - // `Url::from_file_path()` fails if the input path isn't an absolute path. - macro_rules! add_root { - ($path:expr) => { - if cfg!(target_os = "windows") { - concat!("C:", $path) - } else { - $path - } - }; - } - - let test_cases = [ - ( - "./subdir/print_hello.ts", - add_root!( - "/Users/rld/go/src/github.com/ry/deno/testdata/006_url_imports.ts" - ), - add_root!( - "/Users/rld/go/src/github.com/ry/deno/testdata/subdir/print_hello.ts" - ), - add_root!( - "/Users/rld/go/src/github.com/ry/deno/testdata/subdir/print_hello.ts" - ), - ), - ( - "testdata/001_hello.js", - add_root!("/Users/rld/go/src/github.com/ry/deno/"), - add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/001_hello.js"), - add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/001_hello.js"), - ), - ( - add_root!("/Users/rld/src/deno/hello.js"), - ".", - add_root!("/Users/rld/src/deno/hello.js"), - add_root!("/Users/rld/src/deno/hello.js"), - ), - ( - add_root!("/this/module/got/imported.js"), - add_root!("/that/module/did/it.js"), - add_root!("/this/module/got/imported.js"), - add_root!("/this/module/got/imported.js"), - ), - /* - ( - "http://localhost:4545/testdata/subdir/print_hello.ts", - add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/006_url_imports.ts"), - "http://localhost:4545/testdata/subdir/print_hello.ts", - path.Join(SrcDir, "localhost:4545/testdata/subdir/print_hello.ts"), - ), - ( - path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"), - ".", - "http://unpkg.com/liltest@0.0.5/index.ts", - path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"), - ), - ( - "./util", - path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"), - "http://unpkg.com/liltest@0.0.5/util", - path.Join(SrcDir, "unpkg.com/liltest@0.0.5/util"), - ), - */ - ]; - for &test in test_cases.iter() { - let module_specifier = String::from(test.0); - let containing_file = String::from(test.1); - let (module_name, filename) = - resolve_module(&module_specifier, &containing_file).unwrap(); - assert_eq!(module_name, test.2); - assert_eq!(filename, test.3); - } -} - -pub fn reply_code_fetch( - d: *const DenoC, - cmd_id: uint32_t, - module_name: &String, - filename: &String, - source_code: &String, - output_code: &String, -) { - let mut builder = flatbuffers::FlatBufferBuilder::new(); - let msg_args = msg::CodeFetchResArgs { - module_name: builder.create_string(module_name), - filename: builder.create_string(filename), - source_code: builder.create_string(source_code), - output_code: builder.create_string(output_code), - ..Default::default() - }; - let msg = msg::CreateCodeFetchRes(&mut builder, &msg_args); - builder.finish(msg); - let args = msg::BaseArgs { - cmdId: cmd_id, - msg: Some(msg.union()), - msg_type: msg::Any::CodeFetchRes, - ..Default::default() - }; - set_response_base(d, &mut builder, &args) -} - fn reply_error(d: *const DenoC, cmd_id: u32, msg: &String) { let mut builder = flatbuffers::FlatBufferBuilder::new(); // println!("reply_error{}", msg); @@ -254,63 +67,67 @@ pub extern "C" fn handle_code_fetch( module_specifier_: *const c_char, containing_file_: *const c_char, ) { - let module_specifier = string_from_ptr(module_specifier_); - let containing_file = string_from_ptr(containing_file_); - - let result = resolve_module(&module_specifier, &containing_file); - if result.is_err() { - let err = result.unwrap_err(); - let errmsg = format!("{} {} {}", err, module_specifier, containing_file); - reply_error(d, cmd_id, &errmsg); - return; - } - let (module_name, filename) = result.unwrap(); + let module_specifier = str_from_ptr!(module_specifier_); + let containing_file = str_from_ptr!(containing_file_); - let mut source_code = String::new(); + let deno = from_c(d); - debug!( - "code_fetch. module_name = {} module_specifier = {} containing_file = {} filename = {}", - module_name, module_specifier, containing_file, filename - ); + assert!(deno.dir.root.join("gen") == deno.dir.gen, "Sanity check"); - 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."); - } else { - assert!( - module_name == filename, - "if a module isn't remote, it should have the same filename" - ); - let result = File::open(&filename); - if result.is_err() { - let err = result.unwrap_err(); - let errmsg = format!("{} {}", err, filename); - reply_error(d, cmd_id, &errmsg); - return; - } - let mut f = result.unwrap(); - let result = f.read_to_string(&mut source_code); - if result.is_err() { - let err = result.unwrap_err(); - let errmsg = format!("{} {}", err, filename); + let result = deno + .dir + .code_fetch(module_specifier, containing_file) + .map_err(|err| { + let errmsg = format!("{}", err); reply_error(d, cmd_id, &errmsg); - return; - } + }); + if result.is_err() { + return; } - - let output_code = String::new(); //load_output_code_cache(filename, source_code); - - reply_code_fetch( - d, - cmd_id, - &module_name, - &filename, - &source_code, - &output_code, - ) + let out = result.unwrap(); + // reply_code_fetch + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let mut msg_args = msg::CodeFetchResArgs { + module_name: builder.create_string(&out.module_name), + filename: builder.create_string(&out.filename), + source_code: builder.create_string(&out.source_code), + ..Default::default() + }; + match out.maybe_output_code { + Some(ref output_code) => { + msg_args.output_code = builder.create_string(output_code); + } + _ => (), + }; + let msg = msg::CreateCodeFetchRes(&mut builder, &msg_args); + builder.finish(msg); + let args = msg::BaseArgs { + cmdId: cmd_id, + msg: Some(msg.union()), + msg_type: msg::Any::CodeFetchRes, + ..Default::default() + }; + set_response_base(d, &mut builder, &args) } -fn is_remote(_module_name: &String) -> bool { - false +// https://github.com/ry/deno/blob/golang/os.go#L156-L169 +#[no_mangle] +pub extern "C" fn handle_code_cache( + d: *const DenoC, + cmd_id: u32, + filename_: *const c_char, + source_code_: *const c_char, + output_code_: *const c_char, +) { + let deno = from_c(d); + let filename = str_from_ptr!(filename_); + let source_code = str_from_ptr!(source_code_); + let output_code = str_from_ptr!(output_code_); + let result = deno.dir.code_cache(filename, source_code, output_code); + if result.is_err() { + let err = result.unwrap_err(); + let errmsg = format!("{}", err); + reply_error(d, cmd_id, &errmsg); + } + // null response indicates success. } diff --git a/src/main.rs b/src/main.rs index a12f95018..c02d918b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,16 @@ -extern crate libc; -#[macro_use] -extern crate log; extern crate flatbuffers; +extern crate libc; extern crate msg_rs as msg_generated; extern crate sha1; extern crate tempfile; extern crate url; +#[macro_use] +extern crate log; + +mod binding; +mod deno_dir; +mod fs; +pub mod handlers; use libc::c_int; use libc::c_void; @@ -14,10 +19,6 @@ use std::ffi::CStr; use std::ffi::CString; use std::mem; -mod handlers; -pub use handlers::*; -mod binding; - // Returns args passed to V8, followed by args passed to JS fn parse_core_args(args: Vec<String>) -> (Vec<String>, Vec<String>) { let mut rest = vec![]; @@ -89,6 +90,7 @@ type DenoException<'a> = &'a str; pub struct Deno { ptr: *const binding::DenoC, + dir: deno_dir::DenoDir, } static DENO_INIT: std::sync::Once = std::sync::ONCE_INIT; @@ -101,6 +103,7 @@ impl Deno { let deno_box = Box::new(Deno { ptr: 0 as *const binding::DenoC, + dir: deno_dir::DenoDir::new(None).unwrap(), }); let deno: &'a mut Deno = Box::leak(deno_box); let external_ptr = deno as *mut _ as *const c_void; @@ -161,6 +164,7 @@ fn test_c_to_rust() { let d = Deno::new(); let d2 = from_c(d.ptr); assert!(d.ptr == d2.ptr); + assert!(d.dir.root.join("gen") == d.dir.gen, "Sanity check"); } static LOGGER: Logger = Logger; diff --git a/src/reply.cc b/src/reply.cc index 435f76f74..007f2c68b 100644 --- a/src/reply.cc +++ b/src/reply.cc @@ -63,16 +63,11 @@ void deno_handle_msg_from_js(Deno* d, deno_buf buf) { } case deno::Any_CodeCache: { - // TODO(ry) Call into rust. - /* + auto msg = base->msg_as_CodeCache(); auto filename = msg->filename()->c_str(); auto source_code = msg->source_code()->c_str(); auto output_code = msg->output_code()->c_str(); - printf( - "HandleCodeCache (not implemeneted) filename %s source_code %s " - "output_code %s\n", - filename, source_code, output_code); - */ + handle_code_cache(d, cmd_id, filename, source_code, output_code); break; } |