@eggjs/scripts 3.1.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.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -0
  3. package/bin/dev.cmd +3 -0
  4. package/bin/dev.js +5 -0
  5. package/bin/run.cmd +3 -0
  6. package/bin/run.js +5 -0
  7. package/dist/commonjs/baseCommand.d.ts +25 -0
  8. package/dist/commonjs/baseCommand.js +62 -0
  9. package/dist/commonjs/commands/start.d.ts +34 -0
  10. package/dist/commonjs/commands/start.js +350 -0
  11. package/dist/commonjs/commands/stop.d.ts +16 -0
  12. package/dist/commonjs/commands/stop.js +90 -0
  13. package/dist/commonjs/helper.d.ts +10 -0
  14. package/dist/commonjs/helper.js +61 -0
  15. package/dist/commonjs/index.d.ts +3 -0
  16. package/dist/commonjs/index.js +26 -0
  17. package/dist/commonjs/package.json +3 -0
  18. package/dist/commonjs/types.d.ts +9 -0
  19. package/dist/commonjs/types.js +3 -0
  20. package/dist/esm/baseCommand.d.ts +25 -0
  21. package/dist/esm/baseCommand.js +55 -0
  22. package/dist/esm/commands/start.d.ts +34 -0
  23. package/dist/esm/commands/start.js +344 -0
  24. package/dist/esm/commands/stop.d.ts +16 -0
  25. package/dist/esm/commands/stop.js +87 -0
  26. package/dist/esm/helper.d.ts +10 -0
  27. package/dist/esm/helper.js +51 -0
  28. package/dist/esm/index.d.ts +3 -0
  29. package/dist/esm/index.js +5 -0
  30. package/dist/esm/package.json +3 -0
  31. package/dist/esm/types.d.ts +9 -0
  32. package/dist/esm/types.js +2 -0
  33. package/dist/package.json +4 -0
  34. package/package.json +103 -0
  35. package/scripts/start-cluster.cjs +15 -0
  36. package/scripts/start-cluster.mjs +14 -0
  37. package/src/baseCommand.ts +68 -0
  38. package/src/commands/start.ts +384 -0
  39. package/src/commands/stop.ts +100 -0
  40. package/src/helper.ts +62 -0
  41. package/src/index.ts +8 -0
  42. package/src/types.ts +9 -0
@@ -0,0 +1,100 @@
1
+ import { debuglog, format } from 'node:util';
2
+ import { scheduler } from 'node:timers/promises';
3
+ import { Args, Flags } from '@oclif/core';
4
+ import { BaseCommand } from '../baseCommand.js';
5
+ import { isWindows, findNodeProcess, NodeProcess, kill } from '../helper.js';
6
+
7
+ const debug = debuglog('@eggjs/scripts/commands/stop');
8
+
9
+ const osRelated = {
10
+ titleTemplate: isWindows ? '\\"title\\":\\"%s\\"' : '"title":"%s"',
11
+ // node_modules/@eggjs/cluster/dist/commonjs/app_worker.js
12
+ // node_modules/@eggjs/cluster/dist/esm/app_worker.js
13
+ appWorkerPath: /@eggjs[\/\\]cluster[\/\\]dist[\/\\](commonjs|esm)[\/\\]app_worker\.js/i,
14
+ // node_modules/@eggjs/cluster/dist/commonjs/agent_worker.js
15
+ // node_modules/@eggjs/cluster/dist/esm/agent_worker.js
16
+ agentWorkerPath: /@eggjs[\/\\]cluster[\/\\]dist[\/\\](commonjs|esm)[\/\\]agent_worker\.js/i,
17
+ };
18
+
19
+ export default class Stop<T extends typeof Stop> extends BaseCommand<T> {
20
+ static override description = 'Stop server';
21
+
22
+ static override examples = [
23
+ '<%= config.bin %> <%= command.id %>',
24
+ ];
25
+
26
+ static override args = {
27
+ baseDir: Args.string({
28
+ description: 'directory of application',
29
+ required: false,
30
+ }),
31
+ };
32
+
33
+ static override flags = {
34
+ title: Flags.string({
35
+ description: 'process title description, use for kill grep',
36
+ }),
37
+ timeout: Flags.integer({
38
+ description: 'the maximum timeout(ms) when app stop',
39
+ default: 5000,
40
+ }),
41
+ };
42
+
43
+ public async run(): Promise<void> {
44
+ const { flags } = this;
45
+
46
+ this.log(`stopping egg application${flags.title ? ` with --title=${flags.title}` : ''}`);
47
+
48
+ // node ~/eggjs/scripts/scripts/start-cluster.cjs {"title":"egg-server","workers":4,"port":7001,"baseDir":"~/eggjs/test/showcase","framework":"~/eggjs/test/showcase/node_modules/egg"}
49
+ let processList = await this.findNodeProcesses(item => {
50
+ const cmd = item.cmd;
51
+ const matched = flags.title ?
52
+ cmd.includes('start-cluster') && cmd.includes(format(osRelated.titleTemplate, flags.title)) :
53
+ cmd.includes('start-cluster');
54
+ if (matched) {
55
+ debug('find master process: %o', item);
56
+ }
57
+ return matched;
58
+ });
59
+ let pids = processList.map(x => x.pid);
60
+
61
+ if (pids.length) {
62
+ this.log('got master pid %j', pids);
63
+ this.killProcesses(pids);
64
+ // wait for 5s to confirm whether any worker process did not kill by master
65
+ await scheduler.wait(flags.timeout);
66
+ } else {
67
+ this.logToStderr('can\'t detect any running egg process');
68
+ }
69
+
70
+ // node --debug-port=5856 /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/agent_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406}
71
+ // node /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/app_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406}
72
+ // ~/bin/node --no-deprecation --trace-warnings ~/eggjs/examples/helloworld/node_modules/@eggjs/cluster/dist/commonjs/agent_worker.js {"baseDir":"~/eggjs/examples/helloworld","startMode":"process","framework":"~/eggjs/examples/helloworld/node_modules/egg","title":"egg-server-helloworld","workers":10,"clusterPort":58977}
73
+ processList = await this.findNodeProcesses(item => {
74
+ const cmd = item.cmd;
75
+ const matched = flags.title ?
76
+ (osRelated.appWorkerPath.test(cmd) || osRelated.agentWorkerPath.test(cmd)) && cmd.includes(format(osRelated.titleTemplate, flags.title)) :
77
+ (osRelated.appWorkerPath.test(cmd) || osRelated.agentWorkerPath.test(cmd));
78
+ if (matched) {
79
+ debug('find app/agent worker process: %o', item);
80
+ }
81
+ return matched;
82
+ });
83
+ pids = processList.map(x => x.pid);
84
+
85
+ if (pids.length) {
86
+ this.log('got worker/agent pids %j that is not killed by master', pids);
87
+ this.killProcesses(pids);
88
+ }
89
+
90
+ this.log('stopped');
91
+ }
92
+
93
+ protected async findNodeProcesses(filter: (item: NodeProcess) => boolean): Promise<NodeProcess[]> {
94
+ return findNodeProcess(filter);
95
+ }
96
+
97
+ protected killProcesses(pids: number[], signal: NodeJS.Signals = 'SIGTERM') {
98
+ kill(pids, signal);
99
+ }
100
+ }
package/src/helper.ts ADDED
@@ -0,0 +1,62 @@
1
+ import { runScript } from 'runscript';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ export const isWindows = process.platform === 'win32';
6
+
7
+ const REGEX = isWindows ? /^(.*)\s+(\d+)\s*$/ : /^\s*(\d+)\s+(.*)/;
8
+
9
+ export interface NodeProcess {
10
+ pid: number;
11
+ cmd: string;
12
+ }
13
+
14
+ export type FilterFunction = (item: NodeProcess) => boolean;
15
+
16
+ export async function findNodeProcess(filterFn?: FilterFunction): Promise<NodeProcess[]> {
17
+ const command = isWindows ?
18
+ 'wmic Path win32_process Where "Name = \'node.exe\'" Get CommandLine,ProcessId' :
19
+ // command, cmd are alias of args, not POSIX standard, so we use args
20
+ 'ps -wweo "pid,args"';
21
+ const stdio = await runScript(command, { stdio: 'pipe' });
22
+ const processList = stdio.stdout!.toString().split('\n')
23
+ .reduce<NodeProcess[]>((arr, line) => {
24
+ if (!!line && !line.includes('/bin/sh') && line.includes('node')) {
25
+ const m = line.match(REGEX);
26
+ if (m) {
27
+ const item: NodeProcess = isWindows ? { pid: parseInt(m[2]), cmd: m[1] } : { pid: parseInt(m[1]), cmd: m[2] };
28
+ if (filterFn?.(item)) {
29
+ arr.push(item);
30
+ }
31
+ }
32
+ }
33
+ return arr;
34
+ }, []);
35
+ return processList;
36
+ }
37
+
38
+ export function kill(pids: number[], signal?: string | number) {
39
+ pids.forEach(pid => {
40
+ try {
41
+ process.kill(pid, signal);
42
+ } catch (err: any) {
43
+ if (err.code !== 'ESRCH') {
44
+ throw err;
45
+ }
46
+ }
47
+ });
48
+ }
49
+
50
+ export function getSourceDirname() {
51
+ if (typeof __dirname === 'string') {
52
+ return __dirname;
53
+ }
54
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
55
+ // @ts-ignore
56
+ const __filename = fileURLToPath(import.meta.url);
57
+ return path.dirname(__filename);
58
+ }
59
+
60
+ export function getSourceFilename(filename: string) {
61
+ return path.join(getSourceDirname(), filename);
62
+ }
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ import Start from './commands/start.js';
2
+
3
+ // exports.StopCommand = require('./lib/cmd/stop');
4
+
5
+ export * from './baseCommand.js';
6
+ export {
7
+ Start, Start as StartCommand,
8
+ };
package/src/types.ts ADDED
@@ -0,0 +1,9 @@
1
+ export interface PackageEgg {
2
+ framework?: boolean;
3
+ typescript?: boolean;
4
+ tscompiler?: string;
5
+ declarations?: boolean;
6
+ revert?: string | string[];
7
+ require?: string | string[];
8
+ import?: string | string[];
9
+ }