ic-mops 0.1.14 → 0.2.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.js +51 -15
- package/commands/init.js +35 -15
- package/commands/install-all.js +8 -3
- package/commands/install.js +10 -7
- package/commands/publish.js +1 -3
- package/commands/sources.js +58 -42
- package/commands/uninstall.js +19 -3
- package/declarations/main/index.d.ts +16 -0
- package/declarations/main/main.did +10 -9
- package/declarations/main/main.did.d.ts +13 -9
- package/declarations/main/main.did.js +13 -9
- package/mops.js +50 -2
- package/package.json +5 -1
- package/vessel.js +162 -0
package/cli.js
CHANGED
|
@@ -4,25 +4,21 @@ import fs from 'fs';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import {program} from 'commander';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
-
import TOML from '@iarna/toml';
|
|
8
7
|
|
|
9
8
|
import {init} from './commands/init.js';
|
|
10
9
|
import {install} from './commands/install.js';
|
|
11
10
|
import {publish} from './commands/publish.js';
|
|
12
11
|
import {importPem} from './commands/import-identity.js';
|
|
13
12
|
import {sources} from './commands/sources.js';
|
|
14
|
-
import {checkApiCompatibility, getHighestVersion, getNetwork, setNetwork} from './mops.js';
|
|
13
|
+
import {checkApiCompatibility, getHighestVersion, getNetwork, parseGithubURL, readConfig, setNetwork, writeConfig} from './mops.js';
|
|
15
14
|
import {whoami} from './commands/whoami.js';
|
|
16
15
|
import {installAll} from './commands/install-all.js';
|
|
17
16
|
import logUpdate from 'log-update';
|
|
17
|
+
import { installFromGithub } from './vessel.js';
|
|
18
18
|
|
|
19
19
|
let cwd = process.cwd();
|
|
20
20
|
let configFile = path.join(cwd, 'mops.toml');
|
|
21
21
|
|
|
22
|
-
function wirteConfig(config) {
|
|
23
|
-
fs.writeFileSync(configFile, TOML.stringify(config).trim());
|
|
24
|
-
}
|
|
25
|
-
|
|
26
22
|
program.name('mops');
|
|
27
23
|
|
|
28
24
|
// init
|
|
@@ -44,8 +40,7 @@ program
|
|
|
44
40
|
let config = {};
|
|
45
41
|
let exists = fs.existsSync(configFile);
|
|
46
42
|
if (exists) {
|
|
47
|
-
|
|
48
|
-
config = TOML.parse(text);
|
|
43
|
+
config = readConfig(configFile);
|
|
49
44
|
}
|
|
50
45
|
else {
|
|
51
46
|
console.log(chalk.red('Error: ') + `mops.toml not found. Please run ${chalk.green('mops init')} first`);
|
|
@@ -62,22 +57,63 @@ program
|
|
|
62
57
|
|
|
63
58
|
if (!pkg) {
|
|
64
59
|
installAll(options);
|
|
60
|
+
return;
|
|
65
61
|
}
|
|
66
|
-
|
|
62
|
+
|
|
63
|
+
let pkgDetails;
|
|
64
|
+
let existingPkg = config.dependencies[pkg];
|
|
65
|
+
|
|
66
|
+
if (pkg.startsWith('https://github.com') || pkg.split('/') > 1){
|
|
67
|
+
const {org, gitName, branch} = parseGithubURL(pkg);
|
|
68
|
+
|
|
69
|
+
pkgDetails = {
|
|
70
|
+
name: parseGithubURL(pkg).gitName,
|
|
71
|
+
repo: `https://github.com/${org}/${gitName}#${branch}`,
|
|
72
|
+
version: ''
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
existingPkg = config.dependencies[pkgDetails.name];
|
|
76
|
+
|
|
77
|
+
}else if (!existingPkg || !existingPkg.repo){
|
|
67
78
|
let versionRes = await getHighestVersion(pkg);
|
|
68
79
|
if (versionRes.err) {
|
|
69
80
|
console.log(chalk.red('Error: ') + versionRes.err);
|
|
70
81
|
return;
|
|
71
82
|
}
|
|
72
|
-
let version = versionRes.ok;
|
|
73
83
|
|
|
74
|
-
|
|
84
|
+
pkgDetails = {
|
|
85
|
+
name: pkg,
|
|
86
|
+
repo: '',
|
|
87
|
+
version: versionRes.ok
|
|
88
|
+
};
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
console.log(chalk.green('Package installed ') + `${pkg} = "${version}"`);
|
|
90
|
+
}else{
|
|
91
|
+
options.silent || logUpdate(`Installing ${existingPkg.name}@${existingPkg.version} (cache) from Github`);
|
|
92
|
+
return;
|
|
80
93
|
}
|
|
94
|
+
|
|
95
|
+
const {name, repo, version} = pkgDetails;
|
|
96
|
+
|
|
97
|
+
if (repo){
|
|
98
|
+
// pkg name conflict with an installed mops pkg
|
|
99
|
+
if (existingPkg && !existingPkg.repo){
|
|
100
|
+
console.log(chalk.red('Error: ') + `Conflicting Package Name '${name}`);
|
|
101
|
+
console.log('Consider entering the repo url and assigning a new name in the \'mops.toml\' file');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
await installFromGithub(name, repo, {verbose: options.verbose});
|
|
106
|
+
}else{
|
|
107
|
+
await install(name, version, {verbose: options.verbose});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
config.dependencies[name] = pkgDetails;
|
|
111
|
+
writeConfig(config);
|
|
112
|
+
|
|
113
|
+
logUpdate.clear();
|
|
114
|
+
console.log(
|
|
115
|
+
chalk.green('Package installed ') + `${name} = "${repo || version}"`
|
|
116
|
+
);
|
|
81
117
|
});
|
|
82
118
|
|
|
83
119
|
// publish
|
package/commands/init.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import TOML from '@iarna/toml';
|
|
2
1
|
import chalk from 'chalk';
|
|
3
2
|
import path from 'path';
|
|
4
3
|
import fs from 'fs';
|
|
5
|
-
import {checkApiCompatibility, mainActor, readDfxJson} from '../mops.js';
|
|
4
|
+
import {checkApiCompatibility, mainActor, readDfxJson, writeConfig} from '../mops.js';
|
|
6
5
|
import {installAll} from './install-all.js';
|
|
6
|
+
import { readVesselConfig } from '../vessel.js';
|
|
7
7
|
|
|
8
8
|
export async function init(name = '') {
|
|
9
9
|
let configFile = path.join(process.cwd(), 'mops.toml');
|
|
@@ -16,18 +16,37 @@ export async function init(name = '') {
|
|
|
16
16
|
console.log('Initializing...');
|
|
17
17
|
|
|
18
18
|
let config = {};
|
|
19
|
+
let vesselConfig = {};
|
|
20
|
+
|
|
21
|
+
const vesselFile = path.join(process.cwd(), 'vessel.dhall');
|
|
22
|
+
|
|
23
|
+
if (fs.existsSync(vesselFile)){
|
|
24
|
+
console.log('Reading vessel.dhall file');
|
|
25
|
+
const res = await readVesselConfig(process.cwd(), { cache: false });
|
|
26
|
+
vesselConfig = {...res};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (vesselConfig.dependencies){
|
|
30
|
+
config.dependencies = {};
|
|
31
|
+
|
|
32
|
+
for (const dep of (vesselConfig.dependencies || [])){
|
|
33
|
+
config.dependencies[dep.name] = dep;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
19
36
|
|
|
20
37
|
// lib mode
|
|
21
38
|
if (name) {
|
|
22
|
-
config = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
repository: '',
|
|
28
|
-
}
|
|
39
|
+
config.package = {
|
|
40
|
+
name,
|
|
41
|
+
version: '0.1.0',
|
|
42
|
+
description: '',
|
|
43
|
+
repository: '',
|
|
29
44
|
};
|
|
30
|
-
|
|
45
|
+
|
|
46
|
+
writeConfig(config);
|
|
47
|
+
|
|
48
|
+
if (Object.keys(config.dependencies || {}).length)
|
|
49
|
+
await installAll({verbose: true});
|
|
31
50
|
}
|
|
32
51
|
|
|
33
52
|
// project mode
|
|
@@ -43,14 +62,15 @@ export async function init(name = '') {
|
|
|
43
62
|
let actor = await mainActor();
|
|
44
63
|
let defaultPackages = await actor.getDefaultPackages(dfxVersion);
|
|
45
64
|
|
|
65
|
+
if (!config.dependencies)
|
|
66
|
+
config.dependencies = {};
|
|
67
|
+
|
|
46
68
|
defaultPackages.forEach(([name, version]) => {
|
|
47
|
-
config.dependencies =
|
|
48
|
-
...config.dependencies,
|
|
49
|
-
[name]: version,
|
|
50
|
-
};
|
|
69
|
+
config.dependencies[name] = version;
|
|
51
70
|
});
|
|
52
71
|
|
|
53
|
-
|
|
72
|
+
writeConfig(config);
|
|
73
|
+
|
|
54
74
|
await installAll({verbose: true});
|
|
55
75
|
}
|
|
56
76
|
|
package/commands/install-all.js
CHANGED
|
@@ -2,6 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import logUpdate from 'log-update';
|
|
3
3
|
import {checkConfigFile, readConfig} from '../mops.js';
|
|
4
4
|
import {install} from './install.js';
|
|
5
|
+
import {installFromGithub} from '../vessel.js';
|
|
5
6
|
|
|
6
7
|
export async function installAll({verbose} = {}) {
|
|
7
8
|
if (!checkConfigFile()) {
|
|
@@ -9,10 +10,14 @@ export async function installAll({verbose} = {}) {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
let config = readConfig();
|
|
12
|
-
|
|
13
|
+
const deps = Object.values(config.dependencies || {});
|
|
13
14
|
|
|
14
|
-
for (let
|
|
15
|
-
|
|
15
|
+
for (let {name, repo, version} of deps) {
|
|
16
|
+
if (repo){
|
|
17
|
+
await installFromGithub(name, repo, {verbose});
|
|
18
|
+
}else{
|
|
19
|
+
await install(name, version, {verbose});
|
|
20
|
+
}
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
logUpdate.clear();
|
package/commands/install.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import logUpdate from 'log-update';
|
|
4
|
-
import {checkConfigFile, getHighestVersion, mainActor, progressBar, readConfig, storageActor} from '../mops.js';
|
|
4
|
+
import {checkConfigFile, formatDir, getHighestVersion, mainActor, progressBar, readConfig, storageActor} from '../mops.js';
|
|
5
5
|
import {parallel} from '../parallel.js';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
+
import { installFromGithub } from '../vessel.js';
|
|
7
8
|
|
|
8
9
|
export async function install(pkg, version = '', {verbose, silent, dep} = {}) {
|
|
9
10
|
if (!checkConfigFile()) {
|
|
@@ -19,7 +20,7 @@ export async function install(pkg, version = '', {verbose, silent, dep} = {}) {
|
|
|
19
20
|
version = versionRes.ok;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
let dir =
|
|
23
|
+
let dir = formatDir(pkg, version);
|
|
23
24
|
let actor = await mainActor();
|
|
24
25
|
|
|
25
26
|
// cache
|
|
@@ -30,9 +31,7 @@ export async function install(pkg, version = '', {verbose, silent, dep} = {}) {
|
|
|
30
31
|
else {
|
|
31
32
|
fs.mkdirSync(dir, {recursive: true});
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
actor.notifyInstall(pkg, version);
|
|
35
|
-
}
|
|
34
|
+
actor.notifyInstall(pkg, version);
|
|
36
35
|
|
|
37
36
|
let packageDetailsRes = await actor.getPackageDetails(pkg, version);
|
|
38
37
|
if (packageDetailsRes.err) {
|
|
@@ -91,7 +90,11 @@ export async function install(pkg, version = '', {verbose, silent, dep} = {}) {
|
|
|
91
90
|
|
|
92
91
|
// install dependencies
|
|
93
92
|
let config = readConfig(path.join(dir, 'mops.toml'));
|
|
94
|
-
for (
|
|
95
|
-
|
|
93
|
+
for (const {name, repo, version} of Object.values(config.dependencies || {})) {
|
|
94
|
+
if (repo){
|
|
95
|
+
await installFromGithub(name, repo, {verbose});
|
|
96
|
+
}else{
|
|
97
|
+
await install(name, version, {verbose});
|
|
98
|
+
}
|
|
96
99
|
}
|
|
97
100
|
}
|
package/commands/publish.js
CHANGED
|
@@ -136,9 +136,7 @@ export async function publish() {
|
|
|
136
136
|
dfx: config.package.dfx || '',
|
|
137
137
|
moc: config.package.moc || '',
|
|
138
138
|
donation: config.package.donation || '',
|
|
139
|
-
dependencies:
|
|
140
|
-
return {name, version};
|
|
141
|
-
}),
|
|
139
|
+
dependencies: Object.values(config.dependencies || {}),
|
|
142
140
|
devDependencies: [],
|
|
143
141
|
scripts: [],
|
|
144
142
|
};
|
package/commands/sources.js
CHANGED
|
@@ -2,7 +2,8 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import {install} from './install.js';
|
|
5
|
-
import {getHighestVersion, readConfig} from '../mops.js';
|
|
5
|
+
import {formatDir, formatGithubDir, getHighestVersion, parseGithubURL, readConfig} from '../mops.js';
|
|
6
|
+
import { readVesselConfig } from '../vessel.js';
|
|
6
7
|
|
|
7
8
|
function rootDir(cwd = process.cwd()) {
|
|
8
9
|
let configFile = path.join(cwd, 'mops.toml');
|
|
@@ -16,8 +17,7 @@ function rootDir(cwd = process.cwd()) {
|
|
|
16
17
|
return rootDir(path.join(cwd, '..'));
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
// TODO: resolve
|
|
20
|
-
// TODO: remove base-unofficial
|
|
20
|
+
// TODO: resolve conflicts
|
|
21
21
|
export async function sources({verbose} = {}) {
|
|
22
22
|
let root = rootDir();
|
|
23
23
|
if (!root) {
|
|
@@ -42,48 +42,63 @@ export async function sources({verbose} = {}) {
|
|
|
42
42
|
return 0;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
for (let [dep, ver] of Object.entries(config.dependencies || {})) {
|
|
47
|
-
// take root dep ver or bigger one
|
|
48
|
-
if (isRoot || !packages[dep] || compareVersions(packages[dep], ver) === -1) {
|
|
49
|
-
packages[dep] = ver;
|
|
50
|
-
}
|
|
45
|
+
const gitVerRegex = new RegExp(/v(\d{1,2}\.\d{1,2}\.\d{1,2})(-.*)?$/);
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
const compareGitVersions = (repoA, repoB) => {
|
|
48
|
+
const {branch: a} = parseGithubURL(repoA);
|
|
49
|
+
const {branch: b} = parseGithubURL(repoB);
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
if (gitVerRegex.test(a) && gitVerRegex.test(b)){
|
|
52
|
+
return compareVersions(a.substring(1) , b.substring(1));
|
|
53
|
+
}else if (!gitVerRegex.test(a)){
|
|
54
|
+
return -1;
|
|
55
|
+
}else{
|
|
56
|
+
return 1;
|
|
59
57
|
}
|
|
60
58
|
};
|
|
61
59
|
|
|
62
|
-
let
|
|
63
|
-
|
|
60
|
+
let collectDeps = async (config, isRoot = false) => {
|
|
61
|
+
for (const pkgDetails of Object.values(config.dependencies || {})) {
|
|
62
|
+
const {name, repo, version} = pkgDetails;
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
// take root dep version or bigger one
|
|
65
|
+
if (
|
|
66
|
+
isRoot ||
|
|
67
|
+
!packages[name] ||
|
|
68
|
+
repo && compareGitVersions(packages[name].repo, repo) === -1 ||
|
|
69
|
+
compareVersions(packages[name].version, version) === -1
|
|
70
|
+
) {
|
|
71
|
+
packages[name] = pkgDetails;
|
|
72
|
+
}
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
let nestedConfig;
|
|
75
|
+
|
|
76
|
+
if (repo){
|
|
77
|
+
const dir = formatGithubDir(name, repo);
|
|
78
|
+
nestedConfig = await readVesselConfig(dir) || {};
|
|
79
|
+
}
|
|
80
|
+
else{
|
|
81
|
+
const dir = formatDir(name, version) + '/mops.toml';
|
|
82
|
+
nestedConfig = readConfig(dir);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await collectDeps(nestedConfig);
|
|
86
|
+
|
|
87
|
+
if (!versions[name]) {
|
|
88
|
+
versions[name] = [];
|
|
80
89
|
}
|
|
81
|
-
let version = versionRes.ok;
|
|
82
90
|
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
if (repo){
|
|
92
|
+
const {branch} = parseGithubURL(repo);
|
|
93
|
+
versions[name].push(branch);
|
|
94
|
+
}else{
|
|
95
|
+
versions[name].push(version);
|
|
96
|
+
}
|
|
85
97
|
}
|
|
86
|
-
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
let config = readConfig(path.join(root, 'mops.toml'));
|
|
101
|
+
await collectDeps(config, true);
|
|
87
102
|
|
|
88
103
|
// show conflicts
|
|
89
104
|
if (verbose) {
|
|
@@ -95,13 +110,14 @@ export async function sources({verbose} = {}) {
|
|
|
95
110
|
}
|
|
96
111
|
|
|
97
112
|
// sources
|
|
98
|
-
for (let [name,
|
|
99
|
-
let pkgDir
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
console.log(`--package base ${pkgDir}`);
|
|
113
|
+
for (let [name, {repo, version}] of Object.entries(packages)) {
|
|
114
|
+
let pkgDir;
|
|
115
|
+
if (repo){
|
|
116
|
+
pkgDir = path.relative(process.cwd(), formatGithubDir(name, repo)) + '/src';
|
|
117
|
+
}else{
|
|
118
|
+
pkgDir = path.relative(process.cwd(), formatDir(name, version)) + '/src';
|
|
105
119
|
}
|
|
120
|
+
|
|
121
|
+
console.log(`--package ${name} ${pkgDir}`);
|
|
106
122
|
}
|
|
107
123
|
}
|
package/commands/uninstall.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {checkConfigFile} from '../mops.js';
|
|
2
|
-
import path from 'path';
|
|
1
|
+
import {checkConfigFile, readConfig} from '../mops.js';
|
|
3
2
|
import fs from 'fs';
|
|
4
3
|
import del from 'del';
|
|
5
4
|
import chalk from 'chalk';
|
|
5
|
+
import { formatDir, formatGithubDir } from '../mops.js';
|
|
6
6
|
|
|
7
7
|
export async function uninstall(pkg, version) {
|
|
8
8
|
if (!checkConfigFile()) {
|
|
@@ -10,7 +10,23 @@ export async function uninstall(pkg, version) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// TODO: check if deps relate on this package
|
|
13
|
-
|
|
13
|
+
const config = readConfig();
|
|
14
|
+
|
|
15
|
+
const pkgDetails = config.dependencies[pkg];
|
|
16
|
+
|
|
17
|
+
if (!pkgDetails){
|
|
18
|
+
console.log(`No dependency to remove ${pkg} = "${version}"`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {repo} = pkgDetails;
|
|
23
|
+
let pkgDir;
|
|
24
|
+
|
|
25
|
+
if (repo){
|
|
26
|
+
pkgDir = formatGithubDir(pkg, repo);
|
|
27
|
+
}else{
|
|
28
|
+
pkgDir = formatDir(pkg, version);
|
|
29
|
+
}
|
|
14
30
|
|
|
15
31
|
if (!fs.existsSync(pkgDir)) {
|
|
16
32
|
console.log(`No cache to remove ${pkg} = "${version}"`);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ActorSubclass, HttpAgentOptions, ActorConfig } from '@dfinity/agent';
|
|
2
|
+
import { Principal } from '@dfinity/principal';
|
|
3
|
+
|
|
4
|
+
import { _SERVICE } from './main.did';
|
|
5
|
+
|
|
6
|
+
export declare interface CreateActorOptions {
|
|
7
|
+
agentOptions?: HttpAgentOptions;
|
|
8
|
+
actorOptions?: ActorConfig;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export declare const createActor: (
|
|
12
|
+
canisterId: string | Principal,
|
|
13
|
+
options: CreateActorOptions
|
|
14
|
+
) => ActorSubclass<_SERVICE>;
|
|
15
|
+
|
|
16
|
+
export declare const main: ActorSubclass<_SERVICE>;
|
|
@@ -56,18 +56,18 @@ type PackageName__1 = text;
|
|
|
56
56
|
type PackageName = text;
|
|
57
57
|
type PackageDetails =
|
|
58
58
|
record {
|
|
59
|
-
config:
|
|
59
|
+
config: PackageConfigV2__1;
|
|
60
60
|
downloadsInLast30Days: nat;
|
|
61
61
|
downloadsTotal: nat;
|
|
62
62
|
owner: principal;
|
|
63
63
|
publication: PackagePublication;
|
|
64
64
|
};
|
|
65
|
-
type
|
|
65
|
+
type PackageConfigV2__1 =
|
|
66
66
|
record {
|
|
67
67
|
baseDir: text;
|
|
68
|
-
dependencies: vec
|
|
68
|
+
dependencies: vec DependencyV2;
|
|
69
69
|
description: text;
|
|
70
|
-
devDependencies: vec
|
|
70
|
+
devDependencies: vec DependencyV2;
|
|
71
71
|
dfx: text;
|
|
72
72
|
documentation: text;
|
|
73
73
|
donation: text;
|
|
@@ -81,12 +81,12 @@ type PackageConfig__1 =
|
|
|
81
81
|
scripts: vec Script;
|
|
82
82
|
version: text;
|
|
83
83
|
};
|
|
84
|
-
type
|
|
84
|
+
type PackageConfigV2 =
|
|
85
85
|
record {
|
|
86
86
|
baseDir: text;
|
|
87
|
-
dependencies: vec
|
|
87
|
+
dependencies: vec DependencyV2;
|
|
88
88
|
description: text;
|
|
89
|
-
devDependencies: vec
|
|
89
|
+
devDependencies: vec DependencyV2;
|
|
90
90
|
dfx: text;
|
|
91
91
|
documentation: text;
|
|
92
92
|
donation: text;
|
|
@@ -102,9 +102,10 @@ type PackageConfig =
|
|
|
102
102
|
};
|
|
103
103
|
type FileId = text;
|
|
104
104
|
type Err = text;
|
|
105
|
-
type
|
|
105
|
+
type DependencyV2 =
|
|
106
106
|
record {
|
|
107
107
|
name: PackageName;
|
|
108
|
+
repo: text;
|
|
108
109
|
version: text;
|
|
109
110
|
};
|
|
110
111
|
service : {
|
|
@@ -128,6 +129,6 @@ service : {
|
|
|
128
129
|
notifyInstall: (PackageName__1, Ver) -> () oneway;
|
|
129
130
|
search: (Text) -> (vec PackageDetails) query;
|
|
130
131
|
startFileUpload: (PublishingId, Text, nat, blob) -> (Result_2);
|
|
131
|
-
startPublish: (
|
|
132
|
+
startPublish: (PackageConfigV2) -> (Result_1);
|
|
132
133
|
uploadFileChunk: (PublishingId, FileId, nat, blob) -> (Result);
|
|
133
134
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { Principal } from '@dfinity/principal';
|
|
2
2
|
import type { ActorMethod } from '@dfinity/agent';
|
|
3
3
|
|
|
4
|
-
export interface
|
|
4
|
+
export interface DependencyV2 {
|
|
5
|
+
'name' : PackageName,
|
|
6
|
+
'repo' : string,
|
|
7
|
+
'version' : string,
|
|
8
|
+
}
|
|
5
9
|
export type Err = string;
|
|
6
10
|
export type FileId = string;
|
|
7
|
-
export interface
|
|
11
|
+
export interface PackageConfigV2 {
|
|
8
12
|
'dfx' : string,
|
|
9
13
|
'moc' : string,
|
|
10
14
|
'scripts' : Array<Script>,
|
|
@@ -16,13 +20,13 @@ export interface PackageConfig {
|
|
|
16
20
|
'version' : string,
|
|
17
21
|
'keywords' : Array<string>,
|
|
18
22
|
'donation' : string,
|
|
19
|
-
'devDependencies' : Array<
|
|
23
|
+
'devDependencies' : Array<DependencyV2>,
|
|
20
24
|
'repository' : string,
|
|
21
|
-
'dependencies' : Array<
|
|
25
|
+
'dependencies' : Array<DependencyV2>,
|
|
22
26
|
'license' : string,
|
|
23
27
|
'readme' : string,
|
|
24
28
|
}
|
|
25
|
-
export interface
|
|
29
|
+
export interface PackageConfigV2__1 {
|
|
26
30
|
'dfx' : string,
|
|
27
31
|
'moc' : string,
|
|
28
32
|
'scripts' : Array<Script>,
|
|
@@ -34,9 +38,9 @@ export interface PackageConfig__1 {
|
|
|
34
38
|
'version' : string,
|
|
35
39
|
'keywords' : Array<string>,
|
|
36
40
|
'donation' : string,
|
|
37
|
-
'devDependencies' : Array<
|
|
41
|
+
'devDependencies' : Array<DependencyV2>,
|
|
38
42
|
'repository' : string,
|
|
39
|
-
'dependencies' : Array<
|
|
43
|
+
'dependencies' : Array<DependencyV2>,
|
|
40
44
|
'license' : string,
|
|
41
45
|
'readme' : string,
|
|
42
46
|
}
|
|
@@ -44,7 +48,7 @@ export interface PackageDetails {
|
|
|
44
48
|
'owner' : Principal,
|
|
45
49
|
'downloadsTotal' : bigint,
|
|
46
50
|
'downloadsInLast30Days' : bigint,
|
|
47
|
-
'config' :
|
|
51
|
+
'config' : PackageConfigV2__1,
|
|
48
52
|
'publication' : PackagePublication,
|
|
49
53
|
}
|
|
50
54
|
export type PackageName = string;
|
|
@@ -100,7 +104,7 @@ export interface _SERVICE {
|
|
|
100
104
|
[PublishingId, Text, bigint, Uint8Array],
|
|
101
105
|
Result_2,
|
|
102
106
|
>,
|
|
103
|
-
'startPublish' : ActorMethod<[
|
|
107
|
+
'startPublish' : ActorMethod<[PackageConfigV2], Result_1>,
|
|
104
108
|
'uploadFileChunk' : ActorMethod<
|
|
105
109
|
[PublishingId, FileId, bigint, Uint8Array],
|
|
106
110
|
Result,
|
|
@@ -11,8 +11,12 @@ export const idlFactory = ({ IDL }) => {
|
|
|
11
11
|
const Result_4 = IDL.Variant({ 'ok' : Ver, 'err' : Err });
|
|
12
12
|
const Script = IDL.Record({ 'value' : IDL.Text, 'name' : IDL.Text });
|
|
13
13
|
const PackageName = IDL.Text;
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const DependencyV2 = IDL.Record({
|
|
15
|
+
'name' : PackageName,
|
|
16
|
+
'repo' : IDL.Text,
|
|
17
|
+
'version' : IDL.Text,
|
|
18
|
+
});
|
|
19
|
+
const PackageConfigV2__1 = IDL.Record({
|
|
16
20
|
'dfx' : IDL.Text,
|
|
17
21
|
'moc' : IDL.Text,
|
|
18
22
|
'scripts' : IDL.Vec(Script),
|
|
@@ -24,9 +28,9 @@ export const idlFactory = ({ IDL }) => {
|
|
|
24
28
|
'version' : IDL.Text,
|
|
25
29
|
'keywords' : IDL.Vec(IDL.Text),
|
|
26
30
|
'donation' : IDL.Text,
|
|
27
|
-
'devDependencies' : IDL.Vec(
|
|
31
|
+
'devDependencies' : IDL.Vec(DependencyV2),
|
|
28
32
|
'repository' : IDL.Text,
|
|
29
|
-
'dependencies' : IDL.Vec(
|
|
33
|
+
'dependencies' : IDL.Vec(DependencyV2),
|
|
30
34
|
'license' : IDL.Text,
|
|
31
35
|
'readme' : IDL.Text,
|
|
32
36
|
});
|
|
@@ -40,7 +44,7 @@ export const idlFactory = ({ IDL }) => {
|
|
|
40
44
|
'owner' : IDL.Principal,
|
|
41
45
|
'downloadsTotal' : IDL.Nat,
|
|
42
46
|
'downloadsInLast30Days' : IDL.Nat,
|
|
43
|
-
'config' :
|
|
47
|
+
'config' : PackageConfigV2__1,
|
|
44
48
|
'publication' : PackagePublication,
|
|
45
49
|
});
|
|
46
50
|
const Result_3 = IDL.Variant({ 'ok' : PackageDetails, 'err' : Err });
|
|
@@ -51,7 +55,7 @@ export const idlFactory = ({ IDL }) => {
|
|
|
51
55
|
'memorySize' : IDL.Nat,
|
|
52
56
|
});
|
|
53
57
|
const Result_2 = IDL.Variant({ 'ok' : FileId, 'err' : Err });
|
|
54
|
-
const
|
|
58
|
+
const PackageConfigV2 = IDL.Record({
|
|
55
59
|
'dfx' : IDL.Text,
|
|
56
60
|
'moc' : IDL.Text,
|
|
57
61
|
'scripts' : IDL.Vec(Script),
|
|
@@ -63,9 +67,9 @@ export const idlFactory = ({ IDL }) => {
|
|
|
63
67
|
'version' : IDL.Text,
|
|
64
68
|
'keywords' : IDL.Vec(IDL.Text),
|
|
65
69
|
'donation' : IDL.Text,
|
|
66
|
-
'devDependencies' : IDL.Vec(
|
|
70
|
+
'devDependencies' : IDL.Vec(DependencyV2),
|
|
67
71
|
'repository' : IDL.Text,
|
|
68
|
-
'dependencies' : IDL.Vec(
|
|
72
|
+
'dependencies' : IDL.Vec(DependencyV2),
|
|
69
73
|
'license' : IDL.Text,
|
|
70
74
|
'readme' : IDL.Text,
|
|
71
75
|
});
|
|
@@ -110,7 +114,7 @@ export const idlFactory = ({ IDL }) => {
|
|
|
110
114
|
[Result_2],
|
|
111
115
|
[],
|
|
112
116
|
),
|
|
113
|
-
'startPublish' : IDL.Func([
|
|
117
|
+
'startPublish' : IDL.Func([PackageConfigV2], [Result_1], []),
|
|
114
118
|
'uploadFileChunk' : IDL.Func(
|
|
115
119
|
[PublishingId, FileId, IDL.Nat, IDL.Vec(IDL.Nat8)],
|
|
116
120
|
[Result],
|
package/mops.js
CHANGED
|
@@ -13,7 +13,7 @@ import {decodeFile} from './pem.js';
|
|
|
13
13
|
global.fetch = fetch;
|
|
14
14
|
|
|
15
15
|
// (!) make changes in pair with backend
|
|
16
|
-
let apiVersion = '
|
|
16
|
+
let apiVersion = '1.2';
|
|
17
17
|
|
|
18
18
|
let networkFile = new URL('./network.txt', import.meta.url);
|
|
19
19
|
|
|
@@ -107,9 +107,57 @@ export async function getHighestVersion(pkgName) {
|
|
|
107
107
|
return actor.getHighestVersion(pkgName);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
export function parseGithubURL(href){
|
|
111
|
+
const url = new URL(href);
|
|
112
|
+
const branch = url.hash?.substring(1) || 'master';
|
|
113
|
+
|
|
114
|
+
let [org, gitName] = url.pathname.split('/').filter(path => !!path);
|
|
115
|
+
|
|
116
|
+
if (gitName.endsWith('.git')){
|
|
117
|
+
gitName = gitName.substring(0, gitName.length - 4);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { org, gitName, branch };
|
|
121
|
+
}
|
|
122
|
+
|
|
110
123
|
export function readConfig(configFile = path.join(process.cwd(), 'mops.toml')) {
|
|
111
124
|
let text = fs.readFileSync(configFile).toString();
|
|
112
|
-
|
|
125
|
+
let toml = TOML.parse(text);
|
|
126
|
+
|
|
127
|
+
const deps = toml.dependencies || {};
|
|
128
|
+
|
|
129
|
+
Object.entries(deps).forEach(([name, data])=>{
|
|
130
|
+
if (data.startsWith('https://github.com/')){
|
|
131
|
+
deps[name] = {name, repo: data, version: ''};
|
|
132
|
+
}else{
|
|
133
|
+
deps[name] = {name, repo: '', version: data};
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return toml;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function writeConfig(config, configFile = path.join(process.cwd(), 'mops.toml')) {
|
|
141
|
+
const deps = config.dependencies || {};
|
|
142
|
+
|
|
143
|
+
Object.entries(deps).forEach(([name, {repo, version}])=>{
|
|
144
|
+
if (repo){
|
|
145
|
+
deps[name] = repo;
|
|
146
|
+
}else{
|
|
147
|
+
deps[name] = version;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
fs.writeFileSync(configFile, TOML.stringify(config).trim());
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function formatDir(name, version){
|
|
155
|
+
return path.join(process.cwd(), '.mops', `${name}@${version}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function formatGithubDir(name, repo){
|
|
159
|
+
const { branch } = parseGithubURL(repo);
|
|
160
|
+
return path.join(process.cwd(), '.mops/_github', `${name}@${branch}`);
|
|
113
161
|
}
|
|
114
162
|
|
|
115
163
|
export function readDfxJson() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ic-mops",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mops": "cli.js"
|
|
@@ -13,9 +13,13 @@
|
|
|
13
13
|
"@iarna/toml": "^2.2.5",
|
|
14
14
|
"chalk": "^4.1.2",
|
|
15
15
|
"commander": "^9.2.0",
|
|
16
|
+
"decompress": "^4.2.1",
|
|
16
17
|
"del": "^6.0.0",
|
|
18
|
+
"dhall-to-json-cli": "^1.7.6",
|
|
17
19
|
"eslint": "^8.15.0",
|
|
20
|
+
"execa": "^6.1.0",
|
|
18
21
|
"globby": "^13.1.1",
|
|
22
|
+
"got": "^12.5.3",
|
|
19
23
|
"log-update": "^5.0.1",
|
|
20
24
|
"minimatch": "^5.0.1",
|
|
21
25
|
"node-fetch": "^2.6.7",
|
package/vessel.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
existsSync, mkdirSync, createWriteStream, readFileSync, writeFileSync
|
|
3
|
+
} from 'fs';
|
|
4
|
+
import del from 'del';
|
|
5
|
+
import { execaCommand} from 'execa';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import logUpdate from 'log-update';
|
|
8
|
+
import { formatGithubDir, parseGithubURL, progressBar } from './mops.js';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import got from 'got';
|
|
11
|
+
import decompress from 'decompress';
|
|
12
|
+
import {pipeline} from 'stream/promises';
|
|
13
|
+
|
|
14
|
+
const dhallFileToJson = async (filePath) => {
|
|
15
|
+
if (existsSync(filePath)) {
|
|
16
|
+
let cwd = new URL(path.dirname(import.meta.url)).pathname;
|
|
17
|
+
const res = await execaCommand(`dhall-to-json --file ${filePath}`, {preferLocal:true, cwd});
|
|
18
|
+
|
|
19
|
+
if (res.exitCode === 0){
|
|
20
|
+
return JSON.parse(res.stdout);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return res;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return null;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const readVesselConfig = async (
|
|
31
|
+
configFile,
|
|
32
|
+
{ cache = true } = { cache: true }
|
|
33
|
+
) => {
|
|
34
|
+
const cachedFile = (configFile || process.cwd()) + '/vessel.json';
|
|
35
|
+
|
|
36
|
+
if (existsSync(cachedFile)) {
|
|
37
|
+
let cachedConfig = readFileSync(cachedFile);
|
|
38
|
+
return JSON.parse(cachedConfig);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const [vessel, packageSetArray] = await Promise.all([
|
|
42
|
+
dhallFileToJson((configFile || process.cwd()) + '/vessel.dhall'),
|
|
43
|
+
dhallFileToJson((configFile || process.cwd()) + '/package-set.dhall')
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
if (!vessel || !packageSetArray) return null;
|
|
47
|
+
|
|
48
|
+
let repos = {};
|
|
49
|
+
for (const { name, repo, version } of packageSetArray) {
|
|
50
|
+
const { org, gitName } = parseGithubURL(repo);
|
|
51
|
+
repos[name] = `https://github.com/${org}/${gitName}#${version}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let config = {
|
|
55
|
+
compiler: vessel.compiler,
|
|
56
|
+
dependencies: vessel.dependencies.map((name) => {
|
|
57
|
+
return { name, repo: repos[name], version: '' };
|
|
58
|
+
}),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (cache === true) {
|
|
62
|
+
writeFileSync(cachedFile, JSON.stringify(config), 'utf-8');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return config;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const downloadFromGithub = async (repo, dest, onProgress = null) => {
|
|
69
|
+
const {branch, org, gitName} = parseGithubURL(repo);
|
|
70
|
+
|
|
71
|
+
const zipFile = `https://github.com/${org}/${gitName}/archive/${branch}.zip`;
|
|
72
|
+
const readStream = got.stream(zipFile);
|
|
73
|
+
|
|
74
|
+
const promise = new Promise((resolve, reject) => {
|
|
75
|
+
|
|
76
|
+
readStream.on('downloadProgress', ({ transferred, total}) => {
|
|
77
|
+
onProgress?.(transferred, total || 2 * (1024 ** 2) );
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
readStream.on('response', (response) => {
|
|
81
|
+
if (response.headers.age > 3600) {
|
|
82
|
+
console.log(chalk.red('Error: ') + 'Failure - response too old');
|
|
83
|
+
readStream.destroy(); // Destroy the stream to prevent hanging resources.
|
|
84
|
+
reject();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Prevent `onError` being called twice.
|
|
89
|
+
readStream.off('error', reject);
|
|
90
|
+
const tmpDir = process.cwd() + '/.mops/_tmp/';
|
|
91
|
+
const tmpFile = tmpDir + `/${gitName}@${branch}.zip`;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
mkdirSync(tmpDir, {recursive: true});
|
|
95
|
+
|
|
96
|
+
pipeline(readStream, createWriteStream(tmpFile))
|
|
97
|
+
.then(() => {
|
|
98
|
+
let options = {
|
|
99
|
+
extract: true,
|
|
100
|
+
strip: 1,
|
|
101
|
+
headers: {
|
|
102
|
+
accept: 'application/zip'
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
return decompress(tmpFile, dest, options);
|
|
107
|
+
|
|
108
|
+
}).then((unzippedFiles) => {
|
|
109
|
+
del.sync([tmpDir]);
|
|
110
|
+
resolve(unzippedFiles);
|
|
111
|
+
|
|
112
|
+
}).catch(err => {
|
|
113
|
+
del.sync([tmpDir]);
|
|
114
|
+
reject(err);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
} catch (err) {
|
|
118
|
+
del.sync([tmpDir]);
|
|
119
|
+
reject(err);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return promise;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const installFromGithub = async (name, repo, options = {})=>{
|
|
128
|
+
|
|
129
|
+
const {verbose, dep, silent} = options;
|
|
130
|
+
|
|
131
|
+
const {branch} = parseGithubURL(repo);
|
|
132
|
+
const dir = formatGithubDir(name, repo);
|
|
133
|
+
|
|
134
|
+
if (existsSync(dir)){
|
|
135
|
+
silent || logUpdate(`${dep ? 'Dependency' : 'Installing'} ${name}@${branch} (cache) from Github`);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
mkdirSync(dir, {recursive: true});
|
|
139
|
+
|
|
140
|
+
let progress = (step, total) => {
|
|
141
|
+
silent || logUpdate(`${dep ? 'Dependency' : 'Installing'} ${name}@${branch} ${progressBar(step, total)}`);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
progress(0, 2 * (1024 ** 2));
|
|
145
|
+
await downloadFromGithub(repo, dir, progress).catch((err)=> {
|
|
146
|
+
del.sync([dir]);
|
|
147
|
+
console.log(chalk.red('Error: ') + err);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (verbose) {
|
|
152
|
+
silent || logUpdate.done();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const config = await readVesselConfig(dir);
|
|
156
|
+
|
|
157
|
+
if (config){
|
|
158
|
+
for (const {name, repo} of config.dependencies){
|
|
159
|
+
await installFromGithub(name, repo, {verbose, silent, dep: true });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|