@flowscripter/dynamic-cli-framework 7.0.11 → 7.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.
- package/dist/src/cli/BaseCLI.d.ts.map +1 -1
- package/dist/src/cli/BaseCLI.js +7 -1
- package/dist/src/cli/BaseCLIFeatureOptions.d.ts +5 -0
- package/dist/src/cli/BaseCLIFeatureOptions.d.ts.map +1 -1
- package/dist/src/cli/DefaultRuntimeCLI.js +1 -1
- package/dist/src/runtime/runner.d.ts +10 -1
- package/dist/src/runtime/runner.d.ts.map +1 -1
- package/dist/src/runtime/runner.js +7 -1
- package/dist/src/service/configuration/DefaultKeyValueService.d.ts +9 -1
- package/dist/src/service/configuration/DefaultKeyValueService.d.ts.map +1 -1
- package/dist/src/service/configuration/DefaultKeyValueService.js +16 -1
- package/dist/src/service/configuration/KeyValueServiceProvider.d.ts.map +1 -1
- package/dist/src/service/configuration/KeyValueServiceProvider.js +13 -6
- package/dist/src/service/shutdown/ShutdownServiceProvider.js +3 -3
- package/dist/src/service/spawn/DefaultSpawnService.d.ts.map +1 -1
- package/dist/src/service/spawn/DefaultSpawnService.js +1 -0
- package/dist/src/service/upgrade/DefaultUpgradeService.d.ts +30 -2
- package/dist/src/service/upgrade/DefaultUpgradeService.d.ts.map +1 -1
- package/dist/src/service/upgrade/DefaultUpgradeService.js +99 -6
- package/dist/src/service/upgrade/UpgradeServiceProvider.d.ts +19 -4
- package/dist/src/service/upgrade/UpgradeServiceProvider.d.ts.map +1 -1
- package/dist/src/service/upgrade/UpgradeServiceProvider.js +51 -12
- package/dist/src/startup/banner/bannerStartupTask.d.ts.map +1 -1
- package/dist/src/startup/banner/bannerStartupTask.js +9 -5
- package/package.json +2 -2
- package/src/cli/BaseCLI.ts +7 -0
- package/src/cli/BaseCLIFeatureOptions.ts +5 -0
- package/src/cli/DefaultRuntimeCLI.ts +1 -1
- package/src/runtime/runner.ts +17 -2
- package/src/service/configuration/DefaultKeyValueService.ts +22 -1
- package/src/service/configuration/KeyValueServiceProvider.ts +18 -6
- package/src/service/shutdown/ShutdownServiceProvider.ts +3 -3
- package/src/service/spawn/DefaultSpawnService.ts +1 -0
- package/src/service/upgrade/DefaultUpgradeService.ts +112 -5
- package/src/service/upgrade/UpgradeServiceProvider.ts +77 -19
- package/src/service/upgrade/command/UpgradeSubCommand.ts +2 -2
- package/src/startup/banner/bannerStartupTask.ts +11 -5
|
@@ -16,7 +16,7 @@ import DefaultUpgradeService from "./DefaultUpgradeService.ts";
|
|
|
16
16
|
import { UpgradeSubCommand } from "./command/UpgradeSubCommand.ts";
|
|
17
17
|
import type { UpgradeLocationsConfig } from "./UpgradeLocationsConfig.ts";
|
|
18
18
|
import getLogger from "../../util/logger.ts";
|
|
19
|
-
import type { StartupTask } from "@flowscripter/dynamic-cli-framework-api";
|
|
19
|
+
import type { StartupTask, StartupTaskOutcome } from "@flowscripter/dynamic-cli-framework-api";
|
|
20
20
|
|
|
21
21
|
const logger = getLogger("UpgradeServiceProvider");
|
|
22
22
|
|
|
@@ -42,7 +42,7 @@ export function createUpgradeCheckStartupTask(
|
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Build the blocking {@link StartupTask} which offers to enable automatic upgrades and, when they
|
|
45
|
-
* are enabled, checks for and installs a newer version (see
|
|
45
|
+
* are enabled, checks for and installs a newer version, optionally restarting into it (see
|
|
46
46
|
* {@link UpgradeServiceProvider.runAutoUpgrade}). It is registered separately from the provider's
|
|
47
47
|
* own init task so it can run at a lower priority, after consumer startup tasks such as the banner.
|
|
48
48
|
*/
|
|
@@ -65,10 +65,31 @@ export default class UpgradeServiceProvider implements ServiceProvider {
|
|
|
65
65
|
#upgradeService: DefaultUpgradeService | undefined;
|
|
66
66
|
#cliConfig: CLIConfig | undefined;
|
|
67
67
|
#keyValueService: KeyValueService | undefined;
|
|
68
|
+
readonly #restartAfterAutoUpgrade: boolean;
|
|
69
|
+
#restartArgs: ReadonlyArray<string> = [];
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
/**
|
|
72
|
+
* @param servicePriority the priority of the service.
|
|
73
|
+
* @param config the upgrade locations.
|
|
74
|
+
* @param restartAfterAutoUpgrade whether to run the upgraded executable, with the arguments from
|
|
75
|
+
* {@link setRestartArgs}, after a successful automatic upgrade and end the run with its result.
|
|
76
|
+
*/
|
|
77
|
+
public constructor(
|
|
78
|
+
servicePriority: number,
|
|
79
|
+
config: UpgradeLocationsConfig,
|
|
80
|
+
restartAfterAutoUpgrade = false,
|
|
81
|
+
) {
|
|
70
82
|
this.servicePriority = servicePriority;
|
|
71
83
|
this.#config = config;
|
|
84
|
+
this.#restartAfterAutoUpgrade = restartAfterAutoUpgrade;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Set the CLI arguments to run the upgraded executable with when restarting after an automatic
|
|
89
|
+
* upgrade. These are kept internal to the framework and never exposed to startup tasks.
|
|
90
|
+
*/
|
|
91
|
+
public setRestartArgs(args: ReadonlyArray<string>): void {
|
|
92
|
+
this.#restartArgs = args;
|
|
72
93
|
}
|
|
73
94
|
|
|
74
95
|
public get upgradeService(): DefaultUpgradeService | undefined {
|
|
@@ -113,13 +134,25 @@ export default class UpgradeServiceProvider implements ServiceProvider {
|
|
|
113
134
|
* service's scope) and, when they are enabled, check for and install a newer version. Must be
|
|
114
135
|
* called after {@link initService}.
|
|
115
136
|
*
|
|
137
|
+
* After a successful upgrade, when restarting is enabled, the upgraded executable is run with the
|
|
138
|
+
* arguments from {@link setRestartArgs} and its result is returned as an `exitRequest`. Does
|
|
139
|
+
* nothing in a process which was itself started by such a restart.
|
|
140
|
+
*
|
|
116
141
|
* @param context the startup task's context, used to look up the Prompter and Printer services.
|
|
117
142
|
*/
|
|
118
|
-
public async runAutoUpgrade(context: Context): Promise<void> {
|
|
143
|
+
public async runAutoUpgrade(context: Context): Promise<void | StartupTaskOutcome> {
|
|
119
144
|
const upgradeService = this.#upgradeService!;
|
|
120
145
|
const cliConfig = this.#cliConfig!;
|
|
121
146
|
const keyValueService = this.#keyValueService;
|
|
122
147
|
|
|
148
|
+
if (upgradeService.restartedFromVersion !== undefined) {
|
|
149
|
+
logger.debug(
|
|
150
|
+
() =>
|
|
151
|
+
`Restarted from version ${upgradeService.restartedFromVersion}, skipping auto-upgrade`,
|
|
152
|
+
);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
123
156
|
if (!context.doesServiceExist(PROMPTER_SERVICE_ID)) {
|
|
124
157
|
logger.debug(() => "PrompterService not available, skipping auto-upgrade");
|
|
125
158
|
return;
|
|
@@ -136,8 +169,7 @@ export default class UpgradeServiceProvider implements ServiceProvider {
|
|
|
136
169
|
return;
|
|
137
170
|
}
|
|
138
171
|
if (status === "enabled") {
|
|
139
|
-
|
|
140
|
-
return;
|
|
172
|
+
return this.#checkAndUpgrade(context, upgradeService, cliConfig, keyValueService);
|
|
141
173
|
}
|
|
142
174
|
}
|
|
143
175
|
|
|
@@ -183,14 +215,15 @@ export default class UpgradeServiceProvider implements ServiceProvider {
|
|
|
183
215
|
}
|
|
184
216
|
|
|
185
217
|
await keyValueService.set("upgrade-status", "enabled");
|
|
186
|
-
|
|
218
|
+
return this.#checkAndUpgrade(context, upgradeService, cliConfig, keyValueService);
|
|
187
219
|
}
|
|
188
220
|
|
|
189
221
|
async #checkAndUpgrade(
|
|
190
222
|
context: Context,
|
|
191
223
|
upgradeService: DefaultUpgradeService,
|
|
192
224
|
cliConfig: CLIConfig,
|
|
193
|
-
|
|
225
|
+
keyValueService: KeyValueService,
|
|
226
|
+
): Promise<void | StartupTaskOutcome> {
|
|
194
227
|
try {
|
|
195
228
|
const checkResult = await upgradeService.getUpgradeCheckResult();
|
|
196
229
|
if (checkResult.status === "failed") {
|
|
@@ -201,21 +234,46 @@ export default class UpgradeServiceProvider implements ServiceProvider {
|
|
|
201
234
|
return;
|
|
202
235
|
}
|
|
203
236
|
const upgradeResult = await upgradeService.upgrade();
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
await printerService.info(
|
|
210
|
-
`${cliConfig.name} upgraded (${upgradeResult.oldVersion} -> ${upgradeResult.newVersion})\n`,
|
|
211
|
-
Icon.SUCCESS,
|
|
212
|
-
);
|
|
213
|
-
} else {
|
|
214
|
-
await printerService.error(
|
|
237
|
+
const printerService = context.doesServiceExist(PRINTER_SERVICE_ID)
|
|
238
|
+
? (context.getServiceById(PRINTER_SERVICE_ID) as PrinterService)
|
|
239
|
+
: undefined;
|
|
240
|
+
if (!upgradeResult.ok) {
|
|
241
|
+
await printerService?.error(
|
|
215
242
|
`Auto-upgrade failed: ${upgradeResult.error?.message ?? "unknown error"}\n`,
|
|
216
243
|
Icon.FAILURE,
|
|
217
244
|
);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
await printerService?.info(
|
|
248
|
+
`${cliConfig.name} upgraded (${upgradeResult.oldVersion} -> ${upgradeResult.newVersion})\n`,
|
|
249
|
+
Icon.SUCCESS,
|
|
250
|
+
);
|
|
251
|
+
if (!this.#restartAfterAutoUpgrade) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const executable = upgradeService.resolveUpgradedExecutable(checkResult.installMethod);
|
|
256
|
+
if (executable === undefined) {
|
|
257
|
+
await printerService?.info(
|
|
258
|
+
`Restart ${cliConfig.name} to use ${upgradeResult.newVersion}\n`,
|
|
259
|
+
Icon.INFORMATION,
|
|
260
|
+
);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// the cache write from the background upgrade check lands before the flush, so the shutdown
|
|
265
|
+
// flush has nothing left to write over the restarted process's configuration
|
|
266
|
+
await upgradeService.refreshUpgradeCheckCache();
|
|
267
|
+
// written now so the restarted process sees the stored upgrade-status
|
|
268
|
+
await keyValueService.flush();
|
|
269
|
+
const runState = await upgradeService.restart(executable, this.#restartArgs);
|
|
270
|
+
if (runState !== undefined) {
|
|
271
|
+
return { exitRequest: { runState } };
|
|
218
272
|
}
|
|
273
|
+
await printerService?.warn(
|
|
274
|
+
`${cliConfig.name} upgraded to ${upgradeResult.newVersion}; restart it to use the new version\n`,
|
|
275
|
+
Icon.ALERT,
|
|
276
|
+
);
|
|
219
277
|
} catch (error) {
|
|
220
278
|
logger.debug(() => `Auto-upgrade check failed: ${error}`);
|
|
221
279
|
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
UPGRADE_SERVICE_ID,
|
|
12
12
|
} from "@flowscripter/dynamic-cli-framework-api";
|
|
13
13
|
import type { PrinterService } from "@flowscripter/dynamic-cli-framework-api";
|
|
14
|
-
import type
|
|
14
|
+
import type { UpgradeService } from "@flowscripter/dynamic-cli-framework-api";
|
|
15
15
|
|
|
16
16
|
export class UpgradeSubCommand implements SubCommand {
|
|
17
17
|
readonly name = "upgrade";
|
|
@@ -38,7 +38,7 @@ export class UpgradeSubCommand implements SubCommand {
|
|
|
38
38
|
|
|
39
39
|
public async execute(context: Context, argumentValues: Values): Promise<void> {
|
|
40
40
|
const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
|
|
41
|
-
const upgradeService = context.getServiceById(UPGRADE_SERVICE_ID) as
|
|
41
|
+
const upgradeService = context.getServiceById(UPGRADE_SERVICE_ID) as UpgradeService;
|
|
42
42
|
const cliName = context.cliConfig.name;
|
|
43
43
|
const currentVersion = context.cliConfig.version;
|
|
44
44
|
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "@flowscripter/dynamic-cli-framework-api";
|
|
8
8
|
import type { AsciiBannerGeneratorService } from "@flowscripter/dynamic-cli-framework-api";
|
|
9
9
|
import type { ConfigurationService } from "@flowscripter/dynamic-cli-framework-api";
|
|
10
|
-
import
|
|
10
|
+
import type { UpgradeService } from "@flowscripter/dynamic-cli-framework-api";
|
|
11
11
|
import NoBannerCommand, { type BannerState } from "./command/NoBannerCommand.ts";
|
|
12
12
|
|
|
13
13
|
export const BANNER_STARTUP_TASK_ID = "@flowscripter/dynamic-cli-framework/banner-startup-task";
|
|
@@ -41,6 +41,15 @@ export default function createBannerStartupTask(
|
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
const upgradeService = context.doesServiceExist(UPGRADE_SERVICE_ID)
|
|
45
|
+
? (context.getServiceById(UPGRADE_SERVICE_ID) as UpgradeService)
|
|
46
|
+
: undefined;
|
|
47
|
+
// a process restarted after an automatic upgrade follows the banner already printed by the
|
|
48
|
+
// process which restarted it
|
|
49
|
+
if (upgradeService?.restartedFromVersion !== undefined) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
|
|
45
54
|
|
|
46
55
|
const asciiBannerGeneratorService = context.getServiceById(
|
|
@@ -64,10 +73,7 @@ export default function createBannerStartupTask(
|
|
|
64
73
|
// result yet) shows no upgrade-available suffix. The cached result is read through the
|
|
65
74
|
// upgrade service because it is stored in that service's own KeyValueService scope, and
|
|
66
75
|
// it is ignored if it was recorded by a different version (e.g. before an upgrade).
|
|
67
|
-
|
|
68
|
-
? context.getServiceById(UPGRADE_SERVICE_ID)
|
|
69
|
-
: undefined;
|
|
70
|
-
if (upgradeService instanceof DefaultUpgradeService) {
|
|
76
|
+
if (upgradeService) {
|
|
71
77
|
const result = await upgradeService.getCachedUpgradeCheckResult();
|
|
72
78
|
if (
|
|
73
79
|
result?.status === "checked" &&
|