reset-framework-cli 1.1.5 → 1.2.1
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/LICENSE +20 -20
- package/README.md +57 -47
- package/package.json +8 -4
- package/src/commands/build.js +125 -113
- package/src/commands/dev.js +156 -144
- package/src/commands/doctor.js +137 -89
- package/src/commands/init.js +822 -822
- package/src/commands/package.js +41 -41
- package/src/index.js +215 -213
- package/src/lib/context.js +66 -66
- package/src/lib/framework.js +126 -39
- package/src/lib/logger.js +11 -11
- package/src/lib/output.js +147 -147
- package/src/lib/process.js +148 -148
- package/src/lib/project.js +759 -468
- package/src/lib/toolchain.js +62 -62
- package/src/lib/ui.js +244 -244
- package/templates/basic/README.md +15 -15
- package/templates/basic/frontend/README.md +73 -73
- package/templates/basic/frontend/eslint.config.js +23 -23
- package/templates/basic/frontend/index.html +13 -13
- package/templates/basic/frontend/package.json +31 -31
- package/templates/basic/frontend/public/icons.svg +24 -24
- package/templates/basic/frontend/src/App.css +216 -216
- package/templates/basic/frontend/src/App.tsx +77 -77
- package/templates/basic/frontend/src/assets/vite.svg +1 -1
- package/templates/basic/frontend/src/index.css +111 -111
- package/templates/basic/frontend/src/lib/reset.ts +1 -1
- package/templates/basic/frontend/src/main.tsx +10 -10
- package/templates/basic/frontend/tsconfig.app.json +28 -28
- package/templates/basic/frontend/tsconfig.json +7 -7
- package/templates/basic/frontend/tsconfig.node.json +26 -26
- package/templates/basic/frontend/vite.config.ts +16 -16
- package/templates/basic/reset.config.json +58 -58
package/src/lib/output.js
CHANGED
|
@@ -8,93 +8,93 @@ import {
|
|
|
8
8
|
resolveFrameworkRuntimeBinary,
|
|
9
9
|
resolveFrameworkRuntimeOutputDir
|
|
10
10
|
} from "./project.js"
|
|
11
|
-
|
|
12
|
-
function escapePlistString(value) {
|
|
13
|
-
return value
|
|
14
|
-
.replaceAll("&", "&")
|
|
15
|
-
.replaceAll("<", "<")
|
|
16
|
-
.replaceAll(">", ">")
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function serializePlistValue(value, indentLevel = 1) {
|
|
20
|
-
const indent = " ".repeat(indentLevel)
|
|
21
|
-
|
|
22
|
-
if (Array.isArray(value)) {
|
|
23
|
-
if (value.length === 0) {
|
|
24
|
-
return `${indent}<array/>\n`
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
`${indent}<array>\n` +
|
|
29
|
-
value.map((entry) => serializePlistValue(entry, indentLevel + 1)).join("") +
|
|
30
|
-
`${indent}</array>\n`
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (typeof value === "object" && value !== null) {
|
|
35
|
-
const entries = Object.entries(value)
|
|
36
|
-
if (entries.length === 0) {
|
|
37
|
-
return `${indent}<dict/>\n`
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
`${indent}<dict>\n` +
|
|
42
|
-
entries
|
|
43
|
-
.map(
|
|
44
|
-
([key, entryValue]) =>
|
|
45
|
-
`${" ".repeat(indentLevel + 1)}<key>${escapePlistString(key)}</key>\n${serializePlistValue(entryValue, indentLevel + 1)}`
|
|
46
|
-
)
|
|
47
|
-
.join("") +
|
|
48
|
-
`${indent}</dict>\n`
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (typeof value === "boolean") {
|
|
53
|
-
return `${indent}<${value ? "true" : "false"}/>\n`
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (typeof value === "number") {
|
|
57
|
-
return `${indent}<integer>${value}</integer>\n`
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return `${indent}<string>${escapePlistString(String(value))}</string>\n`
|
|
61
|
-
}
|
|
62
|
-
|
|
11
|
+
|
|
12
|
+
function escapePlistString(value) {
|
|
13
|
+
return value
|
|
14
|
+
.replaceAll("&", "&")
|
|
15
|
+
.replaceAll("<", "<")
|
|
16
|
+
.replaceAll(">", ">")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function serializePlistValue(value, indentLevel = 1) {
|
|
20
|
+
const indent = " ".repeat(indentLevel)
|
|
21
|
+
|
|
22
|
+
if (Array.isArray(value)) {
|
|
23
|
+
if (value.length === 0) {
|
|
24
|
+
return `${indent}<array/>\n`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
`${indent}<array>\n` +
|
|
29
|
+
value.map((entry) => serializePlistValue(entry, indentLevel + 1)).join("") +
|
|
30
|
+
`${indent}</array>\n`
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeof value === "object" && value !== null) {
|
|
35
|
+
const entries = Object.entries(value)
|
|
36
|
+
if (entries.length === 0) {
|
|
37
|
+
return `${indent}<dict/>\n`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
`${indent}<dict>\n` +
|
|
42
|
+
entries
|
|
43
|
+
.map(
|
|
44
|
+
([key, entryValue]) =>
|
|
45
|
+
`${" ".repeat(indentLevel + 1)}<key>${escapePlistString(key)}</key>\n${serializePlistValue(entryValue, indentLevel + 1)}`
|
|
46
|
+
)
|
|
47
|
+
.join("") +
|
|
48
|
+
`${indent}</dict>\n`
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (typeof value === "boolean") {
|
|
53
|
+
return `${indent}<${value ? "true" : "false"}/>\n`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (typeof value === "number") {
|
|
57
|
+
return `${indent}<integer>${value}</integer>\n`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return `${indent}<string>${escapePlistString(String(value))}</string>\n`
|
|
61
|
+
}
|
|
62
|
+
|
|
63
63
|
function buildMacOSInfoPlist(config) {
|
|
64
|
-
const urlTypes = Array.isArray(config.protocols?.schemes)
|
|
65
|
-
? config.protocols.schemes.map((schemeConfig) => ({
|
|
66
|
-
CFBundleTypeRole: schemeConfig.role ?? "Viewer",
|
|
67
|
-
CFBundleURLName:
|
|
68
|
-
typeof schemeConfig.name === "string" && schemeConfig.name.trim() !== ""
|
|
69
|
-
? schemeConfig.name
|
|
70
|
-
: `${config.appId}.${schemeConfig.scheme}`,
|
|
71
|
-
CFBundleURLSchemes: [schemeConfig.scheme]
|
|
72
|
-
}))
|
|
73
|
-
: []
|
|
74
|
-
|
|
75
|
-
const plist = {
|
|
76
|
-
CFBundleDevelopmentRegion: "English",
|
|
77
|
-
CFBundleDisplayName: config.productName,
|
|
78
|
-
CFBundleExecutable: "reset-framework",
|
|
79
|
-
CFBundleIdentifier: config.appId,
|
|
80
|
-
CFBundleInfoDictionaryVersion: "6.0",
|
|
81
|
-
CFBundleName: config.productName,
|
|
82
|
-
CFBundlePackageType: "APPL",
|
|
83
|
-
CFBundleShortVersionString: config.version,
|
|
84
|
-
CFBundleVersion: config.version,
|
|
85
|
-
CSResourcesFileMapped: true
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (urlTypes.length > 0) {
|
|
89
|
-
plist.CFBundleURLTypes = urlTypes
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
`<?xml version="1.0" encoding="UTF-8"?>\n` +
|
|
94
|
-
`<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n` +
|
|
95
|
-
`<plist version="1.0">\n` +
|
|
96
|
-
serializePlistValue(plist, 0) +
|
|
97
|
-
`</plist>\n`
|
|
64
|
+
const urlTypes = Array.isArray(config.protocols?.schemes)
|
|
65
|
+
? config.protocols.schemes.map((schemeConfig) => ({
|
|
66
|
+
CFBundleTypeRole: schemeConfig.role ?? "Viewer",
|
|
67
|
+
CFBundleURLName:
|
|
68
|
+
typeof schemeConfig.name === "string" && schemeConfig.name.trim() !== ""
|
|
69
|
+
? schemeConfig.name
|
|
70
|
+
: `${config.appId}.${schemeConfig.scheme}`,
|
|
71
|
+
CFBundleURLSchemes: [schemeConfig.scheme]
|
|
72
|
+
}))
|
|
73
|
+
: []
|
|
74
|
+
|
|
75
|
+
const plist = {
|
|
76
|
+
CFBundleDevelopmentRegion: "English",
|
|
77
|
+
CFBundleDisplayName: config.productName,
|
|
78
|
+
CFBundleExecutable: "reset-framework",
|
|
79
|
+
CFBundleIdentifier: config.appId,
|
|
80
|
+
CFBundleInfoDictionaryVersion: "6.0",
|
|
81
|
+
CFBundleName: config.productName,
|
|
82
|
+
CFBundlePackageType: "APPL",
|
|
83
|
+
CFBundleShortVersionString: config.version,
|
|
84
|
+
CFBundleVersion: config.version,
|
|
85
|
+
CSResourcesFileMapped: true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (urlTypes.length > 0) {
|
|
89
|
+
plist.CFBundleURLTypes = urlTypes
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
`<?xml version="1.0" encoding="UTF-8"?>\n` +
|
|
94
|
+
`<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n` +
|
|
95
|
+
`<plist version="1.0">\n` +
|
|
96
|
+
serializePlistValue(plist, 0) +
|
|
97
|
+
`</plist>\n`
|
|
98
98
|
)
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -116,59 +116,59 @@ function shouldCopyWindowsRuntimeArtifact(entryName) {
|
|
|
116
116
|
function escapePowerShellLiteral(value) {
|
|
117
117
|
return String(value).replaceAll("'", "''")
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
export async function stageMacOSAppBundle(
|
|
121
|
-
const { dryRun = false, outputPaths, configPath } = options
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (!
|
|
128
|
-
throw new Error(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
logger.info(`- copy ${
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
await
|
|
149
|
-
|
|
150
|
-
await
|
|
151
|
-
|
|
152
|
-
await
|
|
153
|
-
await cp(
|
|
154
|
-
await
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
161
|
-
|
|
119
|
+
|
|
120
|
+
export async function stageMacOSAppBundle(frameworkPaths, frameworkBuildPaths, config, options = {}) {
|
|
121
|
+
const { dryRun = false, outputPaths, configPath, preferSource = false } = options
|
|
122
|
+
const runtimeSourceBundle = resolveFrameworkRuntimeOutputDir(frameworkPaths, frameworkBuildPaths, "release", {
|
|
123
|
+
mustExist: !dryRun,
|
|
124
|
+
preferSource
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
if (!outputPaths) {
|
|
128
|
+
throw new Error("stageMacOSAppBundle requires resolved output paths")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!existsSync(outputPaths.frontendEntryFile) && !dryRun) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`Missing frontend build output at ${outputPaths.frontendEntryFile}. Run the frontend build first.`
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
logger.info(`Staging app bundle into ${outputPaths.appBundlePath}`)
|
|
138
|
+
|
|
139
|
+
if (dryRun) {
|
|
140
|
+
logger.info(`- copy ${runtimeSourceBundle} -> ${outputPaths.appBundlePath}`)
|
|
141
|
+
logger.info(`- copy ${configPath} -> ${outputPaths.bundledConfigPath}`)
|
|
142
|
+
logger.info(`- copy ${outputPaths.frontendDistDir} -> ${outputPaths.bundledFrontendDir}`)
|
|
143
|
+
return outputPaths
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
await mkdir(outputPaths.macosDir, { recursive: true })
|
|
147
|
+
await rm(outputPaths.appBundlePath, { recursive: true, force: true })
|
|
148
|
+
await cp(runtimeSourceBundle, outputPaths.appBundlePath, { recursive: true })
|
|
149
|
+
|
|
150
|
+
await mkdir(outputPaths.resourcesDir, { recursive: true })
|
|
151
|
+
await cp(configPath, outputPaths.bundledConfigPath, { force: true })
|
|
152
|
+
await rm(outputPaths.bundledFrontendDir, { recursive: true, force: true })
|
|
153
|
+
await cp(outputPaths.frontendDistDir, outputPaths.bundledFrontendDir, { recursive: true })
|
|
154
|
+
await writeFile(
|
|
155
|
+
path.join(outputPaths.appBundlePath, "Contents", "Info.plist"),
|
|
156
|
+
buildMacOSInfoPlist(config),
|
|
157
|
+
"utf8"
|
|
158
|
+
)
|
|
159
|
+
|
|
162
160
|
return outputPaths
|
|
163
161
|
}
|
|
164
162
|
|
|
165
|
-
export async function stageWindowsAppBundle(
|
|
166
|
-
const { dryRun = false, outputPaths, configPath } = options
|
|
167
|
-
const runtimeSourceBinary = resolveFrameworkRuntimeBinary(frameworkBuildPaths, "release", {
|
|
168
|
-
mustExist: !dryRun
|
|
163
|
+
export async function stageWindowsAppBundle(frameworkPaths, frameworkBuildPaths, config, options = {}) {
|
|
164
|
+
const { dryRun = false, outputPaths, configPath, preferSource = false } = options
|
|
165
|
+
const runtimeSourceBinary = resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPaths, "release", {
|
|
166
|
+
mustExist: !dryRun,
|
|
167
|
+
preferSource
|
|
169
168
|
})
|
|
170
|
-
const runtimeSourceDir = resolveFrameworkRuntimeOutputDir(frameworkBuildPaths, "release", {
|
|
171
|
-
mustExist: !dryRun
|
|
169
|
+
const runtimeSourceDir = resolveFrameworkRuntimeOutputDir(frameworkPaths, frameworkBuildPaths, "release", {
|
|
170
|
+
mustExist: !dryRun,
|
|
171
|
+
preferSource
|
|
172
172
|
})
|
|
173
173
|
|
|
174
174
|
if (!outputPaths) {
|
|
@@ -218,20 +218,20 @@ export async function stageWindowsAppBundle(frameworkBuildPaths, appPaths, confi
|
|
|
218
218
|
|
|
219
219
|
return outputPaths
|
|
220
220
|
}
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
export async function createMacOSZipArchive(outputPaths, options = {}) {
|
|
223
223
|
const { dryRun = false } = options
|
|
224
|
-
|
|
225
|
-
logger.info(`Packaging ${outputPaths.appBundlePath} -> ${outputPaths.zipPath}`)
|
|
226
|
-
|
|
227
|
-
if (process.platform !== "darwin") {
|
|
228
|
-
throw new Error("Packaging is only implemented for macOS right now")
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (!dryRun) {
|
|
232
|
-
await mkdir(outputPaths.packagesDir, { recursive: true })
|
|
233
|
-
}
|
|
234
|
-
|
|
224
|
+
|
|
225
|
+
logger.info(`Packaging ${outputPaths.appBundlePath} -> ${outputPaths.zipPath}`)
|
|
226
|
+
|
|
227
|
+
if (process.platform !== "darwin") {
|
|
228
|
+
throw new Error("Packaging is only implemented for macOS right now")
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (!dryRun) {
|
|
232
|
+
await mkdir(outputPaths.packagesDir, { recursive: true })
|
|
233
|
+
}
|
|
234
|
+
|
|
235
235
|
await runCommand(
|
|
236
236
|
"ditto",
|
|
237
237
|
["-c", "-k", "--sequesterRsrc", "--keepParent", outputPaths.appBundlePath, outputPaths.zipPath],
|
package/src/lib/process.js
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process"
|
|
2
|
-
|
|
3
|
-
import { logger } from "./logger.js"
|
|
4
|
-
|
|
5
|
-
function sleep(ms) {
|
|
6
|
-
return new Promise((resolve) => {
|
|
7
|
-
setTimeout(resolve, ms)
|
|
8
|
-
})
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function resolveNpmCommand() {
|
|
12
|
-
return process.platform === "win32" ? "npm.cmd" : "npm"
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function resolvePackageManagerCommand(packageManager = "npm") {
|
|
16
|
-
if (packageManager === "npm") {
|
|
17
|
-
return resolveNpmCommand()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (packageManager === "yarn") {
|
|
21
|
-
return process.platform === "win32" ? "yarn.cmd" : "yarn"
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (packageManager === "pnpm") {
|
|
25
|
-
return process.platform === "win32" ? "pnpm.cmd" : "pnpm"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (packageManager === "bun") {
|
|
29
|
-
return process.platform === "win32" ? "bun.exe" : "bun"
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
throw new Error(`Unsupported package manager: ${packageManager}`)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function getInstallCommandArgs(packageManager = "npm") {
|
|
36
|
-
if (packageManager === "npm") {
|
|
37
|
-
return ["install", "--include=optional"]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (packageManager === "yarn") {
|
|
41
|
-
return ["install"]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return ["install"]
|
|
45
|
-
}
|
|
46
|
-
|
|
2
|
+
|
|
3
|
+
import { logger } from "./logger.js"
|
|
4
|
+
|
|
5
|
+
function sleep(ms) {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
setTimeout(resolve, ms)
|
|
8
|
+
})
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function resolveNpmCommand() {
|
|
12
|
+
return process.platform === "win32" ? "npm.cmd" : "npm"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resolvePackageManagerCommand(packageManager = "npm") {
|
|
16
|
+
if (packageManager === "npm") {
|
|
17
|
+
return resolveNpmCommand()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (packageManager === "yarn") {
|
|
21
|
+
return process.platform === "win32" ? "yarn.cmd" : "yarn"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (packageManager === "pnpm") {
|
|
25
|
+
return process.platform === "win32" ? "pnpm.cmd" : "pnpm"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (packageManager === "bun") {
|
|
29
|
+
return process.platform === "win32" ? "bun.exe" : "bun"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw new Error(`Unsupported package manager: ${packageManager}`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getInstallCommandArgs(packageManager = "npm") {
|
|
36
|
+
if (packageManager === "npm") {
|
|
37
|
+
return ["install", "--include=optional"]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (packageManager === "yarn") {
|
|
41
|
+
return ["install"]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return ["install"]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
47
|
export function formatCommand(command, args = []) {
|
|
48
48
|
return [command, ...args].join(" ")
|
|
49
49
|
}
|
|
@@ -56,11 +56,11 @@ export async function runCommand(command, args = [], options = {}) {
|
|
|
56
56
|
const { cwd, dryRun = false, env } = options
|
|
57
57
|
|
|
58
58
|
logger.info(`$ ${formatCommand(command, args)}`)
|
|
59
|
-
|
|
60
|
-
if (dryRun) {
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
|
|
59
|
+
|
|
60
|
+
if (dryRun) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
64
|
await new Promise((resolve, reject) => {
|
|
65
65
|
const child = spawn(command, args, {
|
|
66
66
|
cwd,
|
|
@@ -70,28 +70,28 @@ export async function runCommand(command, args = [], options = {}) {
|
|
|
70
70
|
})
|
|
71
71
|
|
|
72
72
|
child.once("error", reject)
|
|
73
|
-
child.once("exit", (code, signal) => {
|
|
74
|
-
if (code === 0) {
|
|
75
|
-
resolve(undefined)
|
|
76
|
-
return
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
reject(
|
|
80
|
-
new Error(
|
|
81
|
-
signal
|
|
82
|
-
? `Command terminated by signal: ${signal}`
|
|
83
|
-
: `Command exited with code ${code}`
|
|
84
|
-
)
|
|
85
|
-
)
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export async function captureCommandOutput(command, args = [], options = {}) {
|
|
91
|
-
const { cwd, env } = options
|
|
92
|
-
|
|
93
|
-
await Promise.resolve()
|
|
94
|
-
|
|
73
|
+
child.once("exit", (code, signal) => {
|
|
74
|
+
if (code === 0) {
|
|
75
|
+
resolve(undefined)
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
reject(
|
|
80
|
+
new Error(
|
|
81
|
+
signal
|
|
82
|
+
? `Command terminated by signal: ${signal}`
|
|
83
|
+
: `Command exited with code ${code}`
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function captureCommandOutput(command, args = [], options = {}) {
|
|
91
|
+
const { cwd, env } = options
|
|
92
|
+
|
|
93
|
+
await Promise.resolve()
|
|
94
|
+
|
|
95
95
|
return await new Promise((resolve, reject) => {
|
|
96
96
|
const child = spawn(command, args, {
|
|
97
97
|
cwd,
|
|
@@ -99,45 +99,45 @@ export async function captureCommandOutput(command, args = [], options = {}) {
|
|
|
99
99
|
stdio: ["ignore", "pipe", "pipe"],
|
|
100
100
|
shell: shouldUseShell(command)
|
|
101
101
|
})
|
|
102
|
-
|
|
103
|
-
let stdout = ""
|
|
104
|
-
let stderr = ""
|
|
105
|
-
|
|
106
|
-
child.stdout?.on("data", (chunk) => {
|
|
107
|
-
stdout += String(chunk)
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
child.stderr?.on("data", (chunk) => {
|
|
111
|
-
stderr += String(chunk)
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
child.once("error", reject)
|
|
115
|
-
child.once("exit", (code, signal) => {
|
|
116
|
-
if (code === 0) {
|
|
117
|
-
resolve(stdout.trim())
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
reject(
|
|
122
|
-
new Error(
|
|
123
|
-
signal
|
|
124
|
-
? `Command terminated by signal: ${signal}`
|
|
125
|
-
: (stderr.trim() || stdout.trim() || `Command exited with code ${code}`)
|
|
126
|
-
)
|
|
127
|
-
)
|
|
128
|
-
})
|
|
129
|
-
})
|
|
130
|
-
}
|
|
131
|
-
|
|
102
|
+
|
|
103
|
+
let stdout = ""
|
|
104
|
+
let stderr = ""
|
|
105
|
+
|
|
106
|
+
child.stdout?.on("data", (chunk) => {
|
|
107
|
+
stdout += String(chunk)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
child.stderr?.on("data", (chunk) => {
|
|
111
|
+
stderr += String(chunk)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
child.once("error", reject)
|
|
115
|
+
child.once("exit", (code, signal) => {
|
|
116
|
+
if (code === 0) {
|
|
117
|
+
resolve(stdout.trim())
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
reject(
|
|
122
|
+
new Error(
|
|
123
|
+
signal
|
|
124
|
+
? `Command terminated by signal: ${signal}`
|
|
125
|
+
: (stderr.trim() || stdout.trim() || `Command exited with code ${code}`)
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
132
|
export function spawnCommand(command, args = [], options = {}) {
|
|
133
133
|
const { cwd, dryRun = false, env } = options
|
|
134
134
|
|
|
135
135
|
logger.info(`$ ${formatCommand(command, args)}`)
|
|
136
|
-
|
|
137
|
-
if (dryRun) {
|
|
138
|
-
return null
|
|
139
|
-
}
|
|
140
|
-
|
|
136
|
+
|
|
137
|
+
if (dryRun) {
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
141
|
return spawn(command, args, {
|
|
142
142
|
cwd,
|
|
143
143
|
env: env ? { ...process.env, ...env } : process.env,
|
|
@@ -146,27 +146,27 @@ export function spawnCommand(command, args = [], options = {}) {
|
|
|
146
146
|
shell: shouldUseShell(command)
|
|
147
147
|
})
|
|
148
148
|
}
|
|
149
|
-
|
|
150
|
-
export function waitForProcessExit(child, label) {
|
|
151
|
-
return new Promise((resolve, reject) => {
|
|
152
|
-
child.once("error", reject)
|
|
153
|
-
child.once("exit", (code, signal) => {
|
|
154
|
-
if (code === 0 || signal === "SIGINT" || signal === "SIGTERM") {
|
|
155
|
-
resolve(undefined)
|
|
156
|
-
return
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
reject(
|
|
160
|
-
new Error(
|
|
161
|
-
signal
|
|
162
|
-
? `${label} terminated by signal: ${signal}`
|
|
163
|
-
: `${label} exited with code ${code}`
|
|
164
|
-
)
|
|
165
|
-
)
|
|
166
|
-
})
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
|
|
149
|
+
|
|
150
|
+
export function waitForProcessExit(child, label) {
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
child.once("error", reject)
|
|
153
|
+
child.once("exit", (code, signal) => {
|
|
154
|
+
if (code === 0 || signal === "SIGINT" || signal === "SIGTERM") {
|
|
155
|
+
resolve(undefined)
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
reject(
|
|
160
|
+
new Error(
|
|
161
|
+
signal
|
|
162
|
+
? `${label} terminated by signal: ${signal}`
|
|
163
|
+
: `${label} exited with code ${code}`
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
170
|
export function registerChildCleanup(children) {
|
|
171
171
|
const activeChildren = children.filter(Boolean)
|
|
172
172
|
let cleanupPromise = null
|
|
@@ -281,23 +281,23 @@ export function registerChildCleanup(children) {
|
|
|
281
281
|
await cleanup()
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
|
-
|
|
285
|
-
export async function waitForUrl(url, options = {}) {
|
|
286
|
-
const { intervalMs = 250, timeoutMs = 15000 } = options
|
|
287
|
-
const deadline = Date.now() + timeoutMs
|
|
288
|
-
|
|
289
|
-
while (Date.now() < deadline) {
|
|
290
|
-
try {
|
|
291
|
-
const response = await fetch(url)
|
|
292
|
-
if (response.status < 500) {
|
|
293
|
-
return
|
|
294
|
-
}
|
|
295
|
-
} catch {
|
|
296
|
-
// Retry until timeout.
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
await sleep(intervalMs)
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
throw new Error(`Timed out waiting for ${url}`)
|
|
303
|
-
}
|
|
284
|
+
|
|
285
|
+
export async function waitForUrl(url, options = {}) {
|
|
286
|
+
const { intervalMs = 250, timeoutMs = 15000 } = options
|
|
287
|
+
const deadline = Date.now() + timeoutMs
|
|
288
|
+
|
|
289
|
+
while (Date.now() < deadline) {
|
|
290
|
+
try {
|
|
291
|
+
const response = await fetch(url)
|
|
292
|
+
if (response.status < 500) {
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
// Retry until timeout.
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
await sleep(intervalMs)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
throw new Error(`Timed out waiting for ${url}`)
|
|
303
|
+
}
|