ic-mops 2.16.0 → 2.16.1
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/CHANGELOG.md +5 -0
- package/bundle/cli.tgz +0 -0
- package/cli.ts +6 -3
- package/commands/bench.ts +29 -12
- package/commands/build.ts +3 -2
- package/commands/check-stable.ts +5 -3
- package/commands/check.ts +5 -3
- package/commands/generate.ts +3 -2
- package/commands/test/test.ts +12 -4
- package/commands/test/utils.ts +6 -2
- package/dist/cli.js +3 -3
- package/dist/commands/bench.js +20 -10
- package/dist/commands/build.js +2 -2
- package/dist/commands/check-stable.js +3 -3
- package/dist/commands/check.js +3 -3
- package/dist/commands/generate.js +2 -2
- package/dist/commands/test/test.js +11 -4
- package/dist/commands/test/utils.d.ts +1 -1
- package/dist/commands/test/utils.js +2 -2
- package/dist/error.d.ts +1 -0
- package/dist/error.js +4 -0
- package/dist/package.json +1 -1
- package/dist/tests/bench.test.d.ts +1 -0
- package/dist/tests/bench.test.js +21 -0
- package/error.ts +5 -0
- package/package.json +1 -1
- package/tests/bench/bench/sanity.bench.mo +27 -0
- package/tests/bench/mops.toml +6 -0
- package/tests/bench.test.ts +22 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## Next
|
|
4
4
|
|
|
5
|
+
## 2.16.1
|
|
6
|
+
|
|
7
|
+
- Fix `mops bench` crashing on moc 0.15+ with the default `--gc copying`: `--copying-gc` is rejected under enhanced orthogonal persistence, which became the default persistence mode in 2.16.0. The default GC is now `incremental` (moc's default and the only collector available under EOP). Selecting a legacy collector (`copying`, `compacting`, `generational`) now implies `--legacy-persistence`, since moc only accepts them there.
|
|
8
|
+
- `mops build`, `mops check`, `mops generate`, and `mops check-stable` now tunnel `moc`'s exit code instead of always exiting `1`. moc exits `2` on a compiler crash (uncaught internal error) versus `1` for normal user errors (type/compile errors, stable-compat mismatch, bad args), so CI and scripts can now distinguish "file a Motoko bug" from "fix your code" via `$?`. `mops test` likewise exits `2` when a `moc` process crashes during a test run, instead of reporting it as an ordinary test failure.
|
|
9
|
+
|
|
5
10
|
## 2.16.0
|
|
6
11
|
|
|
7
12
|
- `mops bench` now compiles benchmark canisters under **enhanced orthogonal persistence** (moc's default) instead of forcing `--legacy-persistence` — measuring the persistence mode real canisters run. Pass `--legacy-persistence` to opt back into legacy persistence.
|
package/bundle/cli.tgz
CHANGED
|
Binary file
|
package/cli.ts
CHANGED
|
@@ -544,9 +544,12 @@ program
|
|
|
544
544
|
).choices(["dfx", "pocket-ic"]),
|
|
545
545
|
)
|
|
546
546
|
.addOption(
|
|
547
|
-
new Option(
|
|
547
|
+
new Option(
|
|
548
|
+
"--gc <gc>",
|
|
549
|
+
"Garbage collector. Under enhanced orthogonal persistence (the default) the GC is fixed to `incremental`; selecting `copying`, `compacting`, or `generational` implies `--legacy-persistence`",
|
|
550
|
+
)
|
|
548
551
|
.choices(["copying", "compacting", "generational", "incremental"])
|
|
549
|
-
.default("
|
|
552
|
+
.default("incremental"),
|
|
550
553
|
)
|
|
551
554
|
.addOption(
|
|
552
555
|
new Option("--save", "Save benchmark results to .bench/<filename>.json"),
|
|
@@ -573,7 +576,7 @@ program
|
|
|
573
576
|
.addOption(
|
|
574
577
|
new Option(
|
|
575
578
|
"--verbose",
|
|
576
|
-
"Print the benchmark pipeline (compiler, replica, GC, optimization) and stream compiler/replica output, including dfx optimization warnings",
|
|
579
|
+
"Print the benchmark pipeline (compiler, replica, GC, context, persistence, profile, optimization) and stream compiler/replica output, including dfx optimization warnings",
|
|
577
580
|
),
|
|
578
581
|
)
|
|
579
582
|
.action(async (filter, options) => {
|
package/commands/bench.ts
CHANGED
|
@@ -61,7 +61,7 @@ export async function bench(
|
|
|
61
61
|
replicaVersion: "",
|
|
62
62
|
compiler: "moc",
|
|
63
63
|
compilerVersion: getMocVersion(true),
|
|
64
|
-
gc: "
|
|
64
|
+
gc: "incremental",
|
|
65
65
|
forceGc: true,
|
|
66
66
|
query: false,
|
|
67
67
|
legacyPersistence: false,
|
|
@@ -112,6 +112,8 @@ export async function bench(
|
|
|
112
112
|
replicaType === "dfx" || replicaType === "dfx-pocket-ic"
|
|
113
113
|
? 'dfx `optimize: "cycles"` (ic-wasm) on deploy'
|
|
114
114
|
: "none (raw moc output)";
|
|
115
|
+
let legacyGc = isLegacyGc(options.gc);
|
|
116
|
+
let effectiveLegacyPersistence = options.legacyPersistence || legacyGc;
|
|
115
117
|
console.log(chalk.gray("Benchmark pipeline:"));
|
|
116
118
|
console.log(chalk.gray(` compiler: moc ${options.compilerVersion}`));
|
|
117
119
|
console.log(
|
|
@@ -129,9 +131,16 @@ export async function bench(
|
|
|
129
131
|
);
|
|
130
132
|
console.log(
|
|
131
133
|
chalk.gray(
|
|
132
|
-
` persistence: ${
|
|
134
|
+
` persistence: ${effectiveLegacyPersistence ? "legacy" : "enhanced"}`,
|
|
133
135
|
),
|
|
134
136
|
);
|
|
137
|
+
if (legacyGc && !options.legacyPersistence) {
|
|
138
|
+
console.log(
|
|
139
|
+
chalk.gray(
|
|
140
|
+
` (gc '${options.gc}' only exists under legacy persistence; enabling --legacy-persistence)`,
|
|
141
|
+
),
|
|
142
|
+
);
|
|
143
|
+
}
|
|
135
144
|
console.log(chalk.gray(` profile: ${options.profile}`));
|
|
136
145
|
console.log(chalk.gray(` optimize: ${optimize}`));
|
|
137
146
|
}
|
|
@@ -279,18 +288,25 @@ function computeDiffAll(
|
|
|
279
288
|
return diff;
|
|
280
289
|
}
|
|
281
290
|
|
|
291
|
+
// Collectors that only exist under legacy persistence. moc 0.15+ fixes the GC to
|
|
292
|
+
// incremental under enhanced orthogonal persistence and rejects these there.
|
|
293
|
+
function isLegacyGc(gc: BenchOptions["gc"]): boolean {
|
|
294
|
+
return gc === "copying" || gc === "compacting" || gc === "generational";
|
|
295
|
+
}
|
|
296
|
+
|
|
282
297
|
function getMocArgs(options: BenchOptions): string {
|
|
283
298
|
let args = "";
|
|
284
299
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
300
|
+
let mocAtLeast015 =
|
|
301
|
+
!!options.compilerVersion &&
|
|
302
|
+
new SemVer(options.compilerVersion).compare("0.15.0") >= 0;
|
|
303
|
+
|
|
304
|
+
// Legacy collectors require legacy persistence; moc < 0.15 is already legacy
|
|
305
|
+
// and has no --legacy-persistence flag.
|
|
306
|
+
let useLegacyPersistence =
|
|
307
|
+
options.legacyPersistence || isLegacyGc(options.gc);
|
|
308
|
+
|
|
309
|
+
if (useLegacyPersistence && mocAtLeast015) {
|
|
294
310
|
args += " --legacy-persistence";
|
|
295
311
|
}
|
|
296
312
|
|
|
@@ -298,7 +314,8 @@ function getMocArgs(options: BenchOptions): string {
|
|
|
298
314
|
args += " --force-gc";
|
|
299
315
|
}
|
|
300
316
|
|
|
301
|
-
|
|
317
|
+
// Under EOP the GC is fixed; only pass a collector flag where it's selectable.
|
|
318
|
+
if (options.gc && (useLegacyPersistence || !mocAtLeast015)) {
|
|
302
319
|
args += ` --${options.gc}-gc`;
|
|
303
320
|
}
|
|
304
321
|
|
package/commands/build.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { exists } from "fs-extra";
|
|
|
4
4
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { lock, unlockSync } from "proper-lockfile";
|
|
7
|
-
import { cliError } from "../error.js";
|
|
7
|
+
import { cliError, cliExit } from "../error.js";
|
|
8
8
|
import { isCandidCompatible } from "../helpers/is-candid-compatible.js";
|
|
9
9
|
import {
|
|
10
10
|
filterCanisters,
|
|
@@ -136,7 +136,8 @@ export async function build(
|
|
|
136
136
|
console.error(result.stdout);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
-
|
|
139
|
+
cliExit(
|
|
140
|
+
result.exitCode ?? 1,
|
|
140
141
|
`Build failed for canister ${canisterName} (exit code: ${result.exitCode})`,
|
|
141
142
|
);
|
|
142
143
|
}
|
package/commands/check-stable.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync, mkdtempSync } from "node:fs";
|
|
|
3
3
|
import { rm } from "node:fs/promises";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { execa } from "execa";
|
|
6
|
-
import { cliError } from "../error.js";
|
|
6
|
+
import { cliError, cliExit } from "../error.js";
|
|
7
7
|
import {
|
|
8
8
|
getCheckLimitPendingIssue,
|
|
9
9
|
prepareMigrationArgs,
|
|
@@ -261,7 +261,8 @@ export async function runStableCheck(
|
|
|
261
261
|
if (result.stderr) {
|
|
262
262
|
console.error(result.stderr);
|
|
263
263
|
}
|
|
264
|
-
|
|
264
|
+
cliExit(
|
|
265
|
+
result.exitCode ?? 1,
|
|
265
266
|
`✗ Stable compatibility check failed for canister '${canisterName}'`,
|
|
266
267
|
);
|
|
267
268
|
}
|
|
@@ -314,7 +315,8 @@ async function generateStableTypes(
|
|
|
314
315
|
if (result.stderr) {
|
|
315
316
|
console.error(result.stderr);
|
|
316
317
|
}
|
|
317
|
-
|
|
318
|
+
cliExit(
|
|
319
|
+
result.exitCode ?? 1,
|
|
318
320
|
`Failed to generate stable types for ${moFile} (exit code: ${result.exitCode})`,
|
|
319
321
|
);
|
|
320
322
|
}
|
package/commands/check.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { execa } from "execa";
|
|
4
|
-
import { cliError } from "../error.js";
|
|
4
|
+
import { cliError, cliExit } from "../error.js";
|
|
5
5
|
import {
|
|
6
6
|
getGlobalMocArgs,
|
|
7
7
|
getRootDir,
|
|
@@ -208,7 +208,8 @@ async function checkCanisters(
|
|
|
208
208
|
});
|
|
209
209
|
|
|
210
210
|
if (result.exitCode !== 0) {
|
|
211
|
-
|
|
211
|
+
cliExit(
|
|
212
|
+
result.exitCode ?? 1,
|
|
212
213
|
`✗ Check failed for canister ${canisterName} (exit code: ${result.exitCode})`,
|
|
213
214
|
);
|
|
214
215
|
}
|
|
@@ -285,7 +286,8 @@ async function checkFiles(
|
|
|
285
286
|
});
|
|
286
287
|
|
|
287
288
|
if (result.exitCode !== 0) {
|
|
288
|
-
|
|
289
|
+
cliExit(
|
|
290
|
+
result.exitCode ?? 1,
|
|
289
291
|
`✗ Check failed for file ${file} (exit code: ${result.exitCode})`,
|
|
290
292
|
);
|
|
291
293
|
}
|
package/commands/generate.ts
CHANGED
|
@@ -2,7 +2,7 @@ import chalk from "chalk";
|
|
|
2
2
|
import { execa } from "execa";
|
|
3
3
|
import { mkdir } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { cliError } from "../error.js";
|
|
5
|
+
import { cliError, cliExit } from "../error.js";
|
|
6
6
|
import {
|
|
7
7
|
filterCanisters,
|
|
8
8
|
resolveCanisterConfigs,
|
|
@@ -104,7 +104,8 @@ export async function generateCandid(
|
|
|
104
104
|
console.error(result.stdout);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
|
|
107
|
+
cliExit(
|
|
108
|
+
result.exitCode ?? 1,
|
|
108
109
|
`Failed to generate Candid for canister ${canisterName} (exit code: ${result.exitCode})`,
|
|
109
110
|
);
|
|
110
111
|
}
|
package/commands/test/test.ts
CHANGED
|
@@ -159,7 +159,7 @@ export async function test(filter = "", options: Partial<TestOptions> = {}) {
|
|
|
159
159
|
explicitReplica,
|
|
160
160
|
);
|
|
161
161
|
if (!passed) {
|
|
162
|
-
process.exit(1);
|
|
162
|
+
process.exit(maxMocExit >= 2 ? 2 : 1);
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
}
|
|
@@ -167,6 +167,13 @@ export async function test(filter = "", options: Partial<TestOptions> = {}) {
|
|
|
167
167
|
let mocPath = "";
|
|
168
168
|
let wasmtimePath = "";
|
|
169
169
|
|
|
170
|
+
let maxMocExit = 0;
|
|
171
|
+
const trackMocExit = (code: number | null) => {
|
|
172
|
+
if (code && code >= 2) {
|
|
173
|
+
maxMocExit = Math.max(maxMocExit, code);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
170
177
|
async function runAll(
|
|
171
178
|
reporterName: ReporterName | undefined,
|
|
172
179
|
filter = "",
|
|
@@ -197,6 +204,7 @@ export async function testWithReporter(
|
|
|
197
204
|
signal?: AbortSignal,
|
|
198
205
|
explicitReplica = false,
|
|
199
206
|
): Promise<boolean> {
|
|
207
|
+
maxMocExit = 0;
|
|
200
208
|
let rootDir = getRootDir();
|
|
201
209
|
let files: string[] = [];
|
|
202
210
|
let libFiles = globSync("**/test?(s)/lib.mo", MOTOKO_GLOB_CONFIG);
|
|
@@ -328,7 +336,7 @@ export async function testWithReporter(
|
|
|
328
336
|
}
|
|
329
337
|
throw error;
|
|
330
338
|
});
|
|
331
|
-
pipeMMF(proc, mmf).then(resolve);
|
|
339
|
+
pipeMMF(proc, mmf, trackMocExit).then(resolve);
|
|
332
340
|
}
|
|
333
341
|
// build and run wasm
|
|
334
342
|
else if (mode === "wasi") {
|
|
@@ -346,7 +354,7 @@ export async function testWithReporter(
|
|
|
346
354
|
}
|
|
347
355
|
throw error;
|
|
348
356
|
});
|
|
349
|
-
pipeMMF(buildProc, mmf)
|
|
357
|
+
pipeMMF(buildProc, mmf, trackMocExit)
|
|
350
358
|
.then(async () => {
|
|
351
359
|
if (mmf.failed > 0) {
|
|
352
360
|
return;
|
|
@@ -413,7 +421,7 @@ export async function testWithReporter(
|
|
|
413
421
|
throw error;
|
|
414
422
|
});
|
|
415
423
|
|
|
416
|
-
pipeMMF(buildProc, mmf)
|
|
424
|
+
pipeMMF(buildProc, mmf, trackMocExit)
|
|
417
425
|
.then(async () => {
|
|
418
426
|
if (mmf.failed > 0) {
|
|
419
427
|
return;
|
package/commands/test/utils.ts
CHANGED
|
@@ -68,18 +68,22 @@ export function pipeStderrToMMF(stderr: Readable, mmf: MMF1, dir = "") {
|
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
export function pipeMMF(
|
|
71
|
+
export function pipeMMF(
|
|
72
|
+
proc: ChildProcessWithoutNullStreams,
|
|
73
|
+
mmf: MMF1,
|
|
74
|
+
onClose?: (code: number | null) => void,
|
|
75
|
+
) {
|
|
72
76
|
return new Promise<void>((resolve) => {
|
|
73
77
|
pipeStdoutToMMF(proc.stdout, mmf);
|
|
74
78
|
pipeStderrToMMF(proc.stderr, mmf);
|
|
75
79
|
|
|
76
|
-
// exit
|
|
77
80
|
proc.on("close", (code) => {
|
|
78
81
|
if (code === 0) {
|
|
79
82
|
mmf.strategy !== "print" && mmf.pass();
|
|
80
83
|
} else if (code !== 1) {
|
|
81
84
|
mmf.fail(`unknown exit code: ${code}`);
|
|
82
85
|
}
|
|
86
|
+
onClose?.(code ?? null);
|
|
83
87
|
resolve();
|
|
84
88
|
});
|
|
85
89
|
});
|
package/dist/cli.js
CHANGED
|
@@ -395,15 +395,15 @@ program
|
|
|
395
395
|
.command("bench [filter]")
|
|
396
396
|
.description("Run benchmarks")
|
|
397
397
|
.addOption(new Option("--replica <replica>", "Which replica to use to run benchmarks (`dfx` is deprecated; prefer `pocket-ic`)").choices(["dfx", "pocket-ic"]))
|
|
398
|
-
.addOption(new Option("--gc <gc>", "Garbage collector")
|
|
398
|
+
.addOption(new Option("--gc <gc>", "Garbage collector. Under enhanced orthogonal persistence (the default) the GC is fixed to `incremental`; selecting `copying`, `compacting`, or `generational` implies `--legacy-persistence`")
|
|
399
399
|
.choices(["copying", "compacting", "generational", "incremental"])
|
|
400
|
-
.default("
|
|
400
|
+
.default("incremental"))
|
|
401
401
|
.addOption(new Option("--save", "Save benchmark results to .bench/<filename>.json"))
|
|
402
402
|
.addOption(new Option("--compare", "Run benchmark and compare results with .bench/<filename>.json"))
|
|
403
403
|
// .addOption(new Option('--force-gc', 'Force GC'))
|
|
404
404
|
.addOption(new Option("--query", "Measure each cell in a query call (how `query` methods run on the IC: no GC). Only for benchmarks whose runner is synchronous (no inter-canister calls)"))
|
|
405
405
|
.addOption(new Option("--legacy-persistence", "Compile benchmark canisters under legacy persistence instead of enhanced orthogonal persistence (the default)"))
|
|
406
|
-
.addOption(new Option("--verbose", "Print the benchmark pipeline (compiler, replica, GC, optimization) and stream compiler/replica output, including dfx optimization warnings"))
|
|
406
|
+
.addOption(new Option("--verbose", "Print the benchmark pipeline (compiler, replica, GC, context, persistence, profile, optimization) and stream compiler/replica output, including dfx optimization warnings"))
|
|
407
407
|
.action(async (filter, options) => {
|
|
408
408
|
checkConfigFile(true);
|
|
409
409
|
await installAll({
|
package/dist/commands/bench.js
CHANGED
|
@@ -29,7 +29,7 @@ export async function bench(filter = "", optionsArg = {}) {
|
|
|
29
29
|
replicaVersion: "",
|
|
30
30
|
compiler: "moc",
|
|
31
31
|
compilerVersion: getMocVersion(true),
|
|
32
|
-
gc: "
|
|
32
|
+
gc: "incremental",
|
|
33
33
|
forceGc: true,
|
|
34
34
|
query: false,
|
|
35
35
|
legacyPersistence: false,
|
|
@@ -69,12 +69,17 @@ export async function bench(filter = "", optionsArg = {}) {
|
|
|
69
69
|
let optimize = replicaType === "dfx" || replicaType === "dfx-pocket-ic"
|
|
70
70
|
? 'dfx `optimize: "cycles"` (ic-wasm) on deploy'
|
|
71
71
|
: "none (raw moc output)";
|
|
72
|
+
let legacyGc = isLegacyGc(options.gc);
|
|
73
|
+
let effectiveLegacyPersistence = options.legacyPersistence || legacyGc;
|
|
72
74
|
console.log(chalk.gray("Benchmark pipeline:"));
|
|
73
75
|
console.log(chalk.gray(` compiler: moc ${options.compilerVersion}`));
|
|
74
76
|
console.log(chalk.gray(` replica: ${replicaType}${options.replicaVersion ? ` ${options.replicaVersion}` : ""}`));
|
|
75
77
|
console.log(chalk.gray(` gc: ${options.gc}${options.forceGc ? " (forced)" : ""}`));
|
|
76
78
|
console.log(chalk.gray(` context: ${options.query ? "query" : "update"}`));
|
|
77
|
-
console.log(chalk.gray(` persistence: ${
|
|
79
|
+
console.log(chalk.gray(` persistence: ${effectiveLegacyPersistence ? "legacy" : "enhanced"}`));
|
|
80
|
+
if (legacyGc && !options.legacyPersistence) {
|
|
81
|
+
console.log(chalk.gray(` (gc '${options.gc}' only exists under legacy persistence; enabling --legacy-persistence)`));
|
|
82
|
+
}
|
|
78
83
|
console.log(chalk.gray(` profile: ${options.profile}`));
|
|
79
84
|
console.log(chalk.gray(` optimize: ${optimize}`));
|
|
80
85
|
}
|
|
@@ -190,21 +195,26 @@ function computeDiffAll(currentResults, prevResults, rows, cols) {
|
|
|
190
195
|
}
|
|
191
196
|
return diff;
|
|
192
197
|
}
|
|
198
|
+
// Collectors that only exist under legacy persistence. moc 0.15+ fixes the GC to
|
|
199
|
+
// incremental under enhanced orthogonal persistence and rejects these there.
|
|
200
|
+
function isLegacyGc(gc) {
|
|
201
|
+
return gc === "copying" || gc === "compacting" || gc === "generational";
|
|
202
|
+
}
|
|
193
203
|
function getMocArgs(options) {
|
|
194
204
|
let args = "";
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
new SemVer(options.compilerVersion).compare("0.15.0") >= 0) {
|
|
205
|
+
let mocAtLeast015 = !!options.compilerVersion &&
|
|
206
|
+
new SemVer(options.compilerVersion).compare("0.15.0") >= 0;
|
|
207
|
+
// Legacy collectors require legacy persistence; moc < 0.15 is already legacy
|
|
208
|
+
// and has no --legacy-persistence flag.
|
|
209
|
+
let useLegacyPersistence = options.legacyPersistence || isLegacyGc(options.gc);
|
|
210
|
+
if (useLegacyPersistence && mocAtLeast015) {
|
|
202
211
|
args += " --legacy-persistence";
|
|
203
212
|
}
|
|
204
213
|
if (options.forceGc) {
|
|
205
214
|
args += " --force-gc";
|
|
206
215
|
}
|
|
207
|
-
|
|
216
|
+
// Under EOP the GC is fixed; only pass a collector flag where it's selectable.
|
|
217
|
+
if (options.gc && (useLegacyPersistence || !mocAtLeast015)) {
|
|
208
218
|
args += ` --${options.gc}-gc`;
|
|
209
219
|
}
|
|
210
220
|
if (options.profile === "Debug") {
|
package/dist/commands/build.js
CHANGED
|
@@ -4,7 +4,7 @@ import { exists } from "fs-extra";
|
|
|
4
4
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { lock, unlockSync } from "proper-lockfile";
|
|
7
|
-
import { cliError } from "../error.js";
|
|
7
|
+
import { cliError, cliExit } from "../error.js";
|
|
8
8
|
import { isCandidCompatible } from "../helpers/is-candid-compatible.js";
|
|
9
9
|
import { filterCanisters, resolveCanisterConfigs, } from "../helpers/resolve-canisters.js";
|
|
10
10
|
import { BUILD_MANAGED_FLAGS, prepareMocArgs } from "../helpers/moc-args.js";
|
|
@@ -107,7 +107,7 @@ export async function build(canisterNames, options) {
|
|
|
107
107
|
console.error(result.stdout);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
|
|
110
|
+
cliExit(result.exitCode ?? 1, `Build failed for canister ${canisterName} (exit code: ${result.exitCode})`);
|
|
111
111
|
}
|
|
112
112
|
if (options.verbose && result.stdout && result.stdout.trim()) {
|
|
113
113
|
console.log(result.stdout);
|
|
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync, mkdtempSync } from "node:fs";
|
|
|
3
3
|
import { rm } from "node:fs/promises";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { execa } from "execa";
|
|
6
|
-
import { cliError } from "../error.js";
|
|
6
|
+
import { cliError, cliExit } from "../error.js";
|
|
7
7
|
import { getCheckLimitPendingIssue, prepareMigrationArgs, reportCheckLimitPendingIssue, } from "../helpers/migrations.js";
|
|
8
8
|
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
9
9
|
import { filterCanisters, looksLikeFile, resolveCanisterConfigs, resolveSingleCanister, validateCanisterArgs, } from "../helpers/resolve-canisters.js";
|
|
@@ -146,7 +146,7 @@ export async function runStableCheck(params) {
|
|
|
146
146
|
if (result.stderr) {
|
|
147
147
|
console.error(result.stderr);
|
|
148
148
|
}
|
|
149
|
-
|
|
149
|
+
cliExit(result.exitCode ?? 1, `✗ Stable compatibility check failed for canister '${canisterName}'`);
|
|
150
150
|
}
|
|
151
151
|
console.log(chalk.green(`✓ Stable compatibility check passed for canister '${canisterName}'`));
|
|
152
152
|
}
|
|
@@ -178,7 +178,7 @@ async function generateStableTypes(mocPath, moFile, outputPath, sources, globalM
|
|
|
178
178
|
if (result.stderr) {
|
|
179
179
|
console.error(result.stderr);
|
|
180
180
|
}
|
|
181
|
-
|
|
181
|
+
cliExit(result.exitCode ?? 1, `Failed to generate stable types for ${moFile} (exit code: ${result.exitCode})`);
|
|
182
182
|
}
|
|
183
183
|
await rm(wasmPath, { force: true });
|
|
184
184
|
return outputPath;
|
package/dist/commands/check.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { execa } from "execa";
|
|
4
|
-
import { cliError } from "../error.js";
|
|
4
|
+
import { cliError, cliExit } from "../error.js";
|
|
5
5
|
import { getGlobalMocArgs, getRootDir, readConfig, resolveConfigPath, } from "../mops.js";
|
|
6
6
|
import { autofixMotoko } from "../helpers/autofix-motoko.js";
|
|
7
7
|
import { withFixLock } from "../helpers/fix-lock.js";
|
|
@@ -127,7 +127,7 @@ async function checkCanisters(config, canisters, options) {
|
|
|
127
127
|
reject: false,
|
|
128
128
|
});
|
|
129
129
|
if (result.exitCode !== 0) {
|
|
130
|
-
|
|
130
|
+
cliExit(result.exitCode ?? 1, `✗ Check failed for canister ${canisterName} (exit code: ${result.exitCode})`);
|
|
131
131
|
}
|
|
132
132
|
console.log(chalk.green(`✓ ${canisterName}`));
|
|
133
133
|
}
|
|
@@ -189,7 +189,7 @@ async function checkFiles(config, files, options) {
|
|
|
189
189
|
reject: false,
|
|
190
190
|
});
|
|
191
191
|
if (result.exitCode !== 0) {
|
|
192
|
-
|
|
192
|
+
cliExit(result.exitCode ?? 1, `✗ Check failed for file ${file} (exit code: ${result.exitCode})`);
|
|
193
193
|
}
|
|
194
194
|
console.log(chalk.green(`✓ ${file}`));
|
|
195
195
|
}
|
|
@@ -2,7 +2,7 @@ import chalk from "chalk";
|
|
|
2
2
|
import { execa } from "execa";
|
|
3
3
|
import { mkdir } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { cliError } from "../error.js";
|
|
5
|
+
import { cliError, cliExit } from "../error.js";
|
|
6
6
|
import { filterCanisters, resolveCanisterConfigs, } from "../helpers/resolve-canisters.js";
|
|
7
7
|
import { GENERATE_CANDID_MANAGED_FLAGS, prepareMocArgs, } from "../helpers/moc-args.js";
|
|
8
8
|
import { getRootDir, readConfig, resolveConfigPath, writeConfig, } from "../mops.js";
|
|
@@ -60,7 +60,7 @@ export async function generateCandid(canisterNames, options) {
|
|
|
60
60
|
console.error(result.stdout);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
cliExit(result.exitCode ?? 1, `Failed to generate Candid for canister ${canisterName} (exit code: ${result.exitCode})`);
|
|
64
64
|
}
|
|
65
65
|
if (dest.configPath !== null) {
|
|
66
66
|
const c = (config.canisters ??= {});
|
|
@@ -98,17 +98,24 @@ export async function test(filter = "", options = {}) {
|
|
|
98
98
|
else {
|
|
99
99
|
let passed = await runAll(options.reporter, filter, options.mode, replicaType, false, undefined, explicitReplica);
|
|
100
100
|
if (!passed) {
|
|
101
|
-
process.exit(1);
|
|
101
|
+
process.exit(maxMocExit >= 2 ? 2 : 1);
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
let mocPath = "";
|
|
106
106
|
let wasmtimePath = "";
|
|
107
|
+
let maxMocExit = 0;
|
|
108
|
+
const trackMocExit = (code) => {
|
|
109
|
+
if (code && code >= 2) {
|
|
110
|
+
maxMocExit = Math.max(maxMocExit, code);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
107
113
|
async function runAll(reporterName, filter = "", mode = "interpreter", replicaType, watch = false, signal, explicitReplica = false) {
|
|
108
114
|
let done = await testWithReporter(reporterName, filter, mode, replicaType, watch, signal, explicitReplica);
|
|
109
115
|
return done;
|
|
110
116
|
}
|
|
111
117
|
export async function testWithReporter(reporterName, filter = "", defaultMode = "interpreter", replicaType, watch = false, signal, explicitReplica = false) {
|
|
118
|
+
maxMocExit = 0;
|
|
112
119
|
let rootDir = getRootDir();
|
|
113
120
|
let files = [];
|
|
114
121
|
let libFiles = globSync("**/test?(s)/lib.mo", MOTOKO_GLOB_CONFIG);
|
|
@@ -217,7 +224,7 @@ export async function testWithReporter(reporterName, filter = "", defaultMode =
|
|
|
217
224
|
}
|
|
218
225
|
throw error;
|
|
219
226
|
});
|
|
220
|
-
pipeMMF(proc, mmf).then(resolve);
|
|
227
|
+
pipeMMF(proc, mmf, trackMocExit).then(resolve);
|
|
221
228
|
}
|
|
222
229
|
// build and run wasm
|
|
223
230
|
else if (mode === "wasi") {
|
|
@@ -230,7 +237,7 @@ export async function testWithReporter(reporterName, filter = "", defaultMode =
|
|
|
230
237
|
}
|
|
231
238
|
throw error;
|
|
232
239
|
});
|
|
233
|
-
pipeMMF(buildProc, mmf)
|
|
240
|
+
pipeMMF(buildProc, mmf, trackMocExit)
|
|
234
241
|
.then(async () => {
|
|
235
242
|
if (mmf.failed > 0) {
|
|
236
243
|
return;
|
|
@@ -288,7 +295,7 @@ export async function testWithReporter(reporterName, filter = "", defaultMode =
|
|
|
288
295
|
}
|
|
289
296
|
throw error;
|
|
290
297
|
});
|
|
291
|
-
pipeMMF(buildProc, mmf)
|
|
298
|
+
pipeMMF(buildProc, mmf, trackMocExit)
|
|
292
299
|
.then(async () => {
|
|
293
300
|
if (mmf.failed > 0) {
|
|
294
301
|
return;
|
|
@@ -4,4 +4,4 @@ import { MMF1 } from "./mmf1.js";
|
|
|
4
4
|
export declare function absToRel(p: string): string;
|
|
5
5
|
export declare function pipeStdoutToMMF(stdout: Readable, mmf: MMF1): void;
|
|
6
6
|
export declare function pipeStderrToMMF(stderr: Readable, mmf: MMF1, dir?: string): void;
|
|
7
|
-
export declare function pipeMMF(proc: ChildProcessWithoutNullStreams, mmf: MMF1): Promise<void>;
|
|
7
|
+
export declare function pipeMMF(proc: ChildProcessWithoutNullStreams, mmf: MMF1, onClose?: (code: number | null) => void): Promise<void>;
|
|
@@ -49,11 +49,10 @@ export function pipeStderrToMMF(stderr, mmf, dir = "") {
|
|
|
49
49
|
mmf.fail(text);
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
|
-
export function pipeMMF(proc, mmf) {
|
|
52
|
+
export function pipeMMF(proc, mmf, onClose) {
|
|
53
53
|
return new Promise((resolve) => {
|
|
54
54
|
pipeStdoutToMMF(proc.stdout, mmf);
|
|
55
55
|
pipeStderrToMMF(proc.stderr, mmf);
|
|
56
|
-
// exit
|
|
57
56
|
proc.on("close", (code) => {
|
|
58
57
|
if (code === 0) {
|
|
59
58
|
mmf.strategy !== "print" && mmf.pass();
|
|
@@ -61,6 +60,7 @@ export function pipeMMF(proc, mmf) {
|
|
|
61
60
|
else if (code !== 1) {
|
|
62
61
|
mmf.fail(`unknown exit code: ${code}`);
|
|
63
62
|
}
|
|
63
|
+
onClose?.(code ?? null);
|
|
64
64
|
resolve();
|
|
65
65
|
});
|
|
66
66
|
});
|
package/dist/error.d.ts
CHANGED
package/dist/error.js
CHANGED
package/dist/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, jest, test } from "@jest/globals";
|
|
2
|
+
import { rmSync } from "node:fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { cli } from "./helpers";
|
|
5
|
+
// Pin moc 1.3.0 (≥ 0.15) to exercise the EOP path — this repo's own mops.toml
|
|
6
|
+
// uses moc 0.14.14, so the default bench run is never EOP-tested here.
|
|
7
|
+
describe("bench", () => {
|
|
8
|
+
jest.setTimeout(180_000);
|
|
9
|
+
test("runs under EOP with the default gc", async () => {
|
|
10
|
+
const cwd = path.join(import.meta.dirname, "bench");
|
|
11
|
+
try {
|
|
12
|
+
const result = await cli(["bench"], { cwd });
|
|
13
|
+
expect(result.stderr).not.toContain("--copying-gc is not supported");
|
|
14
|
+
expect(result.stderr).not.toContain("Invalid compiler flag combination");
|
|
15
|
+
expect(result.exitCode).toBe(0);
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
rmSync(path.join(cwd, ".mops"), { recursive: true, force: true });
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
package/error.ts
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Exercises the bench pipeline under EOP; the template only needs
|
|
2
|
+
// init() -> { getVersion; getSchema; runCell }, so no mo:bench dep.
|
|
3
|
+
module {
|
|
4
|
+
type Schema = {
|
|
5
|
+
name : Text;
|
|
6
|
+
description : Text;
|
|
7
|
+
rows : [Text];
|
|
8
|
+
cols : [Text];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class Bench(schema : Schema, run : (Nat, Nat) -> ()) {
|
|
12
|
+
public func getVersion() : Nat = 1;
|
|
13
|
+
public func getSchema() : Schema = schema;
|
|
14
|
+
public let runCell = run;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
public func init() : Bench {
|
|
18
|
+
let schema : Schema = {
|
|
19
|
+
name = "Sanity";
|
|
20
|
+
description = "Trivial bench to exercise the mops bench pipeline under EOP";
|
|
21
|
+
rows = ["a"];
|
|
22
|
+
cols = ["1"];
|
|
23
|
+
};
|
|
24
|
+
func run(_ri : Nat, _ci : Nat) {};
|
|
25
|
+
Bench(schema, run);
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, jest, test } from "@jest/globals";
|
|
2
|
+
import { rmSync } from "node:fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { cli } from "./helpers";
|
|
5
|
+
|
|
6
|
+
// Pin moc 1.3.0 (≥ 0.15) to exercise the EOP path — this repo's own mops.toml
|
|
7
|
+
// uses moc 0.14.14, so the default bench run is never EOP-tested here.
|
|
8
|
+
describe("bench", () => {
|
|
9
|
+
jest.setTimeout(180_000);
|
|
10
|
+
|
|
11
|
+
test("runs under EOP with the default gc", async () => {
|
|
12
|
+
const cwd = path.join(import.meta.dirname, "bench");
|
|
13
|
+
try {
|
|
14
|
+
const result = await cli(["bench"], { cwd });
|
|
15
|
+
expect(result.stderr).not.toContain("--copying-gc is not supported");
|
|
16
|
+
expect(result.stderr).not.toContain("Invalid compiler flag combination");
|
|
17
|
+
expect(result.exitCode).toBe(0);
|
|
18
|
+
} finally {
|
|
19
|
+
rmSync(path.join(cwd, ".mops"), { recursive: true, force: true });
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
});
|