@agoric/xsnap 0.14.3-dev-49dfe9b.0.49dfe9b → 0.14.3-dev-4cac2f2.0.4cac2f2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/build.env +8 -0
- package/package.json +6 -5
- package/scripts/get_expected_xsnap_binary_version.sh +7 -0
- package/src/build.js +81 -29
- package/src/install-prebuilt.js +50 -13
- package/src/prebuilt-manifest-sha256.js +0 -6
package/README.md
CHANGED
|
@@ -45,10 +45,11 @@ instead of compiling native sources locally.
|
|
|
45
45
|
|
|
46
46
|
Optional environment overrides:
|
|
47
47
|
|
|
48
|
-
- `XSNAP_BINARY_VERSION` (default: package version)
|
|
49
48
|
- `XSNAP_BINARY_REPO` (default: `Agoric/xsnap-worker-binaries`)
|
|
50
49
|
- `XSNAP_BINARY_BASE_URL` (advanced override)
|
|
51
|
-
- `
|
|
50
|
+
- `XSNAP_BINARY_VERSION` (default: package `build.env`, then package version)
|
|
51
|
+
- `XSNAP_BINARY_MANIFEST_SHA256` (default: package `build.env` manifest hash;
|
|
52
|
+
required trust anchor when overriding `XSNAP_BINARY_VERSION`)
|
|
52
53
|
- `XSNAP_CACHE_DIR` (advanced override for cached downloads)
|
|
53
54
|
|
|
54
55
|
Some time later, possibly on a different computer…
|
package/build.env
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Bump this as needed for a different prebuilt binary release.
|
|
2
|
+
XSNAP_BINARY_VERSION=0.14.2
|
|
3
|
+
XSNAP_BINARY_MANIFEST_HASH=377030e37b10554e73d0aff655639051d33281c9e17e7da98275fb9efcaae6f2
|
|
4
|
+
XSNAP_PACKAGE=@agoric/xsnap
|
|
5
|
+
MODDABLE_URL=https://github.com/agoric-labs/moddable.git
|
|
6
|
+
MODDABLE_COMMIT_HASH=f6c5951fc055e4ca592b9166b9ae3cbb9cca6bf0
|
|
7
|
+
XSNAP_NATIVE_URL=https://github.com/agoric-labs/xsnap-pub
|
|
8
|
+
XSNAP_NATIVE_COMMIT_HASH=105bc6862050695b1723fa76df91564fe8111a37
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/xsnap",
|
|
3
|
-
"version": "0.14.3-dev-
|
|
3
|
+
"version": "0.14.3-dev-4cac2f2.0.4cac2f2",
|
|
4
4
|
"description": "Snapshotting VM worker based on Moddable's XS Javascript engine",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"repl": "node src/xsrepl.js",
|
|
19
19
|
"install:prebuilt": "node src/install-prebuilt.js",
|
|
20
20
|
"build": "yarn install:prebuilt",
|
|
21
|
-
"check-version": "/bin/sh -c '
|
|
21
|
+
"check-version": "/bin/sh -c 'expected=\"$(./scripts/get_expected_xsnap_binary_version.sh)\"; actual=\"$(./scripts/get_xsnap_version.sh)\"; if test \"$expected\" != \"$actual\"; then echo \"xsnap version mismatch; expected $expected\"; exit 1; fi'",
|
|
22
22
|
"postinstall": "npm run install:prebuilt",
|
|
23
23
|
"clean": "rm -rf xsnap-native/xsnap/build",
|
|
24
24
|
"lint": "yarn run -T run-s --continue-on-error 'lint:*'",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"test:xs": "exit 0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@agoric/xsnap-lockdown": "0.14.1-dev-
|
|
33
|
+
"@agoric/xsnap-lockdown": "0.14.1-dev-4cac2f2.0.4cac2f2",
|
|
34
34
|
"@endo/bundle-source": "^4.3.2",
|
|
35
35
|
"@endo/errors": "^1.3.1",
|
|
36
36
|
"@endo/eventual-send": "^1.5.0",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"tmp": "^0.2.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@agoric/internal": "0.3.3-dev-
|
|
45
|
+
"@agoric/internal": "0.3.3-dev-4cac2f2.0.4cac2f2",
|
|
46
46
|
"@endo/base64": "^1.1.1",
|
|
47
47
|
"@endo/nat": "^5.2.0",
|
|
48
48
|
"ava": "^8.0.1",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"files": [
|
|
54
54
|
"LICENSE*",
|
|
55
55
|
"api.js",
|
|
56
|
+
"build.env",
|
|
56
57
|
"scripts/**",
|
|
57
58
|
"src/**"
|
|
58
59
|
],
|
|
@@ -65,5 +66,5 @@
|
|
|
65
66
|
"engines": {
|
|
66
67
|
"node": "^22.11 || ^24.14"
|
|
67
68
|
},
|
|
68
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "4cac2f2827c82d40fbf65afaaa987face9be50c6"
|
|
69
70
|
}
|
package/src/build.js
CHANGED
|
@@ -7,7 +7,6 @@ import osTop from 'node:os';
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @import {ChildProcess} from 'node:child_process';
|
|
10
|
-
* @import {promises} from 'node:fs';
|
|
11
10
|
*/
|
|
12
11
|
|
|
13
12
|
const { freeze } = Object;
|
|
@@ -40,7 +39,7 @@ const ModdableSDK = {
|
|
|
40
39
|
*
|
|
41
40
|
* @param {string} command
|
|
42
41
|
* @param {{
|
|
43
|
-
* spawn: typeof
|
|
42
|
+
* spawn: typeof childProcessTop.spawn,
|
|
44
43
|
* }} io
|
|
45
44
|
*/
|
|
46
45
|
function makeCLI(command, { spawn }) {
|
|
@@ -114,21 +113,35 @@ const SOURCE_STAMP_FILE = '.agoric-source-stamp.json';
|
|
|
114
113
|
|
|
115
114
|
/**
|
|
116
115
|
* @param {string} text
|
|
117
|
-
* @returns {Record<string, string
|
|
116
|
+
* @returns {{ record: Record<string, string>, entries: ([string, string] | string)[] }}
|
|
118
117
|
*/
|
|
119
|
-
const
|
|
118
|
+
const parseEnvTextEntries = text => {
|
|
119
|
+
/** @type {([string, string] | string)[]} */
|
|
120
|
+
const entries = [];
|
|
120
121
|
/** @type {Record<string, string>} */
|
|
121
|
-
const
|
|
122
|
+
const record = {};
|
|
122
123
|
for (const line of text.split('\n')) {
|
|
123
124
|
const trimmed = line.trim();
|
|
124
|
-
if (!trimmed || trimmed.startsWith('#'))
|
|
125
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
126
|
+
entries.push(line);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
125
129
|
const index = trimmed.indexOf('=');
|
|
126
|
-
if (index <= 0)
|
|
130
|
+
if (index <= 0) {
|
|
131
|
+
entries.push(line);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
127
135
|
const key = trimmed.slice(0, index);
|
|
128
136
|
const value = trimmed.slice(index + 1);
|
|
129
|
-
|
|
137
|
+
entries.push([key, value]);
|
|
138
|
+
record[key] = value;
|
|
139
|
+
}
|
|
140
|
+
if (entries.at(-1) === '') {
|
|
141
|
+
// Avoid empty trailing line in showEnv.
|
|
142
|
+
entries.pop();
|
|
130
143
|
}
|
|
131
|
-
return
|
|
144
|
+
return { record, entries };
|
|
132
145
|
};
|
|
133
146
|
|
|
134
147
|
/**
|
|
@@ -142,28 +155,61 @@ const parseEnvText = text => {
|
|
|
142
155
|
*/
|
|
143
156
|
|
|
144
157
|
/**
|
|
158
|
+
* @param {{ name: string; version: string; }} pkg
|
|
159
|
+
* @param {Record<string, string>} oldBuildEnv
|
|
160
|
+
* @param {Readonly<([string, string] | string)[]>} buildEnvEntries
|
|
145
161
|
* @param {SourceDescriptor[]} sources
|
|
146
162
|
* @param {{
|
|
147
163
|
* stdout: typeof process.stdout,
|
|
148
164
|
* }} io
|
|
149
165
|
*/
|
|
150
|
-
const showEnv = async (
|
|
166
|
+
const showEnv = async (
|
|
167
|
+
pkg,
|
|
168
|
+
oldBuildEnv,
|
|
169
|
+
buildEnvEntries,
|
|
170
|
+
sources,
|
|
171
|
+
{ stdout },
|
|
172
|
+
) => {
|
|
151
173
|
await null;
|
|
174
|
+
const buildEnv = { ...oldBuildEnv };
|
|
175
|
+
if (buildEnv.XSNAP_PACKAGE == null) {
|
|
176
|
+
buildEnv.XSNAP_PACKAGE = pkg.name;
|
|
177
|
+
}
|
|
178
|
+
if (buildEnv.XSNAP_BINARY_VERSION == null) {
|
|
179
|
+
buildEnv.XSNAP_BINARY_VERSION = pkg.version;
|
|
180
|
+
}
|
|
181
|
+
|
|
152
182
|
for (const { envPrefix, url, commitHash, archiveUrl } of sources) {
|
|
153
|
-
|
|
154
|
-
|
|
183
|
+
buildEnv[`${envPrefix}URL`] = url;
|
|
184
|
+
buildEnv[`${envPrefix}COMMIT_HASH`] = commitHash;
|
|
155
185
|
const defaultUrl = defaultArchiveUrl(url, commitHash);
|
|
156
186
|
if (archiveUrl && archiveUrl !== defaultUrl) {
|
|
157
|
-
|
|
187
|
+
buildEnv[`${envPrefix}ARCHIVE_URL`] = archiveUrl;
|
|
158
188
|
}
|
|
159
189
|
}
|
|
190
|
+
|
|
191
|
+
// Gathered all the replacements, so iterate on the entries.
|
|
192
|
+
for (const line of buildEnvEntries) {
|
|
193
|
+
if (typeof line === 'string') {
|
|
194
|
+
stdout.write(`${line}\n`);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const [key, value] = line;
|
|
198
|
+
stdout.write(`${key}=${buildEnv[key] ?? value}\n`);
|
|
199
|
+
delete buildEnv[key];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Append any new key-values.
|
|
203
|
+
for (const [key, value] of Object.entries(buildEnv)) {
|
|
204
|
+
stdout.write(`${key}=${value}\n`);
|
|
205
|
+
}
|
|
160
206
|
};
|
|
161
207
|
|
|
162
208
|
/**
|
|
163
209
|
* @param {SourceDescriptor[]} sources
|
|
164
210
|
* @param {{
|
|
165
|
-
* fs: Pick<typeof
|
|
166
|
-
* Pick<typeof promises, 'mkdir' | 'rm' | 'readFile' | 'writeFile' | 'rename'>,
|
|
211
|
+
* fs: Pick<typeof fsTop, 'existsSync'> &
|
|
212
|
+
* Pick<typeof fsTop.promises, 'mkdir' | 'rm' | 'readFile' | 'writeFile' | 'rename'>,
|
|
167
213
|
* curl: ReturnType<typeof makeCLI>,
|
|
168
214
|
* tar: ReturnType<typeof makeCLI>,
|
|
169
215
|
* }} io
|
|
@@ -217,17 +263,19 @@ const updateSources = async (sources, { fs, curl, tar }) => {
|
|
|
217
263
|
};
|
|
218
264
|
|
|
219
265
|
/**
|
|
266
|
+
* @param {{ name: string; version: string; }} pkg
|
|
220
267
|
* @param {ModdablePlatform} platform
|
|
221
268
|
* @param {boolean} force
|
|
222
269
|
* @param {{
|
|
223
|
-
* fs: Pick<typeof
|
|
224
|
-
* Pick<typeof promises, 'readFile' | 'writeFile'>,
|
|
270
|
+
* fs: Pick<typeof fsTop, 'existsSync'> &
|
|
271
|
+
* Pick<typeof fsTop.promises, 'readFile' | 'writeFile'>,
|
|
225
272
|
* make: ReturnType<typeof makeCLI>,
|
|
226
273
|
* }} io
|
|
227
274
|
*/
|
|
228
|
-
const buildXsnap = async (platform, force, { fs, make }) => {
|
|
229
|
-
|
|
230
|
-
|
|
275
|
+
const buildXsnap = async (pkg, platform, force, { fs, make }) => {
|
|
276
|
+
// I solemnly swear I will do no synchronous work followed by a variable
|
|
277
|
+
// number turns of the event loop.
|
|
278
|
+
await null;
|
|
231
279
|
|
|
232
280
|
const configEnvs = [
|
|
233
281
|
`XSNAP_VERSION=${pkg.version}`,
|
|
@@ -268,16 +316,15 @@ const buildXsnap = async (platform, force, { fs, make }) => {
|
|
|
268
316
|
* @param {{
|
|
269
317
|
* env: Record<string, string | undefined>,
|
|
270
318
|
* stdout: typeof process.stdout,
|
|
271
|
-
* spawn: typeof
|
|
319
|
+
* spawn: typeof childProcessTop.spawn,
|
|
272
320
|
* fs: Pick<typeof import('fs'), 'existsSync'> &
|
|
273
|
-
* Pick<typeof promises, 'readFile' | 'writeFile' | 'mkdir' | 'rm' | 'rename'>,
|
|
321
|
+
* Pick<typeof fsTop.promises, 'readFile' | 'writeFile' | 'mkdir' | 'rm' | 'rename'>,
|
|
274
322
|
* os: Pick<typeof import('os'), 'type'>,
|
|
275
323
|
* }} io
|
|
276
324
|
*/
|
|
277
325
|
async function main(args, { env, stdout, spawn, fs, os }) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
await null;
|
|
326
|
+
const pjson = await fs.readFile(asset('../package.json'), 'utf-8');
|
|
327
|
+
const pkg = JSON.parse(pjson);
|
|
281
328
|
|
|
282
329
|
const osType = os.type();
|
|
283
330
|
const platform = ModdableSDK.platforms[osType];
|
|
@@ -291,10 +338,13 @@ async function main(args, { env, stdout, spawn, fs, os }) {
|
|
|
291
338
|
|
|
292
339
|
/** @type {Record<string, string>} */
|
|
293
340
|
let pinnedEnvFromFile = {};
|
|
341
|
+
/** @type {(string | [string, string])[]} */
|
|
342
|
+
let pinnedEnvTextEntries = [];
|
|
294
343
|
let hasPinnedEnvFile = false;
|
|
295
344
|
try {
|
|
296
345
|
const text = await fs.readFile(asset('../build.env'), 'utf-8');
|
|
297
|
-
pinnedEnvFromFile =
|
|
346
|
+
({ record: pinnedEnvFromFile, entries: pinnedEnvTextEntries } =
|
|
347
|
+
parseEnvTextEntries(text));
|
|
298
348
|
hasPinnedEnvFile = true;
|
|
299
349
|
} catch (_err) {
|
|
300
350
|
// Allow explicit environment overrides to run without a checked-in build.env.
|
|
@@ -363,7 +413,7 @@ async function main(args, { env, stdout, spawn, fs, os }) {
|
|
|
363
413
|
* @returns {Promise<boolean>} whether the source needs to be refreshed from
|
|
364
414
|
* its archive URL based on whether the existing source stamp matches the
|
|
365
415
|
* expected URL and commit hash
|
|
366
|
-
* @throws if the source stamp exists but cannot be read or parsed
|
|
416
|
+
* @throws {Error} if the source stamp exists but cannot be read or parsed
|
|
367
417
|
*/
|
|
368
418
|
const needsSourceRefresh = async source => {
|
|
369
419
|
await null;
|
|
@@ -423,7 +473,9 @@ async function main(args, { env, stdout, spawn, fs, os }) {
|
|
|
423
473
|
|
|
424
474
|
// --show-env reports effective URL/hash pins without making changes.
|
|
425
475
|
if (args.includes('--show-env')) {
|
|
426
|
-
await showEnv(sources, {
|
|
476
|
+
await showEnv(pkg, pinnedEnvFromFile, pinnedEnvTextEntries, sources, {
|
|
477
|
+
stdout,
|
|
478
|
+
});
|
|
427
479
|
return;
|
|
428
480
|
}
|
|
429
481
|
|
|
@@ -442,7 +494,7 @@ async function main(args, { env, stdout, spawn, fs, os }) {
|
|
|
442
494
|
isRejected(
|
|
443
495
|
npm.run(['run', '-s', 'check-version'], { cwd: asset('..') }),
|
|
444
496
|
));
|
|
445
|
-
await buildXsnap(platform, force, { fs, make });
|
|
497
|
+
await buildXsnap(pkg, platform, force, { fs, make });
|
|
446
498
|
} else if (!hasBin) {
|
|
447
499
|
throw Error(
|
|
448
500
|
'XSnap has neither sources nor a pre-built binary. Docker? .dockerignore? npm files?',
|
package/src/install-prebuilt.js
CHANGED
|
@@ -6,7 +6,6 @@ import osTop from 'node:os';
|
|
|
6
6
|
import pathTop from 'node:path';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
8
|
import * as childProcess from 'node:child_process';
|
|
9
|
-
import { manifestHashes } from './prebuilt-manifest-sha256.js';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* @import {promises as fsPromises} from 'fs';
|
|
@@ -202,17 +201,22 @@ const validateTarball = async (tarballPath, expectedFiles) => {
|
|
|
202
201
|
};
|
|
203
202
|
|
|
204
203
|
/**
|
|
205
|
-
* @param {string}
|
|
206
|
-
* @
|
|
204
|
+
* @param {string} text
|
|
205
|
+
* @returns {Record<string, string>}
|
|
207
206
|
*/
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
);
|
|
207
|
+
const parseEnvText = text => {
|
|
208
|
+
/** @type {Record<string, string>} */
|
|
209
|
+
const envMap = {};
|
|
210
|
+
for (const line of text.split('\n')) {
|
|
211
|
+
const trimmed = line.trim();
|
|
212
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
213
|
+
const index = trimmed.indexOf('=');
|
|
214
|
+
if (index <= 0) continue;
|
|
215
|
+
const key = trimmed.slice(0, index);
|
|
216
|
+
const value = trimmed.slice(index + 1);
|
|
217
|
+
envMap[key] = value;
|
|
214
218
|
}
|
|
215
|
-
return
|
|
219
|
+
return envMap;
|
|
216
220
|
};
|
|
217
221
|
|
|
218
222
|
const main = async () => {
|
|
@@ -222,10 +226,44 @@ const main = async () => {
|
|
|
222
226
|
return;
|
|
223
227
|
}
|
|
224
228
|
|
|
225
|
-
|
|
229
|
+
await null;
|
|
230
|
+
|
|
231
|
+
const packageJsonPath = env.npm_package_json || asset('../package.json');
|
|
232
|
+
const buildEnvPath = pathTop.join(
|
|
233
|
+
pathTop.dirname(packageJsonPath),
|
|
234
|
+
'build.env',
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
let buildEnv = {};
|
|
238
|
+
try {
|
|
239
|
+
const buildEnvContents = await fsTop.promises.readFile(buildEnvPath, {
|
|
240
|
+
encoding: 'utf8',
|
|
241
|
+
});
|
|
242
|
+
buildEnv = parseEnvText(buildEnvContents);
|
|
243
|
+
} catch (e) {
|
|
244
|
+
if (e?.code !== 'ENOENT') {
|
|
245
|
+
throw Error(`Cannot parse ${buildEnvPath}: ${e}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const version =
|
|
250
|
+
env.XSNAP_BINARY_VERSION ||
|
|
251
|
+
buildEnv.XSNAP_BINARY_VERSION ||
|
|
252
|
+
env.npm_package_version;
|
|
253
|
+
const expectedManifestHash =
|
|
254
|
+
env.XSNAP_BINARY_MANIFEST_SHA256 ||
|
|
255
|
+
env.XSNAP_BINARY_MANIFEST_HASH ||
|
|
256
|
+
buildEnv.XSNAP_BINARY_MANIFEST_HASH;
|
|
257
|
+
|
|
226
258
|
if (!version) {
|
|
227
259
|
throw Error(
|
|
228
|
-
'Missing XSNAP_BINARY_VERSION
|
|
260
|
+
'Missing $XSNAP_BINARY_VERSION, build.env $XSNAP_BINARY_VERSION, or npm package version; cannot resolve prebuilt release',
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (!expectedManifestHash) {
|
|
265
|
+
throw Error(
|
|
266
|
+
`Missing $XSNAP_BINARY_MANIFEST_SHA256 or build.env $XSNAP_BINARY_MANIFEST_HASH; cannot resolve prebuilt manifest hash`,
|
|
229
267
|
);
|
|
230
268
|
}
|
|
231
269
|
|
|
@@ -249,7 +287,6 @@ const main = async () => {
|
|
|
249
287
|
const tarballPath = pathTop.join(cacheRoot, tarballName);
|
|
250
288
|
const manifestPath = pathTop.join(cacheRoot, manifestName);
|
|
251
289
|
const extractRoot = pathTop.join(cacheRoot, 'bundle');
|
|
252
|
-
const expectedManifestHash = getExpectedManifestHash(version, env);
|
|
253
290
|
|
|
254
291
|
const releaseSrc = pathTop.join(
|
|
255
292
|
extractRoot,
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export const manifestHashes = {
|
|
2
|
-
'0.14.2': '377030e37b10554e73d0aff655639051d33281c9e17e7da98275fb9efcaae6f2',
|
|
3
|
-
'0.15.0': 'b481d7d5e66ed17a00624c9fea2f666b097e3bbef0d244201dd26a09e34064f1',
|
|
4
|
-
'0.16.0-u23.0':
|
|
5
|
-
'97400cbffc970b7e9172882d8f6c5b861f0c714b929822195b5818ca4f447197',
|
|
6
|
-
};
|