@mpis/run 0.0.3 → 0.0.5

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mpis/run",
3
3
  "type": "module",
4
- "version": "0.0.3",
4
+ "version": "0.0.5",
5
5
  "keywords": [],
6
6
  "bin": {
7
7
  "run": "./loader/bin.js",
@@ -13,27 +13,21 @@
13
13
  "dependencies": {
14
14
  "execa": "^9.6.0",
15
15
  "source-map-support": "^0.5.21",
16
- "@build-script/rushstack-config-loader": "^0.0.21",
17
- "@idlebox/common": "^1.4.15",
18
- "@idlebox/logger": "^0.0.3",
19
- "@idlebox/args": "^0.0.10",
20
- "@mpis/client": "^0.0.3",
21
- "@idlebox/node": "^1.4.8",
22
- "@mpis/server": "^0.0.2",
23
- "@mpis/shared": "^0.0.3"
16
+ "@idlebox/node": "^1.4.10",
17
+ "@idlebox/args": "^0.0.12",
18
+ "@idlebox/common": "^1.4.17",
19
+ "@idlebox/logger": "^0.0.5",
20
+ "@mpis/client": "^0.0.5",
21
+ "@build-script/rushstack-config-loader": "^0.0.23",
22
+ "@mpis/shared": "^0.0.5",
23
+ "@mpis/server": "^0.0.4"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/node": "^24.0.14",
27
- "@build-script/single-dog-asset": "^1.0.36",
28
- "@idlebox/esbuild-executer": "^0.0.3",
27
+ "@build-script/single-dog-asset": "^1.0.38",
28
+ "@idlebox/esbuild-executer": "^0.0.5",
29
29
  "@internal/local-rig": "^1.0.1"
30
30
  },
31
- "publishConfig": {
32
- "packCommand": [
33
- "publisher",
34
- "pack"
35
- ]
36
- },
37
31
  "license": "MIT",
38
32
  "author": "GongT <admin@gongt.me>",
39
33
  "repository": "https://github.com/GongT/baobao",
package/src/autoindex.ts CHANGED
@@ -3,16 +3,16 @@
3
3
  /* eslint-disable */
4
4
 
5
5
  /* common/args.ts */
6
- // Identifiers
7
- export { printUsage } from "./common/args.js";
6
+ // Identifiers
7
+ export { printUsage } from './common/args.js';
8
8
  /* common/paths.ts */
9
- // Identifiers
10
- export { projectRoot } from "./common/paths.js";
11
- export { selfRoot } from "./common/paths.js";
9
+ // Identifiers
10
+ export { projectRoot } from './common/paths.js';
11
+ export { selfRoot } from './common/paths.js';
12
12
  /* common/config-file.ts */
13
- // Identifiers
14
- export type { ICommand } from "./common/config-file.js";
15
- export type { IConfigFile } from "./common/config-file.js";
16
- export { loadConfigFile } from "./common/config-file.js";
13
+ // Identifiers
14
+ export type { ICommand } from './common/config-file.js';
15
+ export type { IConfigFile } from './common/config-file.js';
16
+ export { loadConfigFile } from './common/config-file.js';
17
17
  /* bin.ts */
18
- // Identifiers
18
+ // Identifiers
package/src/bin.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { humanDate, prettyFormatError, registerGlobalLifecycle, toDisposable } from '@idlebox/common';
2
2
  import { logger } from '@idlebox/logger';
3
- import { registerNodejsExitHandler } from '@idlebox/node';
3
+ import { registerNodejsExitHandler, shutdown } from '@idlebox/node';
4
4
  import { channelClient } from '@mpis/client';
5
5
  import { CompileError, ModeKind, ProcessIPCClient, WorkersManager } from '@mpis/server';
6
6
  import { rmSync } from 'node:fs';
@@ -46,12 +46,18 @@ switch (context.command) {
46
46
  {
47
47
  if (context.withCleanup) executeClean();
48
48
 
49
- await executeBuild();
49
+ await executeBuild().catch((e: Error) => {
50
+ logger.error`failed ${context.command} project: ${e.message}`;
51
+ shutdown(1);
52
+ });
50
53
  }
51
54
  break;
52
55
  case 'watch':
53
56
  initializeStdin();
54
- await executeBuild();
57
+ await executeBuild().catch((e: Error) => {
58
+ logger.error`failed ${context.command} project: ${e.message}`;
59
+ shutdown(1);
60
+ });
55
61
  break;
56
62
  }
57
63
 
@@ -61,14 +67,17 @@ async function executeBuild() {
61
67
  workersManager = new WorkersManager(context.watchMode ? ModeKind.Watch : ModeKind.Build);
62
68
 
63
69
  initializeWorkers();
70
+ const graph = workersManager.finalize();
71
+
72
+ workersManager.onTerminate((trans) => {
73
+ const w = trans.worker;
64
74
 
65
- workersManager.onTerminate((w) => {
66
75
  if (!ProcessIPCClient.is(w)) {
67
76
  logger.fatal`worker "${w._id}" is not a ProcessIPCClient, this is a bug.`;
68
77
  return;
69
78
  }
70
79
 
71
- const times = `(+${humanDate.delta(w.time.executeEnd! - w.time.executeStart!)})`;
80
+ const times = `(+${humanDate.delta(w.time.executeStart!, w.time.executeEnd!)})`;
72
81
 
73
82
  if (context.watchMode) {
74
83
  printFailedRunError(w, `unexpected exit in watch mode ${times}`);
@@ -79,7 +88,10 @@ async function executeBuild() {
79
88
  }
80
89
  });
81
90
 
82
- workersManager.finalize();
91
+ if (workersManager.nodeNames.length === 0) {
92
+ logger.fatal`No workers to execute, check your config file.`;
93
+ return;
94
+ }
83
95
 
84
96
  channelClient.start();
85
97
 
@@ -89,7 +101,9 @@ async function executeBuild() {
89
101
  return;
90
102
  }
91
103
  logger.verbose`Workers initialized, starting execution...`;
92
- await workersManager.startup();
104
+ await graph.startup();
105
+
106
+ logger.verbose`Startup returned.`;
93
107
 
94
108
  reprintWatchModeError();
95
109
  }
@@ -148,36 +162,32 @@ function printFailedRunError(worker: ProcessIPCClient, message: string) {
148
162
  const text = worker.outputStream.toString().trimEnd();
149
163
 
150
164
  if (text) {
151
- console.error(
152
- '\n\x1B[48;5;1m%s\r \x1B[0;38;5;9;1m %s \x1B[0m',
153
- ' '.repeat(process.stderr.columns || 80),
154
- `below is output of ${worker._id}`,
155
- );
165
+ console.error('\n\x1B[48;5;1m%s\r \x1B[0;38;5;9;1m %s \x1B[0m', ' '.repeat(process.stderr.columns || 80), `below is output of ${worker._id}`);
156
166
  console.error(text);
157
167
 
158
- console.error(
159
- '\x1B[48;5;1m%s\r \x1B[0;38;5;9;1m %s \x1B[0m\n',
160
- ' '.repeat(process.stderr.columns || 80),
161
- `ending output of ${worker._id}`,
162
- );
168
+ console.error('\x1B[48;5;1m%s\r \x1B[0;38;5;9;1m %s \x1B[0m\n', ' '.repeat(process.stderr.columns || 80), `ending output of ${worker._id}`);
163
169
  } else {
164
- console.error(
165
- '\n\x1B[48;5;1m%s\r \x1B[0;38;5;9;1m %s \x1B[0m',
166
- ' '.repeat(process.stderr.columns || 80),
167
- `no output from ${worker._id}`,
168
- );
170
+ console.error('\n\x1B[48;5;1m%s\r \x1B[0;38;5;9;1m %s \x1B[0m', ' '.repeat(process.stderr.columns || 80), `no output from ${worker._id}`);
169
171
  }
170
172
 
171
- console.error(workersManager.formatDebugGraph());
173
+ const graph = workersManager.finalize();
174
+ console.error('%s\n%s', graph.debugFormatGraph(), graph.debugFormatSummary());
172
175
  logger.fatal`"${worker._id}" ${message}`;
173
176
  }
174
177
 
178
+ let printTo: NodeJS.Timeout | undefined;
175
179
  function reprintWatchModeError(noClear?: boolean) {
176
- if (context.watchMode) {
177
- if (!noClear && !defaultNoClear) process.stderr.write('\x1Bc');
178
- }
179
- console.error(workersManager.formatDebugList());
180
- printAllErrors();
180
+ if (printTo) clearTimeout(printTo);
181
+ printTo = setTimeout(() => {
182
+ printTo = undefined;
183
+
184
+ if (context.watchMode) {
185
+ if (!noClear && !defaultNoClear) process.stderr.write('\x1Bc');
186
+ }
187
+ const graph = workersManager.finalize();
188
+ console.error('%s\n%s', graph.debugFormatList(), graph.debugFormatSummary());
189
+ printAllErrors();
190
+ }, 50);
181
191
  }
182
192
 
183
193
  function addDebugCommand() {
@@ -185,7 +195,7 @@ function addDebugCommand() {
185
195
  name: ['continue', 'c'],
186
196
  description: '开始执行',
187
197
  callback: () => {
188
- workersManager.startup();
198
+ workersManager.finalize().startup();
189
199
  },
190
200
  });
191
201
  registerCommand({
@@ -193,7 +203,7 @@ function addDebugCommand() {
193
203
  description: '切换调试模式(仅在启动前有效)',
194
204
  callback: (text: string) => {
195
205
  const [_, index, on_off] = text.split(/\s+/);
196
- const list: ProcessIPCClient[] = workersManager.allWorkers as ProcessIPCClient[];
206
+ const list = workersManager._allWorkers as ProcessIPCClient[];
197
207
  const worker = list[Number(index)];
198
208
  if (!worker) {
199
209
  logger.error`worker index out of range: ${index}`;
@@ -225,8 +235,15 @@ function sendStatus() {
225
235
  if (noError) {
226
236
  channelClient.success(`All workers completed successfully.`);
227
237
  } else {
228
- const errorCnt = errors.values().filter((e) => !!e);
229
- channelClient.failed(`${errorCnt} (of ${workersManager.size}) workers error.`, formatAllErrors());
238
+ let errorCnt = 0;
239
+ const arr: string[] = [];
240
+ for (const [client, err] of errors.entries()) {
241
+ if (err) {
242
+ errorCnt++;
243
+ arr.push(client._id);
244
+ }
245
+ }
246
+ channelClient.failed(`mpis-run: ${arr.join(', ')} (${errorCnt} / ${workersManager.size()})`, formatAllErrors());
230
247
  }
231
248
  }
232
249
 
@@ -265,8 +282,8 @@ function printAllErrors() {
265
282
  if (numFailed !== 0) {
266
283
  console.error(formatAllErrors());
267
284
 
268
- logger.error(`💥 ${numFailed} of ${workersManager.size} worker failed (${execTip})`);
285
+ logger.error(`💥 ${numFailed} of ${workersManager.size()} worker failed (${execTip})`);
269
286
  } else {
270
- logger.success(`✅ no error in ${workersManager.size} workers (${execTip})`);
287
+ logger.success(`✅ no error in ${workersManager.size()} workers (${execTip})`);
271
288
  }
272
289
  }
@@ -15,7 +15,7 @@ interface IPackageBinary {
15
15
  interface ICommandInput {
16
16
  title?: string;
17
17
  command: string | readonly string[] | IPackageBinary;
18
- watch?: string | readonly string[];
18
+ watch?: string | readonly string[] | boolean;
19
19
  cwd?: string;
20
20
  env?: Record<string, string>;
21
21
  }
@@ -38,14 +38,13 @@ export interface IConfigFile {
38
38
  additionalPaths: readonly string[];
39
39
  }
40
40
 
41
- function watchModeCmd(
42
- command: string | readonly string[],
43
- watch?: string | readonly string[],
44
- watchMode?: boolean,
45
- ): string | readonly string[] {
41
+ function watchModeCmd(command: string | readonly string[], watch?: string | readonly string[] | boolean, watchMode?: boolean): string | readonly string[] {
46
42
  if (!watchMode) {
47
43
  return command;
48
44
  }
45
+ if (typeof watch === 'boolean') {
46
+ throw new Error(`Invalid watch value: ${watch}. Expected string or array.`);
47
+ }
49
48
 
50
49
  if (typeof command === 'string') {
51
50
  if (!watch) watch = '-w';
@@ -66,8 +65,19 @@ export function loadConfigFile(watchMode: boolean): IConfigFile {
66
65
  logger.debug`using config file long<${configFile.effective}>`;
67
66
 
68
67
  const input: IConfigFileInput = config.loadBothJson('commands', schemaFile, {
69
- arrayMerge(target, _source) {
70
- return target;
68
+ array(left, right, keyPath) {
69
+ switch (keyPath[0]) {
70
+ case 'build':
71
+ case 'clean': {
72
+ if (!Array.isArray(right)) {
73
+ return left;
74
+ }
75
+ const s = new Set([...left, ...right]);
76
+ return [...s.values()];
77
+ }
78
+ default:
79
+ return right;
80
+ }
71
81
  },
72
82
  });
73
83
 
@@ -83,10 +93,26 @@ export function loadConfigFile(watchMode: boolean): IConfigFile {
83
93
 
84
94
  for (let item of input.build) {
85
95
  if (typeof item === 'string') {
86
- item = input.commands[item];
87
- if (!item) {
88
- logger.fatal`command "${item}" not found in commands`;
96
+ const found = input.commands[item];
97
+ if (!found) {
98
+ logger.fatal`command ${input.build.indexOf(item)} "${item}" not found in "commands" list<${Object.keys(input.commands)}>`;
99
+ }
100
+ item = found;
101
+ }
102
+
103
+ if (item.watch === false && watchMode) {
104
+ let debug_title = item.title;
105
+ if (!debug_title) {
106
+ if (Array.isArray(item.command)) {
107
+ debug_title = item.command[0];
108
+ } else if (typeof item.command === 'string') {
109
+ debug_title = item.command;
110
+ } else if (typeof item.command === 'object' && 'package' in item.command) {
111
+ debug_title = item.command.package;
112
+ }
89
113
  }
114
+ logger.log`command "${debug_title}" watch mode is disabled.`;
115
+ continue;
90
116
  }
91
117
 
92
118
  const cmd = item.command;
@@ -111,9 +137,7 @@ export function loadConfigFile(watchMode: boolean): IConfigFile {
111
137
  if (config.rigConfig.rigFound) {
112
138
  const nmPath = findUpUntilSync({ file: 'node_modules', from: config.rigConfig.getResolvedProfileFolder() });
113
139
  if (!nmPath) {
114
- throw new Error(
115
- `Failed to find "node_modules" folder in rig profile "${config.rigConfig.getResolvedProfileFolder()}".`,
116
- );
140
+ throw new Error(`Failed to find "node_modules" folder in rig profile "${config.rigConfig.getResolvedProfileFolder()}".`);
117
141
  }
118
142
  additionalPaths.push(resolve(nmPath, '.bin'));
119
143
  }
@@ -12,4 +12,3 @@ if (!self) {
12
12
  throw new Error('Could not find self directory');
13
13
  }
14
14
  export const selfRoot = dirname(self);
15
-