@flowscripter/dynamic-cli-framework 2.3.0 → 2.3.2
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/service/spawn/DefaultSpawnService.d.ts +6 -0
- package/dist/src/service/spawn/DefaultSpawnService.d.ts.map +1 -1
- package/dist/src/service/spawn/DefaultSpawnService.js +21 -1
- package/dist/src/service/upgrade/DefaultUpgradeService.d.ts +2 -2
- package/dist/src/service/upgrade/DefaultUpgradeService.d.ts.map +1 -1
- package/dist/src/service/upgrade/DefaultUpgradeService.js +23 -7
- package/dist/src/service/upgrade/UpgradeServiceProvider.d.ts.map +1 -1
- package/dist/src/service/upgrade/UpgradeServiceProvider.js +5 -1
- package/package.json +2 -2
- package/src/service/spawn/DefaultSpawnService.ts +22 -1
- package/src/service/upgrade/DefaultUpgradeService.ts +27 -6
- package/src/service/upgrade/UpgradeServiceProvider.ts +6 -1
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { PrinterService, ShutdownService, SpawnOptions, SpawnResult, SpawnService } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
|
+
/**
|
|
3
|
+
* On Windows, batch-file shims (e.g. `npm.cmd`, `bun.cmd`) cannot be launched directly via
|
|
4
|
+
* `CreateProcess` - they must be run through `cmd.exe /c`. Resolve the command through the shell
|
|
5
|
+
* in that case; leave it untouched on other platforms.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveForPlatform(command: ReadonlyArray<string>): string[];
|
|
2
8
|
export default class DefaultSpawnService implements SpawnService {
|
|
3
9
|
#private;
|
|
4
10
|
setDependencies(printerService: PrinterService, shutdownService: ShutdownService): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultSpawnService.d.ts","sourceRoot":"","sources":["../../../../src/service/spawn/DefaultSpawnService.ts"],"names":[],"mappings":"
|
|
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;IAkCjF,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC;CAiExB"}
|
|
@@ -1,6 +1,26 @@
|
|
|
1
|
+
import process from "node:process";
|
|
1
2
|
import getLogger from "../../util/logger.js";
|
|
2
3
|
const logger = getLogger("DefaultSpawnService");
|
|
3
4
|
const SHUTDOWN_GRACE_PERIOD_MS = 5000;
|
|
5
|
+
/**
|
|
6
|
+
* On Windows, batch-file shims (e.g. `npm.cmd`, `bun.cmd`) cannot be launched directly via
|
|
7
|
+
* `CreateProcess` - they must be run through `cmd.exe /c`. Resolve the command through the shell
|
|
8
|
+
* in that case; leave it untouched on other platforms.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveForPlatform(command) {
|
|
11
|
+
if (process.platform !== "win32") {
|
|
12
|
+
return [...command];
|
|
13
|
+
}
|
|
14
|
+
const [bin, ...args] = command;
|
|
15
|
+
if (bin === undefined) {
|
|
16
|
+
return [...command];
|
|
17
|
+
}
|
|
18
|
+
const resolved = Bun.which(bin) ?? bin;
|
|
19
|
+
if (!/\.(cmd|bat)$/i.test(resolved)) {
|
|
20
|
+
return [resolved, ...args];
|
|
21
|
+
}
|
|
22
|
+
return ["cmd.exe", "/d", "/s", "/c", resolved, ...args];
|
|
23
|
+
}
|
|
4
24
|
export default class DefaultSpawnService {
|
|
5
25
|
#printerService;
|
|
6
26
|
#shutdownService;
|
|
@@ -46,7 +66,7 @@ export default class DefaultSpawnService {
|
|
|
46
66
|
}
|
|
47
67
|
let proc;
|
|
48
68
|
try {
|
|
49
|
-
proc = Bun.spawn(
|
|
69
|
+
proc = Bun.spawn(resolveForPlatform(command), {
|
|
50
70
|
cwd: options.cwd,
|
|
51
71
|
stdin: stdio === "wrapped" ? "ignore" : "inherit",
|
|
52
72
|
stdout: stdio === "wrapped" ? "pipe" : "inherit",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { CLIConfig, SpawnService, UpgradeCheckResult, UpgradeResult } from "@flowscripter/dynamic-cli-framework-api";
|
|
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
4
|
export default class DefaultUpgradeService implements UpgradeService {
|
|
5
5
|
#private;
|
|
6
6
|
constructor(config: UpgradeLocationsConfig, cliConfig: CLIConfig);
|
|
7
|
-
setDependencies(spawnService: SpawnService): void;
|
|
7
|
+
setDependencies(spawnService: SpawnService, shutdownService?: ShutdownService): void;
|
|
8
8
|
detectOs(): SupportedOs | undefined;
|
|
9
9
|
detectArch(): SupportedArch | undefined;
|
|
10
10
|
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,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;
|
|
1
|
+
{"version":3,"file":"DefaultUpgradeService.d.ts","sourceRoot":"","sources":["../../../../src/service/upgrade/DefaultUpgradeService.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,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;AAe1E,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,cAAc;;gBAM/C,MAAM,EAAE,sBAAsB,EAAE,SAAS,EAAE,SAAS;IAKhE,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI;IAKpF,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;CA2Q1B"}
|
|
@@ -6,6 +6,9 @@ import { InstallMethod, SupportedArch, SupportedOs, } from "@flowscripter/dynami
|
|
|
6
6
|
import semver from "semver";
|
|
7
7
|
import getLogger from "../../util/logger.js";
|
|
8
8
|
const logger = getLogger("DefaultUpgradeService");
|
|
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;
|
|
9
12
|
const OS_LABELS = {
|
|
10
13
|
[SupportedOs.LINUX]: "Linux",
|
|
11
14
|
[SupportedOs.MACOS]: "MacOS",
|
|
@@ -13,14 +16,16 @@ const OS_LABELS = {
|
|
|
13
16
|
};
|
|
14
17
|
export default class DefaultUpgradeService {
|
|
15
18
|
#spawnService;
|
|
19
|
+
#shutdownService;
|
|
16
20
|
#config;
|
|
17
21
|
#cliConfig;
|
|
18
22
|
constructor(config, cliConfig) {
|
|
19
23
|
this.#config = config;
|
|
20
24
|
this.#cliConfig = cliConfig;
|
|
21
25
|
}
|
|
22
|
-
setDependencies(spawnService) {
|
|
26
|
+
setDependencies(spawnService, shutdownService) {
|
|
23
27
|
this.#spawnService = spawnService;
|
|
28
|
+
this.#shutdownService = shutdownService;
|
|
24
29
|
}
|
|
25
30
|
detectOs() {
|
|
26
31
|
switch (process.platform) {
|
|
@@ -162,7 +167,7 @@ export default class DefaultUpgradeService {
|
|
|
162
167
|
}
|
|
163
168
|
const { owner, repo } = this.#config.githubRelease;
|
|
164
169
|
try {
|
|
165
|
-
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases/latest
|
|
170
|
+
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases/latest`, { signal: AbortSignal.timeout(VERSION_CHECK_TIMEOUT_MS) });
|
|
166
171
|
if (!response.ok) {
|
|
167
172
|
return undefined;
|
|
168
173
|
}
|
|
@@ -184,7 +189,7 @@ export default class DefaultUpgradeService {
|
|
|
184
189
|
return undefined;
|
|
185
190
|
}
|
|
186
191
|
try {
|
|
187
|
-
const response = await fetch(`https://raw.githubusercontent.com/${tapOwner}/homebrew-${tapName}/main/${formula}.rb
|
|
192
|
+
const response = await fetch(`https://raw.githubusercontent.com/${tapOwner}/homebrew-${tapName}/main/${formula}.rb`, { signal: AbortSignal.timeout(VERSION_CHECK_TIMEOUT_MS) });
|
|
188
193
|
if (!response.ok) {
|
|
189
194
|
return undefined;
|
|
190
195
|
}
|
|
@@ -251,13 +256,24 @@ export default class DefaultUpgradeService {
|
|
|
251
256
|
const archLabel = os === SupportedOs.MACOS ? "aarch64" : arch === SupportedArch.X64 ? "x64" : "arm64";
|
|
252
257
|
const assetName = assetPattern.replace("{os}", OS_LABELS[os]).replace("{arch}", archLabel);
|
|
253
258
|
const url = `https://github.com/${owner}/${repo}/releases/latest/download/${assetName}`;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
259
|
+
// Downloading the release asset happens outside SpawnService (which enters long-running mode
|
|
260
|
+
// for its own subprocesses by default), so bracket it here to get the same cooperative
|
|
261
|
+
// Ctrl-C handling during what can be the slowest step of the upgrade.
|
|
262
|
+
this.#shutdownService?.enterLongRunningMode();
|
|
263
|
+
let archiveData;
|
|
264
|
+
try {
|
|
265
|
+
const response = await fetch(url);
|
|
266
|
+
if (!response.ok) {
|
|
267
|
+
throw new Error(`Failed to download release asset '${assetName}': HTTP ${response.status}`);
|
|
268
|
+
}
|
|
269
|
+
archiveData = await response.arrayBuffer();
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
this.#shutdownService?.leaveLongRunningMode();
|
|
257
273
|
}
|
|
258
274
|
const tmpDir = await mkdtemp(join(tmpdir(), "upgrade-"));
|
|
259
275
|
const archivePath = join(tmpDir, assetName);
|
|
260
|
-
await Bun.write(archivePath,
|
|
276
|
+
await Bun.write(archivePath, archiveData);
|
|
261
277
|
const currentExecutable = process.execPath;
|
|
262
278
|
if (os === SupportedOs.WINDOWS) {
|
|
263
279
|
const extractResult = await this.#spawnService.spawn([
|
|
@@ -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;
|
|
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;CAgH1D"}
|
|
@@ -2,6 +2,7 @@ import { UPGRADE_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
|
2
2
|
import { PROMPTER_SERVICE_ID, PromptType } from "@flowscripter/dynamic-cli-framework-api";
|
|
3
3
|
import { KEY_VALUE_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
4
4
|
import { SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
5
|
+
import { SHUTDOWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
5
6
|
import { Icon, PRINTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
6
7
|
import DefaultUpgradeService from "./DefaultUpgradeService.js";
|
|
7
8
|
import { UpgradeSubCommand } from "./command/UpgradeSubCommand.js";
|
|
@@ -30,7 +31,10 @@ export default class UpgradeServiceProvider {
|
|
|
30
31
|
const cliConfig = this.#cliConfig;
|
|
31
32
|
if (context.doesServiceExist(SPAWN_SERVICE_ID)) {
|
|
32
33
|
const spawnService = context.getServiceById(SPAWN_SERVICE_ID);
|
|
33
|
-
|
|
34
|
+
const shutdownService = context.doesServiceExist(SHUTDOWN_SERVICE_ID)
|
|
35
|
+
? context.getServiceById(SHUTDOWN_SERVICE_ID)
|
|
36
|
+
: undefined;
|
|
37
|
+
upgradeService.setDependencies(spawnService, shutdownService);
|
|
34
38
|
}
|
|
35
39
|
else {
|
|
36
40
|
logger.debug(() => "SpawnService not available, upgrade install methods will be unavailable");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowscripter/dynamic-cli-framework",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"description": "A framework for developing CLI applications which supports dynamic discovery and installation of new commands",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@flowscripter/dynamic-cli-framework-api": "^1.2.0",
|
|
52
|
-
"@flowscripter/dynamic-plugin-framework": "1.11.
|
|
52
|
+
"@flowscripter/dynamic-plugin-framework": "1.11.1",
|
|
53
53
|
"emphasize": "^7.0.0",
|
|
54
54
|
"fastest-levenshtein": "^1.0.16",
|
|
55
55
|
"figlet": "^1.11.0",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import process from "node:process";
|
|
1
2
|
import type {
|
|
2
3
|
PrinterService,
|
|
3
4
|
ShutdownService,
|
|
@@ -11,6 +12,26 @@ const logger = getLogger("DefaultSpawnService");
|
|
|
11
12
|
|
|
12
13
|
const SHUTDOWN_GRACE_PERIOD_MS = 5000;
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* On Windows, batch-file shims (e.g. `npm.cmd`, `bun.cmd`) cannot be launched directly via
|
|
17
|
+
* `CreateProcess` - they must be run through `cmd.exe /c`. Resolve the command through the shell
|
|
18
|
+
* in that case; leave it untouched on other platforms.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveForPlatform(command: ReadonlyArray<string>): string[] {
|
|
21
|
+
if (process.platform !== "win32") {
|
|
22
|
+
return [...command];
|
|
23
|
+
}
|
|
24
|
+
const [bin, ...args] = command;
|
|
25
|
+
if (bin === undefined) {
|
|
26
|
+
return [...command];
|
|
27
|
+
}
|
|
28
|
+
const resolved = Bun.which(bin) ?? bin;
|
|
29
|
+
if (!/\.(cmd|bat)$/i.test(resolved)) {
|
|
30
|
+
return [resolved, ...args];
|
|
31
|
+
}
|
|
32
|
+
return ["cmd.exe", "/d", "/s", "/c", resolved, ...args];
|
|
33
|
+
}
|
|
34
|
+
|
|
14
35
|
export default class DefaultSpawnService implements SpawnService {
|
|
15
36
|
#printerService: PrinterService | undefined;
|
|
16
37
|
#shutdownService: ShutdownService | undefined;
|
|
@@ -68,7 +89,7 @@ export default class DefaultSpawnService implements SpawnService {
|
|
|
68
89
|
|
|
69
90
|
let proc;
|
|
70
91
|
try {
|
|
71
|
-
proc = Bun.spawn(
|
|
92
|
+
proc = Bun.spawn(resolveForPlatform(command), {
|
|
72
93
|
cwd: options.cwd,
|
|
73
94
|
stdin: stdio === "wrapped" ? "ignore" : "inherit",
|
|
74
95
|
stdout: stdio === "wrapped" ? "pipe" : "inherit",
|
|
@@ -4,6 +4,7 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import type {
|
|
6
6
|
CLIConfig,
|
|
7
|
+
ShutdownService,
|
|
7
8
|
SpawnService,
|
|
8
9
|
UpgradeCheckResult,
|
|
9
10
|
UpgradeResult,
|
|
@@ -20,6 +21,10 @@ import getLogger from "../../util/logger.ts";
|
|
|
20
21
|
|
|
21
22
|
const logger = getLogger("DefaultUpgradeService");
|
|
22
23
|
|
|
24
|
+
// 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
|
+
|
|
23
28
|
const OS_LABELS: Record<SupportedOs, string> = {
|
|
24
29
|
[SupportedOs.LINUX]: "Linux",
|
|
25
30
|
[SupportedOs.MACOS]: "MacOS",
|
|
@@ -28,6 +33,7 @@ const OS_LABELS: Record<SupportedOs, string> = {
|
|
|
28
33
|
|
|
29
34
|
export default class DefaultUpgradeService implements UpgradeService {
|
|
30
35
|
#spawnService: SpawnService | undefined;
|
|
36
|
+
#shutdownService: ShutdownService | undefined;
|
|
31
37
|
readonly #config: UpgradeLocationsConfig;
|
|
32
38
|
readonly #cliConfig: CLIConfig;
|
|
33
39
|
|
|
@@ -36,8 +42,9 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
36
42
|
this.#cliConfig = cliConfig;
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
public setDependencies(spawnService: SpawnService): void {
|
|
45
|
+
public setDependencies(spawnService: SpawnService, shutdownService?: ShutdownService): void {
|
|
40
46
|
this.#spawnService = spawnService;
|
|
47
|
+
this.#shutdownService = shutdownService;
|
|
41
48
|
}
|
|
42
49
|
|
|
43
50
|
public detectOs(): SupportedOs | undefined {
|
|
@@ -210,7 +217,10 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
210
217
|
}
|
|
211
218
|
const { owner, repo } = this.#config.githubRelease;
|
|
212
219
|
try {
|
|
213
|
-
const response = await fetch(
|
|
220
|
+
const response = await fetch(
|
|
221
|
+
`https://api.github.com/repos/${owner}/${repo}/releases/latest`,
|
|
222
|
+
{ signal: AbortSignal.timeout(VERSION_CHECK_TIMEOUT_MS) },
|
|
223
|
+
);
|
|
214
224
|
if (!response.ok) {
|
|
215
225
|
return undefined;
|
|
216
226
|
}
|
|
@@ -234,6 +244,7 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
234
244
|
try {
|
|
235
245
|
const response = await fetch(
|
|
236
246
|
`https://raw.githubusercontent.com/${tapOwner}/homebrew-${tapName}/main/${formula}.rb`,
|
|
247
|
+
{ signal: AbortSignal.timeout(VERSION_CHECK_TIMEOUT_MS) },
|
|
237
248
|
);
|
|
238
249
|
if (!response.ok) {
|
|
239
250
|
return undefined;
|
|
@@ -316,14 +327,24 @@ export default class DefaultUpgradeService implements UpgradeService {
|
|
|
316
327
|
const assetName = assetPattern.replace("{os}", OS_LABELS[os]).replace("{arch}", archLabel);
|
|
317
328
|
const url = `https://github.com/${owner}/${repo}/releases/latest/download/${assetName}`;
|
|
318
329
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
330
|
+
// Downloading the release asset happens outside SpawnService (which enters long-running mode
|
|
331
|
+
// for its own subprocesses by default), so bracket it here to get the same cooperative
|
|
332
|
+
// Ctrl-C handling during what can be the slowest step of the upgrade.
|
|
333
|
+
this.#shutdownService?.enterLongRunningMode();
|
|
334
|
+
let archiveData: ArrayBuffer;
|
|
335
|
+
try {
|
|
336
|
+
const response = await fetch(url);
|
|
337
|
+
if (!response.ok) {
|
|
338
|
+
throw new Error(`Failed to download release asset '${assetName}': HTTP ${response.status}`);
|
|
339
|
+
}
|
|
340
|
+
archiveData = await response.arrayBuffer();
|
|
341
|
+
} finally {
|
|
342
|
+
this.#shutdownService?.leaveLongRunningMode();
|
|
322
343
|
}
|
|
323
344
|
|
|
324
345
|
const tmpDir = await mkdtemp(join(tmpdir(), "upgrade-"));
|
|
325
346
|
const archivePath = join(tmpDir, assetName);
|
|
326
|
-
await Bun.write(archivePath,
|
|
347
|
+
await Bun.write(archivePath, archiveData);
|
|
327
348
|
|
|
328
349
|
const currentExecutable = process.execPath;
|
|
329
350
|
|
|
@@ -8,6 +8,8 @@ import { KEY_VALUE_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
|
8
8
|
import type { KeyValueService } from "@flowscripter/dynamic-cli-framework-api";
|
|
9
9
|
import { SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
10
10
|
import type { SpawnService } from "@flowscripter/dynamic-cli-framework-api";
|
|
11
|
+
import { SHUTDOWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
12
|
+
import type { ShutdownService } from "@flowscripter/dynamic-cli-framework-api";
|
|
11
13
|
import { Icon, PRINTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
12
14
|
import type { PrinterService } from "@flowscripter/dynamic-cli-framework-api";
|
|
13
15
|
import DefaultUpgradeService from "./DefaultUpgradeService.ts";
|
|
@@ -44,7 +46,10 @@ export default class UpgradeServiceProvider implements ServiceProvider {
|
|
|
44
46
|
|
|
45
47
|
if (context.doesServiceExist(SPAWN_SERVICE_ID)) {
|
|
46
48
|
const spawnService = context.getServiceById(SPAWN_SERVICE_ID) as SpawnService;
|
|
47
|
-
|
|
49
|
+
const shutdownService = context.doesServiceExist(SHUTDOWN_SERVICE_ID)
|
|
50
|
+
? (context.getServiceById(SHUTDOWN_SERVICE_ID) as ShutdownService)
|
|
51
|
+
: undefined;
|
|
52
|
+
upgradeService.setDependencies(spawnService, shutdownService);
|
|
48
53
|
} else {
|
|
49
54
|
logger.debug(() => "SpawnService not available, upgrade install methods will be unavailable");
|
|
50
55
|
}
|