mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
Implement CodeCache
This commit is contained in:
parent
1f093c12f8
commit
4d386e9e1c
7 changed files with 514 additions and 263 deletions
8
js/os.ts
8
js/os.ts
|
@ -71,7 +71,13 @@ export function codeCache(
|
|||
fbs.Base.addMsgType(builder, fbs.Any.CodeCache);
|
||||
builder.finish(fbs.Base.endBase(builder));
|
||||
const resBuf = deno.send(builder.asUint8Array());
|
||||
assert(resBuf == null);
|
||||
// Expect null or error.
|
||||
if (resBuf != null) {
|
||||
const bb = new flatbuffers.ByteBuffer(new Uint8Array(resBuf));
|
||||
const baseRes = fbs.Base.getRootAsBase(bb);
|
||||
assert(fbs.Any.NONE === baseRes.msgType());
|
||||
throw Error(baseRes.error());
|
||||
}
|
||||
}
|
||||
|
||||
export function readFileSync(filename: string): Uint8Array {
|
||||
|
|
402
src/deno_dir.rs
Normal file
402
src/deno_dir.rs
Normal file
|
@ -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))
|
||||
}
|
||||
}
|
25
src/fs.rs
Normal file
25
src/fs.rs
Normal file
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -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_
|
||||
|
|
313
src/handlers.rs
313
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 module_specifier = str_from_ptr!(module_specifier_);
|
||||
let containing_file = str_from_ptr!(containing_file_);
|
||||
|
||||
let result = resolve_module(&module_specifier, &containing_file);
|
||||
let deno = from_c(d);
|
||||
|
||||
assert!(deno.dir.root.join("gen") == deno.dir.gen, "Sanity check");
|
||||
|
||||
let result = deno
|
||||
.dir
|
||||
.code_fetch(module_specifier, containing_file)
|
||||
.map_err(|err| {
|
||||
let errmsg = format!("{}", err);
|
||||
reply_error(d, cmd_id, &errmsg);
|
||||
});
|
||||
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 mut source_code = String::new();
|
||||
|
||||
debug!(
|
||||
"code_fetch. module_name = {} module_specifier = {} containing_file = {} filename = {}",
|
||||
module_name, module_specifier, containing_file, filename
|
||||
);
|
||||
|
||||
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);
|
||||
reply_error(d, cmd_id, &errmsg);
|
||||
return;
|
||||
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)
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
||||
fn is_remote(_module_name: &String) -> bool {
|
||||
false
|
||||
// null response indicates success.
|
||||
}
|
||||
|
|
18
src/main.rs
18
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue