@flowscripter/dynamic-cli-framework 2.3.3 → 2.4.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/command/VersionCommand.js +1 -1
- package/dist/src/service/banner/BannerServiceProvider.js +1 -1
- package/dist/src/service/plugin/SpawnInterfaceAdapter.d.ts.map +1 -1
- package/dist/src/service/plugin/SpawnInterfaceAdapter.js +5 -2
- package/dist/src/service/spawn/DefaultSpawnService.d.ts.map +1 -1
- package/dist/src/service/spawn/DefaultSpawnService.js +32 -10
- package/dist/src/service/upgrade/DefaultUpgradeService.d.ts +2 -0
- package/dist/src/service/upgrade/DefaultUpgradeService.d.ts.map +1 -1
- package/dist/src/service/upgrade/DefaultUpgradeService.js +32 -27
- package/dist/src/service/upgrade/UpgradeServiceProvider.d.ts.map +1 -1
- package/dist/src/service/upgrade/UpgradeServiceProvider.js +2 -1
- package/dist/src/service/upgrade/command/UpgradeSubCommand.d.ts.map +1 -1
- package/dist/src/service/upgrade/command/UpgradeSubCommand.js +3 -1
- package/package.json +2 -2
- package/src/command/VersionCommand.ts +1 -1
- package/src/service/banner/BannerServiceProvider.ts +1 -1
- package/src/service/plugin/SpawnInterfaceAdapter.ts +5 -2
- package/src/service/spawn/DefaultSpawnService.ts +39 -10
- package/src/service/upgrade/DefaultUpgradeService.ts +44 -40
- package/src/service/upgrade/UpgradeServiceProvider.ts +3 -1
- package/src/service/upgrade/command/UpgradeSubCommand.ts +4 -1
|
@@ -12,7 +12,7 @@ export default class VersionCommand {
|
|
|
12
12
|
let line = context.cliConfig.version;
|
|
13
13
|
if (context.doesServiceExist(UPGRADE_SERVICE_ID)) {
|
|
14
14
|
const upgradeService = context.getServiceById(UPGRADE_SERVICE_ID);
|
|
15
|
-
const result = await upgradeService.
|
|
15
|
+
const result = await upgradeService.getUpgradeCheckResult().catch(() => undefined);
|
|
16
16
|
if (result?.updateAvailable) {
|
|
17
17
|
line += ` (${result.latestVersion} available, run '${context.cliConfig.name} upgrade')`;
|
|
18
18
|
}
|
|
@@ -52,7 +52,7 @@ export default class BannerServiceProvider {
|
|
|
52
52
|
}
|
|
53
53
|
if (context.doesServiceExist(UPGRADE_SERVICE_ID)) {
|
|
54
54
|
const upgradeService = context.getServiceById(UPGRADE_SERVICE_ID);
|
|
55
|
-
const result = await upgradeService.
|
|
55
|
+
const result = await upgradeService.getUpgradeCheckResult().catch(() => undefined);
|
|
56
56
|
if (result?.updateAvailable) {
|
|
57
57
|
await printerService.info(` ${printerService.secondary(`(${result.latestVersion} available, run '${cliConfig.name} upgrade')`)}\n`);
|
|
58
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpawnInterfaceAdapter.d.ts","sourceRoot":"","sources":["../../../../src/service/plugin/SpawnInterfaceAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAE1F,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,cAAc;;gBAOhE,YAAY,EAAE,YAAY,EAC1B,cAAc,EAAE,cAAc,EAC9B,OAAO,GAAE,4BAAiC;IAQ/B,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GACvB,OAAO,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"SpawnInterfaceAdapter.d.ts","sourceRoot":"","sources":["../../../../src/service/plugin/SpawnInterfaceAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAE1F,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,cAAc;;gBAOhE,YAAY,EAAE,YAAY,EAC1B,cAAc,EAAE,cAAc,EAC9B,OAAO,GAAE,4BAAiC;IAQ/B,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GACvB,OAAO,CAAC,WAAW,CAAC;CA+BxB"}
|
|
@@ -33,8 +33,11 @@ export default class SpawnInterfaceAdapter {
|
|
|
33
33
|
this.#printerService.endQuote();
|
|
34
34
|
this.#printerService.endMark();
|
|
35
35
|
await this.#printerService.clearMarked(this.#markMinimumDisplayTimeMs);
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
if (result.ok) {
|
|
37
|
+
return { ok: true, exitCode: result.exitCode };
|
|
38
|
+
}
|
|
39
|
+
return "timedOut" in result
|
|
40
|
+
? { ok: false, error: new Error("Command timed out") }
|
|
38
41
|
: { ok: false, exitCode: result.exitCode, error: result.error };
|
|
39
42
|
}
|
|
40
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultSpawnService.d.ts","sourceRoot":"","sources":["../../../../src/service/spawn/DefaultSpawnService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,YAAY,EACZ,WAAW,EACX,YAAY,EACb,MAAM,yCAAyC,CAAC;AAOjD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAa3E;AAED,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,YAAY;;IAIvD,eAAe,CAAC,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"DefaultSpawnService.d.ts","sourceRoot":"","sources":["../../../../src/service/spawn/DefaultSpawnService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,YAAY,EACZ,WAAW,EACX,YAAY,EACb,MAAM,yCAAyC,CAAC;AAOjD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAa3E;AAED,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,YAAY;;IAIvD,eAAe,CAAC,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI;IAkDjF,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC;CA8ExB"}
|
|
@@ -28,6 +28,18 @@ export default class DefaultSpawnService {
|
|
|
28
28
|
this.#printerService = printerService;
|
|
29
29
|
this.#shutdownService = shutdownService;
|
|
30
30
|
}
|
|
31
|
+
async #terminate(proc, command) {
|
|
32
|
+
logger.debug(() => `Sending SIGTERM to spawned command '${command.join(" ")}'`);
|
|
33
|
+
proc.kill("SIGTERM");
|
|
34
|
+
const exitedInTime = await Promise.race([
|
|
35
|
+
proc.exited.then(() => true),
|
|
36
|
+
new Promise((resolve) => setTimeout(() => resolve(false), SHUTDOWN_GRACE_PERIOD_MS)),
|
|
37
|
+
]);
|
|
38
|
+
if (!exitedInTime) {
|
|
39
|
+
logger.debug(() => `Sending SIGKILL to spawned command '${command.join(" ")}'`);
|
|
40
|
+
proc.kill("SIGKILL");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
31
43
|
async #pipeLines(stream, streamName, onOutput) {
|
|
32
44
|
if (typeof stream !== "object" || stream === null) {
|
|
33
45
|
return;
|
|
@@ -85,16 +97,7 @@ export default class DefaultSpawnService {
|
|
|
85
97
|
if (settled) {
|
|
86
98
|
return;
|
|
87
99
|
}
|
|
88
|
-
|
|
89
|
-
proc.kill("SIGTERM");
|
|
90
|
-
await Promise.race([
|
|
91
|
-
proc.exited.then(() => { }),
|
|
92
|
-
new Promise((resolve) => setTimeout(resolve, SHUTDOWN_GRACE_PERIOD_MS)),
|
|
93
|
-
]);
|
|
94
|
-
if (!settled) {
|
|
95
|
-
logger.debug(() => `Sending SIGKILL to spawned command '${command.join(" ")}'`);
|
|
96
|
-
proc.kill("SIGKILL");
|
|
97
|
-
}
|
|
100
|
+
await this.#terminate(proc, command);
|
|
98
101
|
});
|
|
99
102
|
if (stdio === "wrapped" && options.onOutput) {
|
|
100
103
|
const onOutput = options.onOutput;
|
|
@@ -102,6 +105,25 @@ export default class DefaultSpawnService {
|
|
|
102
105
|
void this.#pipeLines(proc.stderr, "stderr", onOutput);
|
|
103
106
|
}
|
|
104
107
|
try {
|
|
108
|
+
if (options.timeoutMs === undefined) {
|
|
109
|
+
const exitCode = await proc.exited;
|
|
110
|
+
settled = true;
|
|
111
|
+
return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
|
|
112
|
+
}
|
|
113
|
+
let timeoutHandle;
|
|
114
|
+
const timedOut = await Promise.race([
|
|
115
|
+
proc.exited.then(() => false),
|
|
116
|
+
new Promise((resolve) => {
|
|
117
|
+
timeoutHandle = setTimeout(() => resolve(true), options.timeoutMs);
|
|
118
|
+
}),
|
|
119
|
+
]);
|
|
120
|
+
clearTimeout(timeoutHandle);
|
|
121
|
+
if (timedOut) {
|
|
122
|
+
logger.debug(() => `Command '${command.join(" ")}' timed out after ${options.timeoutMs}ms`);
|
|
123
|
+
await this.#terminate(proc, command);
|
|
124
|
+
settled = true;
|
|
125
|
+
return { ok: false, timedOut: true };
|
|
126
|
+
}
|
|
105
127
|
const exitCode = await proc.exited;
|
|
106
128
|
settled = true;
|
|
107
129
|
return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { CLIConfig, ShutdownService, SpawnService, UpgradeCheckResult, UpgradeResult } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
2
|
import { InstallMethod, SupportedArch, SupportedOs, type UpgradeService } from "@flowscripter/dynamic-cli-framework-api";
|
|
3
3
|
import type { UpgradeLocationsConfig } from "./UpgradeLocationsConfig.ts";
|
|
4
|
+
export declare const VERSION_CHECK_TIMEOUT_MS = 250;
|
|
4
5
|
export default class DefaultUpgradeService implements UpgradeService {
|
|
5
6
|
#private;
|
|
6
7
|
constructor(config: UpgradeLocationsConfig, cliConfig: CLIConfig);
|
|
7
8
|
setDependencies(spawnService: SpawnService, shutdownService?: ShutdownService): void;
|
|
9
|
+
getUpgradeCheckResult(waitForResult?: boolean): Promise<UpgradeCheckResult | undefined>;
|
|
8
10
|
detectOs(): SupportedOs | undefined;
|
|
9
11
|
detectArch(): SupportedArch | undefined;
|
|
10
12
|
detectInstallMethod(os: SupportedOs): Promise<InstallMethod | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultUpgradeService.d.ts","sourceRoot":"","sources":["../../../../src/service/upgrade/DefaultUpgradeService.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,
|
|
1
|
+
{"version":3,"file":"DefaultUpgradeService.d.ts","sourceRoot":"","sources":["../../../../src/service/upgrade/DefaultUpgradeService.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EAEf,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACd,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,aAAa,EACb,aAAa,EACb,WAAW,EACX,KAAK,cAAc,EACpB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAO1E,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAc5C,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,cAAc;;gBAO/C,MAAM,EAAE,sBAAsB,EAAE,SAAS,EAAE,SAAS;IAKhE,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI;IAKpF,qBAAqB,CAAC,aAAa,UAAQ,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC;IAerF,QAAQ,IAAI,WAAW,GAAG,SAAS;IAanC,UAAU,IAAI,aAAa,GAAG,SAAS;IAWjC,mBAAmB,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAgBxE,eAAe,CAC1B,UAAU,CAAC,EAAE,WAAW,EACxB,YAAY,CAAC,EAAE,aAAa,EAC5B,qBAAqB,CAAC,EAAE,aAAa,GACpC,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC;IAmC7B,OAAO,CAClB,UAAU,CAAC,EAAE,WAAW,EACxB,YAAY,CAAC,EAAE,aAAa,EAC5B,qBAAqB,CAAC,EAAE,aAAa,GACpC,OAAO,CAAC,aAAa,CAAC;CAyQ1B"}
|
|
@@ -7,17 +7,12 @@ import semver from "semver";
|
|
|
7
7
|
import getLogger from "../../util/logger.js";
|
|
8
8
|
const logger = getLogger("DefaultUpgradeService");
|
|
9
9
|
// checkForUpgrade() runs opportunistically on every CLI invocation (via BannerServiceProvider),
|
|
10
|
-
// so its version-check network calls must never be allowed to stall CLI startup.
|
|
11
|
-
const VERSION_CHECK_TIMEOUT_MS = 250;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
async function withSpawnTimeout(spawnPromise, fallback) {
|
|
17
|
-
return Promise.race([
|
|
18
|
-
spawnPromise,
|
|
19
|
-
new Promise((resolve) => setTimeout(() => resolve(fallback), VERSION_CHECK_TIMEOUT_MS)),
|
|
20
|
-
]);
|
|
10
|
+
// so its version-check network/spawn calls must never be allowed to stall CLI startup.
|
|
11
|
+
export const VERSION_CHECK_TIMEOUT_MS = 250;
|
|
12
|
+
function describeSpawnFailure(result) {
|
|
13
|
+
return "timedOut" in result
|
|
14
|
+
? "timed out"
|
|
15
|
+
: (result.error?.message ?? `exit code ${result.exitCode}`);
|
|
21
16
|
}
|
|
22
17
|
const OS_LABELS = {
|
|
23
18
|
[SupportedOs.LINUX]: "Linux",
|
|
@@ -27,6 +22,7 @@ const OS_LABELS = {
|
|
|
27
22
|
export default class DefaultUpgradeService {
|
|
28
23
|
#spawnService;
|
|
29
24
|
#shutdownService;
|
|
25
|
+
#upgradeCheckPromise;
|
|
30
26
|
#config;
|
|
31
27
|
#cliConfig;
|
|
32
28
|
constructor(config, cliConfig) {
|
|
@@ -37,6 +33,18 @@ export default class DefaultUpgradeService {
|
|
|
37
33
|
this.#spawnService = spawnService;
|
|
38
34
|
this.#shutdownService = shutdownService;
|
|
39
35
|
}
|
|
36
|
+
getUpgradeCheckResult(waitForResult = false) {
|
|
37
|
+
if (!this.#upgradeCheckPromise) {
|
|
38
|
+
this.#upgradeCheckPromise = this.checkForUpgrade();
|
|
39
|
+
}
|
|
40
|
+
if (waitForResult) {
|
|
41
|
+
return this.#upgradeCheckPromise;
|
|
42
|
+
}
|
|
43
|
+
return Promise.race([
|
|
44
|
+
this.#upgradeCheckPromise,
|
|
45
|
+
new Promise((resolve) => setTimeout(() => resolve(undefined), VERSION_CHECK_TIMEOUT_MS)),
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
40
48
|
detectOs() {
|
|
41
49
|
switch (process.platform) {
|
|
42
50
|
case "linux":
|
|
@@ -106,7 +114,10 @@ export default class DefaultUpgradeService {
|
|
|
106
114
|
}
|
|
107
115
|
async upgrade(osOverride, archOverride, installMethodOverride) {
|
|
108
116
|
const oldVersion = this.#cliConfig.version;
|
|
109
|
-
const
|
|
117
|
+
const hasOverride = osOverride !== undefined || archOverride !== undefined || installMethodOverride !== undefined;
|
|
118
|
+
const checkResult = hasOverride
|
|
119
|
+
? await this.checkForUpgrade(osOverride, archOverride, installMethodOverride)
|
|
120
|
+
: await this.getUpgradeCheckResult(true);
|
|
110
121
|
if (!checkResult) {
|
|
111
122
|
return {
|
|
112
123
|
ok: false,
|
|
@@ -145,20 +156,14 @@ export default class DefaultUpgradeService {
|
|
|
145
156
|
if (!this.#spawnService || !this.#config.homebrew) {
|
|
146
157
|
return false;
|
|
147
158
|
}
|
|
148
|
-
const result = await
|
|
149
|
-
stdio: "wrapped",
|
|
150
|
-
longRunning: false,
|
|
151
|
-
}), { ok: false });
|
|
159
|
+
const result = await this.#spawnService.spawn(["brew", "list", "--versions", this.#config.homebrew.formula], { stdio: "wrapped", longRunning: false, timeoutMs: VERSION_CHECK_TIMEOUT_MS });
|
|
152
160
|
return result.ok;
|
|
153
161
|
}
|
|
154
162
|
async #isWingetInstalled() {
|
|
155
163
|
if (!this.#spawnService || !this.#config.winget) {
|
|
156
164
|
return false;
|
|
157
165
|
}
|
|
158
|
-
const result = await
|
|
159
|
-
stdio: "wrapped",
|
|
160
|
-
longRunning: false,
|
|
161
|
-
}), { ok: false });
|
|
166
|
+
const result = await this.#spawnService.spawn(["winget", "list", "--id", this.#config.winget.packageId], { stdio: "wrapped", longRunning: false, timeoutMs: VERSION_CHECK_TIMEOUT_MS });
|
|
162
167
|
return result.ok;
|
|
163
168
|
}
|
|
164
169
|
#isLinuxScriptInstall() {
|
|
@@ -222,11 +227,12 @@ export default class DefaultUpgradeService {
|
|
|
222
227
|
return undefined;
|
|
223
228
|
}
|
|
224
229
|
const lines = [];
|
|
225
|
-
const result = await
|
|
230
|
+
const result = await this.#spawnService.spawn(["winget", "show", "--id", this.#config.winget.packageId], {
|
|
226
231
|
stdio: "wrapped",
|
|
227
232
|
longRunning: false,
|
|
233
|
+
timeoutMs: VERSION_CHECK_TIMEOUT_MS,
|
|
228
234
|
onOutput: (line) => lines.push(line),
|
|
229
|
-
})
|
|
235
|
+
});
|
|
230
236
|
if (!result.ok) {
|
|
231
237
|
return undefined;
|
|
232
238
|
}
|
|
@@ -242,14 +248,14 @@ export default class DefaultUpgradeService {
|
|
|
242
248
|
const { scriptUrl } = this.#config.linuxScript;
|
|
243
249
|
const result = await this.#spawnService.spawn(["sh", "-c", `curl -fsSL ${scriptUrl} | sh`]);
|
|
244
250
|
if (!result.ok) {
|
|
245
|
-
throw new Error(`Install script failed: ${result
|
|
251
|
+
throw new Error(`Install script failed: ${describeSpawnFailure(result)}`);
|
|
246
252
|
}
|
|
247
253
|
}
|
|
248
254
|
async #upgradeViaHomebrew() {
|
|
249
255
|
const { tap, formula } = this.#config.homebrew;
|
|
250
256
|
const result = await this.#spawnService.spawn(["brew", "upgrade", `${tap}/${formula}`]);
|
|
251
257
|
if (!result.ok) {
|
|
252
|
-
throw new Error(`brew upgrade failed: ${result
|
|
258
|
+
throw new Error(`brew upgrade failed: ${describeSpawnFailure(result)}`);
|
|
253
259
|
}
|
|
254
260
|
}
|
|
255
261
|
async #upgradeViaWinget() {
|
|
@@ -264,7 +270,7 @@ export default class DefaultUpgradeService {
|
|
|
264
270
|
"--accept-source-agreements",
|
|
265
271
|
]);
|
|
266
272
|
if (!result.ok) {
|
|
267
|
-
throw new Error(`winget upgrade failed: ${result
|
|
273
|
+
throw new Error(`winget upgrade failed: ${describeSpawnFailure(result)}`);
|
|
268
274
|
}
|
|
269
275
|
}
|
|
270
276
|
async #upgradeViaGithubRelease(os, arch) {
|
|
@@ -272,8 +278,7 @@ export default class DefaultUpgradeService {
|
|
|
272
278
|
const archLabel = os === SupportedOs.MACOS ? "aarch64" : arch === SupportedArch.X64 ? "x64" : "arm64";
|
|
273
279
|
const assetName = assetPattern.replace("{os}", OS_LABELS[os]).replace("{arch}", archLabel);
|
|
274
280
|
const url = `https://github.com/${owner}/${repo}/releases/latest/download/${assetName}`;
|
|
275
|
-
// Downloading the release asset
|
|
276
|
-
// for its own subprocesses by default), so bracket it here to get the same cooperative
|
|
281
|
+
// Downloading the release asset but enter long-running mode to get cooperative
|
|
277
282
|
// Ctrl-C handling during what can be the slowest step of the upgrade.
|
|
278
283
|
this.#shutdownService?.enterLongRunningMode();
|
|
279
284
|
let archiveData;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UpgradeServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/upgrade/UpgradeServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAczE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAK1E,MAAM,CAAC,OAAO,OAAO,sBAAuB,YAAW,eAAe;;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAsB;IAChD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;gBAKd,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB;IAKnE,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASpD,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"UpgradeServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/upgrade/UpgradeServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAczE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAK1E,MAAM,CAAC,OAAO,OAAO,sBAAuB,YAAW,eAAe;;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAsB;IAChD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;gBAKd,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB;IAKnE,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASpD,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAkH1D"}
|
|
@@ -39,6 +39,7 @@ export default class UpgradeServiceProvider {
|
|
|
39
39
|
else {
|
|
40
40
|
logger.debug(() => "SpawnService not available, upgrade install methods will be unavailable");
|
|
41
41
|
}
|
|
42
|
+
void upgradeService.getUpgradeCheckResult();
|
|
42
43
|
if (!context.doesServiceExist(PROMPTER_SERVICE_ID)) {
|
|
43
44
|
logger.debug(() => "PrompterService not available, skipping auto-upgrade");
|
|
44
45
|
return;
|
|
@@ -101,7 +102,7 @@ export default class UpgradeServiceProvider {
|
|
|
101
102
|
}
|
|
102
103
|
async #checkAndUpgrade(context, upgradeService, cliConfig) {
|
|
103
104
|
try {
|
|
104
|
-
const checkResult = await upgradeService.
|
|
105
|
+
const checkResult = await upgradeService.getUpgradeCheckResult();
|
|
105
106
|
if (!checkResult?.updateAvailable) {
|
|
106
107
|
return;
|
|
107
108
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UpgradeSubCommand.d.ts","sourceRoot":"","sources":["../../../../../src/service/upgrade/command/UpgradeSubCommand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yCAAyC,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,EACL,KAAK,cAAc,EAEpB,MAAM,yCAAyC,CAAC;AASjD,OAAO,KAAK,qBAAqB,MAAM,6BAA6B,CAAC;AAErE,qBAAa,iBAAkB,YAAW,UAAU;;IAClD,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,WAAW,6CAA6C;IACjE,QAAQ,CAAC,mBAAmB,SAAS;IACrC,QAAQ,CAAC,WAAW,UAAM;IAE1B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAerC;gBAIiB,cAAc,EAAE,qBAAqB;IAI3C,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"UpgradeSubCommand.d.ts","sourceRoot":"","sources":["../../../../../src/service/upgrade/command/UpgradeSubCommand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yCAAyC,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,EACL,KAAK,cAAc,EAEpB,MAAM,yCAAyC,CAAC;AASjD,OAAO,KAAK,qBAAqB,MAAM,6BAA6B,CAAC;AAErE,qBAAa,iBAAkB,YAAW,UAAU;;IAClD,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,WAAW,6CAA6C;IACjE,QAAQ,CAAC,mBAAmB,SAAS;IACrC,QAAQ,CAAC,WAAW,UAAM;IAE1B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAerC;gBAIiB,cAAc,EAAE,qBAAqB;IAI3C,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAyCtF"}
|
|
@@ -31,7 +31,9 @@ export class UpgradeSubCommand {
|
|
|
31
31
|
const os = argumentValues.os;
|
|
32
32
|
const arch = undefined;
|
|
33
33
|
const installMethod = argumentValues["install-method"];
|
|
34
|
-
const checkResult =
|
|
34
|
+
const checkResult = os === undefined && installMethod === undefined
|
|
35
|
+
? await this.#upgradeService.getUpgradeCheckResult(true)
|
|
36
|
+
: await this.#upgradeService.checkForUpgrade(os, arch, installMethod);
|
|
35
37
|
if (!checkResult) {
|
|
36
38
|
await printerService.error(`No upgrade location is configured for the detected or requested platform.\n`, Icon.FAILURE);
|
|
37
39
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowscripter/dynamic-cli-framework",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "A framework for developing CLI applications which supports dynamic discovery and installation of new commands",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"build": "tsc -p tsconfig.build.json"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@flowscripter/dynamic-cli-framework-api": "^1.
|
|
51
|
+
"@flowscripter/dynamic-cli-framework-api": "^1.3.0",
|
|
52
52
|
"@flowscripter/dynamic-plugin-framework": "1.11.1",
|
|
53
53
|
"emphasize": "^7.0.0",
|
|
54
54
|
"fastest-levenshtein": "^1.0.16",
|
|
@@ -19,7 +19,7 @@ export default class VersionCommand implements GlobalCommand {
|
|
|
19
19
|
let line = context.cliConfig.version;
|
|
20
20
|
if (context.doesServiceExist(UPGRADE_SERVICE_ID)) {
|
|
21
21
|
const upgradeService = context.getServiceById(UPGRADE_SERVICE_ID) as UpgradeService;
|
|
22
|
-
const result = await upgradeService.
|
|
22
|
+
const result = await upgradeService.getUpgradeCheckResult().catch(() => undefined);
|
|
23
23
|
if (result?.updateAvailable) {
|
|
24
24
|
line += ` (${result.latestVersion} available, run '${context.cliConfig.name} upgrade')`;
|
|
25
25
|
}
|
|
@@ -72,7 +72,7 @@ export default class BannerServiceProvider implements ServiceProvider {
|
|
|
72
72
|
}
|
|
73
73
|
if (context.doesServiceExist(UPGRADE_SERVICE_ID)) {
|
|
74
74
|
const upgradeService = context.getServiceById(UPGRADE_SERVICE_ID) as UpgradeService;
|
|
75
|
-
const result = await upgradeService.
|
|
75
|
+
const result = await upgradeService.getUpgradeCheckResult().catch(() => undefined);
|
|
76
76
|
if (result?.updateAvailable) {
|
|
77
77
|
await printerService.info(
|
|
78
78
|
` ${printerService.secondary(
|
|
@@ -55,8 +55,11 @@ export default class SpawnInterfaceAdapter implements SpawnInterface {
|
|
|
55
55
|
this.#printerService.endMark();
|
|
56
56
|
await this.#printerService.clearMarked(this.#markMinimumDisplayTimeMs);
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
if (result.ok) {
|
|
59
|
+
return { ok: true, exitCode: result.exitCode };
|
|
60
|
+
}
|
|
61
|
+
return "timedOut" in result
|
|
62
|
+
? { ok: false, error: new Error("Command timed out") }
|
|
60
63
|
: { ok: false, exitCode: result.exitCode, error: result.error };
|
|
61
64
|
}
|
|
62
65
|
}
|
|
@@ -41,6 +41,22 @@ export default class DefaultSpawnService implements SpawnService {
|
|
|
41
41
|
this.#shutdownService = shutdownService;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
async #terminate(
|
|
45
|
+
proc: ReturnType<typeof Bun.spawn>,
|
|
46
|
+
command: ReadonlyArray<string>,
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
logger.debug(() => `Sending SIGTERM to spawned command '${command.join(" ")}'`);
|
|
49
|
+
proc.kill("SIGTERM");
|
|
50
|
+
const exitedInTime = await Promise.race([
|
|
51
|
+
proc.exited.then(() => true),
|
|
52
|
+
new Promise<boolean>((resolve) => setTimeout(() => resolve(false), SHUTDOWN_GRACE_PERIOD_MS)),
|
|
53
|
+
]);
|
|
54
|
+
if (!exitedInTime) {
|
|
55
|
+
logger.debug(() => `Sending SIGKILL to spawned command '${command.join(" ")}'`);
|
|
56
|
+
proc.kill("SIGKILL");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
async #pipeLines(
|
|
45
61
|
stream: ReadableStream<Uint8Array> | number | undefined,
|
|
46
62
|
streamName: "stdout" | "stderr",
|
|
@@ -110,16 +126,7 @@ export default class DefaultSpawnService implements SpawnService {
|
|
|
110
126
|
if (settled) {
|
|
111
127
|
return;
|
|
112
128
|
}
|
|
113
|
-
|
|
114
|
-
proc.kill("SIGTERM");
|
|
115
|
-
await Promise.race([
|
|
116
|
-
proc.exited.then(() => {}),
|
|
117
|
-
new Promise<void>((resolve) => setTimeout(resolve, SHUTDOWN_GRACE_PERIOD_MS)),
|
|
118
|
-
]);
|
|
119
|
-
if (!settled) {
|
|
120
|
-
logger.debug(() => `Sending SIGKILL to spawned command '${command.join(" ")}'`);
|
|
121
|
-
proc.kill("SIGKILL");
|
|
122
|
-
}
|
|
129
|
+
await this.#terminate(proc, command);
|
|
123
130
|
});
|
|
124
131
|
|
|
125
132
|
if (stdio === "wrapped" && options.onOutput) {
|
|
@@ -129,6 +136,28 @@ export default class DefaultSpawnService implements SpawnService {
|
|
|
129
136
|
}
|
|
130
137
|
|
|
131
138
|
try {
|
|
139
|
+
if (options.timeoutMs === undefined) {
|
|
140
|
+
const exitCode = await proc.exited;
|
|
141
|
+
settled = true;
|
|
142
|
+
return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let timeoutHandle: ReturnType<typeof setTimeout>;
|
|
146
|
+
const timedOut = await Promise.race([
|
|
147
|
+
proc.exited.then(() => false),
|
|
148
|
+
new Promise<boolean>((resolve) => {
|
|
149
|
+
timeoutHandle = setTimeout(() => resolve(true), options.timeoutMs);
|
|
150
|
+
}),
|
|
151
|
+
]);
|
|
152
|
+
clearTimeout(timeoutHandle!);
|
|
153
|
+
|
|
154
|
+
if (timedOut) {
|
|
155
|
+
logger.debug(() => `Command '${command.join(" ")}' timed out after ${options.timeoutMs}ms`);
|
|
156
|
+
await this.#terminate(proc, command);
|
|
157
|
+
settled = true;
|
|
158
|
+
return { ok: false, timedOut: true };
|
|
159
|
+
}
|
|
160
|
+
|
|
132
161
|
const exitCode = await proc.exited;
|
|
133
162
|
settled = true;
|
|
134
163
|
return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
|
|
@@ -5,6 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import type {
|
|
6
6
|
CLIConfig,
|
|
7
7
|
ShutdownService,
|
|
8
|
+
SpawnResult,
|
|
8
9
|
SpawnService,
|
|
9
10
|
UpgradeCheckResult,
|
|
10
11
|
UpgradeResult,
|
|
@@ -22,18 +23,13 @@ import getLogger from "../../util/logger.ts";
|
|
|
22
23
|
const logger = getLogger("DefaultUpgradeService");
|
|
23
24
|
|
|
24
25
|
// checkForUpgrade() runs opportunistically on every CLI invocation (via BannerServiceProvider),
|
|
25
|
-
// so its version-check network calls must never be allowed to stall CLI startup.
|
|
26
|
-
const VERSION_CHECK_TIMEOUT_MS = 250;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
async function withSpawnTimeout<T>(spawnPromise: Promise<T>, fallback: T): Promise<T> {
|
|
33
|
-
return Promise.race([
|
|
34
|
-
spawnPromise,
|
|
35
|
-
new Promise<T>((resolve) => setTimeout(() => resolve(fallback), VERSION_CHECK_TIMEOUT_MS)),
|
|
36
|
-
]);
|
|
26
|
+
// so its version-check network/spawn calls must never be allowed to stall CLI startup.
|
|
27
|
+
export const VERSION_CHECK_TIMEOUT_MS = 250;
|
|
28
|
+
|
|
29
|
+
function describeSpawnFailure(result: Extract<SpawnResult, { ok: false }>): string {
|
|
30
|
+
return "timedOut" in result
|
|
31
|
+
? "timed out"
|
|
32
|
+
: (result.error?.message ?? `exit code ${result.exitCode}`);
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
const OS_LABELS: Record<SupportedOs, string> = {
|
|
@@ -45,6 +41,7 @@ const OS_LABELS: Record<SupportedOs, string> = {
|
|
|
45
41
|
export default class DefaultUpgradeService implements UpgradeService {
|
|
46
42
|
#spawnService: SpawnService | undefined;
|
|
47
43
|
#shutdownService: ShutdownService | undefined;
|
|
44
|
+
#upgradeCheckPromise: Promise<UpgradeCheckResult | undefined> | undefined;
|
|
48
45
|
readonly #config: UpgradeLocationsConfig;
|
|
49
46
|
readonly #cliConfig: CLIConfig;
|
|
50
47
|
|
|
@@ -58,6 +55,21 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
58
55
|
this.#shutdownService = shutdownService;
|
|
59
56
|
}
|
|
60
57
|
|
|
58
|
+
public getUpgradeCheckResult(waitForResult = false): Promise<UpgradeCheckResult | undefined> {
|
|
59
|
+
if (!this.#upgradeCheckPromise) {
|
|
60
|
+
this.#upgradeCheckPromise = this.checkForUpgrade();
|
|
61
|
+
}
|
|
62
|
+
if (waitForResult) {
|
|
63
|
+
return this.#upgradeCheckPromise;
|
|
64
|
+
}
|
|
65
|
+
return Promise.race([
|
|
66
|
+
this.#upgradeCheckPromise,
|
|
67
|
+
new Promise<undefined>((resolve) =>
|
|
68
|
+
setTimeout(() => resolve(undefined), VERSION_CHECK_TIMEOUT_MS),
|
|
69
|
+
),
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
|
|
61
73
|
public detectOs(): SupportedOs | undefined {
|
|
62
74
|
switch (process.platform) {
|
|
63
75
|
case "linux":
|
|
@@ -143,7 +155,11 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
143
155
|
installMethodOverride?: InstallMethod,
|
|
144
156
|
): Promise<UpgradeResult> {
|
|
145
157
|
const oldVersion = this.#cliConfig.version;
|
|
146
|
-
const
|
|
158
|
+
const hasOverride =
|
|
159
|
+
osOverride !== undefined || archOverride !== undefined || installMethodOverride !== undefined;
|
|
160
|
+
const checkResult = hasOverride
|
|
161
|
+
? await this.checkForUpgrade(osOverride, archOverride, installMethodOverride)
|
|
162
|
+
: await this.getUpgradeCheckResult(true);
|
|
147
163
|
if (!checkResult) {
|
|
148
164
|
return {
|
|
149
165
|
ok: false,
|
|
@@ -186,12 +202,9 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
186
202
|
if (!this.#spawnService || !this.#config.homebrew) {
|
|
187
203
|
return false;
|
|
188
204
|
}
|
|
189
|
-
const result = await
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
longRunning: false,
|
|
193
|
-
}),
|
|
194
|
-
{ ok: false } as const,
|
|
205
|
+
const result = await this.#spawnService.spawn(
|
|
206
|
+
["brew", "list", "--versions", this.#config.homebrew.formula],
|
|
207
|
+
{ stdio: "wrapped", longRunning: false, timeoutMs: VERSION_CHECK_TIMEOUT_MS },
|
|
195
208
|
);
|
|
196
209
|
return result.ok;
|
|
197
210
|
}
|
|
@@ -200,12 +213,9 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
200
213
|
if (!this.#spawnService || !this.#config.winget) {
|
|
201
214
|
return false;
|
|
202
215
|
}
|
|
203
|
-
const result = await
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
longRunning: false,
|
|
207
|
-
}),
|
|
208
|
-
{ ok: false } as const,
|
|
216
|
+
const result = await this.#spawnService.spawn(
|
|
217
|
+
["winget", "list", "--id", this.#config.winget.packageId],
|
|
218
|
+
{ stdio: "wrapped", longRunning: false, timeoutMs: VERSION_CHECK_TIMEOUT_MS },
|
|
209
219
|
);
|
|
210
220
|
return result.ok;
|
|
211
221
|
}
|
|
@@ -279,13 +289,14 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
279
289
|
return undefined;
|
|
280
290
|
}
|
|
281
291
|
const lines: string[] = [];
|
|
282
|
-
const result = await
|
|
283
|
-
|
|
292
|
+
const result = await this.#spawnService.spawn(
|
|
293
|
+
["winget", "show", "--id", this.#config.winget.packageId],
|
|
294
|
+
{
|
|
284
295
|
stdio: "wrapped",
|
|
285
296
|
longRunning: false,
|
|
297
|
+
timeoutMs: VERSION_CHECK_TIMEOUT_MS,
|
|
286
298
|
onOutput: (line) => lines.push(line),
|
|
287
|
-
}
|
|
288
|
-
{ ok: false } as const,
|
|
299
|
+
},
|
|
289
300
|
);
|
|
290
301
|
if (!result.ok) {
|
|
291
302
|
return undefined;
|
|
@@ -303,9 +314,7 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
303
314
|
const { scriptUrl } = this.#config.linuxScript!;
|
|
304
315
|
const result = await this.#spawnService!.spawn(["sh", "-c", `curl -fsSL ${scriptUrl} | sh`]);
|
|
305
316
|
if (!result.ok) {
|
|
306
|
-
throw new Error(
|
|
307
|
-
`Install script failed: ${result.error?.message ?? `exit code ${result.exitCode}`}`,
|
|
308
|
-
);
|
|
317
|
+
throw new Error(`Install script failed: ${describeSpawnFailure(result)}`);
|
|
309
318
|
}
|
|
310
319
|
}
|
|
311
320
|
|
|
@@ -313,9 +322,7 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
313
322
|
const { tap, formula } = this.#config.homebrew!;
|
|
314
323
|
const result = await this.#spawnService!.spawn(["brew", "upgrade", `${tap}/${formula}`]);
|
|
315
324
|
if (!result.ok) {
|
|
316
|
-
throw new Error(
|
|
317
|
-
`brew upgrade failed: ${result.error?.message ?? `exit code ${result.exitCode}`}`,
|
|
318
|
-
);
|
|
325
|
+
throw new Error(`brew upgrade failed: ${describeSpawnFailure(result)}`);
|
|
319
326
|
}
|
|
320
327
|
}
|
|
321
328
|
|
|
@@ -331,9 +338,7 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
331
338
|
"--accept-source-agreements",
|
|
332
339
|
]);
|
|
333
340
|
if (!result.ok) {
|
|
334
|
-
throw new Error(
|
|
335
|
-
`winget upgrade failed: ${result.error?.message ?? `exit code ${result.exitCode}`}`,
|
|
336
|
-
);
|
|
341
|
+
throw new Error(`winget upgrade failed: ${describeSpawnFailure(result)}`);
|
|
337
342
|
}
|
|
338
343
|
}
|
|
339
344
|
|
|
@@ -344,8 +349,7 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
344
349
|
const assetName = assetPattern.replace("{os}", OS_LABELS[os]).replace("{arch}", archLabel);
|
|
345
350
|
const url = `https://github.com/${owner}/${repo}/releases/latest/download/${assetName}`;
|
|
346
351
|
|
|
347
|
-
// Downloading the release asset
|
|
348
|
-
// for its own subprocesses by default), so bracket it here to get the same cooperative
|
|
352
|
+
// Downloading the release asset but enter long-running mode to get cooperative
|
|
349
353
|
// Ctrl-C handling during what can be the slowest step of the upgrade.
|
|
350
354
|
this.#shutdownService?.enterLongRunningMode();
|
|
351
355
|
let archiveData: ArrayBuffer;
|
|
@@ -54,6 +54,8 @@ export default class UpgradeServiceProvider implements ServiceProvider {
|
|
|
54
54
|
logger.debug(() => "SpawnService not available, upgrade install methods will be unavailable");
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
void upgradeService.getUpgradeCheckResult();
|
|
58
|
+
|
|
57
59
|
if (!context.doesServiceExist(PROMPTER_SERVICE_ID)) {
|
|
58
60
|
logger.debug(() => "PrompterService not available, skipping auto-upgrade");
|
|
59
61
|
return;
|
|
@@ -128,7 +130,7 @@ export default class UpgradeServiceProvider implements ServiceProvider {
|
|
|
128
130
|
cliConfig: CLIConfig,
|
|
129
131
|
): Promise<void> {
|
|
130
132
|
try {
|
|
131
|
-
const checkResult = await upgradeService.
|
|
133
|
+
const checkResult = await upgradeService.getUpgradeCheckResult();
|
|
132
134
|
if (!checkResult?.updateAvailable) {
|
|
133
135
|
return;
|
|
134
136
|
}
|
|
@@ -52,7 +52,10 @@ export class UpgradeSubCommand implements SubCommand {
|
|
|
52
52
|
const arch = undefined as SupportedArch | undefined;
|
|
53
53
|
const installMethod = argumentValues["install-method"] as InstallMethod | undefined;
|
|
54
54
|
|
|
55
|
-
const checkResult =
|
|
55
|
+
const checkResult =
|
|
56
|
+
os === undefined && installMethod === undefined
|
|
57
|
+
? await this.#upgradeService.getUpgradeCheckResult(true)
|
|
58
|
+
: await this.#upgradeService.checkForUpgrade(os, arch, installMethod);
|
|
56
59
|
if (!checkResult) {
|
|
57
60
|
await printerService.error(
|
|
58
61
|
`No upgrade location is configured for the detected or requested platform.\n`,
|