ic-mops 0.27.3 → 0.28.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/commands/add.ts +8 -2
- package/commands/install-all.ts +7 -2
- package/commands/install.ts +16 -6
- package/commands/publish.ts +27 -5
- package/commands/sources.ts +13 -112
- package/declarations/main/main.did +4 -0
- package/declarations/main/main.did.d.ts +4 -0
- package/declarations/main/main.did.js +5 -0
- package/dist/commands/add.js +6 -2
- package/dist/commands/install-all.js +6 -2
- package/dist/commands/install.d.ts +1 -1
- package/dist/commands/install.js +14 -4
- package/dist/commands/publish.js +23 -5
- package/dist/commands/sources.js +12 -95
- package/dist/declarations/main/main.did +4 -0
- package/dist/declarations/main/main.did.d.ts +4 -0
- package/dist/declarations/main/main.did.js +5 -0
- package/dist/mops.d.ts +1 -0
- package/dist/mops.js +17 -2
- package/dist/notify-installs.d.ts +1 -0
- package/dist/notify-installs.js +10 -0
- package/dist/package.json +1 -1
- package/dist/resolve-packages.d.ts +3 -0
- package/dist/resolve-packages.js +108 -0
- package/mops.ts +18 -2
- package/notify-installs.ts +11 -0
- package/package.json +1 -1
- package/resolve-packages.ts +131 -0
package/commands/add.ts
CHANGED
|
@@ -4,6 +4,7 @@ import logUpdate from 'log-update';
|
|
|
4
4
|
import {checkConfigFile, getHighestVersion, parseGithubURL, readConfig, writeConfig} from '../mops.js';
|
|
5
5
|
import {installFromGithub} from '../vessel.js';
|
|
6
6
|
import {install} from './install.js';
|
|
7
|
+
import {notifyInstalls} from '../notify-installs.js';
|
|
7
8
|
|
|
8
9
|
export async function add(name: string, {verbose = false, dev = false} = {}) {
|
|
9
10
|
if (!checkConfigFile()) {
|
|
@@ -66,14 +67,17 @@ export async function add(name: string, {verbose = false, dev = false} = {}) {
|
|
|
66
67
|
};
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
let installedPackages = {};
|
|
71
|
+
|
|
69
72
|
if (pkgDetails.repo) {
|
|
70
73
|
await installFromGithub(pkgDetails.name, pkgDetails.repo, {verbose: verbose});
|
|
71
74
|
}
|
|
72
75
|
else if (!pkgDetails.path) {
|
|
73
|
-
let
|
|
74
|
-
if (
|
|
76
|
+
let res = await install(pkgDetails.name, pkgDetails.version, {verbose: verbose});
|
|
77
|
+
if (res === false) {
|
|
75
78
|
return;
|
|
76
79
|
}
|
|
80
|
+
installedPackages = {...installedPackages, ...res};
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
const depsProp = dev ? 'dev-dependencies' : 'dependencies';
|
|
@@ -84,7 +88,9 @@ export async function add(name: string, {verbose = false, dev = false} = {}) {
|
|
|
84
88
|
else {
|
|
85
89
|
throw Error(`Invalid config file: [${depsProp}] not found`);
|
|
86
90
|
}
|
|
91
|
+
|
|
87
92
|
writeConfig(config);
|
|
93
|
+
await notifyInstalls(Object.keys(installedPackages));
|
|
88
94
|
|
|
89
95
|
logUpdate.clear();
|
|
90
96
|
console.log(chalk.green('Package installed ') + `${pkgDetails.name} = "${pkgDetails.repo || pkgDetails.path || pkgDetails.version}"`);
|
package/commands/install-all.ts
CHANGED
|
@@ -3,6 +3,7 @@ import logUpdate from 'log-update';
|
|
|
3
3
|
import {checkConfigFile, readConfig} from '../mops.js';
|
|
4
4
|
import {install} from './install.js';
|
|
5
5
|
import {installFromGithub} from '../vessel.js';
|
|
6
|
+
import {notifyInstalls} from '../notify-installs.js';
|
|
6
7
|
|
|
7
8
|
export async function installAll({verbose = false, silent = false} = {}) {
|
|
8
9
|
if (!checkConfigFile()) {
|
|
@@ -13,19 +14,23 @@ export async function installAll({verbose = false, silent = false} = {}) {
|
|
|
13
14
|
let deps = Object.values(config.dependencies || {});
|
|
14
15
|
let devDeps = Object.values(config['dev-dependencies'] || {});
|
|
15
16
|
let allDeps = [...deps, ...devDeps];
|
|
17
|
+
let installedPackages = {};
|
|
16
18
|
|
|
17
19
|
for (let {name, repo, path, version} of allDeps) {
|
|
18
20
|
if (repo) {
|
|
19
21
|
await installFromGithub(name, repo, {verbose, silent});
|
|
20
22
|
}
|
|
21
23
|
else if (!path) {
|
|
22
|
-
let
|
|
23
|
-
if (
|
|
24
|
+
let res = await install(name, version, {verbose, silent});
|
|
25
|
+
if (res === false) {
|
|
24
26
|
return;
|
|
25
27
|
}
|
|
28
|
+
installedPackages = {...installedPackages, ...res};
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
await notifyInstalls(Object.keys(installedPackages));
|
|
33
|
+
|
|
29
34
|
if (!silent) {
|
|
30
35
|
logUpdate.clear();
|
|
31
36
|
console.log(chalk.green('All packages installed'));
|
package/commands/install.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {parallel} from '../parallel.js';
|
|
|
7
7
|
import {installFromGithub} from '../vessel.js';
|
|
8
8
|
import {addCache, copyCache, isCached} from '../cache.js';
|
|
9
9
|
|
|
10
|
-
export async function install(pkg: string, version = '', {verbose = false, silent = false, dep = false} = {}) {
|
|
10
|
+
export async function install(pkg: string, version = '', {verbose = false, silent = false, dep = false} = {}): Promise<Record<string, string> | false> {
|
|
11
11
|
if (!checkConfigFile()) {
|
|
12
12
|
return false;
|
|
13
13
|
}
|
|
@@ -32,14 +32,15 @@ export async function install(pkg: string, version = '', {verbose = false, silen
|
|
|
32
32
|
|
|
33
33
|
let dir = formatDir(pkg, version);
|
|
34
34
|
let actor = await mainActor();
|
|
35
|
+
let alreadyInstalled = false;
|
|
35
36
|
|
|
36
37
|
// already installed
|
|
37
38
|
if (fs.existsSync(dir)) {
|
|
38
39
|
silent || logUpdate(`${dep ? 'Dependency' : 'Installing'} ${pkg}@${version} (already installed)`);
|
|
40
|
+
alreadyInstalled = true;
|
|
39
41
|
}
|
|
40
42
|
// copy from cache
|
|
41
43
|
else if (isCached(`${pkg}@${version}`)) {
|
|
42
|
-
actor.notifyInstall(pkg, version);
|
|
43
44
|
await copyCache(`${pkg}@${version}`, dir);
|
|
44
45
|
silent || logUpdate(`${dep ? 'Dependency' : 'Installing'} ${pkg}@${version} (cache)`);
|
|
45
46
|
}
|
|
@@ -65,8 +66,6 @@ export async function install(pkg: string, version = '', {verbose = false, silen
|
|
|
65
66
|
|
|
66
67
|
let storage = await storageActor(packageDetails.publication.storage);
|
|
67
68
|
|
|
68
|
-
actor.notifyInstall(pkg, version);
|
|
69
|
-
|
|
70
69
|
// download files
|
|
71
70
|
let filesData = new Map;
|
|
72
71
|
let threads = 16;
|
|
@@ -118,17 +117,28 @@ export async function install(pkg: string, version = '', {verbose = false, silen
|
|
|
118
117
|
let ok = true;
|
|
119
118
|
let config = readConfig(path.join(dir, 'mops.toml'));
|
|
120
119
|
let deps = Object.values(config.dependencies || {});
|
|
120
|
+
let installedDeps = {};
|
|
121
121
|
for (const {name, repo, version} of deps) {
|
|
122
122
|
if (repo) {
|
|
123
123
|
await installFromGithub(name, repo, {silent, verbose});
|
|
124
124
|
}
|
|
125
125
|
else {
|
|
126
126
|
let res = await install(name, version, {silent, verbose});
|
|
127
|
-
if (
|
|
127
|
+
if (res) {
|
|
128
|
+
installedDeps = {...installedDeps, ...res};
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
128
131
|
ok = false;
|
|
129
132
|
}
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
|
|
133
|
-
|
|
136
|
+
if (!alreadyInstalled) {
|
|
137
|
+
installedDeps = {...installedDeps, [pkg]: version};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (ok) {
|
|
141
|
+
return installedDeps;
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
134
144
|
}
|
package/commands/publish.ts
CHANGED
|
@@ -233,6 +233,14 @@ export async function publish(options: {docs?: boolean, test?: boolean} = {}) {
|
|
|
233
233
|
// parse changelog
|
|
234
234
|
console.log('Parsing CHANGELOG.md...');
|
|
235
235
|
let changelog = parseChangelog(config.package.version);
|
|
236
|
+
if (!changelog && config.package.repository) {
|
|
237
|
+
console.log('Fetching release notes from GitHub...');
|
|
238
|
+
changelog = await fetchGitHubReleaseNotes(config.package.repository, config.package.version);
|
|
239
|
+
}
|
|
240
|
+
if (changelog) {
|
|
241
|
+
console.log('Changelog:');
|
|
242
|
+
console.log(chalk.gray(changelog));
|
|
243
|
+
}
|
|
236
244
|
|
|
237
245
|
// test
|
|
238
246
|
let reporter = new SilentReporter;
|
|
@@ -342,17 +350,31 @@ function parseChangelog(version: string): string {
|
|
|
342
350
|
let str = fs.readFileSync(changelogFile, 'utf-8');
|
|
343
351
|
let changelog = findChangelogEntry(str, version);
|
|
344
352
|
|
|
345
|
-
if (changelog) {
|
|
346
|
-
console.log('Changelog:');
|
|
347
|
-
console.log(chalk.gray(changelog));
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
353
|
+
if (!changelog) {
|
|
350
354
|
console.log(chalk.yellow('No changelog entry found'));
|
|
351
355
|
}
|
|
352
356
|
|
|
353
357
|
return changelog || '';
|
|
354
358
|
}
|
|
355
359
|
|
|
360
|
+
async function fetchGitHubReleaseNotes(repo: string, version: string): Promise<string> {
|
|
361
|
+
let repoPath = new URL(repo).pathname;
|
|
362
|
+
let res = await fetch(`https://api.github.com/repos${repoPath}/releases/tags/${version}`);
|
|
363
|
+
let release = await res.json();
|
|
364
|
+
|
|
365
|
+
if (release.message === 'Not Found') {
|
|
366
|
+
res = await fetch(`https://api.github.com/repos${repoPath}/releases/tags/v${version}`);
|
|
367
|
+
release = await res.json();
|
|
368
|
+
|
|
369
|
+
if (release.message === 'Not Found') {
|
|
370
|
+
console.log(chalk.yellow(`No GitHub release found with name ${version} or v${version}`));
|
|
371
|
+
return '';
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return release.body;
|
|
376
|
+
}
|
|
377
|
+
|
|
356
378
|
function findChangelogEntry(changelog: string, version: string): string {
|
|
357
379
|
let tree = fromMarkdown(changelog);
|
|
358
380
|
let found = false;
|
package/commands/sources.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {VesselConfig, readVesselConfig} from '../vessel.js';
|
|
6
|
-
import {Config, Dependency} from '../types.js';
|
|
3
|
+
import {checkConfigFile, formatDir, formatGithubDir, getDependencyType, readConfig} from '../mops.js';
|
|
4
|
+
import {resolvePackages} from '../resolve-packages.js';
|
|
7
5
|
|
|
8
6
|
// TODO: resolve conflicts
|
|
9
7
|
export async function sources({verbose = false} = {}) {
|
|
@@ -11,118 +9,21 @@ export async function sources({verbose = false} = {}) {
|
|
|
11
9
|
return [];
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
let
|
|
15
|
-
let versions: Record<string, string[]> = {};
|
|
16
|
-
|
|
17
|
-
let compareVersions = (a: string = '0.0.0', b: string = '0.0.0') => {
|
|
18
|
-
let ap = a.split('.').map((x: string) => parseInt(x)) as [number, number, number];
|
|
19
|
-
let bp = b.split('.').map((x: string) => parseInt(x)) as [number, number, number];
|
|
20
|
-
if (ap[0] - bp[0]) {
|
|
21
|
-
return Math.sign(ap[0] - bp[0]);
|
|
22
|
-
}
|
|
23
|
-
if (ap[0] === bp[0] && ap[1] - bp[1]) {
|
|
24
|
-
return Math.sign(ap[1] - bp[1]);
|
|
25
|
-
}
|
|
26
|
-
if (ap[0] === bp[0] && ap[1] === bp[1] && ap[2] - bp[2]) {
|
|
27
|
-
return Math.sign(ap[2] - bp[2]);
|
|
28
|
-
}
|
|
29
|
-
return 0;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const gitVerRegex = new RegExp(/v(\d{1,2}\.\d{1,2}\.\d{1,2})(-.*)?$/);
|
|
33
|
-
|
|
34
|
-
const compareGitVersions = (repoA: string, repoB: string) => {
|
|
35
|
-
const {branch: a} = parseGithubURL(repoA);
|
|
36
|
-
const {branch: b} = parseGithubURL(repoB);
|
|
37
|
-
|
|
38
|
-
if (gitVerRegex.test(a) && gitVerRegex.test(b)) {
|
|
39
|
-
return compareVersions(a.substring(1) , b.substring(1));
|
|
40
|
-
}
|
|
41
|
-
else if (!gitVerRegex.test(a)) {
|
|
42
|
-
return -1;
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
return 1;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
let collectDeps = async (config: Config | VesselConfig, isRoot = false) => {
|
|
50
|
-
let allDeps = [...Object.values(config.dependencies || {})];
|
|
51
|
-
if (isRoot) {
|
|
52
|
-
allDeps = [...allDeps, ...Object.values(config['dev-dependencies'] || {})];
|
|
53
|
-
}
|
|
54
|
-
for (const pkgDetails of allDeps) {
|
|
55
|
-
const {name, repo, version} = pkgDetails;
|
|
56
|
-
|
|
57
|
-
// take root dep version or bigger one
|
|
58
|
-
if (
|
|
59
|
-
isRoot
|
|
60
|
-
|| !packages[name]
|
|
61
|
-
|| !packages[name]?.isRoot
|
|
62
|
-
&& (
|
|
63
|
-
repo && packages[name]?.repo && compareGitVersions(packages[name]?.repo || '', repo) === -1
|
|
64
|
-
|| compareVersions(packages[name]?.version, version) === -1)
|
|
65
|
-
) {
|
|
66
|
-
packages[name] = {
|
|
67
|
-
...pkgDetails,
|
|
68
|
-
isRoot,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let nestedConfig;
|
|
73
|
-
|
|
74
|
-
if (repo) {
|
|
75
|
-
const dir = formatGithubDir(name, repo);
|
|
76
|
-
nestedConfig = await readVesselConfig(dir) || {};
|
|
77
|
-
}
|
|
78
|
-
else if (!pkgDetails.path && version) {
|
|
79
|
-
const file = formatDir(name, version) + '/mops.toml';
|
|
80
|
-
nestedConfig = readConfig(file);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (nestedConfig && !pkgDetails.path) {
|
|
84
|
-
await collectDeps(nestedConfig);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (!versions[name]) {
|
|
88
|
-
versions[name] = [];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (repo) {
|
|
92
|
-
const {branch} = parseGithubURL(repo);
|
|
93
|
-
versions[name]?.push(branch);
|
|
94
|
-
}
|
|
95
|
-
else if (version) {
|
|
96
|
-
versions[name]?.push(version);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
let config = readConfig();
|
|
102
|
-
await collectDeps(config, true);
|
|
103
|
-
|
|
104
|
-
// show conflicts
|
|
105
|
-
if (verbose) {
|
|
106
|
-
for (let [dep, vers] of Object.entries(versions)) {
|
|
107
|
-
if (vers.length > 1) {
|
|
108
|
-
console.log(chalk.yellow('WARN:'), `Conflicting package versions "${dep}" - ${vers.join(', ')}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
12
|
+
let resolvedPackages = await resolvePackages({verbose});
|
|
112
13
|
|
|
113
14
|
// sources
|
|
114
|
-
|
|
115
|
-
|
|
15
|
+
return Object.entries(resolvedPackages).map(([name, version]) => {
|
|
16
|
+
let depType = getDependencyType(version);
|
|
17
|
+
|
|
116
18
|
let pkgDir;
|
|
117
|
-
if (
|
|
118
|
-
pkgDir = path.relative(process.cwd(),
|
|
119
|
-
pkgDir = pkgDir.replaceAll('{MOPS_ENV}', process.env.MOPS_ENV || 'local');
|
|
19
|
+
if (depType === 'local') {
|
|
20
|
+
pkgDir = path.relative(process.cwd(), version);
|
|
120
21
|
}
|
|
121
|
-
else if (
|
|
122
|
-
pkgDir = path.relative(process.cwd(), formatGithubDir(name,
|
|
22
|
+
else if (depType === 'github') {
|
|
23
|
+
pkgDir = path.relative(process.cwd(), formatGithubDir(name, version));
|
|
123
24
|
}
|
|
124
|
-
else if (
|
|
125
|
-
pkgDir = path.relative(process.cwd(), formatDir(name,
|
|
25
|
+
else if (depType === 'mops') {
|
|
26
|
+
pkgDir = path.relative(process.cwd(), formatDir(name, version));
|
|
126
27
|
}
|
|
127
28
|
else {
|
|
128
29
|
return;
|
|
@@ -139,7 +40,7 @@ export async function sources({verbose = false} = {}) {
|
|
|
139
40
|
}
|
|
140
41
|
|
|
141
42
|
// use pkgDir if baseDir doesn't exist for local packages
|
|
142
|
-
if (
|
|
43
|
+
if (depType === 'local' && !fs.existsSync(pkgBaseDir)) {
|
|
143
44
|
pkgBaseDir = pkgDir;
|
|
144
45
|
}
|
|
145
46
|
|
|
@@ -301,6 +301,10 @@ service : {
|
|
|
301
301
|
getTotalPackages: () -> (nat) query;
|
|
302
302
|
getUser: (principal) -> (opt User__1) query;
|
|
303
303
|
notifyInstall: (PackageName__1, PackageVersion) -> () oneway;
|
|
304
|
+
notifyInstalls: (vec record {
|
|
305
|
+
PackageName__1;
|
|
306
|
+
PackageVersion;
|
|
307
|
+
}) -> () oneway;
|
|
304
308
|
restore: (nat, nat) -> ();
|
|
305
309
|
search: (Text, opt nat, opt nat) -> (vec PackageSummary, PageCount) query;
|
|
306
310
|
setUserProp: (text, text) -> (Result_3);
|
|
@@ -247,6 +247,10 @@ export interface _SERVICE {
|
|
|
247
247
|
'getTotalPackages' : ActorMethod<[], bigint>,
|
|
248
248
|
'getUser' : ActorMethod<[Principal], [] | [User__1]>,
|
|
249
249
|
'notifyInstall' : ActorMethod<[PackageName__1, PackageVersion], undefined>,
|
|
250
|
+
'notifyInstalls' : ActorMethod<
|
|
251
|
+
[Array<[PackageName__1, PackageVersion]>],
|
|
252
|
+
undefined
|
|
253
|
+
>,
|
|
250
254
|
'restore' : ActorMethod<[bigint, bigint], undefined>,
|
|
251
255
|
'search' : ActorMethod<
|
|
252
256
|
[Text, [] | [bigint], [] | [bigint]],
|
|
@@ -275,6 +275,11 @@ export const idlFactory = ({ IDL }) => {
|
|
|
275
275
|
[],
|
|
276
276
|
['oneway'],
|
|
277
277
|
),
|
|
278
|
+
'notifyInstalls' : IDL.Func(
|
|
279
|
+
[IDL.Vec(IDL.Tuple(PackageName__1, PackageVersion))],
|
|
280
|
+
[],
|
|
281
|
+
['oneway'],
|
|
282
|
+
),
|
|
278
283
|
'restore' : IDL.Func([IDL.Nat, IDL.Nat], [], []),
|
|
279
284
|
'search' : IDL.Func(
|
|
280
285
|
[Text, IDL.Opt(IDL.Nat), IDL.Opt(IDL.Nat)],
|
package/dist/commands/add.js
CHANGED
|
@@ -4,6 +4,7 @@ import logUpdate from 'log-update';
|
|
|
4
4
|
import { checkConfigFile, getHighestVersion, parseGithubURL, readConfig, writeConfig } from '../mops.js';
|
|
5
5
|
import { installFromGithub } from '../vessel.js';
|
|
6
6
|
import { install } from './install.js';
|
|
7
|
+
import { notifyInstalls } from '../notify-installs.js';
|
|
7
8
|
export async function add(name, { verbose = false, dev = false } = {}) {
|
|
8
9
|
if (!checkConfigFile()) {
|
|
9
10
|
return;
|
|
@@ -59,14 +60,16 @@ export async function add(name, { verbose = false, dev = false } = {}) {
|
|
|
59
60
|
version: ver,
|
|
60
61
|
};
|
|
61
62
|
}
|
|
63
|
+
let installedPackages = {};
|
|
62
64
|
if (pkgDetails.repo) {
|
|
63
65
|
await installFromGithub(pkgDetails.name, pkgDetails.repo, { verbose: verbose });
|
|
64
66
|
}
|
|
65
67
|
else if (!pkgDetails.path) {
|
|
66
|
-
let
|
|
67
|
-
if (
|
|
68
|
+
let res = await install(pkgDetails.name, pkgDetails.version, { verbose: verbose });
|
|
69
|
+
if (res === false) {
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
72
|
+
installedPackages = { ...installedPackages, ...res };
|
|
70
73
|
}
|
|
71
74
|
const depsProp = dev ? 'dev-dependencies' : 'dependencies';
|
|
72
75
|
let deps = config[depsProp];
|
|
@@ -77,6 +80,7 @@ export async function add(name, { verbose = false, dev = false } = {}) {
|
|
|
77
80
|
throw Error(`Invalid config file: [${depsProp}] not found`);
|
|
78
81
|
}
|
|
79
82
|
writeConfig(config);
|
|
83
|
+
await notifyInstalls(Object.keys(installedPackages));
|
|
80
84
|
logUpdate.clear();
|
|
81
85
|
console.log(chalk.green('Package installed ') + `${pkgDetails.name} = "${pkgDetails.repo || pkgDetails.path || pkgDetails.version}"`);
|
|
82
86
|
}
|
|
@@ -3,6 +3,7 @@ import logUpdate from 'log-update';
|
|
|
3
3
|
import { checkConfigFile, readConfig } from '../mops.js';
|
|
4
4
|
import { install } from './install.js';
|
|
5
5
|
import { installFromGithub } from '../vessel.js';
|
|
6
|
+
import { notifyInstalls } from '../notify-installs.js';
|
|
6
7
|
export async function installAll({ verbose = false, silent = false } = {}) {
|
|
7
8
|
if (!checkConfigFile()) {
|
|
8
9
|
return;
|
|
@@ -11,17 +12,20 @@ export async function installAll({ verbose = false, silent = false } = {}) {
|
|
|
11
12
|
let deps = Object.values(config.dependencies || {});
|
|
12
13
|
let devDeps = Object.values(config['dev-dependencies'] || {});
|
|
13
14
|
let allDeps = [...deps, ...devDeps];
|
|
15
|
+
let installedPackages = {};
|
|
14
16
|
for (let { name, repo, path, version } of allDeps) {
|
|
15
17
|
if (repo) {
|
|
16
18
|
await installFromGithub(name, repo, { verbose, silent });
|
|
17
19
|
}
|
|
18
20
|
else if (!path) {
|
|
19
|
-
let
|
|
20
|
-
if (
|
|
21
|
+
let res = await install(name, version, { verbose, silent });
|
|
22
|
+
if (res === false) {
|
|
21
23
|
return;
|
|
22
24
|
}
|
|
25
|
+
installedPackages = { ...installedPackages, ...res };
|
|
23
26
|
}
|
|
24
27
|
}
|
|
28
|
+
await notifyInstalls(Object.keys(installedPackages));
|
|
25
29
|
if (!silent) {
|
|
26
30
|
logUpdate.clear();
|
|
27
31
|
console.log(chalk.green('All packages installed'));
|
package/dist/commands/install.js
CHANGED
|
@@ -28,13 +28,14 @@ export async function install(pkg, version = '', { verbose = false, silent = fal
|
|
|
28
28
|
}
|
|
29
29
|
let dir = formatDir(pkg, version);
|
|
30
30
|
let actor = await mainActor();
|
|
31
|
+
let alreadyInstalled = false;
|
|
31
32
|
// already installed
|
|
32
33
|
if (fs.existsSync(dir)) {
|
|
33
34
|
silent || logUpdate(`${dep ? 'Dependency' : 'Installing'} ${pkg}@${version} (already installed)`);
|
|
35
|
+
alreadyInstalled = true;
|
|
34
36
|
}
|
|
35
37
|
// copy from cache
|
|
36
38
|
else if (isCached(`${pkg}@${version}`)) {
|
|
37
|
-
actor.notifyInstall(pkg, version);
|
|
38
39
|
await copyCache(`${pkg}@${version}`, dir);
|
|
39
40
|
silent || logUpdate(`${dep ? 'Dependency' : 'Installing'} ${pkg}@${version} (cache)`);
|
|
40
41
|
}
|
|
@@ -56,7 +57,6 @@ export async function install(pkg, version = '', { verbose = false, silent = fal
|
|
|
56
57
|
let filesIds = filesIdsRes.ok;
|
|
57
58
|
total = filesIds.length + 2;
|
|
58
59
|
let storage = await storageActor(packageDetails.publication.storage);
|
|
59
|
-
actor.notifyInstall(pkg, version);
|
|
60
60
|
// download files
|
|
61
61
|
let filesData = new Map;
|
|
62
62
|
let threads = 16;
|
|
@@ -100,16 +100,26 @@ export async function install(pkg, version = '', { verbose = false, silent = fal
|
|
|
100
100
|
let ok = true;
|
|
101
101
|
let config = readConfig(path.join(dir, 'mops.toml'));
|
|
102
102
|
let deps = Object.values(config.dependencies || {});
|
|
103
|
+
let installedDeps = {};
|
|
103
104
|
for (const { name, repo, version } of deps) {
|
|
104
105
|
if (repo) {
|
|
105
106
|
await installFromGithub(name, repo, { silent, verbose });
|
|
106
107
|
}
|
|
107
108
|
else {
|
|
108
109
|
let res = await install(name, version, { silent, verbose });
|
|
109
|
-
if (
|
|
110
|
+
if (res) {
|
|
111
|
+
installedDeps = { ...installedDeps, ...res };
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
110
114
|
ok = false;
|
|
111
115
|
}
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
|
-
|
|
118
|
+
if (!alreadyInstalled) {
|
|
119
|
+
installedDeps = { ...installedDeps, [pkg]: version };
|
|
120
|
+
}
|
|
121
|
+
if (ok) {
|
|
122
|
+
return installedDeps;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
115
125
|
}
|
package/dist/commands/publish.js
CHANGED
|
@@ -208,6 +208,14 @@ export async function publish(options = {}) {
|
|
|
208
208
|
// parse changelog
|
|
209
209
|
console.log('Parsing CHANGELOG.md...');
|
|
210
210
|
let changelog = parseChangelog(config.package.version);
|
|
211
|
+
if (!changelog && config.package.repository) {
|
|
212
|
+
console.log('Fetching release notes from GitHub...');
|
|
213
|
+
changelog = await fetchGitHubReleaseNotes(config.package.repository, config.package.version);
|
|
214
|
+
}
|
|
215
|
+
if (changelog) {
|
|
216
|
+
console.log('Changelog:');
|
|
217
|
+
console.log(chalk.gray(changelog));
|
|
218
|
+
}
|
|
211
219
|
// test
|
|
212
220
|
let reporter = new SilentReporter;
|
|
213
221
|
if (options.test) {
|
|
@@ -298,15 +306,25 @@ function parseChangelog(version) {
|
|
|
298
306
|
}
|
|
299
307
|
let str = fs.readFileSync(changelogFile, 'utf-8');
|
|
300
308
|
let changelog = findChangelogEntry(str, version);
|
|
301
|
-
if (changelog) {
|
|
302
|
-
console.log('Changelog:');
|
|
303
|
-
console.log(chalk.gray(changelog));
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
309
|
+
if (!changelog) {
|
|
306
310
|
console.log(chalk.yellow('No changelog entry found'));
|
|
307
311
|
}
|
|
308
312
|
return changelog || '';
|
|
309
313
|
}
|
|
314
|
+
async function fetchGitHubReleaseNotes(repo, version) {
|
|
315
|
+
let repoPath = new URL(repo).pathname;
|
|
316
|
+
let res = await fetch(`https://api.github.com/repos${repoPath}/releases/tags/${version}`);
|
|
317
|
+
let release = await res.json();
|
|
318
|
+
if (release.message === 'Not Found') {
|
|
319
|
+
res = await fetch(`https://api.github.com/repos${repoPath}/releases/tags/v${version}`);
|
|
320
|
+
release = await res.json();
|
|
321
|
+
if (release.message === 'Not Found') {
|
|
322
|
+
console.log(chalk.yellow(`No GitHub release found with name ${version} or v${version}`));
|
|
323
|
+
return '';
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return release.body;
|
|
327
|
+
}
|
|
310
328
|
function findChangelogEntry(changelog, version) {
|
|
311
329
|
let tree = fromMarkdown(changelog);
|
|
312
330
|
let found = false;
|
package/dist/commands/sources.js
CHANGED
|
@@ -1,108 +1,25 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import { readVesselConfig } from '../vessel.js';
|
|
3
|
+
import { checkConfigFile, formatDir, formatGithubDir, getDependencyType, readConfig } from '../mops.js';
|
|
4
|
+
import { resolvePackages } from '../resolve-packages.js';
|
|
6
5
|
// TODO: resolve conflicts
|
|
7
6
|
export async function sources({ verbose = false } = {}) {
|
|
8
7
|
if (!checkConfigFile()) {
|
|
9
8
|
return [];
|
|
10
9
|
}
|
|
11
|
-
let
|
|
12
|
-
let versions = {};
|
|
13
|
-
let compareVersions = (a = '0.0.0', b = '0.0.0') => {
|
|
14
|
-
let ap = a.split('.').map((x) => parseInt(x));
|
|
15
|
-
let bp = b.split('.').map((x) => parseInt(x));
|
|
16
|
-
if (ap[0] - bp[0]) {
|
|
17
|
-
return Math.sign(ap[0] - bp[0]);
|
|
18
|
-
}
|
|
19
|
-
if (ap[0] === bp[0] && ap[1] - bp[1]) {
|
|
20
|
-
return Math.sign(ap[1] - bp[1]);
|
|
21
|
-
}
|
|
22
|
-
if (ap[0] === bp[0] && ap[1] === bp[1] && ap[2] - bp[2]) {
|
|
23
|
-
return Math.sign(ap[2] - bp[2]);
|
|
24
|
-
}
|
|
25
|
-
return 0;
|
|
26
|
-
};
|
|
27
|
-
const gitVerRegex = new RegExp(/v(\d{1,2}\.\d{1,2}\.\d{1,2})(-.*)?$/);
|
|
28
|
-
const compareGitVersions = (repoA, repoB) => {
|
|
29
|
-
const { branch: a } = parseGithubURL(repoA);
|
|
30
|
-
const { branch: b } = parseGithubURL(repoB);
|
|
31
|
-
if (gitVerRegex.test(a) && gitVerRegex.test(b)) {
|
|
32
|
-
return compareVersions(a.substring(1), b.substring(1));
|
|
33
|
-
}
|
|
34
|
-
else if (!gitVerRegex.test(a)) {
|
|
35
|
-
return -1;
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
return 1;
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
let collectDeps = async (config, isRoot = false) => {
|
|
42
|
-
let allDeps = [...Object.values(config.dependencies || {})];
|
|
43
|
-
if (isRoot) {
|
|
44
|
-
allDeps = [...allDeps, ...Object.values(config['dev-dependencies'] || {})];
|
|
45
|
-
}
|
|
46
|
-
for (const pkgDetails of allDeps) {
|
|
47
|
-
const { name, repo, version } = pkgDetails;
|
|
48
|
-
// take root dep version or bigger one
|
|
49
|
-
if (isRoot
|
|
50
|
-
|| !packages[name]
|
|
51
|
-
|| !packages[name]?.isRoot
|
|
52
|
-
&& (repo && packages[name]?.repo && compareGitVersions(packages[name]?.repo || '', repo) === -1
|
|
53
|
-
|| compareVersions(packages[name]?.version, version) === -1)) {
|
|
54
|
-
packages[name] = {
|
|
55
|
-
...pkgDetails,
|
|
56
|
-
isRoot,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
let nestedConfig;
|
|
60
|
-
if (repo) {
|
|
61
|
-
const dir = formatGithubDir(name, repo);
|
|
62
|
-
nestedConfig = await readVesselConfig(dir) || {};
|
|
63
|
-
}
|
|
64
|
-
else if (!pkgDetails.path && version) {
|
|
65
|
-
const file = formatDir(name, version) + '/mops.toml';
|
|
66
|
-
nestedConfig = readConfig(file);
|
|
67
|
-
}
|
|
68
|
-
if (nestedConfig && !pkgDetails.path) {
|
|
69
|
-
await collectDeps(nestedConfig);
|
|
70
|
-
}
|
|
71
|
-
if (!versions[name]) {
|
|
72
|
-
versions[name] = [];
|
|
73
|
-
}
|
|
74
|
-
if (repo) {
|
|
75
|
-
const { branch } = parseGithubURL(repo);
|
|
76
|
-
versions[name]?.push(branch);
|
|
77
|
-
}
|
|
78
|
-
else if (version) {
|
|
79
|
-
versions[name]?.push(version);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
let config = readConfig();
|
|
84
|
-
await collectDeps(config, true);
|
|
85
|
-
// show conflicts
|
|
86
|
-
if (verbose) {
|
|
87
|
-
for (let [dep, vers] of Object.entries(versions)) {
|
|
88
|
-
if (vers.length > 1) {
|
|
89
|
-
console.log(chalk.yellow('WARN:'), `Conflicting package versions "${dep}" - ${vers.join(', ')}`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
10
|
+
let resolvedPackages = await resolvePackages({ verbose });
|
|
93
11
|
// sources
|
|
94
|
-
|
|
95
|
-
|
|
12
|
+
return Object.entries(resolvedPackages).map(([name, version]) => {
|
|
13
|
+
let depType = getDependencyType(version);
|
|
96
14
|
let pkgDir;
|
|
97
|
-
if (
|
|
98
|
-
pkgDir = path.relative(process.cwd(),
|
|
99
|
-
pkgDir = pkgDir.replaceAll('{MOPS_ENV}', process.env.MOPS_ENV || 'local');
|
|
15
|
+
if (depType === 'local') {
|
|
16
|
+
pkgDir = path.relative(process.cwd(), version);
|
|
100
17
|
}
|
|
101
|
-
else if (
|
|
102
|
-
pkgDir = path.relative(process.cwd(), formatGithubDir(name,
|
|
18
|
+
else if (depType === 'github') {
|
|
19
|
+
pkgDir = path.relative(process.cwd(), formatGithubDir(name, version));
|
|
103
20
|
}
|
|
104
|
-
else if (
|
|
105
|
-
pkgDir = path.relative(process.cwd(), formatDir(name,
|
|
21
|
+
else if (depType === 'mops') {
|
|
22
|
+
pkgDir = path.relative(process.cwd(), formatDir(name, version));
|
|
106
23
|
}
|
|
107
24
|
else {
|
|
108
25
|
return;
|
|
@@ -117,7 +34,7 @@ export async function sources({ verbose = false } = {}) {
|
|
|
117
34
|
pkgBaseDir = path.join(pkgDir, 'src');
|
|
118
35
|
}
|
|
119
36
|
// use pkgDir if baseDir doesn't exist for local packages
|
|
120
|
-
if (
|
|
37
|
+
if (depType === 'local' && !fs.existsSync(pkgBaseDir)) {
|
|
121
38
|
pkgBaseDir = pkgDir;
|
|
122
39
|
}
|
|
123
40
|
return `--package ${name} ${pkgBaseDir}`;
|
|
@@ -301,6 +301,10 @@ service : {
|
|
|
301
301
|
getTotalPackages: () -> (nat) query;
|
|
302
302
|
getUser: (principal) -> (opt User__1) query;
|
|
303
303
|
notifyInstall: (PackageName__1, PackageVersion) -> () oneway;
|
|
304
|
+
notifyInstalls: (vec record {
|
|
305
|
+
PackageName__1;
|
|
306
|
+
PackageVersion;
|
|
307
|
+
}) -> () oneway;
|
|
304
308
|
restore: (nat, nat) -> ();
|
|
305
309
|
search: (Text, opt nat, opt nat) -> (vec PackageSummary, PageCount) query;
|
|
306
310
|
setUserProp: (text, text) -> (Result_3);
|
|
@@ -247,6 +247,10 @@ export interface _SERVICE {
|
|
|
247
247
|
'getTotalPackages' : ActorMethod<[], bigint>,
|
|
248
248
|
'getUser' : ActorMethod<[Principal], [] | [User__1]>,
|
|
249
249
|
'notifyInstall' : ActorMethod<[PackageName__1, PackageVersion], undefined>,
|
|
250
|
+
'notifyInstalls' : ActorMethod<
|
|
251
|
+
[Array<[PackageName__1, PackageVersion]>],
|
|
252
|
+
undefined
|
|
253
|
+
>,
|
|
250
254
|
'restore' : ActorMethod<[bigint, bigint], undefined>,
|
|
251
255
|
'search' : ActorMethod<
|
|
252
256
|
[Text, [] | [bigint], [] | [bigint]],
|
|
@@ -275,6 +275,11 @@ export const idlFactory = ({ IDL }) => {
|
|
|
275
275
|
[],
|
|
276
276
|
['oneway'],
|
|
277
277
|
),
|
|
278
|
+
'notifyInstalls' : IDL.Func(
|
|
279
|
+
[IDL.Vec(IDL.Tuple(PackageName__1, PackageVersion))],
|
|
280
|
+
[],
|
|
281
|
+
['oneway'],
|
|
282
|
+
),
|
|
278
283
|
'restore' : IDL.Func([IDL.Nat, IDL.Nat], [], []),
|
|
279
284
|
'search' : IDL.Func(
|
|
280
285
|
[Text, IDL.Opt(IDL.Nat), IDL.Opt(IDL.Nat)],
|
package/dist/mops.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare function parseGithubURL(href: string): {
|
|
|
25
25
|
gitName: string | undefined;
|
|
26
26
|
branch: string;
|
|
27
27
|
};
|
|
28
|
+
export declare function getDependencyType(version: string): "mops" | "github" | "local";
|
|
28
29
|
export declare function readConfig(configFile?: string): Config;
|
|
29
30
|
export declare function writeConfig(config: Config, configFile?: string): void;
|
|
30
31
|
export declare function formatDir(name: string, version: string): string;
|
package/dist/mops.js
CHANGED
|
@@ -186,6 +186,20 @@ export function parseGithubURL(href) {
|
|
|
186
186
|
}
|
|
187
187
|
return { org, gitName, branch };
|
|
188
188
|
}
|
|
189
|
+
export function getDependencyType(version) {
|
|
190
|
+
if (!version || typeof version !== 'string') {
|
|
191
|
+
throw Error(`Invalid dependency value "${version}"`);
|
|
192
|
+
}
|
|
193
|
+
if (version.startsWith('https://github.com/')) {
|
|
194
|
+
return 'github';
|
|
195
|
+
}
|
|
196
|
+
else if (version.match(/^(\.?\.)?\//)) {
|
|
197
|
+
return 'local';
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
return 'mops';
|
|
201
|
+
}
|
|
202
|
+
}
|
|
189
203
|
export function readConfig(configFile = getClosestConfigFile()) {
|
|
190
204
|
let text = fs.readFileSync(configFile).toString();
|
|
191
205
|
let toml = TOML.parse(text);
|
|
@@ -194,10 +208,11 @@ export function readConfig(configFile = getClosestConfigFile()) {
|
|
|
194
208
|
if (!data || typeof data !== 'string') {
|
|
195
209
|
throw Error(`Invalid dependency value ${name} = "${data}"`);
|
|
196
210
|
}
|
|
197
|
-
|
|
211
|
+
let depType = getDependencyType(data);
|
|
212
|
+
if (depType === 'github') {
|
|
198
213
|
deps[name] = { name, repo: data, version: '' };
|
|
199
214
|
}
|
|
200
|
-
else if (
|
|
215
|
+
else if (depType === 'local') {
|
|
201
216
|
deps[name] = { name, repo: '', path: data, version: '' };
|
|
202
217
|
}
|
|
203
218
|
else {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function notifyInstalls(names: string[]): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { mainActor } from './mops.js';
|
|
2
|
+
import { resolvePackages } from './resolve-packages.js';
|
|
3
|
+
export async function notifyInstalls(names) {
|
|
4
|
+
let resolvedPackages = await resolvePackages();
|
|
5
|
+
let packages = names.map(name => [name, resolvedPackages[name]]);
|
|
6
|
+
if (packages.length) {
|
|
7
|
+
let actor = await mainActor();
|
|
8
|
+
await actor.notifyInstalls(packages);
|
|
9
|
+
}
|
|
10
|
+
}
|
package/dist/package.json
CHANGED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { checkConfigFile, formatDir, formatGithubDir, getRootDir, parseGithubURL, readConfig } from './mops.js';
|
|
4
|
+
import { readVesselConfig } from './vessel.js';
|
|
5
|
+
export async function resolvePackages({ verbose = false } = {}) {
|
|
6
|
+
if (!checkConfigFile()) {
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
let packages = {};
|
|
10
|
+
let versions = {};
|
|
11
|
+
let compareVersions = (a = '0.0.0', b = '0.0.0') => {
|
|
12
|
+
let ap = a.split('.').map((x) => parseInt(x));
|
|
13
|
+
let bp = b.split('.').map((x) => parseInt(x));
|
|
14
|
+
if (ap[0] - bp[0]) {
|
|
15
|
+
return Math.sign(ap[0] - bp[0]);
|
|
16
|
+
}
|
|
17
|
+
if (ap[0] === bp[0] && ap[1] - bp[1]) {
|
|
18
|
+
return Math.sign(ap[1] - bp[1]);
|
|
19
|
+
}
|
|
20
|
+
if (ap[0] === bp[0] && ap[1] === bp[1] && ap[2] - bp[2]) {
|
|
21
|
+
return Math.sign(ap[2] - bp[2]);
|
|
22
|
+
}
|
|
23
|
+
return 0;
|
|
24
|
+
};
|
|
25
|
+
const gitVerRegex = new RegExp(/v(\d{1,2}\.\d{1,2}\.\d{1,2})(-.*)?$/);
|
|
26
|
+
const compareGitVersions = (repoA, repoB) => {
|
|
27
|
+
const { branch: a } = parseGithubURL(repoA);
|
|
28
|
+
const { branch: b } = parseGithubURL(repoB);
|
|
29
|
+
if (gitVerRegex.test(a) && gitVerRegex.test(b)) {
|
|
30
|
+
return compareVersions(a.substring(1), b.substring(1));
|
|
31
|
+
}
|
|
32
|
+
else if (!gitVerRegex.test(a)) {
|
|
33
|
+
return -1;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
let collectDeps = async (config, isRoot = false) => {
|
|
40
|
+
let allDeps = [...Object.values(config.dependencies || {})];
|
|
41
|
+
if (isRoot) {
|
|
42
|
+
allDeps = [...allDeps, ...Object.values(config['dev-dependencies'] || {})];
|
|
43
|
+
}
|
|
44
|
+
for (const pkgDetails of allDeps) {
|
|
45
|
+
const { name, repo, version } = pkgDetails;
|
|
46
|
+
// take root dep version or bigger one
|
|
47
|
+
if (isRoot
|
|
48
|
+
|| !packages[name]
|
|
49
|
+
|| !packages[name]?.isRoot
|
|
50
|
+
&& (repo && packages[name]?.repo && compareGitVersions(packages[name]?.repo || '', repo) === -1
|
|
51
|
+
|| compareVersions(packages[name]?.version, version) === -1)) {
|
|
52
|
+
packages[name] = {
|
|
53
|
+
...pkgDetails,
|
|
54
|
+
isRoot,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
let nestedConfig;
|
|
58
|
+
if (repo) {
|
|
59
|
+
const dir = formatGithubDir(name, repo);
|
|
60
|
+
nestedConfig = await readVesselConfig(dir) || {};
|
|
61
|
+
}
|
|
62
|
+
else if (!pkgDetails.path && version) {
|
|
63
|
+
const file = formatDir(name, version) + '/mops.toml';
|
|
64
|
+
nestedConfig = readConfig(file);
|
|
65
|
+
}
|
|
66
|
+
if (nestedConfig && !pkgDetails.path) {
|
|
67
|
+
await collectDeps(nestedConfig);
|
|
68
|
+
}
|
|
69
|
+
if (!versions[name]) {
|
|
70
|
+
versions[name] = [];
|
|
71
|
+
}
|
|
72
|
+
if (repo) {
|
|
73
|
+
const { branch } = parseGithubURL(repo);
|
|
74
|
+
versions[name]?.push(branch);
|
|
75
|
+
}
|
|
76
|
+
else if (version) {
|
|
77
|
+
versions[name]?.push(version);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
let config = readConfig();
|
|
82
|
+
await collectDeps(config, true);
|
|
83
|
+
// show conflicts
|
|
84
|
+
if (verbose) {
|
|
85
|
+
for (let [dep, vers] of Object.entries(versions)) {
|
|
86
|
+
if (vers.length > 1) {
|
|
87
|
+
console.log(chalk.yellow('WARN:'), `Conflicting package versions "${dep}" - ${vers.join(', ')}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
let rootDir = getRootDir();
|
|
92
|
+
return Object.fromEntries(Object.entries(packages).map(([name, pkg]) => {
|
|
93
|
+
let version;
|
|
94
|
+
if (pkg.path) {
|
|
95
|
+
version = path.resolve(rootDir, pkg.path).replaceAll('{MOPS_ENV}', process.env.MOPS_ENV || 'local');
|
|
96
|
+
}
|
|
97
|
+
else if (pkg.repo) {
|
|
98
|
+
version = pkg.repo;
|
|
99
|
+
}
|
|
100
|
+
else if (pkg.version) {
|
|
101
|
+
version = pkg.version;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
return [name, ''];
|
|
105
|
+
}
|
|
106
|
+
return [name, version];
|
|
107
|
+
}).filter(([, version]) => version !== ''));
|
|
108
|
+
}
|
package/mops.ts
CHANGED
|
@@ -221,6 +221,21 @@ export function parseGithubURL(href: string) {
|
|
|
221
221
|
return {org, gitName, branch};
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
export function getDependencyType(version: string) {
|
|
225
|
+
if (!version || typeof version !== 'string') {
|
|
226
|
+
throw Error(`Invalid dependency value "${version}"`);
|
|
227
|
+
}
|
|
228
|
+
if (version.startsWith('https://github.com/')) {
|
|
229
|
+
return 'github';
|
|
230
|
+
}
|
|
231
|
+
else if (version.match(/^(\.?\.)?\//)) {
|
|
232
|
+
return 'local';
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
return 'mops';
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
224
239
|
export function readConfig(configFile = getClosestConfigFile()): Config {
|
|
225
240
|
let text = fs.readFileSync(configFile).toString();
|
|
226
241
|
let toml = TOML.parse(text);
|
|
@@ -230,10 +245,11 @@ export function readConfig(configFile = getClosestConfigFile()): Config {
|
|
|
230
245
|
if (!data || typeof data !== 'string') {
|
|
231
246
|
throw Error(`Invalid dependency value ${name} = "${data}"`);
|
|
232
247
|
}
|
|
233
|
-
|
|
248
|
+
let depType = getDependencyType(data);
|
|
249
|
+
if (depType === 'github') {
|
|
234
250
|
deps[name] = {name, repo: data, version: ''};
|
|
235
251
|
}
|
|
236
|
-
else if (
|
|
252
|
+
else if (depType === 'local') {
|
|
237
253
|
deps[name] = {name, repo: '', path: data, version: ''};
|
|
238
254
|
}
|
|
239
255
|
else {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {mainActor} from './mops.js';
|
|
2
|
+
import {resolvePackages} from './resolve-packages.js';
|
|
3
|
+
|
|
4
|
+
export async function notifyInstalls(names: string[]) {
|
|
5
|
+
let resolvedPackages = await resolvePackages();
|
|
6
|
+
let packages: [string, string][] = names.map(name => [name, resolvedPackages[name] as string]);
|
|
7
|
+
if (packages.length) {
|
|
8
|
+
let actor = await mainActor();
|
|
9
|
+
await actor.notifyInstalls(packages);
|
|
10
|
+
}
|
|
11
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import {checkConfigFile, formatDir, formatGithubDir, getRootDir, parseGithubURL, readConfig} from './mops.js';
|
|
4
|
+
import {VesselConfig, readVesselConfig} from './vessel.js';
|
|
5
|
+
import {Config, Dependency} from './types.js';
|
|
6
|
+
|
|
7
|
+
export async function resolvePackages({verbose = false} = {}): Promise<Record<string, string>> {
|
|
8
|
+
if (!checkConfigFile()) {
|
|
9
|
+
return {};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let packages: Record<string, Dependency & {isRoot: boolean;}> = {};
|
|
13
|
+
let versions: Record<string, string[]> = {};
|
|
14
|
+
|
|
15
|
+
let compareVersions = (a: string = '0.0.0', b: string = '0.0.0') => {
|
|
16
|
+
let ap = a.split('.').map((x: string) => parseInt(x)) as [number, number, number];
|
|
17
|
+
let bp = b.split('.').map((x: string) => parseInt(x)) as [number, number, number];
|
|
18
|
+
if (ap[0] - bp[0]) {
|
|
19
|
+
return Math.sign(ap[0] - bp[0]);
|
|
20
|
+
}
|
|
21
|
+
if (ap[0] === bp[0] && ap[1] - bp[1]) {
|
|
22
|
+
return Math.sign(ap[1] - bp[1]);
|
|
23
|
+
}
|
|
24
|
+
if (ap[0] === bp[0] && ap[1] === bp[1] && ap[2] - bp[2]) {
|
|
25
|
+
return Math.sign(ap[2] - bp[2]);
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const gitVerRegex = new RegExp(/v(\d{1,2}\.\d{1,2}\.\d{1,2})(-.*)?$/);
|
|
31
|
+
|
|
32
|
+
const compareGitVersions = (repoA: string, repoB: string) => {
|
|
33
|
+
const {branch: a} = parseGithubURL(repoA);
|
|
34
|
+
const {branch: b} = parseGithubURL(repoB);
|
|
35
|
+
|
|
36
|
+
if (gitVerRegex.test(a) && gitVerRegex.test(b)) {
|
|
37
|
+
return compareVersions(a.substring(1), b.substring(1));
|
|
38
|
+
}
|
|
39
|
+
else if (!gitVerRegex.test(a)) {
|
|
40
|
+
return -1;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
let collectDeps = async (config: Config | VesselConfig, isRoot = false) => {
|
|
48
|
+
let allDeps = [...Object.values(config.dependencies || {})];
|
|
49
|
+
if (isRoot) {
|
|
50
|
+
allDeps = [...allDeps, ...Object.values(config['dev-dependencies'] || {})];
|
|
51
|
+
}
|
|
52
|
+
for (const pkgDetails of allDeps) {
|
|
53
|
+
const {name, repo, version} = pkgDetails;
|
|
54
|
+
|
|
55
|
+
// take root dep version or bigger one
|
|
56
|
+
if (
|
|
57
|
+
isRoot
|
|
58
|
+
|| !packages[name]
|
|
59
|
+
|| !packages[name]?.isRoot
|
|
60
|
+
&& (
|
|
61
|
+
repo && packages[name]?.repo && compareGitVersions(packages[name]?.repo || '', repo) === -1
|
|
62
|
+
|| compareVersions(packages[name]?.version, version) === -1)
|
|
63
|
+
) {
|
|
64
|
+
packages[name] = {
|
|
65
|
+
...pkgDetails,
|
|
66
|
+
isRoot,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let nestedConfig;
|
|
71
|
+
|
|
72
|
+
if (repo) {
|
|
73
|
+
const dir = formatGithubDir(name, repo);
|
|
74
|
+
nestedConfig = await readVesselConfig(dir) || {};
|
|
75
|
+
}
|
|
76
|
+
else if (!pkgDetails.path && version) {
|
|
77
|
+
const file = formatDir(name, version) + '/mops.toml';
|
|
78
|
+
nestedConfig = readConfig(file);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (nestedConfig && !pkgDetails.path) {
|
|
82
|
+
await collectDeps(nestedConfig);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!versions[name]) {
|
|
86
|
+
versions[name] = [];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (repo) {
|
|
90
|
+
const {branch} = parseGithubURL(repo);
|
|
91
|
+
versions[name]?.push(branch);
|
|
92
|
+
}
|
|
93
|
+
else if (version) {
|
|
94
|
+
versions[name]?.push(version);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
let config = readConfig();
|
|
100
|
+
await collectDeps(config, true);
|
|
101
|
+
|
|
102
|
+
// show conflicts
|
|
103
|
+
if (verbose) {
|
|
104
|
+
for (let [dep, vers] of Object.entries(versions)) {
|
|
105
|
+
if (vers.length > 1) {
|
|
106
|
+
console.log(chalk.yellow('WARN:'), `Conflicting package versions "${dep}" - ${vers.join(', ')}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let rootDir = getRootDir();
|
|
112
|
+
|
|
113
|
+
return Object.fromEntries(
|
|
114
|
+
Object.entries(packages).map(([name, pkg]) => {
|
|
115
|
+
let version: string;
|
|
116
|
+
if (pkg.path) {
|
|
117
|
+
version = path.resolve(rootDir, pkg.path).replaceAll('{MOPS_ENV}', process.env.MOPS_ENV || 'local');
|
|
118
|
+
}
|
|
119
|
+
else if (pkg.repo) {
|
|
120
|
+
version = pkg.repo;
|
|
121
|
+
}
|
|
122
|
+
else if (pkg.version) {
|
|
123
|
+
version = pkg.version;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
return [name, ''];
|
|
127
|
+
}
|
|
128
|
+
return [name, version];
|
|
129
|
+
}).filter(([, version]) => version !== '')
|
|
130
|
+
);
|
|
131
|
+
}
|