@akala/pm 5.2.6 → 5.2.8

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/src/akala.mts ADDED
@@ -0,0 +1,531 @@
1
+ import * as path from 'path'
2
+ import { Processors, NetSocketAdapter, Metadata, Container, ICommandProcessor, proxy, Triggers, Cli } from '@akala/commands';
3
+ import { Socket } from 'net';
4
+ import { TLSSocket } from 'tls';
5
+ import { platform, homedir } from 'os';
6
+ import start from './commands/start.js'
7
+ import { Readable } from 'stream';
8
+
9
+ import { spawnAsync } from './cli-helper.js';
10
+ import State, { StateConfiguration } from './state.js';
11
+ import program, { buildCliContextFromProcess, CliContext, ErrorMessage, NamespaceMiddleware, unparse } from '@akala/cli';
12
+ import { InteractError } from './index.js';
13
+ import { Binding } from '@akala/core';
14
+ import module from 'module'
15
+
16
+ const require = module.createRequire(import.meta.url);
17
+
18
+ const tableChars = {
19
+ 'top': '─'
20
+ , 'top-mid': '┬'
21
+ , 'top-left': '┌'
22
+ , 'top-right': '┐'
23
+ , 'bottom': '─'
24
+ , 'bottom-mid': '┴'
25
+ , 'bottom-left': '└'
26
+ , 'bottom-right': '┘'
27
+ , 'left': '│'
28
+ , 'left-mid': '├'
29
+ , 'mid': '─'
30
+ , 'mid-mid': '┼'
31
+ , 'right': '│'
32
+ , 'right-mid': '┤'
33
+ , 'middle': '│'
34
+ }
35
+ const truncate = '…';
36
+
37
+ type CliOptions = { output: string, verbose: boolean, pmSock: string | number, tls: boolean, help: boolean };
38
+ export default function (_config, program: NamespaceMiddleware)
39
+ {
40
+
41
+ const cli = program.command('pm').state<{ pm?: StateConfiguration }>().options<CliOptions>({ output: { aliases: ['o'], needsValue: true, doc: 'output as `table` if array otherwise falls back to standard node output' }, verbose: { aliases: ['v'] }, tls: { doc: "enables tls connection to the `pmSock`" }, pmSock: { aliases: ['pm-sock'], needsValue: true, doc: "path to the unix socket or destination in the form host:port" }, help: { doc: "displays this help message" } });
42
+ cli.command('start pm')
43
+ .option('inspect', { doc: "starts the process with --inspect-brk parameter to help debugging" })
44
+ .option('keepAttached', { doc: "keeps the process attached" })
45
+ .action(c =>
46
+ {
47
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
+ c.options['name'] = 'pm'
49
+ c.options['program'] = require.resolve('../../commands.json');
50
+ return start.call({} as unknown as State, null, 'pm', c as any);
51
+ });
52
+
53
+ let socket: Socket;
54
+ let processor: Processors.JsonRpc;
55
+ let metaContainer: Metadata.Container;
56
+ let container: Container<unknown>;
57
+ const handle = new NamespaceMiddleware(null);
58
+ cli.preAction(async c =>
59
+ {
60
+ process.stdin.pause();
61
+ process.stdin.setEncoding('utf8');
62
+ if (!socket)
63
+ {
64
+ const netsocket = socket = new Socket();
65
+ if (c.options.tls)
66
+ {
67
+ socket = new TLSSocket(socket, {});
68
+ }
69
+
70
+ await new Promise<void>((resolve, reject) =>
71
+ {
72
+ if (c.options.pmSock)
73
+ {
74
+ if (typeof (c.options.pmSock) == 'string')
75
+ {
76
+ const indexOfColon = c.options.pmSock.indexOf(':');
77
+ if (indexOfColon > -1)
78
+ netsocket.connect(Number(c.options.pmSock.substring(indexOfColon + 1)), c.options.pmSock.substring(0, indexOfColon));
79
+ else
80
+ netsocket.connect(c.options.pmSock);
81
+ }
82
+ else
83
+ netsocket.connect(c.options.pmSock as number);
84
+ }
85
+ else if (platform() == 'win32')
86
+ netsocket.connect('\\\\?\\pipe\\pm')
87
+ else
88
+ {
89
+ try
90
+ {
91
+ if (c.state?.pm)
92
+ netsocket.connect(c.state.pm.mapping.pm.connect.socket[0]);
93
+ else
94
+ netsocket.destroy(Object.assign(new Error(), { code: 'ENOENT' }))
95
+ }
96
+ catch (e)
97
+ {
98
+ if (e.code != 'MODULE_NOT_FOUND')
99
+ reject(e);
100
+ else
101
+ {
102
+ e.code = 'ENOENT';
103
+ socket.destroy(e);
104
+ }
105
+
106
+ }
107
+ }
108
+ if (c.options.tls)
109
+ {
110
+ // socket.on('data', function (e) { console.log(e) });
111
+ socket.connect({} as any);
112
+ netsocket.on('error', function (e)
113
+ {
114
+ console.log(e);
115
+ });
116
+ socket.on('error', function (e)
117
+ {
118
+ console.log(e);
119
+ });
120
+ }
121
+ socket.on('connect', async function ()
122
+ {
123
+ resolve();
124
+ socket.setEncoding('utf-8');
125
+ });
126
+ socket.on('error', async (e: Error & { code?: string }) =>
127
+ {
128
+ if (c.options.help)
129
+ resolve();
130
+ else
131
+ {
132
+ if (e.code === 'ENOENT')
133
+ {
134
+ // return tryLocalProcessing(c).catch(() =>
135
+ // {
136
+ resolve();
137
+ // reject(new Error('pm is not started'));
138
+ // });
139
+ }
140
+ else
141
+ reject(e);
142
+ }
143
+ });
144
+ });
145
+ }
146
+ if (socket.readyState == 'open')
147
+ {
148
+ if (!processor)
149
+ processor = new Processors.JsonRpc(Processors.JsonRpc.getConnection(new NetSocketAdapter(socket)));
150
+ if (!metaContainer)
151
+ metaContainer = require('../../commands.json');
152
+ if (!container)
153
+ {
154
+ container = proxy(metaContainer, processor);
155
+
156
+ container.unregister(Cli.Metadata.name);
157
+ container.register(Metadata.extractCommandMetadata(Cli.Metadata));
158
+
159
+ await container.attach(Triggers.cli, cli);
160
+ }
161
+ }
162
+ }).
163
+ // cli.
164
+ // useMiddleware(null, handle).
165
+ useError(async (err: InteractError, args) =>
166
+ {
167
+ if (err.code === 'INTERACT')
168
+ {
169
+ console.log(err.message);
170
+ const value = await readLine();
171
+ if (typeof err.as == 'string')
172
+ {
173
+ const indexOfDot = err.as.indexOf('.');
174
+ if (indexOfDot > 0)
175
+ {
176
+ Binding.getSetter(args.options, err.as)(value);
177
+ }
178
+ args.options[err.as] = value;
179
+ }
180
+ else
181
+ args.args.push(value);
182
+ return await cli.process(args);
183
+ }
184
+ throw err;
185
+ })
186
+
187
+ // handle.action(async args =>
188
+ // {
189
+ // try
190
+ // {
191
+ // const cmdName = args.args[0].toString();
192
+ // if (cmdName == '$metadata')
193
+ // return formatResult(metaContainer, args.options.output);
194
+ // else
195
+ // {
196
+ // const cmd = metaContainer.commands.find(c => c.name === cmdName);
197
+ // await tryRun(processor, cmd, args, false);
198
+ // }
199
+ // await new Promise<void>((resolve) => socket.end(resolve));
200
+ // }
201
+ // catch (e)
202
+ // {
203
+ // if (e.code == 'INTERACT')
204
+ // {
205
+ // console.log(e.message);
206
+ // const value = await readLine();
207
+ // if (e.as)
208
+ // args.options[e] = value;
209
+ // else
210
+ // args.args.push(value);
211
+ // return handle.handle(args).then(e => { if (e) throw e }, res => res);
212
+ // }
213
+ // if (args.options.verbose)
214
+ // console.log(e);
215
+ // else
216
+ // console.log(e.message)
217
+ // await new Promise<void>((resolve) => socket.end(resolve));
218
+ // }
219
+ // });
220
+ cli.format((result, context) =>
221
+ {
222
+ if (result instanceof Readable)
223
+ {
224
+ result.pipe(process.stdout);
225
+ return;
226
+ }
227
+ if (socket)
228
+ socket.end();
229
+
230
+ formatResult(result, context.options.output);
231
+ });
232
+ program.useError((err: Error, context) =>
233
+ {
234
+ if (context.options.verbose)
235
+ console.error(err);
236
+ else if (err instanceof ErrorMessage)
237
+ console.log(err.message)
238
+ else
239
+ console.error('Error: ' + err.message);
240
+ return Promise.resolve();
241
+ })
242
+ }
243
+
244
+ function formatResult(result: unknown, outputFormat: string)
245
+ {
246
+ if (typeof result == 'undefined')
247
+ return;
248
+ if (result instanceof Readable)
249
+ {
250
+ return result;
251
+ }
252
+ switch (outputFormat)
253
+ {
254
+ case 'table':
255
+ {
256
+ const columnNames: string[] = [];
257
+ const columns: { [key: string]: { maxWidthContent: number, maxWidth: number, values: string[] } } = {};
258
+ if (Array.isArray(result))
259
+ {
260
+ for (const r of result)
261
+ {
262
+ Object.keys(r).forEach(k =>
263
+ {
264
+ if (columnNames.indexOf(k) == -1)
265
+ columnNames.push(k);
266
+ })
267
+ }
268
+
269
+ columnNames.forEach(c =>
270
+ {
271
+ columns[c] = { maxWidthContent: 0, maxWidth: c.length + 2, values: [] };
272
+
273
+ for (const r of result)
274
+ {
275
+ if (typeof (r[c]) == 'undefined' || typeof r[c] == 'string' && r[c].length == 0)
276
+ columns[c].values.push('');
277
+ else if (r[c] == null)
278
+ {
279
+ columns[c].values.push('-');
280
+ columns[c].maxWidthContent = Math.max(columns[c].maxWidthContent, 1);
281
+ }
282
+ else
283
+ {
284
+ columns[c].values.push(r[c].toString());
285
+ columns[c].maxWidthContent = Math.max(columns[c].maxWidthContent, r[c].toString().length);
286
+ }
287
+ columns[c].maxWidth = Math.max(columns[c].maxWidthContent, columns[c].maxWidth);
288
+ }
289
+ });
290
+
291
+ let columnNamesForDisplay = columnNames.slice(0);
292
+ let width = columnNamesForDisplay.reduce((length, c, i) => columns[columnNames[i]].maxWidth + length, 0) + columnNamesForDisplay.length + 1
293
+ if (process.stdout.columns < width)
294
+ {
295
+ for (const c of columnNames)
296
+ {
297
+ if (columns[c].maxWidthContent == 0)
298
+ columnNamesForDisplay = columnNamesForDisplay.splice(columnNamesForDisplay.indexOf(c), 1)
299
+ }
300
+ width = columnNamesForDisplay.reduce((length, c, i) => columns[columnNames[i]].maxWidth + length, 0) + columnNamesForDisplay.length + 1
301
+ }
302
+ if (process.stdout.columns < width)
303
+ {
304
+ columnNamesForDisplay = columnNamesForDisplay.map(c =>
305
+ {
306
+ if (c.length > 8 + truncate.length)
307
+ {
308
+ const newName = c.substring(0, 8) + truncate;
309
+ columns[c].maxWidth = Math.max(columns[c].maxWidthContent, newName.length);
310
+ return newName;
311
+ }
312
+
313
+ return c;
314
+ })
315
+ width = columnNamesForDisplay.reduce((length, c, i) => columns[columnNames[i]].maxWidth + length, 0) + columnNamesForDisplay.length + 1
316
+ }
317
+ if (process.stdout.columns < width)
318
+ {
319
+ columnNamesForDisplay.forEach(c =>
320
+ {
321
+ columns[c].maxWidth = Math.max(columns[c].maxWidthContent, c.length);
322
+ })
323
+ width = columnNamesForDisplay.reduce((length, c, i) => columns[columnNames[i]].maxWidth + length, 0) + columnNamesForDisplay.length + 1
324
+ }
325
+ if (process.stdout.columns >= width)
326
+ {
327
+ process.stdout.write(tableChars["top-left"]);
328
+ columnNamesForDisplay.forEach((c, i) =>
329
+ {
330
+ for (let j = 0; j < columns[columnNames[i]].maxWidth; j++)
331
+ process.stdout.write(tableChars["top"]);
332
+
333
+ if (i == columnNames.length - 1)
334
+ process.stdout.write(tableChars["top-right"]);
335
+ else
336
+ process.stdout.write(tableChars["top-mid"]);
337
+ })
338
+
339
+ process.stdout.write('\n');
340
+ process.stdout.write(tableChars["left"]);
341
+
342
+ columnNamesForDisplay.forEach((c, i) =>
343
+ {
344
+ let pad: number;
345
+ for (pad = 0; pad < (columns[columnNames[i]].maxWidth - c.length) / 2; pad++)
346
+ process.stdout.write(' ');
347
+ process.stdout.write(c);
348
+ for (pad += c.length; pad < columns[columnNames[i]].maxWidth; pad++)
349
+ process.stdout.write(' ');
350
+
351
+ if (i == columnNames.length - 1)
352
+ process.stdout.write(tableChars["right"]);
353
+ else
354
+ process.stdout.write(tableChars["middle"]);
355
+ })
356
+ process.stdout.write('\n');
357
+
358
+ process.stdout.write(tableChars["left-mid"]);
359
+
360
+ columnNamesForDisplay.forEach((c, i) =>
361
+ {
362
+ for (let j = 0; j < columns[columnNames[i]].maxWidth; j++)
363
+ process.stdout.write(tableChars["mid"]);
364
+
365
+ if (i == columnNames.length - 1)
366
+ process.stdout.write(tableChars["right-mid"]);
367
+ else
368
+ process.stdout.write(tableChars["mid-mid"]);
369
+ })
370
+ process.stdout.write('\n');
371
+ for (let r = 0; r < result.length; r++)
372
+ {
373
+ process.stdout.write(tableChars["left"]);
374
+ columnNamesForDisplay.forEach((c, i) =>
375
+ {
376
+ const value = columns[columnNames[i]].values[r];
377
+ let pad: number;
378
+ for (pad = 0; pad < Math.floor((columns[columnNames[i]].maxWidth - value.length) / 2); pad++)
379
+ process.stdout.write(' ');
380
+ process.stdout.write(value);
381
+ for (pad += value.length; pad < columns[columnNames[i]].maxWidth; pad++)
382
+ process.stdout.write(' ');
383
+
384
+ if (i == columnNames.length - 1)
385
+ process.stdout.write(tableChars["right"]);
386
+ else
387
+ process.stdout.write(tableChars["middle"]);
388
+ })
389
+ process.stdout.write('\n');
390
+ }
391
+ process.stdout.write(tableChars["bottom-left"]);
392
+ columnNamesForDisplay.forEach((c, i) =>
393
+ {
394
+ for (let j = 0; j < columns[columnNames[i]].maxWidth; j++)
395
+ process.stdout.write(tableChars["bottom"]);
396
+
397
+ if (i == columnNames.length - 1)
398
+ process.stdout.write(tableChars["bottom-right"]);
399
+ else
400
+ process.stdout.write(tableChars["bottom-mid"]);
401
+ })
402
+ process.stdout.write('\n');
403
+ return;
404
+ }
405
+ }
406
+ }
407
+ // eslint-disable-next-line no-fallthrough
408
+ default:
409
+
410
+ console.log(result);
411
+ break;
412
+ }
413
+ }
414
+
415
+ function prepareParam(cmd: Metadata.Command, args: CliContext, standalone?: boolean)
416
+ {
417
+ if (!cmd)
418
+ return false;
419
+
420
+ if (!cmd.config || !cmd.config.cli || (standalone && !cmd.config.cli.standalone))
421
+ return false;
422
+
423
+ delete args.options.pmSock;
424
+ return {
425
+ options: args.options, param: args.args.slice(1), _trigger: 'cli', cwd: args.currentWorkingDirectory, context: args, get stdin()
426
+ {
427
+ return new Promise<string>((resolve) =>
428
+ {
429
+ const buffers = [];
430
+ process.stdin.on('data', data => buffers.push(data));
431
+ process.stdin.on('end', () => resolve(Buffer.concat(buffers).toString('utf8')));
432
+ })
433
+ }
434
+ };
435
+ }
436
+
437
+ async function tryRun(processor: ICommandProcessor, cmd: Metadata.Command, args: CliContext, localProcessing: boolean)
438
+ {
439
+ const params = prepareParam(cmd, args, localProcessing);
440
+ if (!params)
441
+ throw new Error('Either command does not exist or it is not standalone');
442
+
443
+ try
444
+ {
445
+ const result = await processor.handle(null, cmd, params).then(err => { throw err }, res => res);
446
+ if (result instanceof Readable)
447
+ result.pipe(process.stdout);
448
+ else
449
+ formatResult(result, args.options.output as string);
450
+ }
451
+
452
+ catch (e)
453
+ {
454
+ if (e.code == 'INTERACT')
455
+ {
456
+ console.log(e.message);
457
+ let value = await readLine();
458
+ value = value.trim();
459
+ if (e.as)
460
+ args.options[e] = value;
461
+ else
462
+ args.args.push(value);
463
+ args.args.unshift(cmd.name);
464
+ return await tryRun(processor, cmd, args, localProcessing);
465
+ }
466
+ if (args.options.verbose)
467
+ console.log(e);
468
+ else
469
+ console.log(e.message);
470
+ }
471
+
472
+ }
473
+
474
+ async function tryLocalProcessing(args: CliContext)
475
+ {
476
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
477
+ const config: StateConfiguration = require(path.join(homedir(), './.pm.config.json'));
478
+ let cmdName = args.args.shift();
479
+ if (!cmdName)
480
+ throw undefined;
481
+ const indexOfDot = cmdName.indexOf('.');
482
+ if (indexOfDot > -1)
483
+ {
484
+ const containerName = cmdName.substring(0, indexOfDot);
485
+ if (config.containers[containerName] && config.containers[containerName].commandable)
486
+ {
487
+ cmdName = cmdName.substring(indexOfDot + 1);
488
+ const container = new Container('cli-temp', {});
489
+ const options: Processors.DiscoveryOptions = {};
490
+ await Processors.FileSystem.discoverCommands(config.containers[containerName].path, container, options);
491
+ const cmd = container.resolve(cmdName);
492
+ return tryRun(options.processor, cmd, args, true);
493
+ }
494
+ }
495
+ else
496
+ {
497
+ if (!config.containers[cmdName].commandable)
498
+ return spawnAsync(config.containers[cmdName].path, null, ...unparse(args));
499
+ }
500
+ }
501
+
502
+ let stdinBuffer = '';
503
+ function readLine()
504
+ {
505
+ process.stdin.pause();
506
+ return new Promise<string>((resolve) =>
507
+ {
508
+
509
+ process.stdin.on('data', function processChunk(chunk)
510
+ {
511
+ const indexOfNewLine = stdinBuffer.length + chunk.indexOf('\n');
512
+ stdinBuffer += chunk;
513
+ if (indexOfNewLine > -1)
514
+ {
515
+ process.stdin.pause();
516
+ process.stdin.removeListener('data', processChunk);
517
+ if (indexOfNewLine < stdinBuffer.length - 1)
518
+ {
519
+ resolve(stdinBuffer.substr(0, indexOfNewLine));
520
+ stdinBuffer = stdinBuffer.substr(indexOfNewLine + 1);
521
+ }
522
+ else
523
+ {
524
+ resolve(stdinBuffer);
525
+ stdinBuffer = '';
526
+ }
527
+ }
528
+ })
529
+ process.stdin.resume();
530
+ })
531
+ }
@@ -9,6 +9,9 @@ import { ErrorWithStatus } from "@akala/core";
9
9
  import getRandomName from "./name.js";
10
10
  import { ProxyConfiguration } from "@akala/config";
11
11
  import { IpcAdapter } from "../ipc-adapter.js";
12
+ import module from 'module'
13
+
14
+ const require = module.createRequire(import.meta.url);
12
15
 
13
16
  export default async function start(this: State, pm: pmContainer.container & Container<State>, name: string, context?: CliContext<{ new?: boolean, name: string, keepAttached?: boolean, inspect?: boolean, verbose?: boolean, wait?: boolean }>): Promise<void | { execPath: string, args: string[], cwd: string, stdio: StdioOptions, shell: boolean, windowsHide: boolean }>
14
17
  {
package/tsconfig.json CHANGED
@@ -1,23 +1,3 @@
1
1
  {
2
- "extends": "../tsconfig.settings.json",
3
- "compileOnSave": true,
4
- "compilerOptions": {
5
- "rootDir": "src",
6
- "outDir": "dist",
7
- "module": "CommonJS"
8
- },
9
- "references": [
10
- {
11
- "path": "../core"
12
- },
13
- {
14
- "path": "../commands"
15
- },
16
- {
17
- "path": "../cli"
18
- },
19
- {
20
- "path": "../config"
21
- }
22
- ]
2
+ "extends": "./tsconfig.esm.json",
23
3
  }