@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 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
- # 启动,在feishu-grafana-alert.json所在目录下
15
- shunjs start @shun-js/feishu-grafana-alert
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-grafana-alert @shun-js/xxx
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
- // pm2
2
- const pm2 = require('pm2');
3
-
4
- // qiao
5
- const cli = require('qiao-cli');
1
+ 'use strict';
6
2
 
7
- /**
8
- * pm2Start
9
- * @param {*} options
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
- pm2.start(options, function (error) {
24
- pm2.disconnect();
25
- return error ? reject(error) : resolve();
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
- // qiao
4
- const cli = require('qiao-cli');
3
+ 'use strict';
5
4
 
6
- // cmds
7
- require('./shun-start.js');
8
- require('./shun-version.js');
5
+ const path = require('path');
6
+ const fs = require('fs');
7
+ const { program } = require('commander');
9
8
 
10
- // parse
11
- cli.cmd.parse(process.argv);
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.2",
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
- "debug": "^4.4.3",
27
- "pm2": "^6.0.14",
28
- "qiao-cli": "^5.0.0",
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": "4fa47fe5cf1b00acfe54f47af836101291093f06"
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
- }
@@ -1,5 +0,0 @@
1
- // qiao
2
- const cli = require('qiao-cli');
3
-
4
- // cmd
5
- cli.cmd.version(require('../package.json').version, '-v, --version').description('shun.js').usage('<command>');
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
- };