Files
scriptc/packages/runtime-pack-common/runtime-pack-matrix.mjs
T
Chris Tate db94b2d257 Add fs.cpSync, fs.cp and fs/promises cp
fs.cpSync, fs.cp and fs/promises cp compile with every option:
dereference, errorOnExist, filter, force, mode, preserveTimestamps,
recursive and verbatimSymlinks. They follow Node's two implementations.
cpSync follows cp-sync.js over the fs binding: copy errors are plain
Errors with a code, std::error_code failures throw an ErrnoException,
and links inside a copied directory point at their canonical targets.
fs.cp and fs/promises cp follow cp.js, whose copy errors are
SystemErrors with code, info, errno, syscall and path.

Options and paths validate in Node's order with Node's errors. filter
runs for the top-level paths and each entry in Node's order; an async
filter must return a promise that is already settled, and a pending one
throws SC2020. The callback and promise forms complete the copy before
the callback runs or the promise settles. Windows builds throw SC2020.

The copy lives in the new scr_fs_cp.c. Directory walks keep their frames
on the heap, so deep trees also copy on a fiber's stack. File contents
copy with sendfile on Linux, and COPYFILE_FICLONE uses FICLONE
where it exists. ScrError gains the SystemError context and the
ErrnoException key order, with matching fields in the compiler's Error
layout. The stored fs.cp callback uses the same implementation.

Corpus 5567-5571 cover the sync, callback and promise forms, errors,
symlinks and 1500-level trees.
2026-10-16 21:06:22 -05:00

162 lines
5.5 KiB
JavaScript

import { withWorkerRuntimeVariants } from "./worker-matrix.mjs";
import { withLibraryRuntimeFlavors } from "./library-matrix.mjs";
/**
* Shared release-runtime pack matrix. Platform package scripts provide the
* target descriptor, then this module fixes feature reachability and the
* compile/link flags required by every generated runtime object.
*/
const any = (...features) => ({ any: features });
const all = (...features) => ({ all: features });
const BASE_RUNTIME_SOURCES = [
"scr_context.c",
"scr_shared.c",
"scr_number.c",
"scr_bigint.c",
"scr_string.c",
"scr_grapheme.c",
"scr_array.c",
"scr_bytes.c",
"scr_bytes_io.c",
"scr_fs_cp.c",
"scr_map.c",
"scr_closure.c",
"scr_ffi.c",
"scr_object.c",
"scr_union.c",
"scr_exception.c",
"scr_error.c",
"scr_console.c",
"scr_lib.c",
"scr_hash.c",
"scr_path.c",
"scr_os.c",
"scr_url.c",
"scr_url_params.c",
"scr_json.c",
"scr_node_builtin.c",
"scr_async.c",
"scr_crypto_async.c",
"scr_child.c",
"scr_cycle.c",
"scr_publish.c",
"scr_region.c",
"scr_itable.c",
"scr_alloc.c",
];
const OPTIONAL = [
["scr_copying.c", "copying"],
["scr_file_handle.c", "fileHandle"],
["scr_regex.c", "regex"],
["scr_glob.c", "regex"],
["scr_idna.c", "regex"],
["scr_assert.c", any("assert", "regex", "symbol")],
["scr_inspect.c", "inspect"],
["scr_console_native.c", "inspect"],
["scr_dyn_invoke.c", any("dynInvoke", "nativeFetch")],
["scr_dc.c", "dc"],
["scr_event_target.c", any("eventTarget", "nativeFetch")],
["scr_async_dyn.c", any("dynAsync", "dynInvoke", "dc", "fileHandle", "nativeFetch")],
// The performance timeline emits its buffer warning through scr_async_dyn.c.
["scr_perf.c", "dynAsync"],
// Blob and File box their reads as dyn promises through scr_async_dyn.c.
["scr_blob.c", "dynAsync"],
["scr_zlib.c", "zlib"],
["scr_events.c", "events"],
["scr_readline.c", "events"],
["scr_events_emitter.c", "emitter"],
["scr_dyn_handle.c", any("emitter", "netEffective")],
["scr_symbol.c", "symbol"],
["scr_bigint_assert.c", all("assert", "bigint")],
["scr_qs.c", "qs"],
// The legacy url unit lowercases and normalizes through the regex unit
// and warns through the dyn-async one.
["scr_url_legacy.c", all("regex", "qs", "dynAsync")],
["scr_util.c", "parseArgs"],
// Utility objects must only reference runtime families selected with them.
["scr_util_compare.c", all("parseArgs", "symbol")],
["scr_util_style.c", all("parseArgs", "inspect", "dynAsync")],
["scr_util_callable.c", all("parseArgs", "inspect", "dynAsync", "dynInvoke", "regex")],
["scr_stream.c", "stream"],
// The zlib stream classes reference both the zlib engine and the stream unit.
["scr_zlib_stream.c", all("zlib", "stream")],
// The Readable operators await through the dyn-async unit.
["scr_stream_ops.c", all("stream", "dynAsync")],
// fs.ReadStream / fs.WriteStream reference only the stream unit and base units.
["scr_fs_stream.c", "stream"],
// FileHandle streams reference both the stream unit and FileHandle.
["scr_fs_stream_fh.c", all("stream", "fileHandle")],
["scr_loop_kqueue.c", any("netEffective", "dgram")],
["scr_loop_epoll.c", any("netEffective", "dgram")],
["scr_loop_wsapoll.c", any("netEffective", "dgram")],
["scr_net.c", "netEffective"],
["scr_http.c", "httpEffective"],
["scr_http2.c", "http2"],
["scr_dgram.c", "dgram"],
["scr_watch.c", "watch"],
["scr_ffi_queue.c", "foreignFfi"],
["scr_test.c", "nodeTest"],
["scr_tls_ca.c", "tlsCaEffective"],
["scr_tls.c", "tlsEffective"],
["scr_cipher.c", "cipher"],
["scr_fetch.c", "nativeFetch"],
];
function variantsFor(source) {
const variants = [{ id: "default", when: {}, defines: [] }];
if (source === "scr_bytes.c") {
variants.push({
id: "text-decoder-legacy",
when: { textDecoderLegacy: true },
defines: ["SCR_TEXT_DECODER_LEGACY"],
});
}
return variants;
}
export function createRuntimePackMatrix({
target,
compileFlags,
systemLibraries,
extraRuntimeSources = [],
omitRuntimeSources = [],
omitOptionalSources = [],
omitArchives = [],
libraryOnly = false,
}) {
const vendorArchives = [
{ id: "quickjs", predicate: false },
{ id: "libregexp", predicate: "regex" },
{ id: "zlib", predicate: "zlibEffective" },
{ id: "mbedtls", predicate: any("tlsEffective", "cipher") },
];
const matrix = withLibraryRuntimeFlavors(
withWorkerRuntimeVariants({
schema: "scriptc.runtime-pack-matrix.v1",
target,
flavors: { release: { optimization: "-O2" }, dev: { optimization: "-O0" } },
executable_section_elimination: { compile_flags: compileFlags },
runtime_units: [
...BASE_RUNTIME_SOURCES.filter((source) => !omitRuntimeSources.includes(source)).map(
(source) => ({ source, predicate: true }),
),
...extraRuntimeSources.map((source) => ({ source, predicate: true })),
...OPTIONAL.filter(([source]) => !omitOptionalSources.includes(source)).map(
([source, predicate]) => ({ source, predicate }),
),
].map((unit) => ({ ...unit, variants: variantsFor(unit.source) })),
archives: vendorArchives.filter(({ id }) => !omitArchives.includes(id)),
system_libraries: systemLibraries,
}),
);
if (libraryOnly) {
matrix.flavors = Object.fromEntries(
Object.entries(matrix.flavors).filter(([name]) => name.startsWith("library-")),
);
matrix.archives = matrix.archives.filter(({ id }) => id === "libregexp" || id === "zlib");
}
return matrix;
}