Skip to content
Closed
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
18 changes: 1 addition & 17 deletions apps/browser-demos/pages/test-runner/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import coreutilsWasmUrl from "@binaries/programs/wasm32/coreutils.wasm?url";
import grepWasmUrl from "@binaries/programs/wasm32/grep.wasm?url";
import sedWasmUrl from "@binaries/programs/wasm32/sed.wasm?url";
import genCatWasmUrl from "@binaries/programs/wasm32/posix-utils-lite/gencat.wasm?url";
import { COREUTILS_NAMES } from "../../lib/init/shell-binaries";

interface DataFile {
path: string;
Expand Down Expand Up @@ -50,23 +51,6 @@ let grepBytes: ArrayBuffer | null = null;
let sedBytes: ArrayBuffer | null = null;
let genCatBytes: ArrayBuffer | null = null;

const COREUTILS_NAMES = [
"arch", "b2sum", "base32", "base64", "basename", "basenc", "cat",
"chcon", "chgrp", "chmod", "chown", "chroot", "cksum", "comm", "cp",
"csplit", "cut", "date", "dd", "df", "dir", "dircolors", "dirname",
"du", "echo", "env", "expand", "expr", "factor", "false", "fmt",
"fold", "groups", "head", "hostid", "id", "install", "join", "link",
"ln", "logname", "ls", "md5sum", "mkdir", "mkfifo", "mknod", "mktemp",
"mv", "nice", "nl", "nohup", "nproc", "numfmt", "od", "paste",
"pathchk", "pr", "printenv", "printf", "ptx", "pwd", "readlink",
"realpath", "rm", "rmdir", "runcon", "seq", "sha1sum", "sha224sum",
"sha256sum", "sha384sum", "sha512sum", "shred", "shuf", "sleep",
"sort", "split", "stat", "stty", "sum", "sync", "tac", "tail",
"tee", "test", "timeout", "touch", "tr", "true", "truncate", "tsort",
"tty", "uname", "unexpand", "uniq", "unlink", "vdir", "wc", "whoami",
"yes",
];

/** Write a binary file to the virtual filesystem. */
function writeFileToFs(fs: import("@host/browser-kernel-host").BrowserKernel["fs"], path: string, data: ArrayBuffer): void {
const bytes = new Uint8Array(data);
Expand Down
11 changes: 2 additions & 9 deletions examples/run-example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { readFileSync, existsSync, statSync } from "fs";
import { resolve, dirname, isAbsolute, relative } from "path";
import { NodeKernelHost } from "../host/src/node-kernel-host";
import { tryResolveBinary } from "../host/src/binary-resolver";
import { COREUTILS_NAMES } from "../images/vfs/lib/init/shell-binaries";

const repoRoot = resolve(dirname(new URL(import.meta.url).pathname), "..");

Expand Down Expand Up @@ -61,15 +62,7 @@ const testfixtureWasm = tryResolveBinary("programs/sqlite/testfixture.wasm");
const mysqltestWasm = tryResolveBinary("programs/mariadb/mysqltest.wasm");
const echoWasm = tryResolveBinary("programs/echo.wasm") ?? resolve(repoRoot, "examples/echo.wasm");

// GNU coreutils multi-call binary supports all of these as argv[0]
const coreutilsNames = [
"cat", "ls", "cp", "mv", "rm", "mkdir", "rmdir", "ln", "chmod", "chown",
"head", "tail", "wc", "sort", "uniq", "tr", "cut", "paste", "tee",
"true", "false", "yes", "env", "printenv", "printf", "expr", "test", "[",
"basename", "dirname", "readlink", "realpath", "stat", "touch", "date",
"sleep", "id", "whoami", "uname", "hostname", "pwd", "dd", "od", "md5sum",
"sha256sum", "base64", "seq", "factor", "nproc", "du", "df",
];
const coreutilsNames = [...COREUTILS_NAMES, "["];

// Values may be null when a program isn't fetched/built locally.
// Consumers filter out null entries before use.
Expand Down
1 change: 1 addition & 0 deletions images/rootfs/PACKAGES.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ aliases = [
"/usr/bin/id", "/bin/id",
"/usr/bin/install", "/bin/install",
"/usr/bin/join", "/bin/join",
"/usr/bin/kill", "/bin/kill",
"/usr/bin/link", "/bin/link",
"/usr/bin/ln", "/bin/ln",
"/usr/bin/logname", "/bin/logname",
Expand Down
2 changes: 1 addition & 1 deletion images/vfs/lib/init/shell-binaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const COREUTILS_NAMES = [
"chcon", "chgrp", "chmod", "chown", "chroot", "cksum", "comm", "cp",
"csplit", "cut", "date", "dd", "df", "dir", "dircolors", "dirname",
"du", "echo", "env", "expand", "expr", "factor", "false", "fmt",
"fold", "groups", "head", "hostid", "id", "install", "join", "link",
"fold", "groups", "head", "hostid", "id", "install", "join", "kill", "link",
"ln", "logname", "ls", "md5sum", "mkdir", "mkfifo", "mknod", "mktemp",
"mv", "nice", "nl", "nohup", "nproc", "numfmt", "od", "paste",
"pathchk", "pr", "printenv", "printf", "ptx", "pwd", "readlink",
Expand Down
21 changes: 5 additions & 16 deletions images/vfs/scripts/build-mariadb-test-vfs-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ import {
writeVfsBinary,
symlink,
} from "../../../host/src/vfs/image-helpers";
import { resolveBinary, tryResolveBinary, findRepoRoot } from "../../../host/src/binary-resolver";
import { resolveBinary, findRepoRoot } from "../../../host/src/binary-resolver";
import { saveImage, walkAndWrite } from "./vfs-image-helpers";
import { addDinitInit, type DinitService } from "./dinit-image-helpers";
import { ensureSourceExtract } from "./source-extract-helper";
import { COREUTILS_NAMES } from "../lib/init/shell-binaries";

const REPO_ROOT = findRepoRoot();
// Local source-build keeps everything under mariadb-install/; for
Expand All @@ -47,22 +48,14 @@ const SYSTEM_DATA_PATH = existsSync(join(MARIADB_LEGACY_INSTALL, "share/mysql/my
? join(MARIADB_LEGACY_INSTALL, "share/mysql/mysql_system_tables_data.sql")
: join(MARIADB_SOURCE, "scripts/mysql_system_tables_data.sql");
const DASH_PATH = resolveBinary("programs/dash.wasm");
const COREUTILS_PATH = tryResolveBinary("programs/coreutils.wasm");
const COREUTILS_PATH = resolveBinary("programs/coreutils.wasm");

const OUT_FILE = process.env.MARIADB_TEST_VFS_OUT
?? join(REPO_ROOT, "apps/browser-demos/public/mariadb-test.vfs.zst");

const includeAll = process.argv.includes("--all");

const COREUTILS_SYMLINK_NAMES = [
"ls", "cat", "cp", "mv", "rm", "echo", "mkdir", "rmdir", "touch", "pwd",
"head", "tail", "wc", "sort", "uniq", "cut", "tr", "date", "basename",
"dirname", "chmod", "chown", "ln", "readlink", "true", "false", "yes",
"sleep", "env", "printenv", "id", "whoami", "hostname", "uname", "stat",
"df", "du", "tee", "nl", "paste", "tac", "rev", "expand", "unexpand",
"fold", "fmt", "pr", "od", "hexdump", "xxd", "sha256sum", "sha512sum",
"md5sum", "seq", "test", "[",
];
const COREUTILS_SYMLINK_NAMES = [...COREUTILS_NAMES, "["];

// 185 tests verified to pass in headless Chromium with MariaDB on kandelo.
const CURATED_TESTS = [
Expand Down Expand Up @@ -234,11 +227,7 @@ async function main() {
symlink(fs, "/bin/dash", "/usr/bin/dash");
symlink(fs, "/bin/dash", "/usr/bin/sh");
}
if (COREUTILS_PATH && existsSync(COREUTILS_PATH)) {
writeVfsBinary(fs, "/bin/coreutils", new Uint8Array(readFileSync(COREUTILS_PATH)));
} else {
console.warn(" Warning: coreutils.wasm not found — bootstrap wrapper will fail at sleep");
}
writeVfsBinary(fs, "/bin/coreutils", new Uint8Array(readFileSync(COREUTILS_PATH)));
for (const name of COREUTILS_SYMLINK_NAMES) {
symlink(fs, "/bin/coreutils", `/bin/${name}`);
symlink(fs, "/bin/coreutils", `/usr/bin/${name}`);
Expand Down
28 changes: 7 additions & 21 deletions images/vfs/scripts/build-mariadb-vfs-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ import {
writeVfsBinary,
symlink,
} from "../../../host/src/vfs/image-helpers";
import { resolveBinary, tryResolveBinary, findRepoRoot } from "../../../host/src/binary-resolver";
import { resolveBinary, findRepoRoot } from "../../../host/src/binary-resolver";
import { saveImage } from "./vfs-image-helpers";
import { addDinitInit, type DinitService } from "./dinit-image-helpers";
import { ensureSourceExtract } from "./source-extract-helper";
import { COREUTILS_NAMES } from "../lib/init/shell-binaries";

const REPO_ROOT = findRepoRoot();
const useWasm64 = process.argv.includes("--wasm64");
Expand All @@ -52,24 +53,15 @@ const SYSTEM_DATA_PATH = existsSync(join(MARIADB_LEGACY_INSTALL, "share/mysql/my
? join(MARIADB_LEGACY_INSTALL, "share/mysql/mysql_system_tables_data.sql")
: join(MARIADB_SOURCE, "scripts/mysql_system_tables_data.sql");
const DASH_PATH = resolveBinary("programs/dash.wasm");
// Coreutils is baked into the VFS so users get an immediate `ls`/`cat`
// in the shell demo without waiting for a lazy-load fetch. Not strictly
// required by the bootstrap wrapper (which is just `exec mariadbd < sql`).
const COREUTILS_PATH = tryResolveBinary("programs/coreutils.wasm");
// Coreutils is a declared package dependency and is baked into the VFS so
// every emitted symlink has a real multicall target.
const COREUTILS_PATH = resolveBinary("programs/coreutils.wasm");

const OUT_FILE = useWasm64
? join(REPO_ROOT, "apps/browser-demos/public/mariadb-64.vfs.zst")
: join(REPO_ROOT, "apps/browser-demos/public/mariadb.vfs.zst");

const COREUTILS_SYMLINK_NAMES = [
"ls", "cat", "cp", "mv", "rm", "echo", "mkdir", "rmdir", "touch", "pwd",
"head", "tail", "wc", "sort", "uniq", "cut", "tr", "date", "basename",
"dirname", "chmod", "chown", "ln", "readlink", "true", "false", "yes",
"sleep", "env", "printenv", "id", "whoami", "hostname", "uname", "stat",
"df", "du", "tee", "nl", "paste", "tac", "rev", "expand", "unexpand",
"fold", "fmt", "pr", "od", "hexdump", "xxd", "sha256sum", "sha512sum",
"md5sum", "seq", "test", "[",
];
const COREUTILS_SYMLINK_NAMES = [...COREUTILS_NAMES, "["];

function commonMariadbArgs(engine: string): string[] {
return [
Expand Down Expand Up @@ -175,13 +167,7 @@ async function main() {
symlink(fs, "/bin/dash", "/usr/bin/dash");
symlink(fs, "/bin/dash", "/usr/bin/sh");
}
// Bake coreutils.wasm so the shell demo has `ls`/`cat`/etc. without
// waiting for a lazy-load fetch on first invocation.
if (COREUTILS_PATH && existsSync(COREUTILS_PATH)) {
writeVfsBinary(fs, "/bin/coreutils", new Uint8Array(readFileSync(COREUTILS_PATH)));
} else {
console.warn(" Warning: coreutils.wasm not found — shell demo will lack /bin/ls etc.");
}
writeVfsBinary(fs, "/bin/coreutils", new Uint8Array(readFileSync(COREUTILS_PATH)));
for (const name of COREUTILS_SYMLINK_NAMES) {
symlink(fs, "/bin/coreutils", `/bin/${name}`);
symlink(fs, "/bin/coreutils", `/usr/bin/${name}`);
Expand Down
7 changes: 2 additions & 5 deletions images/vfs/scripts/build-sqlite-test-vfs-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from "../../../host/src/vfs/image-helpers";
import { findRepoRoot, tryResolveBinary } from "../../../host/src/binary-resolver";
import { saveImage, walkAndWrite } from "./vfs-image-helpers";
import { COREUTILS_NAMES } from "../lib/init/shell-binaries";

const REPO_ROOT = findRepoRoot();
const SQLITE_DIR = join(REPO_ROOT, "packages/registry/sqlite");
Expand All @@ -31,11 +32,7 @@ const COREUTILS_PATH = tryResolveBinary("programs/coreutils.wasm");
const OUT_FILE = process.env.SQLITE_TEST_VFS_OUT
?? join(REPO_ROOT, "apps/browser-demos/public/sqlite-test.vfs.zst");

const COREUTILS_SYMLINK_NAMES = [
"cat", "chmod", "cp", "date", "dirname", "echo", "env", "expr", "false",
"head", "ln", "ls", "mkdir", "mv", "pwd", "rm", "rmdir", "sed", "sleep",
"sort", "tail", "tee", "test", "touch", "tr", "true", "uname", "wc", "[",
];
const COREUTILS_SYMLINK_NAMES = [...COREUTILS_NAMES, "["];

function checkPrereqs(): void {
const missing: string[] = [];
Expand Down
1 change: 1 addition & 0 deletions packages/registry/coreutils/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
coreutils-src/
coreutils-*-src/
bin/
16 changes: 9 additions & 7 deletions packages/registry/coreutils/build-coreutils.sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail

# Build GNU coreutils 9.5 for wasm32-posix-kernel.
# Build GNU coreutils 9.6 for wasm32-posix-kernel.
#
# Uses the SDK's wasm32posix-configure wrapper for cross-compilation.
# Output: packages/registry/coreutils/bin/*.wasm

COREUTILS_VERSION="${COREUTILS_VERSION:-9.5}"
COREUTILS_VERSION="${COREUTILS_VERSION:-9.6}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
SRC_DIR="$SCRIPT_DIR/coreutils-src"
SRC_DIR="$SCRIPT_DIR/coreutils-${COREUTILS_VERSION}-src"
BIN_DIR="$SCRIPT_DIR/bin"
SYSROOT="$REPO_ROOT/sysroot"

Expand Down Expand Up @@ -41,8 +41,10 @@ fi
cd "$SRC_DIR"

# --- Configure ---
if [ ! -f Makefile ]; then
echo "==> Configuring coreutils for wasm32..."
# Rerun configure even when this source tree was built before. Package recipe
# changes can alter the multicall member set without changing the upstream
# version, and an old Makefile must never define the published command surface.
echo "==> Configuring coreutils for wasm32..."

# GNU coreutils + gnulib does hundreds of configure tests.
# Cross-compilation link-based tests fail, so we override with correct
Expand Down Expand Up @@ -228,15 +230,15 @@ if [ ! -f Makefile ]; then
wasm32posix-configure \
--disable-nls \
--without-selinux \
--without-gmp \
--without-libgmp \
--disable-acl \
--disable-xattr \
--enable-single-binary=symlinks \
--enable-install-program=arch \
--enable-no-install-program=stdbuf,pinky,who,users,uptime \
2>&1 | tail -30

echo "==> Configure complete."
fi

# --- Build ---
echo "==> Building coreutils..."
Expand Down
2 changes: 1 addition & 1 deletion packages/registry/coreutils/build.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
script_path = "packages/registry/coreutils/build-coreutils.sh"
repo_url = "https://github.com/brandonpayton/kandelo.git"
commit = "8c53383229fab78f97b098c3207a655159c03041"
revision = 2
revision = 3

[binary]
index_url = "https://github.com/Automattic/kandelo/releases/download/binaries-abi-v{abi}/index.toml"
42 changes: 42 additions & 0 deletions packages/registry/coreutils/test/coreutils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import { describe, it, expect } from "vitest";
import { runCentralizedProgram } from "../../../../host/test/centralized-test-helper";
import { tryResolveBinary } from "../../../../host/src/binary-resolver";
import { COREUTILS_NAMES } from "../../../../images/vfs/lib/init/shell-binaries";

const coreutilsBinary = tryResolveBinary("programs/coreutils.wasm");
const dashBinary = tryResolveBinary("programs/dash.wasm");

const hasCoreutils = !!coreutilsBinary;

Expand Down Expand Up @@ -41,6 +43,46 @@ describe.skipIf(!hasCoreutils)("GNU coreutils", () => {
expect(result.exitCode).toBe(1);
});

it("arch reports the wasm32 machine", async () => {
const result = await runCentralizedProgram({
programPath: coreutilsBinary!,
argv: ["arch"],
timeout: 10_000,
});
expect(result.exitCode).toBe(0);
expect(result.stdout.trim()).toBe("wasm32");
});

it("kill is included in the multicall binary", async () => {
const result = await runCentralizedProgram({
programPath: coreutilsBinary!,
argv: ["kill", "--version"],
timeout: 10_000,
});
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain("kill (GNU coreutils) 9.6");
});

it.skipIf(!dashBinary)(
"executes arch and kill through /bin aliases",
async () => {
const execPrograms = new Map(
COREUTILS_NAMES.map(
(name) => [`/bin/${name}`, coreutilsBinary!] as const,
),
);
const result = await runCentralizedProgram({
programPath: dashBinary!,
argv: ["dash", "-c", "/bin/arch; /bin/kill --version"],
execPrograms,
timeout: 10_000,
});
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain("wasm32\n");
expect(result.stdout).toContain("kill (GNU coreutils) 9.6");
},
);

it("printf formats output", async () => {
const result = await runCentralizedProgram({
programPath: coreutilsBinary!,
Expand Down
2 changes: 1 addition & 1 deletion packages/registry/lamp/build.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ inputs = [
]
repo_url = "https://github.com/brandonpayton/kandelo.git"
commit = "8c53383229fab78f97b098c3207a655159c03041"
revision = 7
revision = 8

[binary]
index_url = "https://github.com/Automattic/kandelo/releases/download/binaries-abi-v{abi}/index.toml"
20 changes: 19 additions & 1 deletion packages/registry/mariadb-test/build.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
script_path = "packages/registry/mariadb-test/build-mariadb-test.sh"
inputs = [
"packages/registry/mariadb-test/build-mariadb-test.sh",
"packages/registry/mariadb-test/package.toml",
"images/vfs/scripts/build-mariadb-test-vfs-image.ts",
"images/vfs/scripts/dinit-image-helpers.ts",
"images/vfs/scripts/source-extract-helper.ts",
"images/vfs/scripts/vfs-image-helpers.ts",
"images/vfs/lib/init/shell-binaries.ts",
"host/src/binary-resolver.ts",
"host/src/constants.ts",
"host/src/statfs.ts",
"host/src/types.ts",
"host/src/vfs/image-helpers.ts",
"host/src/vfs/memory-fs.ts",
"host/src/vfs/sharedfs-vendor.ts",
"host/src/vfs/types.ts",
"host/src/vfs/zip.ts",
]
repo_url = "https://github.com/brandonpayton/kandelo.git"
commit = "8c53383229fab78f97b098c3207a655159c03041"
revision = 1
revision = 2

[binary]
index_url = "https://github.com/Automattic/kandelo/releases/download/binaries-abi-v{abi}/index.toml"
4 changes: 3 additions & 1 deletion packages/registry/mariadb-test/package.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ kernel_abi = 7
# on demand.
# - calls `resolveBinary("programs/dash.wasm")` (strict — throws if missing)
# to bake `/bin/dash` + `/bin/sh` symlink
# - calls `resolveBinary("programs/coreutils.wasm")` (strict — throws if
# missing) before creating the multicall command symlinks
# - calls `addDinitInit(...)` which calls `resolveDinitBinaries()` (strict —
# throws if neither tryResolveBinary nor the source-tree path resolves)
# to bake the init system that boots the test runner.
# Without these declarations a clean source-build (e.g., during manual
# force-rebuild) fails. Folds each prereq's cache_key into ours.
depends_on = ["mariadb@10.5.28", "dash@0.5.12", "dinit@0.19.4"]
depends_on = ["mariadb@10.5.28", "dash@0.5.12", "coreutils@9.6", "dinit@0.19.4"]

# Pre-built VFS image for the MariaDB test runner: mariadbd binary,
# mysql-test test files (curated 185 tests), system-table SQL,
Expand Down
Loading
Loading