Skip to content

Commit

Permalink
Got most of the Wasmer.spawn() fs tests working
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael-F-Bryan committed Nov 23, 2023
1 parent e95e82a commit 68db359
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 99 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"build": "wasm-pack build --release --target=web --weak-refs --no-pack && wasm-opt pkg/wasmer_js_bg.wasm -O2 -o pkg/wasmer_js_bg.wasm && rollup -c --environment BUILD:production",
"build:dev": "wasm-pack build --dev --target=web --weak-refs --no-pack && rollup -c --environment BUILD:development",
"dev": "rollup -c -w",
"test": "web-test-runner 'tests/**/*.test.ts' --node-resolve --esbuild-target auto --config ./web-dev-server.config.mjs",
"test": "web-test-runner --node-resolve --esbuild-target auto --config ./web-dev-server.config.mjs",
"clean": "rimraf dist coverage pkg target"
},
"devDependencies": {
Expand Down
41 changes: 32 additions & 9 deletions src/fs/directory.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::sync::Arc;

use tracing::Instrument;
use virtual_fs::{AsyncReadExt, AsyncWriteExt, FileSystem};
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
use web_sys::FileSystemDirectoryHandle;

use crate::utils::Error;
use crate::{utils::Error, StringOrBytes};

/// A directory that can be mounted inside a WASIX instance.
#[derive(Debug, Clone, wasm_bindgen_derive::TryFromJsValue)]
Expand Down Expand Up @@ -41,24 +42,27 @@ impl Directory {
}

#[wasm_bindgen(js_name = "readDir")]
pub fn read_dir(&self, mut path: String) -> Result<Vec<String>, Error> {
pub async fn read_dir(&self, mut path: String) -> Result<js_sys::Array, Error> {
if !path.starts_with('/') {
path.insert(0, '/');
}

let mut contents = Vec::new();
let contents = js_sys::Array::new();

for entry in FileSystem::read_dir(self, path.as_ref())? {
let entry = entry?;
contents.push(entry.path.display().to_string());
let value = JsValue::from(entry.path.display().to_string());
contents.push(&value);
}

Ok(contents)
}

/// Write to a file.
///
/// If a string is provided, it is encoded as UTF-8.
#[wasm_bindgen(js_name = "writeFile")]
pub async fn write_file(&self, mut path: String, contents: Vec<u8>) -> Result<(), Error> {
pub async fn write_file(&self, mut path: String, contents: StringOrBytes) -> Result<(), Error> {
if !path.starts_with('/') {
path.insert(0, '/');
}
Expand All @@ -68,6 +72,8 @@ impl Directory {
.write(true)
.create(true)
.open(&path)?;

let contents = contents.as_bytes();
f.write_all(&contents).await?;

Ok(())
Expand All @@ -91,7 +97,7 @@ impl Directory {

/// Create a directory.
#[wasm_bindgen(js_name = "createDir")]
pub fn create_dir(&self, mut path: String) -> Result<(), Error> {
pub async fn create_dir(&self, mut path: String) -> Result<(), Error> {
if !path.starts_with('/') {
path.insert(0, '/');
}
Expand All @@ -109,35 +115,52 @@ impl Default for Directory {
}

impl FileSystem for Directory {
#[tracing::instrument(level = "trace", skip(self))]
fn read_dir(&self, path: &std::path::Path) -> virtual_fs::Result<virtual_fs::ReadDir> {
self.0.read_dir(path)
}

#[tracing::instrument(level = "trace", skip(self))]
fn create_dir(&self, path: &std::path::Path) -> virtual_fs::Result<()> {
self.0.create_dir(path)
}

#[tracing::instrument(level = "trace", skip(self))]
fn remove_dir(&self, path: &std::path::Path) -> virtual_fs::Result<()> {
self.0.remove_dir(path)
}

#[tracing::instrument(level = "trace", skip(self))]
fn rename<'a>(
&'a self,
from: &'a std::path::Path,
to: &'a std::path::Path,
) -> futures::future::BoxFuture<'a, virtual_fs::Result<()>> {
self.0.rename(from, to)
Box::pin(self.0.rename(from, to).in_current_span())
}

#[tracing::instrument(level = "trace", skip(self))]
fn metadata(&self, path: &std::path::Path) -> virtual_fs::Result<virtual_fs::Metadata> {
self.0.metadata(path)
}

#[tracing::instrument(level = "trace", skip(self))]
fn remove_file(&self, path: &std::path::Path) -> virtual_fs::Result<()> {
self.0.remove_file(path)
}

fn new_open_options(&self) -> virtual_fs::OpenOptions {
self.0.new_open_options()
virtual_fs::OpenOptions::new(self)
}
}

impl virtual_fs::FileOpener for Directory {
#[tracing::instrument(level = "trace", skip(self))]
fn open(
&self,
path: &std::path::Path,
conf: &virtual_fs::OpenOptionsConfig,
) -> virtual_fs::Result<Box<dyn virtual_fs::VirtualFile + Send + Sync + 'static>> {
self.0.new_open_options().options(conf.clone()).open(path)
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub use crate::{
logging::initialize_logger,
run::{run, RunConfig},
runtime::Runtime,
utils::StringOrBytes,
};

use once_cell::sync::Lazy;
Expand Down
20 changes: 7 additions & 13 deletions src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use virtual_fs::TmpFileSystem;
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue, UnwrapThrowExt};
use wasmer_wasix::{Runtime as _, WasiEnvBuilder};

use crate::{instance::ExitCondition, utils::Error, Directory, Instance, Runtime};
use crate::{instance::ExitCondition, utils::Error, Directory, Instance, Runtime, StringOrBytes};

const DEFAULT_PROGRAM_NAME: &str = "wasm";

Expand Down Expand Up @@ -41,6 +41,7 @@ pub async fn run(wasm_module: WasmModule, config: RunConfig) -> Result<Instance,
Box::new(move |module| {
let _span = tracing::debug_span!("run").entered();
let result = builder.run(module).map_err(anyhow::Error::new);
tracing::warn!(?result);
let _ = exit_code_tx.send(ExitCondition::from_result(result));
}),
)?;
Expand Down Expand Up @@ -118,7 +119,7 @@ extern "C" {
fn env(this: &RunConfig) -> JsValue;

#[wasm_bindgen(method, getter)]
fn stdin(this: &RunConfig) -> JsValue;
fn stdin(this: &RunConfig) -> Option<StringOrBytes>;

#[wasm_bindgen(method, getter)]
fn mount(this: &RunConfig) -> OptionalDirectories;
Expand Down Expand Up @@ -199,16 +200,7 @@ impl RunConfig {
}

pub(crate) fn read_stdin(&self) -> Option<Vec<u8>> {
let stdin = self.stdin();

if let Some(s) = stdin.as_string() {
return Some(s.into_bytes());
}

stdin
.dyn_into::<js_sys::Uint8Array>()
.map(|buf| buf.to_vec())
.ok()
self.stdin().map(|s| s.as_bytes())
}

pub(crate) fn mounted_directories(&self) -> Result<Vec<(String, Directory)>, Error> {
Expand Down Expand Up @@ -236,12 +228,14 @@ impl RunConfig {
let root = TmpFileSystem::new();

for (dest, fs) in self.mounted_directories()? {
tracing::trace!(%dest, ?fs, "Mounting directory");

let fs = Arc::new(fs) as Arc<_>;
root.mount(dest.as_str().into(), &fs, "/".into())
.with_context(|| format!("Unable to mount to \"{dest}\""))?;
}

tracing::warn!(?root);
tracing::trace!(?root, "Initialized the filesystem");

Ok(root)
}
Expand Down
22 changes: 20 additions & 2 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use std::{
num::NonZeroUsize,
};

use js_sys::{JsString, Promise};
use js_sys::{JsString, Promise, Uint8Array};

use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
use web_sys::{Window, WorkerGlobalScope};

/// Try to extract the most appropriate error message from a [`JsValue`],
Expand Down Expand Up @@ -252,3 +252,21 @@ pub(crate) fn js_record_of_strings(obj: &js_sys::Object) -> Result<Vec<(String,

Ok(parsed)
}

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = "string | Uint8Array")]
pub type StringOrBytes;
}

impl StringOrBytes {
pub fn as_bytes(&self) -> Vec<u8> {
if let Some(s) = self.dyn_ref::<JsString>() {
String::from(s).into()
} else if let Some(buffer) = self.dyn_ref::<Uint8Array>() {
buffer.to_vec()
} else {
unreachable!()
}
}
}
Loading

0 comments on commit 68db359

Please sign in to comment.