ic-mops 1.0.1 → 1.1.0-pre.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/cli.ts CHANGED
@@ -89,6 +89,7 @@ program
89
89
  .command('install')
90
90
  .alias('i')
91
91
  .description('Install all dependencies specified in mops.toml')
92
+ .option('--no-toolchain', 'Do not install toolchain')
92
93
  .option('--verbose')
93
94
  .addOption(new Option('--lock <action>', 'Lockfile action').choices(['check', 'update', 'ignore']))
94
95
  .action(async (options) => {
@@ -101,10 +102,15 @@ program
101
102
  return;
102
103
  }
103
104
 
104
- await toolchain.ensureToolchainInited({strict: false});
105
+ if (options.toolchain) {
106
+ await toolchain.ensureToolchainInited({strict: false});
107
+ }
105
108
 
106
109
  let ok = await installAll(options);
107
- await toolchain.installAll(options);
110
+
111
+ if (options.toolchain) {
112
+ await toolchain.installAll(options);
113
+ }
108
114
 
109
115
  // check conflicts
110
116
  await resolvePackages({conflicts: 'warning'});
@@ -162,7 +168,7 @@ program
162
168
  process.exit(1);
163
169
  }
164
170
  if (options.install) {
165
- await installAll({silent: true, lock: 'ignore', threads: 6});
171
+ await installAll({silent: true, lock: 'ignore', threads: 6, installFromLockFile: true});
166
172
  }
167
173
  await toolchain.ensureToolchainInited({strict: false});
168
174
  let sourcesArr = await sources(options);
@@ -206,7 +212,7 @@ program
206
212
  .option('-w, --watch', 'Enable watch mode')
207
213
  .action(async (filter, options) => {
208
214
  checkConfigFile(true);
209
- await installAll({silent: true, lock: 'ignore'});
215
+ await installAll({silent: true, lock: 'ignore', installFromLockFile: true});
210
216
  await test(filter, options);
211
217
  });
212
218
 
@@ -222,7 +228,7 @@ program
222
228
  .addOption(new Option('--verbose', 'Show more information'))
223
229
  .action(async (filter, options) => {
224
230
  checkConfigFile(true);
225
- await installAll({silent: true, lock: 'ignore'});
231
+ await installAll({silent: true, lock: 'ignore', installFromLockFile: true});
226
232
  await bench(filter, options);
227
233
  });
228
234
 
@@ -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
- let ok = await installDeps(allDeps, {silent, verbose, threads});
29
- if (!ok) {
30
- return false;
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 deps = Object.entries(lockFileJson.deps).map(([name, version]) => {
38
+ return parseDepValue(name, version);
39
+ });
40
+ let ok = await installDeps(deps, {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
- let dir = path.resolve(getRootDir(), pkgPath);
29
- let config = readConfig(path.join(dir, 'mops.toml'));
30
- return installDeps(Object.values(config.dependencies || {}), {silent, verbose}, pkgPath);
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
- let config = readConfig(path.join(cacheDir, 'mops.toml'));
117
- let res = await installDeps(Object.values(config.dependencies || {}), {silent, verbose});
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
- if (!res) {
120
- return false;
121
+ if (!res) {
122
+ return false;
123
+ }
121
124
  }
122
125
 
123
126
  return true;
package/dist/cli.js CHANGED
@@ -72,6 +72,7 @@ program
72
72
  .command('install')
73
73
  .alias('i')
74
74
  .description('Install all dependencies specified in mops.toml')
75
+ .option('--no-toolchain', 'Do not install toolchain')
75
76
  .option('--verbose')
76
77
  .addOption(new Option('--lock <action>', 'Lockfile action').choices(['check', 'update', 'ignore']))
77
78
  .action(async (options) => {
@@ -82,9 +83,13 @@ program
82
83
  if (!compatible) {
83
84
  return;
84
85
  }
85
- await toolchain.ensureToolchainInited({ strict: false });
86
+ if (options.toolchain) {
87
+ await toolchain.ensureToolchainInited({ strict: false });
88
+ }
86
89
  let ok = await installAll(options);
87
- await toolchain.installAll(options);
90
+ if (options.toolchain) {
91
+ await toolchain.installAll(options);
92
+ }
88
93
  // check conflicts
89
94
  await resolvePackages({ conflicts: 'warning' });
90
95
  if (!ok) {
@@ -136,7 +141,7 @@ program
136
141
  process.exit(1);
137
142
  }
138
143
  if (options.install) {
139
- await installAll({ silent: true, lock: 'ignore', threads: 6 });
144
+ await installAll({ silent: true, lock: 'ignore', threads: 6, installFromLockFile: true });
140
145
  }
141
146
  await toolchain.ensureToolchainInited({ strict: false });
142
147
  let sourcesArr = await sources(options);
@@ -177,7 +182,7 @@ program
177
182
  .option('-w, --watch', 'Enable watch mode')
178
183
  .action(async (filter, options) => {
179
184
  checkConfigFile(true);
180
- await installAll({ silent: true, lock: 'ignore' });
185
+ await installAll({ silent: true, lock: 'ignore', installFromLockFile: true });
181
186
  await test(filter, options);
182
187
  });
183
188
  // bench
@@ -192,7 +197,7 @@ program
192
197
  .addOption(new Option('--verbose', 'Show more information'))
193
198
  .action(async (filter, options) => {
194
199
  checkConfigFile(true);
195
- await installAll({ silent: true, lock: 'ignore' });
200
+ await installAll({ silent: true, lock: 'ignore', installFromLockFile: true });
196
201
  await bench(filter, options);
197
202
  });
198
203
  // template
@@ -3,6 +3,7 @@ type InstallAllOptions = {
3
3
  silent?: boolean;
4
4
  lock?: 'check' | 'update' | 'ignore';
5
5
  threads?: number;
6
+ installFromLockFile?: boolean;
6
7
  };
7
- export declare function installAll({ verbose, silent, threads, lock }?: InstallAllOptions): Promise<boolean>;
8
+ export declare function installAll({ verbose, silent, threads, lock, installFromLockFile }?: InstallAllOptions): Promise<boolean>;
8
9
  export {};
@@ -1,13 +1,13 @@
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';
9
9
  import { notifyInstalls } from '../../notify-installs.js';
10
- export async function installAll({ verbose = false, silent = false, threads, lock } = {}) {
10
+ export async function installAll({ verbose = false, silent = false, threads, lock, installFromLockFile } = {}) {
11
11
  if (!checkConfigFile()) {
12
12
  return false;
13
13
  }
@@ -15,9 +15,27 @@ export async function installAll({ verbose = false, silent = false, threads, loc
15
15
  let deps = Object.values(config.dependencies || {});
16
16
  let devDeps = Object.values(config['dev-dependencies'] || {});
17
17
  let allDeps = [...deps, ...devDeps];
18
- let ok = await installDeps(allDeps, { silent, verbose, threads });
19
- if (!ok) {
20
- return false;
18
+ let installedFromLockFile = false;
19
+ // install from lock file to avoid installing intermediate dependencies
20
+ if ((lock !== 'ignore' || installFromLockFile) && checkLockFileLight()) {
21
+ let lockFileJson = readLockFile();
22
+ if (lockFileJson && lockFileJson.version === 3) {
23
+ verbose && console.log('Installing from lock file...');
24
+ installedFromLockFile = true;
25
+ let deps = Object.entries(lockFileJson.deps).map(([name, version]) => {
26
+ return parseDepValue(name, version);
27
+ });
28
+ let ok = await installDeps(deps, { silent, verbose, threads, ignoreTransitive: true });
29
+ if (!ok) {
30
+ return false;
31
+ }
32
+ }
33
+ }
34
+ if (!installedFromLockFile) {
35
+ let ok = await installDeps(allDeps, { silent, verbose, threads });
36
+ if (!ok) {
37
+ return false;
38
+ }
21
39
  }
22
40
  let logUpdate = createLogUpdate(process.stdout, { showCursor: true });
23
41
  if (!silent && lock !== 'ignore') {
@@ -3,6 +3,7 @@ type InstallDepOptions = {
3
3
  verbose?: boolean;
4
4
  silent?: boolean;
5
5
  threads?: number;
6
+ ignoreTransitive?: boolean;
6
7
  };
7
- export declare function installDep(dep: Dependency, { verbose, silent, threads }?: InstallDepOptions, parentPkgPath?: string): Promise<boolean>;
8
+ export declare function installDep(dep: Dependency, { verbose, silent, threads, ignoreTransitive }?: InstallDepOptions, parentPkgPath?: string): Promise<boolean>;
8
9
  export {};
@@ -5,9 +5,9 @@ import { installLocalDep } from './install-local-dep.js';
5
5
  import { getRootDir } from '../../mops.js';
6
6
  // install dependency
7
7
  // returns false if failed
8
- export async function installDep(dep, { verbose, silent, threads } = {}, parentPkgPath) {
8
+ export async function installDep(dep, { verbose, silent, threads, ignoreTransitive } = {}, parentPkgPath) {
9
9
  if (dep.repo) {
10
- await installFromGithub(dep.name, dep.repo, { silent, verbose });
10
+ await installFromGithub(dep.name, dep.repo, { silent, verbose, ignoreTransitive });
11
11
  return true;
12
12
  }
13
13
  else if (dep.path) {
@@ -16,10 +16,10 @@ export async function installDep(dep, { verbose, silent, threads } = {}, parentP
16
16
  if (parentPkgPath) {
17
17
  depPath = path.resolve(parentPkgPath, dep.path);
18
18
  }
19
- return installLocalDep(dep.name, depPath, { silent, verbose });
19
+ return installLocalDep(dep.name, depPath, { silent, verbose, ignoreTransitive });
20
20
  }
21
21
  else if (dep.version) {
22
- return installMopsDep(dep.name, dep.version, { silent, verbose, threads });
22
+ return installMopsDep(dep.name, dep.version, { silent, verbose, threads, ignoreTransitive });
23
23
  }
24
24
  return true;
25
25
  }
@@ -3,6 +3,7 @@ type InstallDepsOptions = {
3
3
  verbose?: boolean;
4
4
  silent?: boolean;
5
5
  threads?: number;
6
+ ignoreTransitive?: boolean;
6
7
  };
7
- export declare function installDeps(deps: Dependency[], { verbose, silent, threads }?: InstallDepsOptions, parentPkgPath?: string): Promise<boolean>;
8
+ export declare function installDeps(deps: Dependency[], { verbose, silent, threads, ignoreTransitive }?: InstallDepsOptions, parentPkgPath?: string): Promise<boolean>;
8
9
  export {};
@@ -2,10 +2,10 @@ import { installDep } from './install-dep.js';
2
2
  // install all dependencies
3
3
  // returns actual installed dependencies
4
4
  // returns false if failed
5
- export async function installDeps(deps, { verbose, silent, threads } = {}, parentPkgPath) {
5
+ export async function installDeps(deps, { verbose, silent, threads, ignoreTransitive } = {}, parentPkgPath) {
6
6
  let ok = true;
7
7
  for (const dep of deps) {
8
- let res = await installDep(dep, { verbose, silent, threads }, parentPkgPath);
8
+ let res = await installDep(dep, { verbose, silent, threads, ignoreTransitive }, parentPkgPath);
9
9
  if (!res) {
10
10
  ok = false;
11
11
  }
@@ -1,6 +1,7 @@
1
1
  type InstallLocalDepOptions = {
2
2
  verbose?: boolean;
3
3
  silent?: boolean;
4
+ ignoreTransitive?: boolean;
4
5
  };
5
- export declare function installLocalDep(pkg: string, pkgPath?: string, { verbose, silent }?: InstallLocalDepOptions): Promise<boolean>;
6
+ export declare function installLocalDep(pkg: string, pkgPath?: string, { verbose, silent, ignoreTransitive }?: InstallLocalDepOptions): Promise<boolean>;
6
7
  export {};
@@ -5,7 +5,7 @@ import { getRootDir, readConfig } from '../../mops.js';
5
5
  import { installDeps } from './install-deps.js';
6
6
  // skip install and just find non-local dependencies to install
7
7
  // pkgPath should be relative to the current root dir or absolute
8
- export async function installLocalDep(pkg, pkgPath = '', { verbose, silent } = {}) {
8
+ export async function installLocalDep(pkg, pkgPath = '', { verbose, silent, ignoreTransitive } = {}) {
9
9
  if (!silent) {
10
10
  let logUpdate = createLogUpdate(process.stdout, { showCursor: true });
11
11
  logUpdate(`Local dependency ${pkg} = "${pkgPath}"`);
@@ -17,7 +17,12 @@ export async function installLocalDep(pkg, pkgPath = '', { verbose, silent } = {
17
17
  }
18
18
  }
19
19
  // install dependencies
20
- let dir = path.resolve(getRootDir(), pkgPath);
21
- let config = readConfig(path.join(dir, 'mops.toml'));
22
- return installDeps(Object.values(config.dependencies || {}), { silent, verbose }, pkgPath);
20
+ if (!ignoreTransitive) {
21
+ let dir = path.resolve(getRootDir(), pkgPath);
22
+ let config = readConfig(path.join(dir, 'mops.toml'));
23
+ return installDeps(Object.values(config.dependencies || {}), { silent, verbose }, pkgPath);
24
+ }
25
+ else {
26
+ return true;
27
+ }
23
28
  }
@@ -3,6 +3,7 @@ type InstallMopsDepOptions = {
3
3
  silent?: boolean;
4
4
  dep?: boolean;
5
5
  threads?: number;
6
+ ignoreTransitive?: boolean;
6
7
  };
7
- export declare function installMopsDep(pkg: string, version?: string, { verbose, silent, dep, threads }?: InstallMopsDepOptions): Promise<boolean>;
8
+ export declare function installMopsDep(pkg: string, version?: string, { verbose, silent, dep, threads, ignoreTransitive }?: InstallMopsDepOptions): Promise<boolean>;
8
9
  export {};
@@ -13,7 +13,7 @@ import { getDepCacheDir, getMopsDepCacheName, isDepCached } from '../../cache.js
13
13
  import { downloadFile, getPackageFilesInfo } from '../../api/downloadPackageFiles.js';
14
14
  import { installDeps } from './install-deps.js';
15
15
  import { getDepName } from '../../helpers/get-dep-name.js';
16
- export async function installMopsDep(pkg, version = '', { verbose, silent, dep, threads } = {}) {
16
+ export async function installMopsDep(pkg, version = '', { verbose, silent, dep, threads, ignoreTransitive } = {}) {
17
17
  threads = threads || 12;
18
18
  let depName = getDepName(pkg);
19
19
  if (!checkConfigFile()) {
@@ -90,10 +90,12 @@ export async function installMopsDep(pkg, version = '', { verbose, silent, dep,
90
90
  logUpdate.clear();
91
91
  }
92
92
  // install dependencies
93
- let config = readConfig(path.join(cacheDir, 'mops.toml'));
94
- let res = await installDeps(Object.values(config.dependencies || {}), { silent, verbose });
95
- if (!res) {
96
- return false;
93
+ if (!ignoreTransitive) {
94
+ let config = readConfig(path.join(cacheDir, 'mops.toml'));
95
+ let res = await installDeps(Object.values(config.dependencies || {}), { silent, verbose });
96
+ if (!res) {
97
+ return false;
98
+ }
97
99
  }
98
100
  return true;
99
101
  }
@@ -1,5 +1,25 @@
1
+ type LockFileV1 = {
2
+ version: 1;
3
+ mopsTomlHash: string;
4
+ hashes: Record<string, Record<string, string>>;
5
+ };
6
+ type LockFileV2 = {
7
+ version: 2;
8
+ mopsTomlDepsHash: string;
9
+ hashes: Record<string, Record<string, string>>;
10
+ };
11
+ type LockFileV3 = {
12
+ version: 3;
13
+ mopsTomlDepsHash: string;
14
+ hashes: Record<string, Record<string, string>>;
15
+ deps: Record<string, string>;
16
+ };
17
+ type LockFile = LockFileV1 | LockFileV2 | LockFileV3;
1
18
  export declare function checkIntegrity(lock?: 'check' | 'update' | 'ignore'): Promise<void>;
2
19
  export declare function getLocalFileHash(fileId: string): string;
3
20
  export declare function checkRemote(): Promise<void>;
21
+ export declare function readLockFile(): LockFile | null;
22
+ export declare function checkLockFileLight(): boolean;
4
23
  export declare function updateLockFile(): Promise<void>;
5
24
  export declare function checkLockFile(force?: boolean): Promise<void>;
25
+ export {};
package/dist/integrity.js CHANGED
@@ -78,21 +78,36 @@ export async function checkRemote() {
78
78
  }
79
79
  }
80
80
  }
81
- export async function updateLockFile() {
81
+ export function readLockFile() {
82
82
  let rootDir = getRootDir();
83
83
  let lockFile = path.join(rootDir, 'mops.lock');
84
- // if lock file exists and mops.toml hasn't changed, don't update it
85
84
  if (fs.existsSync(lockFile)) {
86
- let lockFileJson = JSON.parse(fs.readFileSync(lockFile).toString());
85
+ return JSON.parse(fs.readFileSync(lockFile).toString());
86
+ }
87
+ return null;
88
+ }
89
+ // check if lock file exists and integrity of mopsTomlDepsHash
90
+ export function checkLockFileLight() {
91
+ let existingLockFileJson = readLockFile();
92
+ if (existingLockFileJson) {
87
93
  let mopsTomlDepsHash = getMopsTomlDepsHash();
88
- if (mopsTomlDepsHash === lockFileJson.mopsTomlDepsHash) {
89
- return;
94
+ if (existingLockFileJson.version === 3 && mopsTomlDepsHash === existingLockFileJson.mopsTomlDepsHash) {
95
+ return true;
90
96
  }
91
97
  }
98
+ return false;
99
+ }
100
+ export async function updateLockFile() {
101
+ // if lock file exists and mops.toml hasn't changed, don't update it
102
+ if (checkLockFileLight()) {
103
+ return;
104
+ }
105
+ let resolvedDeps = await resolvePackages();
92
106
  let fileHashes = await getFileHashesFromRegistry();
93
107
  let lockFileJson = {
94
- version: 2,
108
+ version: 3,
95
109
  mopsTomlDepsHash: getMopsTomlDepsHash(),
110
+ deps: resolvedDeps,
96
111
  hashes: fileHashes.reduce((acc, [packageId, fileHashes]) => {
97
112
  acc[packageId] = fileHashes.reduce((acc, [fileId, hash]) => {
98
113
  acc[fileId] = bytesToHex(new Uint8Array(hash));
@@ -101,6 +116,8 @@ export async function updateLockFile() {
101
116
  return acc;
102
117
  }, {}),
103
118
  };
119
+ let rootDir = getRootDir();
120
+ let lockFile = path.join(rootDir, 'mops.lock');
104
121
  fs.writeFileSync(lockFile, JSON.stringify(lockFileJson, null, 2));
105
122
  }
106
123
  // compare hashes of local files with hashes from the lock file
@@ -118,9 +135,9 @@ export async function checkLockFile(force = false) {
118
135
  let lockFileJsonGeneric = JSON.parse(fs.readFileSync(lockFile).toString());
119
136
  let packageIds = await getResolvedMopsPackageIds();
120
137
  // check lock file version
121
- if (lockFileJsonGeneric.version !== 1 && lockFileJsonGeneric.version !== 2) {
138
+ if (lockFileJsonGeneric.version !== 1 && lockFileJsonGeneric.version !== 2 && lockFileJsonGeneric.version !== 3) {
122
139
  console.error('Integrity check failed');
123
- console.error(`Invalid lock file version: ${lockFileJsonGeneric.version}. Supported versions: 1`);
140
+ console.error(`Invalid lock file version: ${lockFileJsonGeneric.version}. Supported versions: 1, 2, 3`);
124
141
  process.exit(1);
125
142
  }
126
143
  let lockFileJson = lockFileJsonGeneric;
@@ -134,8 +151,8 @@ export async function checkLockFile(force = false) {
134
151
  process.exit(1);
135
152
  }
136
153
  }
137
- // V2: check mops.toml deps hash
138
- if (lockFileJson.version === 2) {
154
+ // V2, V3: check mops.toml deps hash
155
+ if (lockFileJson.version === 2 || lockFileJson.version === 3) {
139
156
  if (lockFileJson.mopsTomlDepsHash !== getMopsTomlDepsHash()) {
140
157
  console.error('Integrity check failed');
141
158
  console.error('Mismatched mops.toml dependencies hash');
@@ -144,6 +161,20 @@ export async function checkLockFile(force = false) {
144
161
  process.exit(1);
145
162
  }
146
163
  }
164
+ // V3: check locked deps (including GitHub and local packages)
165
+ if (lockFileJson.version === 3) {
166
+ let lockedDeps = { ...lockFileJson.deps };
167
+ let resolvedDeps = await resolvePackages();
168
+ for (let name of Object.keys(resolvedDeps)) {
169
+ if (lockedDeps[name] !== resolvedDeps[name]) {
170
+ console.error('Integrity check failed');
171
+ console.error(`Mismatched package ${name}`);
172
+ console.error(`Locked: ${lockedDeps[name]}`);
173
+ console.error(`Actual: ${resolvedDeps[name]}`);
174
+ process.exit(1);
175
+ }
176
+ }
177
+ }
147
178
  // check number of packages
148
179
  if (Object.keys(lockFileJson.hashes).length !== packageIds.length) {
149
180
  console.error('Integrity check failed');
package/dist/mops.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Identity } from '@dfinity/agent';
2
- import { Config } from './types.js';
2
+ import { Config, Dependency } from './types.js';
3
3
  import { mainActor, storageActor } from './api/actors.js';
4
4
  import { getNetwork } from './api/network.js';
5
5
  import { getHighestVersion } from './api/getHighestVersion.js';
@@ -21,6 +21,7 @@ export declare function parseGithubURL(href: string): {
21
21
  };
22
22
  export declare function getGithubCommit(repo: string, ref: string): Promise<any>;
23
23
  export declare function getDependencyType(version: string): "local" | "mops" | "github";
24
+ export declare function parseDepValue(name: string, value: string): Dependency;
24
25
  export declare function readConfig(configFile?: string): Config;
25
26
  export declare function writeConfig(config: Config, configFile?: string): void;
26
27
  export declare function formatDir(name: string, version: string): string;
package/dist/mops.js CHANGED
@@ -135,6 +135,18 @@ export function getDependencyType(version) {
135
135
  return 'mops';
136
136
  }
137
137
  }
138
+ export function parseDepValue(name, value) {
139
+ let depType = getDependencyType(value);
140
+ if (depType === 'github') {
141
+ return { name, repo: value, version: '' };
142
+ }
143
+ else if (depType === 'local') {
144
+ return { name, repo: '', path: value, version: '' };
145
+ }
146
+ else {
147
+ return { name, repo: '', version: value };
148
+ }
149
+ }
138
150
  export function readConfig(configFile = getClosestConfigFile()) {
139
151
  let text = fs.readFileSync(configFile).toString();
140
152
  let toml = TOML.parse(text);
@@ -143,16 +155,7 @@ export function readConfig(configFile = getClosestConfigFile()) {
143
155
  if (!data || typeof data !== 'string') {
144
156
  throw Error(`Invalid dependency value ${name} = "${data}"`);
145
157
  }
146
- let depType = getDependencyType(data);
147
- if (depType === 'github') {
148
- deps[name] = { name, repo: data, version: '' };
149
- }
150
- else if (depType === 'local') {
151
- deps[name] = { name, repo: '', path: data, version: '' };
152
- }
153
- else {
154
- deps[name] = { name, repo: '', version: data };
155
- }
158
+ deps[name] = parseDepValue(name, data);
156
159
  });
157
160
  };
158
161
  processDeps(toml.dependencies || {});
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ic-mops",
3
- "version": "1.0.1",
3
+ "version": "1.1.0-pre.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mops": "bin/mops.js",
@@ -5,10 +5,17 @@ import { checkConfigFile, getRootDir, parseGithubURL, readConfig } from './mops.
5
5
  import { readVesselConfig } from './vessel.js';
6
6
  import { getDepCacheDir, getDepCacheName } from './cache.js';
7
7
  import { getPackageId } from './helpers/get-package-id.js';
8
+ import { checkLockFileLight, readLockFile } from './integrity.js';
8
9
  export async function resolvePackages({ conflicts = 'ignore' } = {}) {
9
10
  if (!checkConfigFile()) {
10
11
  return {};
11
12
  }
13
+ if (checkLockFileLight()) {
14
+ let lockFileJson = readLockFile();
15
+ if (lockFileJson && lockFileJson.version === 3) {
16
+ return lockFileJson.deps;
17
+ }
18
+ }
12
19
  let rootDir = getRootDir();
13
20
  let packages = {};
14
21
  let versions = {};
package/dist/vessel.d.ts CHANGED
@@ -13,8 +13,9 @@ export declare const readVesselConfig: (dir: string, { cache, silent }?: {
13
13
  silent?: boolean | undefined;
14
14
  }) => Promise<VesselConfig | null>;
15
15
  export declare const downloadFromGithub: (repo: string, dest: string, onProgress: any) => Promise<unknown>;
16
- export declare const installFromGithub: (name: string, repo: string, { verbose, dep, silent }?: {
16
+ export declare const installFromGithub: (name: string, repo: string, { verbose, dep, silent, ignoreTransitive }?: {
17
17
  verbose?: boolean | undefined;
18
18
  dep?: boolean | undefined;
19
19
  silent?: boolean | undefined;
20
+ ignoreTransitive?: boolean | undefined;
20
21
  }) => Promise<void>;
package/dist/vessel.js CHANGED
@@ -116,7 +116,7 @@ export const downloadFromGithub = async (repo, dest, onProgress) => {
116
116
  });
117
117
  return promise;
118
118
  };
119
- export const installFromGithub = async (name, repo, { verbose = false, dep = false, silent = false } = {}) => {
119
+ export const installFromGithub = async (name, repo, { verbose = false, dep = false, silent = false, ignoreTransitive = false } = {}) => {
120
120
  let cacheName = getGithubDepCacheName(name, repo);
121
121
  let cacheDir = getDepCacheDir(cacheName);
122
122
  let logUpdate = createLogUpdate(process.stdout, { showCursor: true });
@@ -143,6 +143,9 @@ export const installFromGithub = async (name, repo, { verbose = false, dep = fal
143
143
  else {
144
144
  logUpdate.clear();
145
145
  }
146
+ if (ignoreTransitive) {
147
+ return;
148
+ }
146
149
  const config = await readVesselConfig(cacheDir, { silent });
147
150
  if (config) {
148
151
  for (const { name, repo } of config.dependencies) {
package/integrity.ts CHANGED
@@ -24,7 +24,14 @@ type LockFileV2 = {
24
24
  hashes : Record<string, Record<string, string>>;
25
25
  };
26
26
 
27
- type LockFile = LockFileV1 | LockFileV2;
27
+ type LockFileV3 = {
28
+ version : 3;
29
+ mopsTomlDepsHash : string;
30
+ hashes : Record<string, Record<string, string>>;
31
+ deps : Record<string, string>;
32
+ };
33
+
34
+ type LockFile = LockFileV1 | LockFileV2 | LockFileV3;
28
35
 
29
36
  export async function checkIntegrity(lock ?: 'check' | 'update' | 'ignore') {
30
37
  let force = !!lock;
@@ -109,24 +116,41 @@ export async function checkRemote() {
109
116
  }
110
117
  }
111
118
 
112
- export async function updateLockFile() {
119
+ export function readLockFile() : LockFile | null {
113
120
  let rootDir = getRootDir();
114
121
  let lockFile = path.join(rootDir, 'mops.lock');
115
-
116
- // if lock file exists and mops.toml hasn't changed, don't update it
117
122
  if (fs.existsSync(lockFile)) {
118
- let lockFileJson : LockFileV2 = JSON.parse(fs.readFileSync(lockFile).toString());
123
+ return JSON.parse(fs.readFileSync(lockFile).toString()) as LockFile;
124
+ }
125
+ return null;
126
+ }
127
+
128
+ // check if lock file exists and integrity of mopsTomlDepsHash
129
+ export function checkLockFileLight() : boolean {
130
+ let existingLockFileJson = readLockFile();
131
+ if (existingLockFileJson) {
119
132
  let mopsTomlDepsHash = getMopsTomlDepsHash();
120
- if (mopsTomlDepsHash === lockFileJson.mopsTomlDepsHash) {
121
- return;
133
+ if (existingLockFileJson.version === 3 && mopsTomlDepsHash === existingLockFileJson.mopsTomlDepsHash) {
134
+ return true;
122
135
  }
123
136
  }
137
+ return false;
138
+ }
139
+
140
+ export async function updateLockFile() {
141
+ // if lock file exists and mops.toml hasn't changed, don't update it
142
+ if (checkLockFileLight()) {
143
+ return;
144
+ }
145
+
146
+ let resolvedDeps = await resolvePackages();
124
147
 
125
148
  let fileHashes = await getFileHashesFromRegistry();
126
149
 
127
- let lockFileJson : LockFileV2 = {
128
- version: 2,
150
+ let lockFileJson : LockFileV3 = {
151
+ version: 3,
129
152
  mopsTomlDepsHash: getMopsTomlDepsHash(),
153
+ deps: resolvedDeps,
130
154
  hashes: fileHashes.reduce((acc, [packageId, fileHashes]) => {
131
155
  acc[packageId] = fileHashes.reduce((acc, [fileId, hash]) => {
132
156
  acc[fileId] = bytesToHex(new Uint8Array(hash));
@@ -136,6 +160,8 @@ export async function updateLockFile() {
136
160
  }, {} as Record<string, Record<string, string>>),
137
161
  };
138
162
 
163
+ let rootDir = getRootDir();
164
+ let lockFile = path.join(rootDir, 'mops.lock');
139
165
  fs.writeFileSync(lockFile, JSON.stringify(lockFileJson, null, 2));
140
166
  }
141
167
 
@@ -157,9 +183,9 @@ export async function checkLockFile(force = false) {
157
183
  let packageIds = await getResolvedMopsPackageIds();
158
184
 
159
185
  // check lock file version
160
- if (lockFileJsonGeneric.version !== 1 && lockFileJsonGeneric.version !== 2) {
186
+ if (lockFileJsonGeneric.version !== 1 && lockFileJsonGeneric.version !== 2 && lockFileJsonGeneric.version !== 3) {
161
187
  console.error('Integrity check failed');
162
- console.error(`Invalid lock file version: ${lockFileJsonGeneric.version}. Supported versions: 1`);
188
+ console.error(`Invalid lock file version: ${lockFileJsonGeneric.version}. Supported versions: 1, 2, 3`);
163
189
  process.exit(1);
164
190
  }
165
191
 
@@ -176,8 +202,8 @@ export async function checkLockFile(force = false) {
176
202
  }
177
203
  }
178
204
 
179
- // V2: check mops.toml deps hash
180
- if (lockFileJson.version === 2) {
205
+ // V2, V3: check mops.toml deps hash
206
+ if (lockFileJson.version === 2 || lockFileJson.version === 3) {
181
207
  if (lockFileJson.mopsTomlDepsHash !== getMopsTomlDepsHash()) {
182
208
  console.error('Integrity check failed');
183
209
  console.error('Mismatched mops.toml dependencies hash');
@@ -187,6 +213,22 @@ export async function checkLockFile(force = false) {
187
213
  }
188
214
  }
189
215
 
216
+ // V3: check locked deps (including GitHub and local packages)
217
+ if (lockFileJson.version === 3) {
218
+ let lockedDeps = {...lockFileJson.deps};
219
+ let resolvedDeps = await resolvePackages();
220
+
221
+ for (let name of Object.keys(resolvedDeps)) {
222
+ if (lockedDeps[name] !== resolvedDeps[name]) {
223
+ console.error('Integrity check failed');
224
+ console.error(`Mismatched package ${name}`);
225
+ console.error(`Locked: ${lockedDeps[name]}`);
226
+ console.error(`Actual: ${resolvedDeps[name]}`);
227
+ process.exit(1);
228
+ }
229
+ }
230
+ }
231
+
190
232
  // check number of packages
191
233
  if (Object.keys(lockFileJson.hashes).length !== packageIds.length) {
192
234
  console.error('Integrity check failed');
package/mops.ts CHANGED
@@ -8,7 +8,7 @@ import prompts from 'prompts';
8
8
  import fetch from 'node-fetch';
9
9
 
10
10
  import {decodeFile} from './pem.js';
11
- import {Config} from './types.js';
11
+ import {Config, Dependency} from './types.js';
12
12
  import {mainActor, storageActor} from './api/actors.js';
13
13
  import {getNetwork} from './api/network.js';
14
14
  import {getHighestVersion} from './api/getHighestVersion.js';
@@ -156,6 +156,19 @@ export function getDependencyType(version : string) {
156
156
  }
157
157
  }
158
158
 
159
+ export function parseDepValue(name : string, value : string) : Dependency {
160
+ let depType = getDependencyType(value);
161
+ if (depType === 'github') {
162
+ return {name, repo: value, version: ''};
163
+ }
164
+ else if (depType === 'local') {
165
+ return {name, repo: '', path: value, version: ''};
166
+ }
167
+ else {
168
+ return {name, repo: '', version: value};
169
+ }
170
+ }
171
+
159
172
  export function readConfig(configFile = getClosestConfigFile()) : Config {
160
173
  let text = fs.readFileSync(configFile).toString();
161
174
  let toml = TOML.parse(text);
@@ -165,16 +178,7 @@ export function readConfig(configFile = getClosestConfigFile()) : Config {
165
178
  if (!data || typeof data !== 'string') {
166
179
  throw Error(`Invalid dependency value ${name} = "${data}"`);
167
180
  }
168
- let depType = getDependencyType(data);
169
- if (depType === 'github') {
170
- deps[name] = {name, repo: data, version: ''};
171
- }
172
- else if (depType === 'local') {
173
- deps[name] = {name, repo: '', path: data, version: ''};
174
- }
175
- else {
176
- deps[name] = {name, repo: '', version: data};
177
- }
181
+ deps[name] = parseDepValue(name, data);
178
182
  });
179
183
  };
180
184
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ic-mops",
3
- "version": "1.0.1",
3
+ "version": "1.1.0-pre.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mops": "dist/bin/mops.js",
@@ -6,12 +6,21 @@ import {VesselConfig, readVesselConfig} from './vessel.js';
6
6
  import {Config, Dependency} from './types.js';
7
7
  import {getDepCacheDir, getDepCacheName} from './cache.js';
8
8
  import {getPackageId} from './helpers/get-package-id.js';
9
+ import {checkLockFileLight, readLockFile} from './integrity.js';
9
10
 
10
11
  export async function resolvePackages({conflicts = 'ignore' as 'warning' | 'error' | 'ignore'} = {}) : Promise<Record<string, string>> {
11
12
  if (!checkConfigFile()) {
12
13
  return {};
13
14
  }
14
15
 
16
+ if (checkLockFileLight()) {
17
+ let lockFileJson = readLockFile();
18
+
19
+ if (lockFileJson && lockFileJson.version === 3) {
20
+ return lockFileJson.deps;
21
+ }
22
+ }
23
+
15
24
  let rootDir = getRootDir();
16
25
  let packages : Record<string, Dependency & {isRoot : boolean;}> = {};
17
26
  let versions : Record<string, Array<{
package/test ADDED
@@ -0,0 +1,4 @@
1
+ dev, toolchain 89s
2
+ no dev, no toolchain 68s
3
+ lockfile, toolchain 60s
4
+ lockfile, no toolchain 49s
package/vessel.ts CHANGED
@@ -149,7 +149,7 @@ export const downloadFromGithub = async (repo : string, dest : string, onProgres
149
149
  return promise;
150
150
  };
151
151
 
152
- export const installFromGithub = async (name : string, repo : string, {verbose = false, dep = false, silent = false} = {}) => {
152
+ export const installFromGithub = async (name : string, repo : string, {verbose = false, dep = false, silent = false, ignoreTransitive = false} = {}) => {
153
153
  let cacheName = getGithubDepCacheName(name, repo);
154
154
  let cacheDir = getDepCacheDir(cacheName);
155
155
 
@@ -183,6 +183,10 @@ export const installFromGithub = async (name : string, repo : string, {verbose =
183
183
  logUpdate.clear();
184
184
  }
185
185
 
186
+ if (ignoreTransitive) {
187
+ return;
188
+ }
189
+
186
190
  const config = await readVesselConfig(cacheDir, {silent});
187
191
 
188
192
  if (config) {