@shun-js/shun-cli 0.3.2 → 1.0.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/README.md +6 -6
- package/bin/log.js +17 -0
- package/bin/npm.js +28 -0
- package/bin/parse.js +25 -0
- package/bin/pm2.js +64 -22
- package/bin/shun.js +81 -7
- package/package.json +5 -6
- package/bin/shun-start.js +0 -94
- package/bin/shun-version.js +0 -5
- package/bin/util.js +0 -27
package/README.md
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
shun.js cli tool
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
7
|
```shell
|
|
8
8
|
npm i -g @shun-js/shun-cli
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Start servers
|
|
12
12
|
|
|
13
13
|
```shell
|
|
14
|
-
#
|
|
15
|
-
shunjs start @shun-js/feishu-
|
|
14
|
+
# start a server (version is required), run in the directory containing config json files
|
|
15
|
+
shunjs start @shun-js/feishu-bot@0.3.1
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
shunjs start @shun-js/feishu-
|
|
17
|
+
# start multiple servers
|
|
18
|
+
shunjs start @shun-js/feishu-bot@0.3.1 @shun-js/aitubiao-server@0.3.8
|
|
19
19
|
```
|
package/bin/log.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const pc = require('picocolors');
|
|
4
|
+
|
|
5
|
+
function info(msg) {
|
|
6
|
+
console.log(pc.gray(msg));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function success(msg) {
|
|
10
|
+
console.log(pc.green(msg));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function error(msg) {
|
|
14
|
+
console.log(pc.red(msg));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = { info, success, error };
|
package/bin/npm.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const log = require('./log.js');
|
|
5
|
+
|
|
6
|
+
function installGlobal(pkgWithVersion) {
|
|
7
|
+
log.info(`npm i -g ${pkgWithVersion} ...`);
|
|
8
|
+
try {
|
|
9
|
+
const output = execSync(`npm i -g ${pkgWithVersion}`, { encoding: 'utf-8' });
|
|
10
|
+
console.log(output);
|
|
11
|
+
} catch (e) {
|
|
12
|
+
log.error(`npm global install failed: ${pkgWithVersion}`);
|
|
13
|
+
console.log(e.message);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getGlobalPath() {
|
|
19
|
+
try {
|
|
20
|
+
return execSync('npm root -g', { encoding: 'utf-8' }).trim();
|
|
21
|
+
} catch (e) {
|
|
22
|
+
log.error('failed to get npm global path');
|
|
23
|
+
console.log(e.message);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = { installGlobal, getGlobalPath };
|
package/bin/parse.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* parseServer
|
|
5
|
+
* parse @shun-js/aitubiao-server@0.3.8
|
|
6
|
+
* return { pkg, version, name }
|
|
7
|
+
*/
|
|
8
|
+
function parseServer(input) {
|
|
9
|
+
const lastAt = input.lastIndexOf('@');
|
|
10
|
+
|
|
11
|
+
let pkg, version;
|
|
12
|
+
if (lastAt <= 0 || input.indexOf('@') === lastAt) {
|
|
13
|
+
return null;
|
|
14
|
+
} else {
|
|
15
|
+
pkg = input.slice(0, lastAt);
|
|
16
|
+
version = input.slice(lastAt + 1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// pm2 process name: extract aitubiao-server from @shun-js/aitubiao-server
|
|
20
|
+
const name = pkg.split('/')[1] || pkg;
|
|
21
|
+
|
|
22
|
+
return { pkg, version, name };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = { parseServer };
|
package/bin/pm2.js
CHANGED
|
@@ -1,29 +1,71 @@
|
|
|
1
|
-
|
|
2
|
-
const pm2 = require('pm2');
|
|
3
|
-
|
|
4
|
-
// qiao
|
|
5
|
-
const cli = require('qiao-cli');
|
|
1
|
+
'use strict';
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* @returns
|
|
11
|
-
*/
|
|
12
|
-
exports.pm2Start = (options) => {
|
|
13
|
-
return new Promise((resolve, reject) => {
|
|
14
|
-
pm2.connect((error) => {
|
|
15
|
-
if (error) {
|
|
16
|
-
console.log(cli.colors.red('连接PM2失败。'));
|
|
17
|
-
console.log();
|
|
18
|
-
console.log(error);
|
|
3
|
+
const pm2 = require('pm2');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const log = require('./log.js');
|
|
19
6
|
|
|
7
|
+
function connect() {
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
pm2.connect((err) => {
|
|
10
|
+
if (err) {
|
|
11
|
+
log.error('failed to connect pm2');
|
|
12
|
+
console.log(err);
|
|
20
13
|
process.exit(2);
|
|
21
14
|
}
|
|
15
|
+
resolve();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function disconnect() {
|
|
21
|
+
pm2.disconnect();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isRunning(name) {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
pm2.list((err, list) => {
|
|
27
|
+
if (err) return resolve(false);
|
|
28
|
+
resolve(list.some((p) => p.name === name));
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
function start(config) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
pm2.start(config, (err) => {
|
|
36
|
+
return err ? reject(err) : resolve();
|
|
27
37
|
});
|
|
28
38
|
});
|
|
29
|
-
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function reload(name) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
pm2.reload(name, (err) => {
|
|
44
|
+
return err ? reject(err) : resolve();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function startOrReload(config) {
|
|
50
|
+
const running = await isRunning(config.name);
|
|
51
|
+
if (running) {
|
|
52
|
+
log.info(`process exists, reloading: ${config.name}`);
|
|
53
|
+
await reload(config.name);
|
|
54
|
+
} else {
|
|
55
|
+
log.info(`starting new process: ${config.name}`);
|
|
56
|
+
await start(config);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function save() {
|
|
61
|
+
try {
|
|
62
|
+
log.info('pm2 saving...');
|
|
63
|
+
execSync('pm2 save', { encoding: 'utf-8' });
|
|
64
|
+
log.success('pm2 saved');
|
|
65
|
+
} catch (e) {
|
|
66
|
+
log.error('pm2 save failed');
|
|
67
|
+
console.log(e.message);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = { connect, disconnect, startOrReload, save };
|
package/bin/shun.js
CHANGED
|
@@ -1,11 +1,85 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const cli = require('qiao-cli');
|
|
3
|
+
'use strict';
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
require('
|
|
8
|
-
require('
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const { program } = require('commander');
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const { parseServer } = require('./parse.js');
|
|
10
|
+
const log = require('./log.js');
|
|
11
|
+
const npm = require('./npm.js');
|
|
12
|
+
const pm2 = require('./pm2.js');
|
|
13
|
+
|
|
14
|
+
// version
|
|
15
|
+
program.version(require('../package.json').version, '-v, --version');
|
|
16
|
+
|
|
17
|
+
// start
|
|
18
|
+
program
|
|
19
|
+
.command('start <servers...>')
|
|
20
|
+
.description('install and start servers, e.g. @shun-js/xxx@1.0.0')
|
|
21
|
+
.action(async (servers) => {
|
|
22
|
+
try {
|
|
23
|
+
await pm2.connect();
|
|
24
|
+
|
|
25
|
+
for (const server of servers) {
|
|
26
|
+
await startServer(server);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pm2.save();
|
|
30
|
+
} catch (e) {
|
|
31
|
+
log.error('failed to start servers');
|
|
32
|
+
console.log(e);
|
|
33
|
+
} finally {
|
|
34
|
+
pm2.disconnect();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
async function startServer(input) {
|
|
39
|
+
const parsed = parseServer(input);
|
|
40
|
+
if (!parsed) {
|
|
41
|
+
log.error(`version is required: ${input}, e.g. ${input}@1.0.0`);
|
|
42
|
+
console.log();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { pkg, version, name } = parsed;
|
|
47
|
+
const pkgWithVersion = `${pkg}@${version}`;
|
|
48
|
+
|
|
49
|
+
log.info(`starting server: ${pkgWithVersion}`);
|
|
50
|
+
|
|
51
|
+
// 1. npm install -g
|
|
52
|
+
npm.installGlobal(pkgWithVersion);
|
|
53
|
+
|
|
54
|
+
// 2. 定位 app.js
|
|
55
|
+
const globalPath = npm.getGlobalPath();
|
|
56
|
+
const serverRoot = path.resolve(globalPath, pkg);
|
|
57
|
+
const appPath = path.resolve(serverRoot, 'app.js');
|
|
58
|
+
|
|
59
|
+
if (!fs.existsSync(appPath)) {
|
|
60
|
+
log.error(`app.js not found: ${appPath}`);
|
|
61
|
+
console.log();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 3. 查找配置文件
|
|
66
|
+
const configPath = path.resolve(process.cwd(), `${name}.json`);
|
|
67
|
+
if (!fs.existsSync(configPath)) {
|
|
68
|
+
log.error(`config not found: ${configPath}`);
|
|
69
|
+
console.log();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 4. pm2 startOrReload
|
|
74
|
+
await pm2.startOrReload({
|
|
75
|
+
name,
|
|
76
|
+
cwd: serverRoot,
|
|
77
|
+
script: appPath,
|
|
78
|
+
args: configPath,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
log.success(`server started: ${pkgWithVersion}`);
|
|
82
|
+
console.log();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shun-js/shun-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "shun.js cli",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shun.js",
|
|
@@ -23,14 +23,13 @@
|
|
|
23
23
|
"bin"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"qiao-file": "^5.0.6"
|
|
26
|
+
"commander": "^13.0.0",
|
|
27
|
+
"picocolors": "^1.1.0",
|
|
28
|
+
"pm2": "^6.0.14"
|
|
30
29
|
},
|
|
31
30
|
"publishConfig": {
|
|
32
31
|
"access": "public",
|
|
33
32
|
"registry": "https://registry.npmjs.org/"
|
|
34
33
|
},
|
|
35
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "4d325ef9b9573b53a35c857d237b91f9a3666353"
|
|
36
35
|
}
|
package/bin/shun-start.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
// path
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
// qiao
|
|
5
|
-
const cli = require('qiao-cli');
|
|
6
|
-
const { isExists } = require('qiao-file');
|
|
7
|
-
|
|
8
|
-
// util
|
|
9
|
-
const { getNPMGlobalPath } = require('./util.js');
|
|
10
|
-
const { pm2Start } = require('./pm2.js');
|
|
11
|
-
|
|
12
|
-
// debug
|
|
13
|
-
const debug = require('debug')('@shun-js/shun-cli');
|
|
14
|
-
|
|
15
|
-
// cmd
|
|
16
|
-
cli.cmd
|
|
17
|
-
.command('start <servers...>')
|
|
18
|
-
.description('待启动的服务名')
|
|
19
|
-
.option('-m, --max', '使用集群模式,CPU核心数最大化')
|
|
20
|
-
.action(startServers);
|
|
21
|
-
|
|
22
|
-
// start servers
|
|
23
|
-
async function startServers(servers, options) {
|
|
24
|
-
try {
|
|
25
|
-
for (let i = 0; i < servers.length; i++) {
|
|
26
|
-
await startServer(servers[i], options);
|
|
27
|
-
}
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.log(cli.colors.red('启动服务出错。'));
|
|
30
|
-
console.log();
|
|
31
|
-
console.log(error);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// start servers
|
|
36
|
-
async function startServer(serverName, options) {
|
|
37
|
-
const methodName = 'startServer';
|
|
38
|
-
console.log(cli.colors.gray(`开始启动服务:${serverName}`));
|
|
39
|
-
|
|
40
|
-
// check
|
|
41
|
-
if (!serverName.startsWith('@shun-js')) {
|
|
42
|
-
console.log(cli.colors.red(`非法服务:${serverName}`));
|
|
43
|
-
console.log();
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// check package
|
|
48
|
-
const npmGlobalPath = getNPMGlobalPath();
|
|
49
|
-
const serverRootPath = path.resolve(npmGlobalPath, `./${serverName}`);
|
|
50
|
-
const serverAppPath = path.resolve(serverRootPath, './app.js');
|
|
51
|
-
const serverAppPathIsExists = await isExists(serverAppPath);
|
|
52
|
-
debug(methodName, 'serverRootPath', serverRootPath);
|
|
53
|
-
debug(methodName, 'serverAppPath', serverAppPath);
|
|
54
|
-
debug(methodName, 'serverAppPathIsExists', serverAppPathIsExists);
|
|
55
|
-
if (!serverAppPathIsExists) {
|
|
56
|
-
console.log(cli.colors.red(`服务未安装:${serverName}`));
|
|
57
|
-
console.log();
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// check config
|
|
62
|
-
const workDir = process.cwd();
|
|
63
|
-
const serverConfigPrefix = serverName.split('/')[1];
|
|
64
|
-
const serverConfigPath = path.resolve(workDir, `./${serverConfigPrefix}.json`);
|
|
65
|
-
const serverConfigPathIsExists = await isExists(serverConfigPath);
|
|
66
|
-
debug(methodName, 'serverConfigPath', serverConfigPath);
|
|
67
|
-
debug(methodName, 'serverConfigPathIsExists', serverConfigPathIsExists);
|
|
68
|
-
|
|
69
|
-
// pm2
|
|
70
|
-
try {
|
|
71
|
-
const pm2Config = {
|
|
72
|
-
name: serverConfigPrefix,
|
|
73
|
-
cwd: serverRootPath,
|
|
74
|
-
script: serverAppPath,
|
|
75
|
-
args: serverConfigPath,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// 集群模式
|
|
79
|
-
if (options && options.max) {
|
|
80
|
-
pm2Config.instances = 'max';
|
|
81
|
-
pm2Config.exec_mode = 'cluster';
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
await pm2Start(pm2Config);
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.log(cli.colors.red(`服务启动失败:${serverName}`));
|
|
87
|
-
console.log();
|
|
88
|
-
console.log(error);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// r
|
|
92
|
-
console.log(cli.colors.green(`服务启动成功:${serverName}`));
|
|
93
|
-
console.log();
|
|
94
|
-
}
|
package/bin/shun-version.js
DELETED
package/bin/util.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// qiao
|
|
2
|
-
const cli = require('qiao-cli');
|
|
3
|
-
|
|
4
|
-
// cp
|
|
5
|
-
const { execSync } = require('child_process');
|
|
6
|
-
|
|
7
|
-
// debug
|
|
8
|
-
const debug = require('debug')('shun.js');
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* getNPMGlobalPath
|
|
12
|
-
* @returns
|
|
13
|
-
*/
|
|
14
|
-
exports.getNPMGlobalPath = () => {
|
|
15
|
-
const methodName = 'getNPMRootPath';
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const npmGlobalPath = execSync('npm root -g').toString().trim();
|
|
19
|
-
debug(methodName, 'npmGlobalPath', npmGlobalPath);
|
|
20
|
-
|
|
21
|
-
return npmGlobalPath;
|
|
22
|
-
} catch (error) {
|
|
23
|
-
console.log(cli.colors.red('获取NPM全局路径出错。'));
|
|
24
|
-
console.log();
|
|
25
|
-
console.log(error);
|
|
26
|
-
}
|
|
27
|
-
};
|