Skip to content

Commit

Permalink
refactor(swingset)!: Convert RESM to NESM
Browse files Browse the repository at this point in the history
*BREAKING CHANGE*: loadSwingsetConfigFile is now async, to facilitate ESM module resolution.

Plugins will need to be converted in a subsequent change, as noted in TODO comments.
  • Loading branch information
kriskowal committed Aug 3, 2021
1 parent 0ffde7f commit bf7fd61
Show file tree
Hide file tree
Showing 60 changed files with 298 additions and 299 deletions.
6 changes: 2 additions & 4 deletions packages/SwingSet/bin/rekernelize.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#!/usr/bin/env -S node -r esm

/* global require */
#!/usr/bin/env -S node

import 'node-lmdb';
import '@agoric/babel-standalone';
Expand Down Expand Up @@ -63,7 +61,7 @@ async function main() {
assert(kvStore.get('initialized'), 'kernel store not initialized');

const kernelBundle = await bundleSource(
require.resolve('../src/kernel/kernel.js'),
new URL('../src/kernel/kernel.js', import.meta.url).pathname,
);

kvStore.set('kernelBundle', JSON.stringify(kernelBundle));
Expand Down
10 changes: 6 additions & 4 deletions packages/SwingSet/bin/replay-transcript.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global WeakRef FinalizationRegistry require */
/* global WeakRef FinalizationRegistry */
// import '@agoric/install-ses';
import '../tools/install-ses-debug.js';
import fs from 'fs';
Expand All @@ -16,7 +16,8 @@ import { startSubprocessWorker } from '../src/spawnSubprocessWorker.js';
import { requireIdentical } from '../src/kernel/vatManager/transcript.js';

async function makeBundles() {
const srcGE = rel => bundleSource(require.resolve(rel), 'getExport');
const srcGE = rel =>
bundleSource(new URL(rel, import.meta.url).pathname, 'getExport');
const lockdown = await srcGE(
'../src/kernel/vatManager/lockdown-subprocess-xsnap.js',
);
Expand Down Expand Up @@ -86,9 +87,10 @@ async function replay(transcriptFile, worker = 'xs-worker') {
// this worker type cannot do blocking syscalls like vatstoreGet, so it's
// kind of useless for vats that use virtual objects
function startSubprocessWorkerNode() {
const supercode = require.resolve(
const supercode = new URL(
'../src/kernel/vatManager/supervisor-subprocess-node.js',
);
import.meta.url,
).pathname;
return startSubprocessWorker(process.execPath, ['-r', 'esm', supercode]);
}
factory = makeNodeSubprocessFactory({
Expand Down
9 changes: 2 additions & 7 deletions packages/SwingSet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
"name": "@agoric/swingset-vat",
"version": "0.19.0",
"description": "Vat/Container Launcher",
"parsers": {
"js": "mjs"
},
"type": "module",
"main": "src/main.js",
"module": "src/index.js",
"engines": {
Expand Down Expand Up @@ -49,7 +47,7 @@
"@endo/base64": "^0.2.5",
"@types/tmp": "^0.2.0",
"anylogger": "^0.21.0",
"esm": "agoric-labs/esm#Agoric-built",
"import-meta-resolve": "^1.1.1",
"node-lmdb": "^0.9.4",
"re2": "^1.10.5",
"semver": "^6.3.0",
Expand Down Expand Up @@ -84,9 +82,6 @@
"files": [
"test/**/test-*.js"
],
"require": [
"esm"
],
"timeout": "20m"
},
"prettier": {
Expand Down
15 changes: 8 additions & 7 deletions packages/SwingSet/src/controller.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global require */
// @ts-check
import fs from 'fs';
import process from 'process';
Expand Down Expand Up @@ -229,17 +228,19 @@ export async function makeSwingsetController(
function makeNodeWorker() {
// TODO: after we move away from `-r esm` and use real ES6 modules, point
// this at nodeWorkerSupervisor.js instead of the CJS intermediate
const supercode = require.resolve(
'./kernel/vatManager/supervisor-nodeworker-cjs.js',
);
const supercode = new URL(
'kernel/vatManager/supervisor-nodeworker.js',
import.meta.url,
).pathname;
return new Worker(supercode);
}

// launch a worker in a subprocess (which runs Node.js)
function startSubprocessWorkerNode() {
const supercode = require.resolve(
'./kernel/vatManager/supervisor-subprocess-node.js',
);
const supercode = new URL(
'kernel/vatManager/supervisor-subprocess-node.js',
import.meta.url,
).pathname;
const args = ['-r', 'esm', supercode];
return startSubprocessWorker(process.execPath, args);
}
Expand Down
3 changes: 1 addition & 2 deletions packages/SwingSet/src/devices/bridge.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global require */
/*
The 'bridge' devices provides bidirectional function calls between objects
on the host and code within a swingset.
Expand Down Expand Up @@ -93,7 +92,7 @@ function sanitize(data) {
}

export function buildBridge(outboundCallback) {
const srcPath = require.resolve('./bridge-src');
const srcPath = new URL('bridge-src.js', import.meta.url).pathname;
let inboundCallback;

function registerInboundCallback(inbound) {
Expand Down
3 changes: 1 addition & 2 deletions packages/SwingSet/src/devices/command.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global require */
import { makePromiseKit } from '@agoric/promise-kit';
import { Nat } from '@agoric/nat';

Expand All @@ -7,7 +6,7 @@ import { assert, details as X } from '@agoric/assert';
export default function buildCommand(broadcastCallback) {
assert(broadcastCallback, X`broadcastCallback must be provided.`);
let inboundCallback;
const srcPath = require.resolve('./command-src');
const srcPath = new URL('command-src.js', import.meta.url).pathname;
let nextCount = 0n;
const responses = new Map();

Expand Down
3 changes: 1 addition & 2 deletions packages/SwingSet/src/devices/loopbox.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global require */
import { assert, details as X } from '@agoric/assert';

/*
Expand All @@ -22,7 +21,7 @@ export function buildLoopbox(deliverMode) {
deliverMode === 'immediate' || deliverMode === 'queued',
X`deliverMode=${deliverMode}, must be 'immediate' or 'queued'`,
);
const loopboxSrcPath = require.resolve('./loopbox-src');
const loopboxSrcPath = new URL('loopbox-src', import.meta.url).pathname;

let loopboxPassOneMessage;
function registerPassOneMessage(lpom) {
Expand Down
3 changes: 1 addition & 2 deletions packages/SwingSet/src/devices/mailbox.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global require */
/*
The 'mailbox' device helps manage bidirectional communication with a number
of 'peers'. Each peer is identified with a string. We exchange ordered
Expand Down Expand Up @@ -157,7 +156,7 @@ export function buildMailboxStateMap(state = harden(new Map())) {
}

export function buildMailbox(state) {
const srcPath = require.resolve('./mailbox-src');
const srcPath = new URL('mailbox-src', import.meta.url).pathname;

// endowments made available to the inner half
let inboundCallback;
Expand Down
3 changes: 1 addition & 2 deletions packages/SwingSet/src/devices/plugin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* global require */
export function buildPlugin(pluginDir, pluginRequire, queueThunkForKernel) {
const srcPath = require.resolve('./plugin-src');
const srcPath = new URL('plugin-src', import.meta.url).pathname;
let resetter;

function reset() {
Expand Down
3 changes: 1 addition & 2 deletions packages/SwingSet/src/devices/timer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global require */
import { Nat } from '@agoric/nat';

import { assert, details as X } from '@agoric/assert';
Expand All @@ -14,7 +13,7 @@ import { assert, details as X } from '@agoric/assert';
* controller.run() when it returns true.
*/
export function buildTimer() {
const srcPath = require.resolve('./timer-src');
const srcPath = new URL('timer-src', import.meta.url).pathname;
let devicePollFunction;

function registerDevicePollFunction(pollFn) {
Expand Down
8 changes: 4 additions & 4 deletions packages/SwingSet/src/engine-gc.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/* eslint-disable global-require */
/* global globalThis require */
import v8 from 'v8';
import vm from 'vm';

/* global globalThis */
let bestGC = globalThis.gc;
if (typeof bestGC !== 'function') {
// Node.js v8 wizardry.
const v8 = require('v8');
const vm = require('vm');
v8.setFlagsFromString('--expose_gc');
bestGC = vm.runInNewContext('gc');
// Hide the gc global from new contexts/workers.
Expand Down
52 changes: 33 additions & 19 deletions packages/SwingSet/src/initializeSwingset.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* global require, process */
/* global process */
// @ts-check
import fs from 'fs';
import path from 'path';

import { resolve as resolveModuleSpecifier } from 'import-meta-resolve';
import { assert, details as X } from '@agoric/assert';
import bundleSource from '@agoric/bundle-source';

Expand Down Expand Up @@ -33,8 +34,9 @@ const allValues = async obj =>
export async function buildKernelBundles() {
// this takes 2.7s on my computer

const src = rel => bundleSource(require.resolve(rel));
const srcGE = rel => bundleSource(require.resolve(rel), 'getExport');
const src = rel => bundleSource(new URL(rel, import.meta.url).pathname);
const srcGE = rel =>
bundleSource(new URL(rel, import.meta.url).pathname, 'getExport');

const bundles = await allValues({
kernel: src('./kernel/kernel.js'),
Expand Down Expand Up @@ -134,21 +136,21 @@ export function loadBasedir(basedir) {
* a module path, and then if that doesn't work try to resolve it as an
* ordinary path relative to the directory in which the config file was found.
*
* @param {string} dirname Path to directory containing the config file
* @param {string} referrer URL of file or directory containing the config file
* @param {string} specPath Path found in a `sourceSpec` or `bundleSpec` property
*
* @returns {string} the absolute path corresponding to `specPath` if it can be
* @returns {Promise<string>} the absolute path corresponding to `specPath` if it can be
* determined.
*/
function resolveSpecFromConfig(dirname, specPath) {
async function resolveSpecFromConfig(referrer, specPath) {
try {
return require.resolve(specPath, { paths: [dirname] });
return new URL(await resolveModuleSpecifier(specPath, referrer)).pathname;
} catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') {
if (e.code !== 'MODULE_NOT_FOUND' && e.code !== 'ERR_MODULE_NOT_FOUND') {
throw e;
}
}
return path.resolve(dirname, specPath);
return new URL(specPath, referrer).pathname;
}

/**
Expand All @@ -157,45 +159,57 @@ function resolveSpecFromConfig(dirname, specPath) {
* path and make sure it has a `parameters` property if it's supposed to.
*
* @param {SwingSetConfigDescriptor | void} desc The config descriptor to be normalized.
* @param {string} dirname The pathname of the directory in which the config file was found
* @param {string} referrer The pathname of the file or directory in which the
* config file was found
* @param {boolean} expectParameters `true` if the entries should have parameters (for
* example, `true` for `vats` but `false` for bundles).
*/
function normalizeConfigDescriptor(desc, dirname, expectParameters) {
async function normalizeConfigDescriptor(desc, referrer, expectParameters) {
const normalizeSpec = async (entry, key) => {
return resolveSpecFromConfig(referrer, entry[key]).then(spec => {
entry[key] = spec;
});
};

const jobs = [];
if (desc) {
for (const name of Object.keys(desc)) {
const entry = desc[name];
if ('sourceSpec' in entry) {
entry.sourceSpec = resolveSpecFromConfig(dirname, entry.sourceSpec);
jobs.push(normalizeSpec(entry, 'sourceSpec'));
}
if ('bundleSpec' in entry) {
entry.bundleSpec = resolveSpecFromConfig(dirname, entry.bundleSpec);
jobs.push(normalizeSpec(entry, 'bundleSpec'));
}
if (expectParameters && !entry.parameters) {
entry.parameters = {};
}
}
}
return Promise.all(jobs);
}

/**
* Read and parse a swingset config file and return it in normalized form.
*
* @param {string} configPath Path to the config file to be processed
*
* @returns {SwingSetConfig | null} the contained config object, in normalized form, or null if the
* @returns {Promise<SwingSetConfig | null>} the contained config object, in normalized form, or null if the
* requested config file did not exist.
*
* @throws {Error} if the file existed but was inaccessible, malformed, or otherwise
* invalid.
*/
export function loadSwingsetConfigFile(configPath) {
export async function loadSwingsetConfigFile(configPath) {
try {
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
const dirname = path.dirname(configPath);
normalizeConfigDescriptor(config.vats, dirname, true);
normalizeConfigDescriptor(config.bundles, dirname, false);
// normalizeConfigDescriptor(config.devices, dirname, true); // TODO: represent devices
const referrer = new URL(
configPath,
`file:///${process.cwd()}/`,
).toString();
await normalizeConfigDescriptor(config.vats, referrer, true);
await normalizeConfigDescriptor(config.bundles, referrer, false);
// await normalizeConfigDescriptor(config.devices, referrer, true); // TODO: represent devices
assert(config.bootstrap, X`no designated bootstrap vat in ${configPath}`);
assert(
config.vats && config.vats[config.bootstrap],
Expand Down
10 changes: 5 additions & 5 deletions packages/SwingSet/src/kernel/deviceTranslator.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { assert, details as X } from '@agoric/assert';
import { insistMessage } from '../message';
import { insistKernelType } from './parseKernelSlots';
import { insistVatType, parseVatSlot } from '../parseVatSlots';
import { insistCapData } from '../capdata';
import { kdebug } from './kdebug';
import { insistMessage } from '../message.js';
import { insistKernelType } from './parseKernelSlots.js';
import { insistVatType, parseVatSlot } from '../parseVatSlots.js';
import { insistCapData } from '../capdata.js';
import { kdebug } from './kdebug.js';

/*
* Return a function that converts KernelInvocation objects into
Expand Down
14 changes: 7 additions & 7 deletions packages/SwingSet/src/kernel/initializeKernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import { makeMarshal, Far } from '@agoric/marshal';
import { assert, details as X } from '@agoric/assert';
import { assertKnownOptions } from '../assertOptions';
import { insistVatID } from './id';
import { makeVatSlot } from '../parseVatSlots';
import { insistStorageAPI } from '../storageAPI';
import { wrapStorage } from './state/storageWrapper';
import makeKernelKeeper from './state/kernelKeeper';
import { exportRootObject, doQueueToKref } from './kernel';
import { assertKnownOptions } from '../assertOptions.js';
import { insistVatID } from './id.js';
import { makeVatSlot } from '../parseVatSlots.js';
import { insistStorageAPI } from '../storageAPI.js';
import { wrapStorage } from './state/storageWrapper.js';
import makeKernelKeeper from './state/kernelKeeper.js';
import { exportRootObject, doQueueToKref } from './kernel.js';

function makeVatRootObjectSlot() {
return makeVatSlot('object', true, 0);
Expand Down
6 changes: 3 additions & 3 deletions packages/SwingSet/src/kernel/loadVat.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @ts-check
import { assert, details as X } from '@agoric/assert';
import { assertKnownOptions } from '../assertOptions';
import { makeVatSlot } from '../parseVatSlots';
import { makeVatTranslators } from './vatTranslator';
import { assertKnownOptions } from '../assertOptions.js';
import { makeVatSlot } from '../parseVatSlots.js';
import { makeVatTranslators } from './vatTranslator.js';

export function makeVatRootObjectSlot() {
return makeVatSlot('object', true, 0n);
Expand Down
Loading

0 comments on commit bf7fd61

Please sign in to comment.