summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2018-07-26 17:54:22 -0400
committerRyan Dahl <ry@tinyclouds.org>2018-07-29 00:22:39 -0400
commit4d386e9e1c79d557cae6af58e6df85eb470c1e0c (patch)
tree2a5bda6620b2d68ea5f06e4c49c9b9a3ad4c76f2 /src
parent1f093c12f84d269cb68370262d68ff6d515aef2e (diff)
Implement CodeCache
Diffstat (limited to 'src')
-rw-r--r--src/deno_dir.rs402
-rw-r--r--src/fs.rs25
-rw-r--r--src/handlers.h2
-rw-r--r--src/handlers.rs311
-rw-r--r--src/main.rs18
-rw-r--r--src/reply.cc9
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;
}