Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fs conformance #268

Merged
merged 8 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/preview2-shim/lib/io/worker-io.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ class Pollable {
this.#ready = true;
}
}
static _getId(pollable) {
return pollable.#id;
}
static _create(id) {
const pollable = new Pollable();
pollable.#id = id;
Expand All @@ -292,12 +295,15 @@ delete Pollable._listToIds;
const pollableMarkReady = Pollable._markReady;
delete Pollable._markReady;

const pollableGetId = Pollable._getId;
delete Pollable._getId;

export const poll = {
Pollable,
poll(list) {
const includeList = ioCall(POLL_POLL_LIST, null, pollableListToIds(list));
return list.filter((pollable) => {
if (includeList.includes(pollable.id)) {
if (includeList.includes(pollableGetId(pollable))) {
pollableMarkReady(pollable);
return true;
}
Expand Down
141 changes: 105 additions & 36 deletions packages/preview2-shim/lib/nodejs/filesystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,22 @@ import {
fdatasyncSync,
fstatSync,
fsyncSync,
ftruncateSync,
futimesSync,
linkSync,
lstatSync,
lutimesSync,
mkdirSync,
opendirSync,
openSync,
readlinkSync,
readSync,
renameSync,
rmdirSync,
statSync,
symlinkSync,
unlinkSync,
utimesSync,
writeSync,
} from "node:fs";
import { platform } from "node:process";
Expand Down Expand Up @@ -57,17 +64,22 @@ let descriptorCnt = 3;
class Descriptor {
#hostPreopen;
#fd;
#mode;
#fullPath;

static _createPreopen(hostPreopen) {
const descriptor = new Descriptor();
descriptor.#hostPreopen = hostPreopen;
descriptor.#hostPreopen = hostPreopen.endsWith("/")
? hostPreopen.slice(0, -1) || '/'
: hostPreopen;
return descriptor;
}

static _create(fd, fullPath) {
static _create(fd, mode, fullPath) {
const descriptor = new Descriptor();
descriptor.#fd = fd;
descriptor.#mode = mode;
if (fullPath.endsWith("/")) throw new Error("bad full path");
descriptor.#fullPath = fullPath;
return descriptor;
}
Expand Down Expand Up @@ -113,22 +125,7 @@ class Descriptor {

getFlags() {
if (this.#hostPreopen) throw "invalid";
let stats;
try {
stats = fstatSync(this.#fd);
} catch (e) {
throw convertFsError(e);
}
const mode = stats.mode;
return {
read: ((mode & constants.O_RDWR) | (mode & constants.O_RDONLY)) > 0,
write: ((mode & constants.O_RDWR) | (mode & constants.O_WRONLY)) > 0,
// TODO:
fileIntegritySync: false,
dataIntegritySync: false,
requestedWriteSync: false,
mutateDirectory: false,
};
return this.#mode;
}

getType() {
Expand All @@ -139,17 +136,46 @@ class Descriptor {

setSize(size) {
if (this.#hostPreopen) throw "is-directory";
console.log(`[filesystem] SET SIZE`, this._id, size);
try {
ftruncateSync(this.#fd, Number(size));
} catch (e) {
throw convertFsError(e);
}
}

setTimes(dataAccessTimestamp, dataModificationTimestamp) {
if (this.#hostPreopen) throw "invalid";
console.log(
`[filesystem] SET TIMES`,
this._id,
let stats;
if (
dataAccessTimestamp.tag === "no-change" ||
dataModificationTimestamp.tag === "no-change"
)
stats = this.stat();
const atime = this.#getNewTimestamp(
dataAccessTimestamp,
dataModificationTimestamp
dataAccessTimestamp.tag === "no-change" && stats.dataAccessTimestamp
);
const mtime = this.#getNewTimestamp(
dataModificationTimestamp,
dataModificationTimestamp.tag === "no-change" &&
stats.dataModificationTimestamp
);
try {
futimesSync(this.#fd, atime, mtime);
} catch (e) {
throw convertFsError(e);
}
}

#getNewTimestamp(newTimestamp, maybeNow) {
switch (newTimestamp.tag) {
case "no-change":
return timestampToMs(maybeNow);
case "now":
return Math.floor(Date.now() / 1e3);
case "timestamp":
return timestampToMs(newTimestamp.val);
}
}

read(length, offset) {
Expand Down Expand Up @@ -238,12 +264,42 @@ class Descriptor {
};
}

setTimesAt() {
console.log(`[filesystem] SET TIMES AT`, this._id);
setTimesAt(pathFlags, path, dataAccessTimestamp, dataModificationTimestamp) {
const fullPath = this.#getFullPath(path, false);
let stats;
if (
dataAccessTimestamp.tag === "no-change" ||
dataModificationTimestamp.tag === "no-change"
)
stats = this.stat();
const atime = this.#getNewTimestamp(
dataAccessTimestamp,
dataAccessTimestamp.tag === "no-change" && stats.dataAccessTimestamp
);
const mtime = this.#getNewTimestamp(
dataModificationTimestamp,
dataModificationTimestamp.tag === "no-change" &&
stats.dataModificationTimestamp
);
try {
(pathFlags.symlinkFollow ? utimesSync : lutimesSync)(
fullPath,
atime,
mtime
);
} catch (e) {
throw convertFsError(e);
}
}

linkAt() {
console.log(`[filesystem] LINK AT`, this._id);
linkAt(oldPathFlags, oldPath, newDescriptor, newPath) {
const oldFullPath = this.#getFullPath(oldPath, oldPathFlags.symlinkFollow);
const newFullPath = newDescriptor.#getFullPath(newPath, false);
try {
linkSync(oldFullPath, newFullPath);
} catch (e) {
throw convertFsError(e);
}
}

openAt(pathFlags, path, openFlags, descriptorFlags) {
Expand All @@ -269,14 +325,19 @@ class Descriptor {
isWindows ? fullPath.slice(1) : fullPath,
fsOpenFlags
);
return descriptorCreate(fd, fullPath, preopenEntries);
return descriptorCreate(fd, descriptorFlags, fullPath, preopenEntries);
} catch (e) {
throw convertFsError(e);
}
}

readlinkAt() {
console.log(`[filesystem] READLINK AT`, this._id);
readlinkAt(path) {
const fullPath = this.#getFullPath(path, false);
try {
return readlinkSync(fullPath);
} catch (e) {
throw convertFsError(e);
}
}

removeDirectoryAt(path) {
Expand All @@ -288,8 +349,14 @@ class Descriptor {
}
}

renameAt() {
console.log(`[filesystem] RENAME AT`, this._id);
renameAt(oldPath, newDescriptor, newPath) {
const oldFullPath = this.#getFullPath(oldPath, false);
const newFullPath = newDescriptor.#getFullPath(newPath, false);
try {
renameSync(oldFullPath, newFullPath);
} catch (e) {
throw convertFsError(e);
}
}

symlinkAt(target, path) {
Expand Down Expand Up @@ -361,11 +428,9 @@ class Descriptor {
subpath = subpath.slice(subpath[1] === "/" ? 2 : 1);
if (descriptor.#hostPreopen)
return (
descriptor.#hostPreopen +
(descriptor.#hostPreopen.endsWith("/") ? "" : "/") +
subpath
descriptor.#hostPreopen + (subpath.length > 0 ? "/" : "") + subpath
);
return descriptor.#fullPath + (subpath.length > 0 ? "/" : '') + subpath;
return descriptor.#fullPath + (subpath.length > 0 ? "/" : "") + subpath;
}

[symbolDispose]() {
Expand Down Expand Up @@ -516,3 +581,7 @@ function convertFsError(e) {
throw e;
}
}

function timestampToMs(timestamp) {
return Number(timestamp.seconds) * 1000 + timestamp.nanoseconds / 1e9;
}
4 changes: 3 additions & 1 deletion packages/preview2-shim/lib/synckit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ function startWorkerThread(
throw new Error(`Internal error: Expected id ${id} but got id ${id2}`);
}
if (error) {
throw Object.assign(error, properties);
if (error instanceof Error)
throw Object.assign(error, properties);
throw error;
}
return result;
};
Expand Down
2 changes: 2 additions & 0 deletions tests/generated/api_proxy.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root

use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_proxy() -> anyhow::Result<()> {
let file_name = "api_proxy";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/api_proxy");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_proxy --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/api_proxy_streaming.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root

use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_proxy_streaming() -> anyhow::Result<()> {
let file_name = "api_proxy_streaming";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/api_proxy_streaming");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_proxy_streaming --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/api_reactor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root

use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_reactor() -> anyhow::Result<()> {
let file_name = "api_reactor";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/api_reactor");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_reactor --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
6 changes: 4 additions & 2 deletions tests/generated/api_read_only.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root

use std::fs;
// use tempdir::TempDir;
// use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_read_only() -> anyhow::Result<()> {
// let file_name = "api_read_only";
// let tempdir = TempDir::new("{file_name}")?;
// let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
panic!("skipped"); // cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_read_only --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
// Ok(())
let _ = fs::remove_dir_all("./tests/rundir/api_read_only");
// cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_read_only --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
panic!("skipped"); // Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/api_time.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root

use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_time() -> anyhow::Result<()> {
let file_name = "api_time";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/api_time");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_time --jco-import ./tests/virtualenvs/fakeclocks.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/cli_args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root

use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn cli_args() -> anyhow::Result<()> {
let file_name = "cli_args";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/cli_args");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/cli_args --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/cli_default_clocks.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root

use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn cli_default_clocks() -> anyhow::Result<()> {
let file_name = "cli_default_clocks";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/cli_default_clocks");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/cli_default_clocks --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
Loading