@travetto/cli 8.0.0-alpha.7 → 8.0.0-alpha.9
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 +5 -5
- package/bin/trv.js +1 -0
- package/package.json +3 -3
- package/src/execute.ts +36 -18
- package/src/help.ts +1 -1
- package/src/registry/decorator.ts +23 -30
- package/src/registry/registry-adapter.ts +8 -1
- package/src/registry/registry-index.ts +6 -2
- package/src/types.ts +3 -3
- package/src/util.ts +14 -14
- package/support/cli.service.ts +4 -4
- package/support/entry.trv.ts +1 -1
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ This module also has a tight integration with the [VSCode plugin](https://market
|
|
|
59
59
|
At it's heart, a cli command is the contract defined by what flags, and what arguments the command supports. Within the framework this requires three criteria to be met:
|
|
60
60
|
* The file must be located in the `support/` folder, and have a name that matches `cli.*.ts`
|
|
61
61
|
* The file must be a class that has a main method
|
|
62
|
-
* The class must use the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#
|
|
62
|
+
* The class must use the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L20) decorator
|
|
63
63
|
|
|
64
64
|
**Code: Basic Command**
|
|
65
65
|
```typescript
|
|
@@ -94,7 +94,7 @@ Examples of mappings:
|
|
|
94
94
|
The pattern is that underscores(_) translate to colons (:), and the `cli.` prefix, and `.ts` suffix are dropped.
|
|
95
95
|
|
|
96
96
|
## Binding Flags
|
|
97
|
-
[@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#
|
|
97
|
+
[@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L20) is a wrapper for [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19), and so every class that uses the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L20) decorator is now a full [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19) class. The fields of the class represent the flags that are available to the command.
|
|
98
98
|
|
|
99
99
|
**Code: Basic Command with Flag**
|
|
100
100
|
```typescript
|
|
@@ -131,7 +131,7 @@ $ trv basic:flag --loud
|
|
|
131
131
|
HELLO
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#
|
|
134
|
+
The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L20) supports the following data types for flags:
|
|
135
135
|
* Boolean values
|
|
136
136
|
* Number values. The [@Integer](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L172), [@Float](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L179), [@Precision](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L165), [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L99) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L110) decorators help provide additional validation.
|
|
137
137
|
* String values. [@MinLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L99), [@MaxLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L110), [@Match](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L90) and [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L64) provide additional constraints
|
|
@@ -390,7 +390,7 @@ npx trv call:db --host localhost --port 3306 --username app --password <custom>
|
|
|
390
390
|
```
|
|
391
391
|
|
|
392
392
|
## VSCode Integration
|
|
393
|
-
By default, cli commands do not expose themselves to the VSCode extension, as the majority of them are not intended for that sort of operation. [Web API](https://github.com/travetto/travetto/tree/main/module/web#readme "Declarative support for creating Web Applications") does expose a cli target `web:http` that will show up, to help run/debug a web application. Any command can mark itself as being a run target, and will be eligible for running from within the [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=arcsine.travetto-plugin). This is achieved by setting the `runTarget` field on the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#
|
|
393
|
+
By default, cli commands do not expose themselves to the VSCode extension, as the majority of them are not intended for that sort of operation. [Web API](https://github.com/travetto/travetto/tree/main/module/web#readme "Declarative support for creating Web Applications") does expose a cli target `web:http` that will show up, to help run/debug a web application. Any command can mark itself as being a run target, and will be eligible for running from within the [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=arcsine.travetto-plugin). This is achieved by setting the `runTarget` field on the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L20) decorator. This means the target will be visible within the editor tooling.
|
|
394
394
|
|
|
395
395
|
**Code: Simple Run Target**
|
|
396
396
|
```typescript
|
|
@@ -460,7 +460,7 @@ export class WebHttpCommand implements CliCommandShape {
|
|
|
460
460
|
profile: string[];
|
|
461
461
|
|
|
462
462
|
@CliRestartOnChangeFlag()
|
|
463
|
-
restartOnChange: boolean =
|
|
463
|
+
restartOnChange: boolean = Runtime.localDevelopment;
|
|
464
464
|
|
|
465
465
|
@CliDebugIpcFlag()
|
|
466
466
|
debugIpc?: boolean;
|
package/bin/trv.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @ts-check
|
|
3
|
+
import '@travetto/runtime/support/patch.js';
|
|
3
4
|
import '@travetto/compiler/bin/hook.js';
|
|
4
5
|
const { invoke } = await import('@travetto/compiler/support/invoke.ts');
|
|
5
6
|
await invoke('exec', ['@travetto/cli/support/entry.trv.ts', ...process.argv.slice(2)]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/cli",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI infrastructure for Travetto framework",
|
|
6
6
|
"keywords": [
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"directory": "module/cli"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@travetto/schema": "^8.0.0-alpha.
|
|
33
|
-
"@travetto/terminal": "^8.0.0-alpha.
|
|
32
|
+
"@travetto/schema": "^8.0.0-alpha.5",
|
|
33
|
+
"@travetto/terminal": "^8.0.0-alpha.5"
|
|
34
34
|
},
|
|
35
35
|
"travetto": {
|
|
36
36
|
"displayName": "Command Line Interface",
|
package/src/execute.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConsoleManager, Runtime, ShutdownManager, Util } from '@travetto/runtime';
|
|
1
|
+
import { ConsoleManager, getClass, Runtime, ShutdownManager, Util } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
import { HelpUtil } from './help.ts';
|
|
4
4
|
import { CliCommandRegistryIndex } from './registry/registry-index.ts';
|
|
@@ -11,20 +11,32 @@ import type { CliCommandShape } from './types.ts';
|
|
|
11
11
|
*/
|
|
12
12
|
export class ExecutionManager {
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
/** Command Execution */
|
|
15
|
+
static async execute(instance: CliCommandShape, args: unknown[]): Promise<void> {
|
|
16
|
+
const config = CliCommandRegistryIndex.get(getClass(instance));
|
|
17
|
+
|
|
18
|
+
for (const item of config.preMain) {
|
|
19
|
+
await item.handler(instance);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Wait 50ms to allow stdout to flush on shutdown
|
|
23
|
+
ShutdownManager.signal.addEventListener('abort', () => Util.blockingTimeout(50));
|
|
24
|
+
ConsoleManager.debug(Runtime.debug);
|
|
25
|
+
await instance.main(...args);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Extract configuration and show help as needed */
|
|
29
|
+
static async getExecutionCommand(argv: string[]): Promise<(() => Promise<void>) | undefined> {
|
|
19
30
|
let command: CliCommandShape | undefined;
|
|
20
31
|
|
|
21
32
|
const { cmd, args, help } = CliParseUtil.getArgs(argv);
|
|
22
33
|
if (!cmd) {
|
|
23
|
-
|
|
34
|
+
console.info!(await HelpUtil.renderAllHelp());
|
|
35
|
+
return;
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
try {
|
|
27
|
-
const [{ instance, schema
|
|
39
|
+
const [{ instance, schema }] = await CliCommandRegistryIndex.load([cmd]);
|
|
28
40
|
command = instance;
|
|
29
41
|
const fullArgs = await CliParseUtil.expandArgs(schema, args);
|
|
30
42
|
|
|
@@ -35,22 +47,28 @@ export class ExecutionManager {
|
|
|
35
47
|
await instance.finalize?.(help);
|
|
36
48
|
|
|
37
49
|
if (help) {
|
|
38
|
-
|
|
50
|
+
console.log!(await HelpUtil.renderCommandHelp(instance));
|
|
51
|
+
return;
|
|
39
52
|
}
|
|
40
53
|
|
|
41
54
|
await CliCommandSchemaUtil.validate(command, boundArgs);
|
|
42
55
|
|
|
43
|
-
|
|
44
|
-
ShutdownManager.signal.addEventListener('abort', () => Util.blockingTimeout(50));
|
|
45
|
-
|
|
46
|
-
for (const preMain of config.preMain ?? []) {
|
|
47
|
-
await preMain(instance);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
ConsoleManager.debug(Runtime.debug);
|
|
51
|
-
await instance.main(...boundArgs);
|
|
56
|
+
return this.execute.bind(this, instance, boundArgs);
|
|
52
57
|
} catch (error) {
|
|
53
58
|
await HelpUtil.renderError(error, cmd, command);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Execute the command line
|
|
64
|
+
* @param args
|
|
65
|
+
*/
|
|
66
|
+
static async run(argv: string[]): Promise<void> {
|
|
67
|
+
try {
|
|
68
|
+
const execute = await this.getExecutionCommand(argv);
|
|
69
|
+
await execute?.();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error!(error);
|
|
54
72
|
} finally {
|
|
55
73
|
await ShutdownManager.shutdown();
|
|
56
74
|
}
|
package/src/help.ts
CHANGED
|
@@ -175,7 +175,7 @@ ${{ identifier: install }}
|
|
|
175
175
|
process.exitCode ??= 1;
|
|
176
176
|
if (error instanceof ValidationResultError) {
|
|
177
177
|
console.error!(this.renderValidationError(error));
|
|
178
|
-
} else if (Error
|
|
178
|
+
} else if (error instanceof Error) {
|
|
179
179
|
console.error!(cliTpl`${{ failure: error.stack }}\n`);
|
|
180
180
|
}
|
|
181
181
|
if (command) {
|
|
@@ -10,13 +10,6 @@ import { CliUtil } from '../util.ts';
|
|
|
10
10
|
type CliCommandConfigOptions = { runTarget?: boolean };
|
|
11
11
|
type CliFlagOptions = { full?: string, short?: string, envVars?: string[] };
|
|
12
12
|
|
|
13
|
-
function runBeforeMain<T>(cls: Class, handler: (item: T) => (unknown | Promise<unknown>), runTarget?: boolean): void {
|
|
14
|
-
CliCommandRegistryIndex.getForRegister(cls).register({
|
|
15
|
-
runTarget,
|
|
16
|
-
preMain: [async (cmd): Promise<void> => { await handler(castTo(cmd)); }]
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
13
|
/**
|
|
21
14
|
* Decorator to register a CLI command
|
|
22
15
|
*
|
|
@@ -72,9 +65,7 @@ export function CliProfilesFlag(config: CliFlagOptions = {}) {
|
|
|
72
65
|
description: 'Application profiles'
|
|
73
66
|
});
|
|
74
67
|
|
|
75
|
-
|
|
76
|
-
Env.TRV_PROFILES.set([...cmd[property] ?? [], ...(Env.TRV_PROFILES.list ?? [])])
|
|
77
|
-
);
|
|
68
|
+
CliCommandRegistryIndex.registerPreMain<typeof instance>(cls, 1, cmd => Env.TRV_PROFILES.add(...cmd[property] ?? []));
|
|
78
69
|
};
|
|
79
70
|
};
|
|
80
71
|
|
|
@@ -103,12 +94,8 @@ export function CliModuleFlag(config: CliFlagOptions & { scope?: 'current' | 'co
|
|
|
103
94
|
const runModule = (config.scope === 'command' ? commandModule : providedModule) || Runtime.main.name;
|
|
104
95
|
|
|
105
96
|
// If we need to run as a specific module
|
|
106
|
-
if (runModule !== Runtime.main.name) {
|
|
107
|
-
|
|
108
|
-
RuntimeIndex.reinitForModule(runModule);
|
|
109
|
-
} catch {
|
|
110
|
-
return { source: 'flag', message: `${runModule} is an unknown module`, kind: 'custom', path: property };
|
|
111
|
-
}
|
|
97
|
+
if (runModule !== Runtime.main.name && RuntimeIndex.getModule(runModule) === undefined) {
|
|
98
|
+
return { source: 'flag', message: `${runModule} is an unknown module`, kind: 'custom', path: property };
|
|
112
99
|
}
|
|
113
100
|
|
|
114
101
|
if (!(await CliModuleUtil.moduleHasDependency(runModule, commandModule))) {
|
|
@@ -116,6 +103,15 @@ export function CliModuleFlag(config: CliFlagOptions & { scope?: 'current' | 'co
|
|
|
116
103
|
}
|
|
117
104
|
}],
|
|
118
105
|
});
|
|
106
|
+
|
|
107
|
+
CliCommandRegistryIndex.registerPreMain<typeof instance>(cls, 5, cmd => {
|
|
108
|
+
const typed: (typeof cmd) & { [property]?: string } = castTo(cmd);
|
|
109
|
+
const providedModule = typed[property];
|
|
110
|
+
const runModule = (config.scope === 'command' ? commandModule : providedModule) || Runtime.main.name;
|
|
111
|
+
if (runModule !== Runtime.main.name) {
|
|
112
|
+
RuntimeIndex.reinitForModule(runModule);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
119
115
|
};
|
|
120
116
|
}
|
|
121
117
|
|
|
@@ -127,17 +123,15 @@ export function CliModuleFlag(config: CliFlagOptions & { scope?: 'current' | 'co
|
|
|
127
123
|
export function CliRestartOnChangeFlag(config: CliFlagOptions = {}) {
|
|
128
124
|
return function <K extends string, T extends Partial<Record<K, boolean>>>(instance: T, property: K): void {
|
|
129
125
|
const cls = getClass(instance);
|
|
126
|
+
if (Runtime.production) { return; }
|
|
127
|
+
|
|
130
128
|
SchemaRegistryIndex.getForRegister(cls).registerField(property, {
|
|
131
129
|
...CliParseUtil.buildAliases(config),
|
|
132
130
|
description: 'Should the invocation automatically restart on source changes'
|
|
133
131
|
});
|
|
134
132
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (Runtime.production) { return; }
|
|
138
|
-
return CliUtil.runWithRestartOnChange(cmd[property]);
|
|
139
|
-
}, true
|
|
140
|
-
);
|
|
133
|
+
CliCommandRegistryIndex.getForRegister(cls).register({ runTarget: true });
|
|
134
|
+
CliCommandRegistryIndex.registerPreMain<typeof instance>(cls, 20, cmd => CliUtil.runWithRestartOnChange(cmd[property]));
|
|
141
135
|
};
|
|
142
136
|
}
|
|
143
137
|
|
|
@@ -148,19 +142,18 @@ export function CliRestartOnChangeFlag(config: CliFlagOptions = {}) {
|
|
|
148
142
|
*/
|
|
149
143
|
export function CliDebugIpcFlag(config: CliFlagOptions = {}) {
|
|
150
144
|
return function <K extends string, T extends Partial<Record<K, boolean>>>(instance: T, property: K): void {
|
|
145
|
+
if (Runtime.production) { return; }
|
|
146
|
+
|
|
151
147
|
const cls = getClass(instance);
|
|
152
148
|
SchemaRegistryIndex.getForRegister(cls).registerField(property, {
|
|
153
149
|
...CliParseUtil.buildAliases(config, Env.TRV_DEBUG_IPC.key),
|
|
154
150
|
description: 'Should the invocation automatically restart on source changes'
|
|
155
151
|
});
|
|
156
152
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
},
|
|
163
|
-
true
|
|
164
|
-
);
|
|
153
|
+
CliCommandRegistryIndex.getForRegister(cls).register({ runTarget: true });
|
|
154
|
+
CliCommandRegistryIndex.registerPreMain<typeof instance>(cls, 10, cmd => {
|
|
155
|
+
const cliConfig = CliCommandRegistryIndex.get(cls);
|
|
156
|
+
return cmd[property] && CliUtil.runWithDebugIpc(cliConfig.name);
|
|
157
|
+
});
|
|
165
158
|
};
|
|
166
159
|
}
|
|
@@ -29,7 +29,7 @@ export class CliCommandRegistryAdapter implements RegistryAdapter<CliCommandConf
|
|
|
29
29
|
this.#cls = cls;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
finalize(): void {
|
|
32
|
+
finalize(parent?: CliCommandConfig): void {
|
|
33
33
|
// Add help command
|
|
34
34
|
const schema = SchemaRegistryIndex.getConfig(this.#cls);
|
|
35
35
|
|
|
@@ -75,6 +75,13 @@ export class CliCommandRegistryAdapter implements RegistryAdapter<CliCommandConf
|
|
|
75
75
|
aliases.push(`--no-${long}`);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
|
|
79
|
+
if (parent) {
|
|
80
|
+
this.#config.preMain = [...this.#config.preMain, ...parent?.preMain ?? []];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Sort
|
|
84
|
+
this.#config.preMain = this.#config.preMain.toSorted((left, right) => left.priority - right.priority);
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
get(): CliCommandConfig {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type Class, getClass, getParentClass, isClass, Runtime, RuntimeIndex } from '@travetto/runtime';
|
|
1
|
+
import { type Any, type Class, getClass, getParentClass, isClass, Runtime, RuntimeIndex } from '@travetto/runtime';
|
|
2
2
|
import { type RegistryAdapter, type RegistryIndex, RegistryIndexStore, Registry } from '@travetto/registry';
|
|
3
3
|
import { type SchemaClassConfig, SchemaRegistryIndex } from '@travetto/schema';
|
|
4
4
|
|
|
5
|
-
import type { CliCommandConfig, CliCommandShape } from '../types.ts';
|
|
5
|
+
import type { CliCommandConfig, CliCommandShape, PreMainHandler } from '../types.ts';
|
|
6
6
|
import { CliCommandRegistryAdapter } from './registry-adapter.ts';
|
|
7
7
|
|
|
8
8
|
const CLI_FILE_REGEX = /\/cli[.](?<name>.{0,100}?)([.]tsx?)?$/;
|
|
@@ -28,6 +28,10 @@ export class CliCommandRegistryIndex implements RegistryIndex {
|
|
|
28
28
|
return this.#instance.load(names);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
static registerPreMain<T = Any>(cls: Class, priority: number, handler: PreMainHandler<T>['handler']): void {
|
|
32
|
+
CliCommandRegistryIndex.getForRegister(cls).register({ preMain: [{ handler, priority }] });
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
#fileMapping: Map<string, string>;
|
|
32
36
|
#instanceMapping: Map<string, CliCommandShape> = new Map();
|
|
33
37
|
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Class } from '@travetto/runtime';
|
|
1
|
+
import type { Any, Class } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
type OrProm<T> = T | Promise<T>;
|
|
4
4
|
type ParsedFlag = { type: 'flag', input: string, array?: boolean, fieldName: string, value?: unknown };
|
|
@@ -32,7 +32,7 @@ export interface CliCommandShape {
|
|
|
32
32
|
help?(): OrProm<string[]>;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
type PreMainHandler = (cmd:
|
|
35
|
+
export type PreMainHandler<T extends Any = Any> = { priority: number, handler: (cmd: T) => Any };
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* CLI Command schema shape
|
|
@@ -41,5 +41,5 @@ export interface CliCommandConfig {
|
|
|
41
41
|
cls: Class<CliCommandShape>;
|
|
42
42
|
name: string;
|
|
43
43
|
runTarget?: boolean;
|
|
44
|
-
preMain
|
|
44
|
+
preMain: PreMainHandler[];
|
|
45
45
|
}
|
package/src/util.ts
CHANGED
|
@@ -2,11 +2,12 @@ import { spawn, type ChildProcess } from 'node:child_process';
|
|
|
2
2
|
|
|
3
3
|
import { RuntimeError, JSONUtil, Env, ExecUtil, Runtime, ShutdownManager, Util, WatchUtil } from '@travetto/runtime';
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const IPC_INVALID_ENV = new Set([
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
)
|
|
5
|
+
const IPC_VALID_ENV = new Set(['NODE_OPTIONS', 'PATH', Env.DEBUG.key, Env.NODE_ENV.key]);
|
|
6
|
+
const IPC_INVALID_ENV = new Set([
|
|
7
|
+
Env.TRV_CLI_IPC, Env.TRV_DEBUG_IPC, Env.TRV_DEBUG_BREAK, Env.TRV_MANIFEST, Env.TRV_MODULE, Env.TRV_RESTART_TARGET
|
|
8
|
+
].map(item => item.key));
|
|
9
|
+
const validEnv = ([key]: [key: string, value: unknown]): boolean =>
|
|
10
|
+
IPC_VALID_ENV.has(key) || (key.startsWith('TRV_') && !IPC_INVALID_ENV.has(key));
|
|
10
11
|
|
|
11
12
|
export class CliUtil {
|
|
12
13
|
/**
|
|
@@ -14,8 +15,7 @@ export class CliUtil {
|
|
|
14
15
|
*/
|
|
15
16
|
static getSimpleModuleName(placeholder: string, module?: string): string {
|
|
16
17
|
const simple = (module ?? Runtime.main.name).replace(/[\/]/, '_').replace(/@/, '');
|
|
17
|
-
|
|
18
|
-
return placeholder.replace('<module>', targetModule);
|
|
18
|
+
return simple ? placeholder.replace('<module>', simple) : placeholder;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -37,7 +37,7 @@ export class CliUtil {
|
|
|
37
37
|
|
|
38
38
|
process
|
|
39
39
|
.on('SIGINT', () => ShutdownManager.shutdownChild(child!, { mode: 'exit' }))
|
|
40
|
-
.on('message',
|
|
40
|
+
.on('message', message => child?.send?.(message!));
|
|
41
41
|
|
|
42
42
|
const env = { ...process.env, ...Env.TRV_RESTART_TARGET.export(true) };
|
|
43
43
|
|
|
@@ -78,32 +78,32 @@ export class CliUtil {
|
|
|
78
78
|
return; // Server not running, run normal
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const env: Record<string, string> = {};
|
|
82
81
|
const request = {
|
|
83
82
|
type: '@travetto/cli:run',
|
|
84
83
|
data: {
|
|
85
84
|
name,
|
|
86
|
-
env,
|
|
85
|
+
env: Object.fromEntries(Object.entries(process.env).filter(validEnv)),
|
|
87
86
|
cwd: process.cwd(),
|
|
88
87
|
args: process.argv.slice(3),
|
|
89
88
|
}
|
|
90
89
|
};
|
|
91
|
-
console.log('Triggering IPC request', request);
|
|
92
90
|
|
|
93
|
-
|
|
91
|
+
console.log('Triggering IPC request', request);
|
|
94
92
|
const sent = await doFetch({ method: 'POST', body: JSONUtil.toUTF8(request) });
|
|
95
93
|
|
|
96
94
|
if (!sent.ok) {
|
|
97
95
|
throw new RuntimeError(`IPC Request failed: ${sent.status} ${await sent.text()}`);
|
|
98
96
|
}
|
|
97
|
+
|
|
98
|
+
await ShutdownManager.shutdown({ mode: 'exit' });
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* Write data to channel and ensure its flushed before continuing
|
|
103
103
|
*/
|
|
104
104
|
static async writeAndEnsureComplete(data: unknown, channel: 'stdout' | 'stderr' = 'stdout'): Promise<void> {
|
|
105
|
-
|
|
106
|
-
JSONUtil.toUTF8Pretty(data),
|
|
105
|
+
await new Promise<unknown>(resolve => process[channel].write(typeof data === 'string' ? data :
|
|
106
|
+
JSONUtil.toUTF8Pretty(data), resolve));
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
/**
|
package/support/cli.service.ts
CHANGED
|
@@ -45,15 +45,15 @@ export class CliServiceCommand implements CliCommandShape {
|
|
|
45
45
|
const jobs = all.map(async (descriptor, i) => {
|
|
46
46
|
const identifier = descriptor.name.padEnd(maxName);
|
|
47
47
|
const type = `${descriptor.version}`.padStart(maxVersion - 3).padEnd(maxVersion);
|
|
48
|
-
let
|
|
48
|
+
let message: string;
|
|
49
49
|
for await (const [valueType, value] of new ServiceRunner(descriptor).action(action)) {
|
|
50
50
|
const details = { [valueType === 'message' ? 'subtitle' : valueType]: value };
|
|
51
|
-
queue.add({ idx: i, text:
|
|
51
|
+
queue.add({ idx: i, text: message = cliTpl`${{ identifier }} ${{ type }} ${details}` });
|
|
52
52
|
if (valueType === 'failure') {
|
|
53
|
-
failureMessages.push(
|
|
53
|
+
failureMessages.push(message);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
queue.add({ idx: i, done: true, text:
|
|
56
|
+
queue.add({ idx: i, done: true, text: message! });
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
Promise.all(jobs).then(() => Util.queueMacroTask()).then(() => queue.close());
|
package/support/entry.trv.ts
CHANGED