ic-mops 1.0.1 → 1.1.0
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 +9 -0
- package/bundle/cli.tgz +0 -0
- package/check-requirements.ts +1 -1
- package/cli.ts +29 -5
- package/commands/bench.ts +1 -1
- package/commands/install/install-all.ts +28 -6
- package/commands/install/install-dep.ts +5 -4
- package/commands/install/install-deps.ts +3 -2
- package/commands/install/install-local-dep.ts +11 -5
- package/commands/install/install-mops-dep.ts +8 -5
- package/commands/replica.ts +33 -3
- package/commands/sources.ts +1 -1
- package/commands/sync.ts +4 -19
- package/commands/test/mmf1.ts +4 -0
- package/commands/test/reporters/silent-reporter.ts +22 -4
- package/commands/test/test.ts +74 -10
- package/commands/watch/deployer.ts +155 -0
- package/commands/watch/error-checker.ts +87 -0
- package/commands/watch/generator.ts +99 -0
- package/commands/watch/globMoFiles.ts +16 -0
- package/commands/watch/parseDfxJson.ts +64 -0
- package/commands/watch/tester.ts +81 -0
- package/commands/watch/warning-checker.ts +133 -0
- package/commands/watch/watch.ts +90 -0
- package/declarations/main/main.did +16 -10
- package/declarations/main/main.did.d.ts +19 -10
- package/declarations/main/main.did.js +25 -11
- package/dist/check-requirements.js +1 -1
- package/dist/cli.js +26 -5
- package/dist/commands/bench.js +1 -1
- package/dist/commands/install/install-all.d.ts +2 -1
- package/dist/commands/install/install-all.js +24 -6
- package/dist/commands/install/install-dep.d.ts +2 -1
- package/dist/commands/install/install-dep.js +4 -4
- package/dist/commands/install/install-deps.d.ts +2 -1
- package/dist/commands/install/install-deps.js +2 -2
- package/dist/commands/install/install-local-dep.d.ts +2 -1
- package/dist/commands/install/install-local-dep.js +9 -4
- package/dist/commands/install/install-mops-dep.d.ts +2 -1
- package/dist/commands/install/install-mops-dep.js +7 -5
- package/dist/commands/replica.d.ts +2 -2
- package/dist/commands/replica.js +26 -3
- package/dist/commands/sources.d.ts +1 -1
- package/dist/commands/sources.js +1 -1
- package/dist/commands/sync.js +3 -18
- package/dist/commands/test/mmf1.d.ts +1 -0
- package/dist/commands/test/mmf1.js +3 -0
- package/dist/commands/test/reporters/silent-reporter.d.ts +6 -1
- package/dist/commands/test/reporters/silent-reporter.js +18 -5
- package/dist/commands/test/test.d.ts +1 -1
- package/dist/commands/test/test.js +62 -10
- package/dist/commands/watch/deployer.d.ts +24 -0
- package/dist/commands/watch/deployer.js +125 -0
- package/dist/commands/watch/error-checker.d.ts +13 -0
- package/dist/commands/watch/error-checker.js +76 -0
- package/dist/commands/watch/generator.d.ts +21 -0
- package/dist/commands/watch/generator.js +79 -0
- package/dist/commands/watch/globMoFiles.d.ts +1 -0
- package/dist/commands/watch/globMoFiles.js +14 -0
- package/dist/commands/watch/parseDfxJson.d.ts +2 -0
- package/dist/commands/watch/parseDfxJson.js +22 -0
- package/dist/commands/watch/tester.d.ts +19 -0
- package/dist/commands/watch/tester.js +63 -0
- package/dist/commands/watch/warning-checker.d.ts +20 -0
- package/dist/commands/watch/warning-checker.js +111 -0
- package/dist/commands/watch/watch.d.ts +7 -0
- package/dist/commands/watch/watch.js +79 -0
- package/dist/declarations/main/main.did +16 -10
- package/dist/declarations/main/main.did.d.ts +19 -10
- package/dist/declarations/main/main.did.js +25 -11
- package/dist/helpers/get-moc-path.d.ts +1 -1
- package/dist/helpers/get-moc-path.js +17 -3
- package/dist/helpers/get-moc-version.d.ts +1 -1
- package/dist/helpers/get-moc-version.js +17 -5
- package/dist/integrity.d.ts +20 -0
- package/dist/integrity.js +42 -10
- package/dist/mops.d.ts +2 -1
- package/dist/mops.js +13 -10
- package/dist/package.json +3 -2
- package/dist/parallel.d.ts +1 -1
- package/dist/resolve-packages.js +7 -0
- package/dist/templates/mops-test.yml +4 -2
- package/dist/vessel.d.ts +2 -1
- package/dist/vessel.js +4 -1
- package/helpers/get-moc-path.ts +19 -3
- package/helpers/get-moc-version.ts +17 -5
- package/integrity.ts +56 -13
- package/mops.ts +15 -11
- package/package.json +3 -2
- package/parallel.ts +2 -2
- package/resolve-packages.ts +9 -0
- package/templates/mops-test.yml +4 -2
- package/vessel.ts +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Mops CLI Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
- New `mops watch` command to check for syntax errors, show warnings, run tests, generate declarations and deploy canisters ([docs](https://docs.mops.one/cli/mops-watch))
|
|
5
|
+
- New flag `--no-toolchain` in `mops install` command to skip toolchain installation
|
|
6
|
+
- New lock file format v3 ([docs](https://docs.mops.one/mops.lock))
|
|
7
|
+
- Faster `mops install` from lock file when lock file is up-to-date and there are no cached packages
|
|
8
|
+
- Fixed replica test hanging in watch mode bug
|
|
9
|
+
- Fixed mops failing when dfx is not installed
|
|
10
|
+
- Fixed `mops test` Github Action template
|
|
11
|
+
|
|
3
12
|
## 1.0.1
|
|
4
13
|
- Fixed `mops user *` commands
|
|
5
14
|
|
package/bundle/cli.tgz
CHANGED
|
Binary file
|
package/check-requirements.ts
CHANGED
|
@@ -11,7 +11,7 @@ export async function checkRequirements({verbose = false} = {}) {
|
|
|
11
11
|
let config = readConfig();
|
|
12
12
|
let mocVersion = config.toolchain?.moc;
|
|
13
13
|
if (!mocVersion) {
|
|
14
|
-
mocVersion = getMocVersion();
|
|
14
|
+
mocVersion = getMocVersion(false);
|
|
15
15
|
}
|
|
16
16
|
if (!mocVersion) {
|
|
17
17
|
return;
|
package/cli.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import process from 'node:process';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
+
import events from 'node:events';
|
|
3
4
|
import {Command, Argument, Option} from 'commander';
|
|
4
5
|
|
|
5
6
|
import {init} from './commands/init.js';
|
|
@@ -25,6 +26,7 @@ import {toolchain} from './commands/toolchain/index.js';
|
|
|
25
26
|
import {Tool} from './types.js';
|
|
26
27
|
import * as self from './commands/self.js';
|
|
27
28
|
import {resolvePackages} from './resolve-packages.js';
|
|
29
|
+
import {watch} from './commands/watch/watch.js';
|
|
28
30
|
|
|
29
31
|
declare global {
|
|
30
32
|
// eslint-disable-next-line no-var
|
|
@@ -33,6 +35,8 @@ declare global {
|
|
|
33
35
|
var mopsReplicaTestRunning : boolean;
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
events.setMaxListeners(20);
|
|
39
|
+
|
|
36
40
|
let networkFile = getNetworkFile();
|
|
37
41
|
if (fs.existsSync(networkFile)) {
|
|
38
42
|
globalThis.MOPS_NETWORK = fs.readFileSync(networkFile).toString() || 'ic';
|
|
@@ -89,6 +93,7 @@ program
|
|
|
89
93
|
.command('install')
|
|
90
94
|
.alias('i')
|
|
91
95
|
.description('Install all dependencies specified in mops.toml')
|
|
96
|
+
.option('--no-toolchain', 'Do not install toolchain')
|
|
92
97
|
.option('--verbose')
|
|
93
98
|
.addOption(new Option('--lock <action>', 'Lockfile action').choices(['check', 'update', 'ignore']))
|
|
94
99
|
.action(async (options) => {
|
|
@@ -101,10 +106,15 @@ program
|
|
|
101
106
|
return;
|
|
102
107
|
}
|
|
103
108
|
|
|
104
|
-
|
|
109
|
+
if (options.toolchain) {
|
|
110
|
+
await toolchain.ensureToolchainInited({strict: false});
|
|
111
|
+
}
|
|
105
112
|
|
|
106
113
|
let ok = await installAll(options);
|
|
107
|
-
|
|
114
|
+
|
|
115
|
+
if (options.toolchain) {
|
|
116
|
+
await toolchain.installAll(options);
|
|
117
|
+
}
|
|
108
118
|
|
|
109
119
|
// check conflicts
|
|
110
120
|
await resolvePackages({conflicts: 'warning'});
|
|
@@ -162,7 +172,7 @@ program
|
|
|
162
172
|
process.exit(1);
|
|
163
173
|
}
|
|
164
174
|
if (options.install) {
|
|
165
|
-
await installAll({silent: true, lock: 'ignore', threads: 6});
|
|
175
|
+
await installAll({silent: true, lock: 'ignore', threads: 6, installFromLockFile: true});
|
|
166
176
|
}
|
|
167
177
|
await toolchain.ensureToolchainInited({strict: false});
|
|
168
178
|
let sourcesArr = await sources(options);
|
|
@@ -206,7 +216,7 @@ program
|
|
|
206
216
|
.option('-w, --watch', 'Enable watch mode')
|
|
207
217
|
.action(async (filter, options) => {
|
|
208
218
|
checkConfigFile(true);
|
|
209
|
-
await installAll({silent: true, lock: 'ignore'});
|
|
219
|
+
await installAll({silent: true, lock: 'ignore', installFromLockFile: true});
|
|
210
220
|
await test(filter, options);
|
|
211
221
|
});
|
|
212
222
|
|
|
@@ -222,7 +232,7 @@ program
|
|
|
222
232
|
.addOption(new Option('--verbose', 'Show more information'))
|
|
223
233
|
.action(async (filter, options) => {
|
|
224
234
|
checkConfigFile(true);
|
|
225
|
-
await installAll({silent: true, lock: 'ignore'});
|
|
235
|
+
await installAll({silent: true, lock: 'ignore', installFromLockFile: true});
|
|
226
236
|
await bench(filter, options);
|
|
227
237
|
});
|
|
228
238
|
|
|
@@ -392,4 +402,18 @@ selfCommand
|
|
|
392
402
|
|
|
393
403
|
program.addCommand(selfCommand);
|
|
394
404
|
|
|
405
|
+
// watch
|
|
406
|
+
program
|
|
407
|
+
.command('watch')
|
|
408
|
+
.description('Watch *.mo files and check for syntax errors, warnings, run tests, generate declarations and deploy canisters')
|
|
409
|
+
.option('-e, --error', 'Check Motoko canisters or *.mo files for syntax errors')
|
|
410
|
+
.option('-w, --warning', 'Check Motoko canisters or *.mo files for warnings')
|
|
411
|
+
.option('-t, --test', 'Run tests')
|
|
412
|
+
.option('-g, --generate', 'Generate declarations for Motoko canisters')
|
|
413
|
+
.option('-d, --deploy', 'Deploy Motoko canisters')
|
|
414
|
+
.action(async (options) => {
|
|
415
|
+
checkConfigFile(true);
|
|
416
|
+
await watch(options);
|
|
417
|
+
});
|
|
418
|
+
|
|
395
419
|
program.parse();
|
package/commands/bench.ts
CHANGED
|
@@ -55,7 +55,7 @@ export async function bench(filter = '', optionsArg : Partial<BenchOptions> = {}
|
|
|
55
55
|
replica: config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx',
|
|
56
56
|
replicaVersion: '',
|
|
57
57
|
compiler: 'moc',
|
|
58
|
-
compilerVersion: getMocVersion(),
|
|
58
|
+
compilerVersion: getMocVersion(true),
|
|
59
59
|
gc: 'copying',
|
|
60
60
|
forceGc: true,
|
|
61
61
|
save: false,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import process from 'node:process';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import {createLogUpdate} from 'log-update';
|
|
4
|
-
import {checkConfigFile, readConfig} from '../../mops.js';
|
|
5
|
-
import {checkIntegrity} from '../../integrity.js';
|
|
4
|
+
import {checkConfigFile, parseDepValue, readConfig} from '../../mops.js';
|
|
5
|
+
import {checkIntegrity, checkLockFileLight, readLockFile} from '../../integrity.js';
|
|
6
6
|
import {installDeps} from './install-deps.js';
|
|
7
7
|
import {checkRequirements} from '../../check-requirements.js';
|
|
8
8
|
import {syncLocalCache} from './sync-local-cache.js';
|
|
@@ -13,9 +13,10 @@ type InstallAllOptions = {
|
|
|
13
13
|
silent ?: boolean;
|
|
14
14
|
lock ?: 'check' | 'update' | 'ignore';
|
|
15
15
|
threads ?: number;
|
|
16
|
+
installFromLockFile ?: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
export async function installAll({verbose = false, silent = false, threads, lock} : InstallAllOptions = {}) : Promise<boolean> {
|
|
19
|
+
export async function installAll({verbose = false, silent = false, threads, lock, installFromLockFile} : InstallAllOptions = {}) : Promise<boolean> {
|
|
19
20
|
if (!checkConfigFile()) {
|
|
20
21
|
return false;
|
|
21
22
|
}
|
|
@@ -24,12 +25,33 @@ export async function installAll({verbose = false, silent = false, threads, lock
|
|
|
24
25
|
let deps = Object.values(config.dependencies || {});
|
|
25
26
|
let devDeps = Object.values(config['dev-dependencies'] || {});
|
|
26
27
|
let allDeps = [...deps, ...devDeps];
|
|
28
|
+
let installedFromLockFile = false;
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
30
|
+
// install from lock file to avoid installing intermediate dependencies
|
|
31
|
+
if ((lock !== 'ignore' || installFromLockFile) && checkLockFileLight()) {
|
|
32
|
+
let lockFileJson = readLockFile();
|
|
33
|
+
|
|
34
|
+
if (lockFileJson && lockFileJson.version === 3) {
|
|
35
|
+
verbose && console.log('Installing from lock file...');
|
|
36
|
+
installedFromLockFile = true;
|
|
37
|
+
let lockedDeps = Object.entries(lockFileJson.deps).map(([name, version]) => {
|
|
38
|
+
return parseDepValue(name, version);
|
|
39
|
+
});
|
|
40
|
+
let ok = await installDeps(lockedDeps, {silent, verbose, threads, ignoreTransitive: true});
|
|
41
|
+
if (!ok) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
31
45
|
}
|
|
32
46
|
|
|
47
|
+
if (!installedFromLockFile) {
|
|
48
|
+
let ok = await installDeps(allDeps, {silent, verbose, threads});
|
|
49
|
+
if (!ok) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
33
55
|
let logUpdate = createLogUpdate(process.stdout, {showCursor: true});
|
|
34
56
|
|
|
35
57
|
if (!silent && lock !== 'ignore') {
|
|
@@ -9,13 +9,14 @@ type InstallDepOptions = {
|
|
|
9
9
|
verbose ?: boolean;
|
|
10
10
|
silent ?: boolean;
|
|
11
11
|
threads ?: number;
|
|
12
|
+
ignoreTransitive ?: boolean;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
// install dependency
|
|
15
16
|
// returns false if failed
|
|
16
|
-
export async function installDep(dep : Dependency, {verbose, silent, threads} : InstallDepOptions = {}, parentPkgPath ?: string) : Promise<boolean> {
|
|
17
|
+
export async function installDep(dep : Dependency, {verbose, silent, threads, ignoreTransitive} : InstallDepOptions = {}, parentPkgPath ?: string) : Promise<boolean> {
|
|
17
18
|
if (dep.repo) {
|
|
18
|
-
await installFromGithub(dep.name, dep.repo, {silent, verbose});
|
|
19
|
+
await installFromGithub(dep.name, dep.repo, {silent, verbose, ignoreTransitive});
|
|
19
20
|
return true;
|
|
20
21
|
}
|
|
21
22
|
else if (dep.path) {
|
|
@@ -24,10 +25,10 @@ export async function installDep(dep : Dependency, {verbose, silent, threads} :
|
|
|
24
25
|
if (parentPkgPath) {
|
|
25
26
|
depPath = path.resolve(parentPkgPath, dep.path);
|
|
26
27
|
}
|
|
27
|
-
return installLocalDep(dep.name, depPath, {silent, verbose});
|
|
28
|
+
return installLocalDep(dep.name, depPath, {silent, verbose, ignoreTransitive});
|
|
28
29
|
}
|
|
29
30
|
else if (dep.version) {
|
|
30
|
-
return installMopsDep(dep.name, dep.version, {silent, verbose, threads});
|
|
31
|
+
return installMopsDep(dep.name, dep.version, {silent, verbose, threads, ignoreTransitive});
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
return true;
|
|
@@ -5,16 +5,17 @@ type InstallDepsOptions = {
|
|
|
5
5
|
verbose ?: boolean;
|
|
6
6
|
silent ?: boolean;
|
|
7
7
|
threads ?: number;
|
|
8
|
+
ignoreTransitive ?: boolean;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
// install all dependencies
|
|
11
12
|
// returns actual installed dependencies
|
|
12
13
|
// returns false if failed
|
|
13
|
-
export async function installDeps(deps : Dependency[], {verbose, silent, threads} : InstallDepsOptions = {}, parentPkgPath ?: string) : Promise<boolean> {
|
|
14
|
+
export async function installDeps(deps : Dependency[], {verbose, silent, threads, ignoreTransitive} : InstallDepsOptions = {}, parentPkgPath ?: string) : Promise<boolean> {
|
|
14
15
|
let ok = true;
|
|
15
16
|
|
|
16
17
|
for (const dep of deps) {
|
|
17
|
-
let res = await installDep(dep, {verbose, silent, threads}, parentPkgPath);
|
|
18
|
+
let res = await installDep(dep, {verbose, silent, threads, ignoreTransitive}, parentPkgPath);
|
|
18
19
|
if (!res) {
|
|
19
20
|
ok = false;
|
|
20
21
|
}
|
|
@@ -7,11 +7,12 @@ import {installDeps} from './install-deps.js';
|
|
|
7
7
|
type InstallLocalDepOptions = {
|
|
8
8
|
verbose ?: boolean;
|
|
9
9
|
silent ?: boolean;
|
|
10
|
+
ignoreTransitive ?: boolean;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
// skip install and just find non-local dependencies to install
|
|
13
14
|
// pkgPath should be relative to the current root dir or absolute
|
|
14
|
-
export async function installLocalDep(pkg : string, pkgPath = '', {verbose, silent} : InstallLocalDepOptions = {}) : Promise<boolean> {
|
|
15
|
+
export async function installLocalDep(pkg : string, pkgPath = '', {verbose, silent, ignoreTransitive} : InstallLocalDepOptions = {}) : Promise<boolean> {
|
|
15
16
|
if (!silent) {
|
|
16
17
|
let logUpdate = createLogUpdate(process.stdout, {showCursor: true});
|
|
17
18
|
logUpdate(`Local dependency ${pkg} = "${pkgPath}"`);
|
|
@@ -25,7 +26,12 @@ export async function installLocalDep(pkg : string, pkgPath = '', {verbose, sile
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
// install dependencies
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
29
|
+
if (!ignoreTransitive) {
|
|
30
|
+
let dir = path.resolve(getRootDir(), pkgPath);
|
|
31
|
+
let config = readConfig(path.join(dir, 'mops.toml'));
|
|
32
|
+
return installDeps(Object.values(config.dependencies || {}), {silent, verbose}, pkgPath);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -19,9 +19,10 @@ type InstallMopsDepOptions = {
|
|
|
19
19
|
silent ?: boolean;
|
|
20
20
|
dep ?: boolean;
|
|
21
21
|
threads ?: number;
|
|
22
|
+
ignoreTransitive ?: boolean;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
|
-
export async function installMopsDep(pkg : string, version = '', {verbose, silent, dep, threads} : InstallMopsDepOptions = {}) : Promise<boolean> {
|
|
25
|
+
export async function installMopsDep(pkg : string, version = '', {verbose, silent, dep, threads, ignoreTransitive} : InstallMopsDepOptions = {}) : Promise<boolean> {
|
|
25
26
|
threads = threads || 12;
|
|
26
27
|
let depName = getDepName(pkg);
|
|
27
28
|
|
|
@@ -113,11 +114,13 @@ export async function installMopsDep(pkg : string, version = '', {verbose, silen
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
// install dependencies
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
if (!ignoreTransitive) {
|
|
118
|
+
let config = readConfig(path.join(cacheDir, 'mops.toml'));
|
|
119
|
+
let res = await installDeps(Object.values(config.dependencies || {}), {silent, verbose});
|
|
118
120
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
if (!res) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
return true;
|
package/commands/replica.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {ChildProcessWithoutNullStreams, execSync, spawn} from 'node:child_proces
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import {PassThrough} from 'node:stream';
|
|
6
|
+
import {spawn as spawnAsync} from 'promisify-child-process';
|
|
6
7
|
|
|
7
8
|
import {IDL} from '@dfinity/candid';
|
|
8
9
|
import {Actor, HttpAgent} from '@dfinity/agent';
|
|
@@ -126,7 +127,7 @@ export class Replica {
|
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
async deploy(name : string, wasm : string, idlFactory : IDL.InterfaceFactory, cwd : string = process.cwd()) {
|
|
130
|
+
async deploy(name : string, wasm : string, idlFactory : IDL.InterfaceFactory, cwd : string = process.cwd(), signal ?: AbortSignal) {
|
|
130
131
|
if (this.type === 'dfx') {
|
|
131
132
|
// prepare dfx.json for current canister
|
|
132
133
|
let dfxJson = path.join(this.dir, 'dfx.json');
|
|
@@ -144,8 +145,27 @@ export class Replica {
|
|
|
144
145
|
fs.mkdirSync(this.dir, {recursive: true});
|
|
145
146
|
fs.writeFileSync(dfxJson, JSON.stringify(newDfxJsonData, null, 2));
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
148
|
+
await spawnAsync('dfx', ['deploy', name, '--mode', 'reinstall', '--yes', '--identity', 'anonymous'], {cwd: this.dir, signal, stdio: this.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe']}).catch((error) => {
|
|
149
|
+
if (error.code === 'ABORT_ERR') {
|
|
150
|
+
return {stderr: ''};
|
|
151
|
+
}
|
|
152
|
+
throw error;
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (signal?.aborted) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
await spawnAsync('dfx', ['ledger', 'fabricate-cycles', '--canister', name, '--t', '100'], {cwd: this.dir, signal, stdio: this.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe']}).catch((error) => {
|
|
160
|
+
if (error.code === 'ABORT_ERR') {
|
|
161
|
+
return {stderr: ''};
|
|
162
|
+
}
|
|
163
|
+
throw error;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (signal?.aborted) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
149
169
|
|
|
150
170
|
let canisterId = execSync(`dfx canister id ${name}`, {cwd: this.dir}).toString().trim();
|
|
151
171
|
|
|
@@ -170,7 +190,17 @@ export class Replica {
|
|
|
170
190
|
idlFactory,
|
|
171
191
|
wasm,
|
|
172
192
|
});
|
|
193
|
+
|
|
194
|
+
if (signal?.aborted) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
173
198
|
await this.pocketIc.addCycles(canisterId, 1_000_000_000_000);
|
|
199
|
+
|
|
200
|
+
if (signal?.aborted) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
174
204
|
this.canisters[name] = {
|
|
175
205
|
cwd,
|
|
176
206
|
canisterId: canisterId.toText(),
|
package/commands/sources.ts
CHANGED
package/commands/sync.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import process from 'node:process';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import {execSync} from 'node:child_process';
|
|
4
3
|
import {globSync} from 'glob';
|
|
@@ -7,6 +6,7 @@ import {checkConfigFile, getRootDir, readConfig} from '../mops.js';
|
|
|
7
6
|
import {add} from './add.js';
|
|
8
7
|
import {remove} from './remove.js';
|
|
9
8
|
import {checkIntegrity} from '../integrity.js';
|
|
9
|
+
import {getMocPath} from '../helpers/get-moc-path.js';
|
|
10
10
|
|
|
11
11
|
type SyncOptions = {
|
|
12
12
|
lock ?: 'update' | 'ignore';
|
|
@@ -48,25 +48,10 @@ let ignore = [
|
|
|
48
48
|
'**/.mops/**',
|
|
49
49
|
];
|
|
50
50
|
|
|
51
|
-
let mocPath = '';
|
|
52
|
-
function getMocPath() : string {
|
|
53
|
-
if (!mocPath) {
|
|
54
|
-
mocPath = process.env.DFX_MOC_PATH || '';
|
|
55
|
-
}
|
|
56
|
-
if (!mocPath) {
|
|
57
|
-
try {
|
|
58
|
-
mocPath = execSync('dfx cache show').toString().trim() + '/moc';
|
|
59
|
-
}
|
|
60
|
-
catch {}
|
|
61
|
-
}
|
|
62
|
-
if (!mocPath) {
|
|
63
|
-
mocPath = 'moc';
|
|
64
|
-
}
|
|
65
|
-
return mocPath;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
51
|
async function getUsedPackages() : Promise<string[]> {
|
|
69
52
|
let rootDir = getRootDir();
|
|
53
|
+
let mocPath = getMocPath();
|
|
54
|
+
|
|
70
55
|
let files = globSync('**/*.mo', {
|
|
71
56
|
cwd: rootDir,
|
|
72
57
|
nocase: true,
|
|
@@ -76,7 +61,7 @@ async function getUsedPackages() : Promise<string[]> {
|
|
|
76
61
|
let packages : Set<string> = new Set;
|
|
77
62
|
|
|
78
63
|
for (let file of files) {
|
|
79
|
-
let deps : string[] = execSync(`${
|
|
64
|
+
let deps : string[] = execSync(`${mocPath} --print-deps ${path.join(rootDir, file)}`).toString().trim().split('\n');
|
|
80
65
|
|
|
81
66
|
for (let dep of deps) {
|
|
82
67
|
if (dep.startsWith('mo:') && !dep.startsWith('mo:prim') && !dep.startsWith('mo:⛔')) {
|
package/commands/test/mmf1.ts
CHANGED
|
@@ -53,6 +53,10 @@ export class MMF1 {
|
|
|
53
53
|
this.output = [];
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
getErrorMessages() {
|
|
57
|
+
return this.output.filter(out => out.type === 'fail').map(out => out.message);
|
|
58
|
+
}
|
|
59
|
+
|
|
56
60
|
parseLine(line : string) {
|
|
57
61
|
if (line.startsWith('mops:1:start ')) {
|
|
58
62
|
this._testStart(line.split('mops:1:start ')[1] || '');
|
|
@@ -5,14 +5,25 @@ import {Reporter} from './reporter.js';
|
|
|
5
5
|
import {TestMode} from '../../../types.js';
|
|
6
6
|
|
|
7
7
|
export class SilentReporter implements Reporter {
|
|
8
|
+
total = 0;
|
|
8
9
|
passed = 0;
|
|
9
10
|
failed = 0;
|
|
10
11
|
skipped = 0;
|
|
11
12
|
passedFiles = 0;
|
|
12
13
|
failedFiles = 0;
|
|
13
14
|
passedNamesFlat : string[] = [];
|
|
15
|
+
flushOnError = true;
|
|
16
|
+
errorOutput = '';
|
|
17
|
+
onProgress = () => {};
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
constructor(flushOnError = true, onProgress = () => {}) {
|
|
20
|
+
this.flushOnError = flushOnError;
|
|
21
|
+
this.onProgress = onProgress;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
addFiles(files : string[]) {
|
|
25
|
+
this.total = files.length;
|
|
26
|
+
}
|
|
16
27
|
|
|
17
28
|
addRun(file : string, mmf : MMF1, state : Promise<void>, _mode : TestMode) {
|
|
18
29
|
state.then(() => {
|
|
@@ -30,10 +41,17 @@ export class SilentReporter implements Reporter {
|
|
|
30
41
|
this.failedFiles += Number(mmf.failed !== 0);
|
|
31
42
|
|
|
32
43
|
if (mmf.failed) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
let output = `${chalk.red('✖')} ${absToRel(file)}\n${mmf.getErrorMessages().join('\n')}\n${'-'.repeat(50)}`;
|
|
45
|
+
|
|
46
|
+
if (this.flushOnError) {
|
|
47
|
+
console.log(output);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
this.errorOutput = `${this.errorOutput}\n${output}`.trim();
|
|
51
|
+
}
|
|
36
52
|
}
|
|
53
|
+
|
|
54
|
+
this.onProgress();
|
|
37
55
|
});
|
|
38
56
|
}
|
|
39
57
|
|
package/commands/test/test.ts
CHANGED
|
@@ -85,14 +85,28 @@ export async function test(filter = '', options : Partial<TestOptions> = {}) {
|
|
|
85
85
|
process.exit(0);
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
|
+
else {
|
|
89
|
+
process.exit(0);
|
|
90
|
+
}
|
|
88
91
|
});
|
|
89
92
|
|
|
90
93
|
// todo: run only changed for *.test.mo?
|
|
91
94
|
// todo: run all for *.mo?
|
|
95
|
+
|
|
96
|
+
let curRun = Promise.resolve(true);
|
|
97
|
+
let controller = new AbortController();
|
|
98
|
+
|
|
92
99
|
let run = debounce(async () => {
|
|
100
|
+
controller.abort();
|
|
101
|
+
await curRun;
|
|
102
|
+
|
|
93
103
|
console.clear();
|
|
94
104
|
process.stdout.write('\x1Bc');
|
|
95
|
-
|
|
105
|
+
|
|
106
|
+
controller = new AbortController();
|
|
107
|
+
curRun = runAll(options.reporter, filter, options.mode, replicaType, true, controller.signal);
|
|
108
|
+
await curRun;
|
|
109
|
+
|
|
96
110
|
console.log('-'.repeat(50));
|
|
97
111
|
console.log('Waiting for file changes...');
|
|
98
112
|
console.log(chalk.gray((`Press ${chalk.gray('Ctrl+C')} to exit.`)));
|
|
@@ -122,12 +136,12 @@ export async function test(filter = '', options : Partial<TestOptions> = {}) {
|
|
|
122
136
|
let mocPath = '';
|
|
123
137
|
let wasmtimePath = '';
|
|
124
138
|
|
|
125
|
-
async function runAll(reporterName : ReporterName | undefined, filter = '', mode : TestMode = 'interpreter', replicaType : ReplicaName, watch = false) : Promise<boolean> {
|
|
126
|
-
let done = await testWithReporter(reporterName, filter, mode, replicaType, watch);
|
|
139
|
+
async function runAll(reporterName : ReporterName | undefined, filter = '', mode : TestMode = 'interpreter', replicaType : ReplicaName, watch = false, signal ?: AbortSignal) : Promise<boolean> {
|
|
140
|
+
let done = await testWithReporter(reporterName, filter, mode, replicaType, watch, signal);
|
|
127
141
|
return done;
|
|
128
142
|
}
|
|
129
143
|
|
|
130
|
-
export async function testWithReporter(reporterName : ReporterName | Reporter | undefined, filter = '', defaultMode : TestMode = 'interpreter', replicaType : ReplicaName, watch = false) : Promise<boolean> {
|
|
144
|
+
export async function testWithReporter(reporterName : ReporterName | Reporter | undefined, filter = '', defaultMode : TestMode = 'interpreter', replicaType : ReplicaName, watch = false, signal ?: AbortSignal) : Promise<boolean> {
|
|
131
145
|
let rootDir = getRootDir();
|
|
132
146
|
let files : string[] = [];
|
|
133
147
|
let libFiles = globSync('**/test?(s)/lib.mo', globConfig);
|
|
@@ -191,6 +205,10 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
191
205
|
fs.mkdirSync(testTempDir, {recursive: true});
|
|
192
206
|
|
|
193
207
|
await parallel(os.cpus().length, files, async (file : string) => {
|
|
208
|
+
if (signal?.aborted) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
194
212
|
let mmf = new MMF1('store', absToRel(file));
|
|
195
213
|
|
|
196
214
|
// mode overrides
|
|
@@ -221,7 +239,13 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
221
239
|
|
|
222
240
|
// interpret
|
|
223
241
|
if (mode === 'interpreter') {
|
|
224
|
-
let proc = spawn(mocPath, ['-r', '-ref-system-api', ...mocArgs]);
|
|
242
|
+
let proc = spawn(mocPath, ['-r', '-ref-system-api', ...mocArgs], {signal});
|
|
243
|
+
proc.addListener('error', (error : any) => {
|
|
244
|
+
if (error?.code === 'ABORT_ERR') {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
throw error;
|
|
248
|
+
});
|
|
225
249
|
pipeMMF(proc, mmf).then(resolve);
|
|
226
250
|
}
|
|
227
251
|
// build and run wasm
|
|
@@ -229,7 +253,13 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
229
253
|
let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
|
|
230
254
|
|
|
231
255
|
// build
|
|
232
|
-
let buildProc = spawn(mocPath, [`-o=${wasmFile}`, '-wasi-system-api', ...mocArgs]);
|
|
256
|
+
let buildProc = spawn(mocPath, [`-o=${wasmFile}`, '-wasi-system-api', ...mocArgs], {signal});
|
|
257
|
+
buildProc.addListener('error', (error : any) => {
|
|
258
|
+
if (error?.code === 'ABORT_ERR') {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
throw error;
|
|
262
|
+
});
|
|
233
263
|
pipeMMF(buildProc, mmf).then(async () => {
|
|
234
264
|
if (mmf.failed > 0) {
|
|
235
265
|
return;
|
|
@@ -252,7 +282,14 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
252
282
|
process.exit(1);
|
|
253
283
|
}
|
|
254
284
|
|
|
255
|
-
let proc = spawn(wasmtimePath, wasmtimeArgs);
|
|
285
|
+
let proc = spawn(wasmtimePath, wasmtimeArgs, {signal});
|
|
286
|
+
proc.addListener('error', (error : any) => {
|
|
287
|
+
if (error?.code === 'ABORT_ERR') {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
throw error;
|
|
291
|
+
});
|
|
292
|
+
|
|
256
293
|
await pipeMMF(proc, mmf);
|
|
257
294
|
}).finally(() => {
|
|
258
295
|
fs.rmSync(wasmFile, {force: true});
|
|
@@ -265,7 +302,13 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
265
302
|
let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
|
|
266
303
|
|
|
267
304
|
// build
|
|
268
|
-
let buildProc = spawn(mocPath, [`-o=${wasmFile}`, ...mocArgs]);
|
|
305
|
+
let buildProc = spawn(mocPath, [`-o=${wasmFile}`, ...mocArgs], {signal});
|
|
306
|
+
buildProc.addListener('error', (error : any) => {
|
|
307
|
+
if (error?.code === 'ABORT_ERR') {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
throw error;
|
|
311
|
+
});
|
|
269
312
|
|
|
270
313
|
pipeMMF(buildProc, mmf).then(async () => {
|
|
271
314
|
if (mmf.failed > 0) {
|
|
@@ -274,15 +317,23 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
274
317
|
|
|
275
318
|
await startReplicaOnce(replica, replicaType);
|
|
276
319
|
|
|
320
|
+
if (signal?.aborted) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
277
324
|
let canisterName = path.parse(file).name;
|
|
278
325
|
let idlFactory = ({IDL} : any) => {
|
|
279
326
|
return IDL.Service({'runTests': IDL.Func([], [], [])});
|
|
280
327
|
};
|
|
281
328
|
interface _SERVICE {'runTests' : ActorMethod<[], undefined>;}
|
|
282
329
|
|
|
283
|
-
let
|
|
330
|
+
let canister = await replica.deploy(canisterName, wasmFile, idlFactory, undefined, signal);
|
|
284
331
|
|
|
285
|
-
|
|
332
|
+
if (signal?.aborted || !canister) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
pipeStdoutToMMF(canister.stream, mmf);
|
|
286
337
|
|
|
287
338
|
let actor = await replica.getActor(canisterName) as _SERVICE;
|
|
288
339
|
|
|
@@ -298,6 +349,10 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
298
349
|
});
|
|
299
350
|
}
|
|
300
351
|
|
|
352
|
+
if (signal?.aborted) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
301
356
|
globalThis.mopsReplicaTestRunning = true;
|
|
302
357
|
await actor.runTests();
|
|
303
358
|
globalThis.mopsReplicaTestRunning = false;
|
|
@@ -310,11 +365,16 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
310
365
|
stderrStream.write(e.message);
|
|
311
366
|
}
|
|
312
367
|
}).finally(async () => {
|
|
368
|
+
globalThis.mopsReplicaTestRunning = false;
|
|
313
369
|
fs.rmSync(wasmFile, {force: true});
|
|
314
370
|
}).then(resolve);
|
|
315
371
|
}
|
|
316
372
|
});
|
|
317
373
|
|
|
374
|
+
if (signal?.aborted) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
318
378
|
reporter.addRun(file, mmf, promise, mode);
|
|
319
379
|
|
|
320
380
|
await promise;
|
|
@@ -325,6 +385,10 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
325
385
|
fs.rmSync(testTempDir, {recursive: true, force: true});
|
|
326
386
|
}
|
|
327
387
|
|
|
388
|
+
if (signal?.aborted) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
328
392
|
return reporter.done();
|
|
329
393
|
}
|
|
330
394
|
|