reset-framework-cli 1.1.2 → 1.1.4
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 +47 -47
- package/package.json +4 -4
- package/src/commands/build.js +114 -113
- package/src/commands/dev.js +157 -153
- package/src/commands/doctor.js +89 -89
- package/src/commands/init.js +925 -920
- package/src/commands/package.js +49 -44
- package/src/index.js +213 -213
- package/src/lib/context.js +66 -66
- package/src/lib/framework.js +150 -28
- package/src/lib/logger.js +11 -11
- package/src/lib/output.js +214 -106
- package/src/lib/process.js +188 -181
- package/src/lib/project.js +559 -475
- 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 -138
- package/templates/basic/frontend/src/App.tsx +77 -76
- 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/framework.js
CHANGED
|
@@ -1,54 +1,176 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { rm } from "node:fs/promises"
|
|
3
|
+
import { readFile } from "node:fs/promises"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
|
|
6
|
+
import { captureCommandOutput, runCommand } from "./process.js"
|
|
2
7
|
import { ensureVcpkgToolchain } from "./toolchain.js"
|
|
8
|
+
|
|
9
|
+
function getBuildDirectory(frameworkBuildPaths, mode) {
|
|
10
|
+
return mode === "release"
|
|
11
|
+
? frameworkBuildPaths.releaseBuildDir
|
|
12
|
+
: frameworkBuildPaths.devBuildDir
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getBuildType(mode) {
|
|
16
|
+
return mode === "release" ? "Release" : "Debug"
|
|
17
|
+
}
|
|
3
18
|
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
19
|
+
function getVsWherePath() {
|
|
20
|
+
const candidates = [
|
|
21
|
+
path.join(process.env["ProgramFiles(x86)"] ?? "", "Microsoft Visual Studio", "Installer", "vswhere.exe"),
|
|
22
|
+
path.join(process.env.ProgramFiles ?? "", "Microsoft Visual Studio", "Installer", "vswhere.exe")
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
return candidates.find((candidate) => candidate && existsSync(candidate)) ?? null
|
|
8
26
|
}
|
|
9
27
|
|
|
10
|
-
function
|
|
11
|
-
|
|
28
|
+
async function findVisualStudioGenerator() {
|
|
29
|
+
const vswherePath = getVsWherePath()
|
|
30
|
+
if (!vswherePath) {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const version = await captureCommandOutput(vswherePath, [
|
|
36
|
+
"-latest",
|
|
37
|
+
"-products",
|
|
38
|
+
"*",
|
|
39
|
+
"-requires",
|
|
40
|
+
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
|
41
|
+
"-property",
|
|
42
|
+
"catalog_productLineVersion"
|
|
43
|
+
])
|
|
44
|
+
|
|
45
|
+
const normalized = String(version).trim()
|
|
46
|
+
if (normalized === "2022") {
|
|
47
|
+
return "Visual Studio 17 2022"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (normalized === "2019") {
|
|
51
|
+
return "Visual Studio 16 2019"
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
// Fall through to the default Windows generator if detection fails.
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return "Visual Studio 17 2022"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function resolveCmakeGenerator() {
|
|
61
|
+
const envGenerator =
|
|
62
|
+
typeof process.env.CMAKE_GENERATOR === "string" && process.env.CMAKE_GENERATOR.trim() !== ""
|
|
63
|
+
? process.env.CMAKE_GENERATOR.trim()
|
|
64
|
+
: null
|
|
65
|
+
|
|
66
|
+
if (envGenerator) {
|
|
67
|
+
return {
|
|
68
|
+
name: envGenerator,
|
|
69
|
+
configureArgs: process.platform === "win32" &&
|
|
70
|
+
!process.env.CMAKE_GENERATOR_PLATFORM &&
|
|
71
|
+
envGenerator.startsWith("Visual Studio ")
|
|
72
|
+
? ["-G", envGenerator, "-A", "x64"]
|
|
73
|
+
: ["-G", envGenerator],
|
|
74
|
+
buildArgs: envGenerator.startsWith("Visual Studio ")
|
|
75
|
+
? ["--config"]
|
|
76
|
+
: [],
|
|
77
|
+
multiConfig: envGenerator.startsWith("Visual Studio ")
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (process.platform === "win32") {
|
|
82
|
+
const generator = await findVisualStudioGenerator()
|
|
83
|
+
if (!generator) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
"Could not find a supported Visual Studio C++ installation. Install Visual Studio Build Tools or set CMAKE_GENERATOR manually."
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
name: generator,
|
|
91
|
+
configureArgs: ["-G", generator, "-A", "x64"],
|
|
92
|
+
buildArgs: ["--config"],
|
|
93
|
+
multiConfig: true
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
name: "Ninja",
|
|
99
|
+
configureArgs: ["-G", "Ninja"],
|
|
100
|
+
buildArgs: [],
|
|
101
|
+
multiConfig: false
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function ensureMatchingCmakeSource(buildDir, frameworkRoot) {
|
|
106
|
+
const cachePath = path.join(buildDir, "CMakeCache.txt")
|
|
107
|
+
if (!existsSync(cachePath)) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let cache
|
|
112
|
+
try {
|
|
113
|
+
cache = await readFile(cachePath, "utf8")
|
|
114
|
+
} catch {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const match = cache.match(/^CMAKE_HOME_DIRECTORY:INTERNAL=(.+)$/m)
|
|
119
|
+
if (!match) {
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const cachedRoot = path.resolve(match[1].trim())
|
|
124
|
+
const currentRoot = path.resolve(frameworkRoot)
|
|
125
|
+
|
|
126
|
+
if (cachedRoot !== currentRoot) {
|
|
127
|
+
await rm(buildDir, { recursive: true, force: true })
|
|
128
|
+
}
|
|
12
129
|
}
|
|
13
130
|
|
|
14
131
|
export async function configureFrameworkBuild(frameworkPaths, frameworkBuildPaths, mode, options = {}) {
|
|
15
132
|
const { dryRun = false, cwd } = options
|
|
16
133
|
const toolchainFile = await ensureVcpkgToolchain({ dryRun })
|
|
17
134
|
const buildDir = getBuildDirectory(frameworkBuildPaths, mode)
|
|
135
|
+
const generator = await resolveCmakeGenerator()
|
|
136
|
+
if (!dryRun) {
|
|
137
|
+
await ensureMatchingCmakeSource(buildDir, frameworkPaths.frameworkRoot)
|
|
138
|
+
}
|
|
139
|
+
const configureArgs = [
|
|
140
|
+
"-S",
|
|
141
|
+
frameworkPaths.frameworkRoot,
|
|
142
|
+
"-B",
|
|
143
|
+
buildDir,
|
|
144
|
+
...generator.configureArgs,
|
|
145
|
+
`-DCMAKE_BUILD_TYPE=${getBuildType(mode)}`,
|
|
146
|
+
"-DCMAKE_CXX_STANDARD=20",
|
|
147
|
+
"-DCMAKE_CXX_STANDARD_REQUIRED=ON",
|
|
148
|
+
"-DCMAKE_CXX_EXTENSIONS=OFF",
|
|
149
|
+
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
|
|
150
|
+
`-DCMAKE_TOOLCHAIN_FILE=${toolchainFile}`
|
|
151
|
+
]
|
|
18
152
|
|
|
19
|
-
|
|
20
|
-
"cmake",
|
|
21
|
-
[
|
|
22
|
-
"-S",
|
|
23
|
-
frameworkPaths.frameworkRoot,
|
|
24
|
-
"-B",
|
|
25
|
-
buildDir,
|
|
26
|
-
"-G",
|
|
27
|
-
"Ninja",
|
|
28
|
-
`-DCMAKE_BUILD_TYPE=${getBuildType(mode)}`,
|
|
29
|
-
"-DCMAKE_CXX_STANDARD=20",
|
|
30
|
-
"-DCMAKE_CXX_STANDARD_REQUIRED=ON",
|
|
31
|
-
"-DCMAKE_CXX_EXTENSIONS=OFF",
|
|
32
|
-
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
|
|
33
|
-
`-DCMAKE_TOOLCHAIN_FILE=${toolchainFile}`
|
|
34
|
-
],
|
|
35
|
-
{
|
|
153
|
+
try {
|
|
154
|
+
await runCommand("cmake", configureArgs, {
|
|
36
155
|
cwd,
|
|
37
156
|
dryRun
|
|
38
|
-
}
|
|
39
|
-
)
|
|
157
|
+
})
|
|
158
|
+
} catch (error) {
|
|
159
|
+
throw error
|
|
160
|
+
}
|
|
40
161
|
}
|
|
41
|
-
|
|
162
|
+
|
|
42
163
|
export async function buildFrameworkRuntime(frameworkPaths, frameworkBuildPaths, mode, options = {}) {
|
|
43
164
|
const { dryRun = false, cwd } = options
|
|
44
165
|
const buildDir = getBuildDirectory(frameworkBuildPaths, mode)
|
|
166
|
+
const generator = await resolveCmakeGenerator()
|
|
45
167
|
|
|
46
168
|
await configureFrameworkBuild(frameworkPaths, frameworkBuildPaths, mode, {
|
|
47
169
|
cwd,
|
|
48
170
|
dryRun
|
|
49
171
|
})
|
|
50
172
|
|
|
51
|
-
await runCommand("cmake", ["--build", buildDir], {
|
|
173
|
+
await runCommand("cmake", ["--build", buildDir, ...generator.buildArgs, ...(generator.multiConfig ? [getBuildType(mode)] : [])], {
|
|
52
174
|
cwd,
|
|
53
175
|
dryRun
|
|
54
176
|
})
|
package/src/lib/logger.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export const logger = {
|
|
2
|
-
info(message) {
|
|
3
|
-
console.log(message)
|
|
4
|
-
},
|
|
5
|
-
warn(message) {
|
|
6
|
-
console.warn(message)
|
|
7
|
-
},
|
|
8
|
-
error(message) {
|
|
9
|
-
console.error(message)
|
|
10
|
-
}
|
|
11
|
-
}
|
|
1
|
+
export const logger = {
|
|
2
|
+
info(message) {
|
|
3
|
+
console.log(message)
|
|
4
|
+
},
|
|
5
|
+
warn(message) {
|
|
6
|
+
console.warn(message)
|
|
7
|
+
},
|
|
8
|
+
error(message) {
|
|
9
|
+
console.error(message)
|
|
10
|
+
}
|
|
11
|
+
}
|
package/src/lib/output.js
CHANGED
|
@@ -1,110 +1,178 @@
|
|
|
1
1
|
import path from "node:path"
|
|
2
|
-
import { cp, mkdir, rm, writeFile } from "node:fs/promises"
|
|
2
|
+
import { cp, mkdir, readdir, rm, writeFile } from "node:fs/promises"
|
|
3
3
|
import { existsSync } from "node:fs"
|
|
4
4
|
|
|
5
5
|
import { logger } from "./logger.js"
|
|
6
6
|
import { runCommand } from "./process.js"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
import {
|
|
8
|
+
resolveFrameworkRuntimeBinary,
|
|
9
|
+
resolveFrameworkRuntimeOutputDir
|
|
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
|
+
|
|
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`
|
|
98
|
+
)
|
|
13
99
|
}
|
|
14
100
|
|
|
15
|
-
function
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
if (Array.isArray(value)) {
|
|
19
|
-
if (value.length === 0) {
|
|
20
|
-
return `${indent}<array/>\n`
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
`${indent}<array>\n` +
|
|
25
|
-
value.map((entry) => serializePlistValue(entry, indentLevel + 1)).join("") +
|
|
26
|
-
`${indent}</array>\n`
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (typeof value === "object" && value !== null) {
|
|
31
|
-
const entries = Object.entries(value)
|
|
32
|
-
if (entries.length === 0) {
|
|
33
|
-
return `${indent}<dict/>\n`
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
`${indent}<dict>\n` +
|
|
38
|
-
entries
|
|
39
|
-
.map(
|
|
40
|
-
([key, entryValue]) =>
|
|
41
|
-
`${" ".repeat(indentLevel + 1)}<key>${escapePlistString(key)}</key>\n${serializePlistValue(entryValue, indentLevel + 1)}`
|
|
42
|
-
)
|
|
43
|
-
.join("") +
|
|
44
|
-
`${indent}</dict>\n`
|
|
45
|
-
)
|
|
46
|
-
}
|
|
101
|
+
function shouldCopyWindowsRuntimeArtifact(entryName) {
|
|
102
|
+
const extension = path.extname(entryName).toLowerCase()
|
|
47
103
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
104
|
+
return [
|
|
105
|
+
".bin",
|
|
106
|
+
".dat",
|
|
107
|
+
".dll",
|
|
108
|
+
".exe",
|
|
109
|
+
".json",
|
|
110
|
+
".manifest",
|
|
111
|
+
".pak",
|
|
112
|
+
".pri"
|
|
113
|
+
].includes(extension)
|
|
57
114
|
}
|
|
58
115
|
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
? config.protocols.schemes.map((schemeConfig) => ({
|
|
62
|
-
CFBundleTypeRole: schemeConfig.role ?? "Viewer",
|
|
63
|
-
CFBundleURLName:
|
|
64
|
-
typeof schemeConfig.name === "string" && schemeConfig.name.trim() !== ""
|
|
65
|
-
? schemeConfig.name
|
|
66
|
-
: `${config.appId}.${schemeConfig.scheme}`,
|
|
67
|
-
CFBundleURLSchemes: [schemeConfig.scheme]
|
|
68
|
-
}))
|
|
69
|
-
: []
|
|
70
|
-
|
|
71
|
-
const plist = {
|
|
72
|
-
CFBundleDevelopmentRegion: "English",
|
|
73
|
-
CFBundleDisplayName: config.productName,
|
|
74
|
-
CFBundleExecutable: "reset-framework",
|
|
75
|
-
CFBundleIdentifier: config.appId,
|
|
76
|
-
CFBundleInfoDictionaryVersion: "6.0",
|
|
77
|
-
CFBundleName: config.productName,
|
|
78
|
-
CFBundlePackageType: "APPL",
|
|
79
|
-
CFBundleShortVersionString: config.version,
|
|
80
|
-
CFBundleVersion: config.version,
|
|
81
|
-
CSResourcesFileMapped: true
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (urlTypes.length > 0) {
|
|
85
|
-
plist.CFBundleURLTypes = urlTypes
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return (
|
|
89
|
-
`<?xml version="1.0" encoding="UTF-8"?>\n` +
|
|
90
|
-
`<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n` +
|
|
91
|
-
`<plist version="1.0">\n` +
|
|
92
|
-
serializePlistValue(plist, 0) +
|
|
93
|
-
`</plist>\n`
|
|
94
|
-
)
|
|
116
|
+
function escapePowerShellLiteral(value) {
|
|
117
|
+
return String(value).replaceAll("'", "''")
|
|
95
118
|
}
|
|
96
|
-
|
|
119
|
+
|
|
97
120
|
export async function stageMacOSAppBundle(frameworkBuildPaths, appPaths, config, options = {}) {
|
|
121
|
+
const { dryRun = false, outputPaths, configPath } = options
|
|
122
|
+
|
|
123
|
+
if (!outputPaths) {
|
|
124
|
+
throw new Error("stageMacOSAppBundle requires resolved output paths")
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!existsSync(frameworkBuildPaths.releaseAppTemplate) && !dryRun) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`Missing runtime app bundle at ${frameworkBuildPaths.releaseAppTemplate}. Run reset-framework-cli build first.`
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!existsSync(outputPaths.frontendEntryFile) && !dryRun) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Missing frontend build output at ${outputPaths.frontendEntryFile}. Run the frontend build first.`
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
logger.info(`Staging app bundle into ${outputPaths.appBundlePath}`)
|
|
140
|
+
|
|
141
|
+
if (dryRun) {
|
|
142
|
+
logger.info(`- copy ${frameworkBuildPaths.releaseAppTemplate} -> ${outputPaths.appBundlePath}`)
|
|
143
|
+
logger.info(`- copy ${configPath} -> ${outputPaths.bundledConfigPath}`)
|
|
144
|
+
logger.info(`- copy ${outputPaths.frontendDistDir} -> ${outputPaths.bundledFrontendDir}`)
|
|
145
|
+
return outputPaths
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
await mkdir(outputPaths.macosDir, { recursive: true })
|
|
149
|
+
await rm(outputPaths.appBundlePath, { recursive: true, force: true })
|
|
150
|
+
await cp(frameworkBuildPaths.releaseAppTemplate, outputPaths.appBundlePath, { recursive: true })
|
|
151
|
+
|
|
152
|
+
await mkdir(outputPaths.resourcesDir, { recursive: true })
|
|
153
|
+
await cp(configPath, outputPaths.bundledConfigPath, { force: true })
|
|
154
|
+
await rm(outputPaths.bundledFrontendDir, { recursive: true, force: true })
|
|
155
|
+
await cp(outputPaths.frontendDistDir, outputPaths.bundledFrontendDir, { recursive: true })
|
|
156
|
+
await writeFile(
|
|
157
|
+
path.join(outputPaths.appBundlePath, "Contents", "Info.plist"),
|
|
158
|
+
buildMacOSInfoPlist(config),
|
|
159
|
+
"utf8"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
return outputPaths
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function stageWindowsAppBundle(frameworkBuildPaths, appPaths, config, options = {}) {
|
|
98
166
|
const { dryRun = false, outputPaths, configPath } = options
|
|
167
|
+
const runtimeSourceBinary = resolveFrameworkRuntimeBinary(frameworkBuildPaths, "release", {
|
|
168
|
+
mustExist: !dryRun
|
|
169
|
+
})
|
|
170
|
+
const runtimeSourceDir = resolveFrameworkRuntimeOutputDir(frameworkBuildPaths, "release", {
|
|
171
|
+
mustExist: !dryRun
|
|
172
|
+
})
|
|
99
173
|
|
|
100
174
|
if (!outputPaths) {
|
|
101
|
-
throw new Error("
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (!existsSync(frameworkBuildPaths.releaseAppTemplate) && !dryRun) {
|
|
105
|
-
throw new Error(
|
|
106
|
-
`Missing runtime app bundle at ${frameworkBuildPaths.releaseAppTemplate}. Run reset-framework-cli build first.`
|
|
107
|
-
)
|
|
175
|
+
throw new Error("stageWindowsAppBundle requires resolved output paths")
|
|
108
176
|
}
|
|
109
177
|
|
|
110
178
|
if (!existsSync(outputPaths.frontendEntryFile) && !dryRun) {
|
|
@@ -113,48 +181,88 @@ export async function stageMacOSAppBundle(frameworkBuildPaths, appPaths, config,
|
|
|
113
181
|
)
|
|
114
182
|
}
|
|
115
183
|
|
|
116
|
-
logger.info(`Staging app
|
|
184
|
+
logger.info(`Staging Windows app into ${outputPaths.appBundlePath}`)
|
|
117
185
|
|
|
118
186
|
if (dryRun) {
|
|
119
|
-
logger.info(`- copy ${
|
|
187
|
+
logger.info(`- copy ${runtimeSourceDir} -> ${outputPaths.appBundlePath}`)
|
|
188
|
+
logger.info(`- rename ${runtimeSourceBinary} -> ${outputPaths.appExecutablePath}`)
|
|
120
189
|
logger.info(`- copy ${configPath} -> ${outputPaths.bundledConfigPath}`)
|
|
121
190
|
logger.info(`- copy ${outputPaths.frontendDistDir} -> ${outputPaths.bundledFrontendDir}`)
|
|
122
191
|
return outputPaths
|
|
123
192
|
}
|
|
124
193
|
|
|
125
|
-
await mkdir(outputPaths.
|
|
194
|
+
await mkdir(outputPaths.windowsDir, { recursive: true })
|
|
126
195
|
await rm(outputPaths.appBundlePath, { recursive: true, force: true })
|
|
127
|
-
await
|
|
196
|
+
await mkdir(outputPaths.appBundlePath, { recursive: true })
|
|
197
|
+
const runtimeEntries = await readdir(runtimeSourceDir, { withFileTypes: true })
|
|
198
|
+
const runtimeBinaryName = path.basename(runtimeSourceBinary)
|
|
199
|
+
|
|
200
|
+
for (const entry of runtimeEntries) {
|
|
201
|
+
if (!entry.isDirectory() && !shouldCopyWindowsRuntimeArtifact(entry.name)) {
|
|
202
|
+
continue
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const sourcePath = path.join(runtimeSourceDir, entry.name)
|
|
206
|
+
const targetPath =
|
|
207
|
+
entry.name.toLowerCase() === runtimeBinaryName.toLowerCase()
|
|
208
|
+
? outputPaths.appExecutablePath
|
|
209
|
+
: path.join(outputPaths.appBundlePath, entry.name)
|
|
210
|
+
|
|
211
|
+
await cp(sourcePath, targetPath, { recursive: true, force: true })
|
|
212
|
+
}
|
|
128
213
|
|
|
129
214
|
await mkdir(outputPaths.resourcesDir, { recursive: true })
|
|
130
215
|
await cp(configPath, outputPaths.bundledConfigPath, { force: true })
|
|
131
216
|
await rm(outputPaths.bundledFrontendDir, { recursive: true, force: true })
|
|
132
217
|
await cp(outputPaths.frontendDistDir, outputPaths.bundledFrontendDir, { recursive: true })
|
|
133
|
-
await writeFile(
|
|
134
|
-
path.join(outputPaths.appBundlePath, "Contents", "Info.plist"),
|
|
135
|
-
buildMacOSInfoPlist(config),
|
|
136
|
-
"utf8"
|
|
137
|
-
)
|
|
138
218
|
|
|
139
219
|
return outputPaths
|
|
140
220
|
}
|
|
141
|
-
|
|
221
|
+
|
|
142
222
|
export async function createMacOSZipArchive(outputPaths, options = {}) {
|
|
143
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
|
+
|
|
235
|
+
await runCommand(
|
|
236
|
+
"ditto",
|
|
237
|
+
["-c", "-k", "--sequesterRsrc", "--keepParent", outputPaths.appBundlePath, outputPaths.zipPath],
|
|
238
|
+
{ dryRun }
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export async function createWindowsZipArchive(outputPaths, options = {}) {
|
|
243
|
+
const { dryRun = false } = options
|
|
144
244
|
|
|
145
245
|
logger.info(`Packaging ${outputPaths.appBundlePath} -> ${outputPaths.zipPath}`)
|
|
146
246
|
|
|
147
|
-
if (process.platform !== "
|
|
148
|
-
throw new Error("Packaging is only implemented for macOS right now")
|
|
247
|
+
if (process.platform !== "win32") {
|
|
248
|
+
throw new Error("Packaging is only implemented for Windows and macOS right now")
|
|
149
249
|
}
|
|
150
250
|
|
|
151
251
|
if (!dryRun) {
|
|
152
252
|
await mkdir(outputPaths.packagesDir, { recursive: true })
|
|
253
|
+
await rm(outputPaths.zipPath, { force: true })
|
|
153
254
|
}
|
|
154
255
|
|
|
256
|
+
const literalSourcePath = escapePowerShellLiteral(outputPaths.appBundlePath)
|
|
257
|
+
const literalDestinationPath = escapePowerShellLiteral(outputPaths.zipPath)
|
|
258
|
+
const archiveCommand = [
|
|
259
|
+
"$ErrorActionPreference = 'Stop'",
|
|
260
|
+
`Compress-Archive -LiteralPath '${literalSourcePath}' -DestinationPath '${literalDestinationPath}' -CompressionLevel Optimal`
|
|
261
|
+
].join("; ")
|
|
262
|
+
|
|
155
263
|
await runCommand(
|
|
156
|
-
"
|
|
157
|
-
["-
|
|
264
|
+
"powershell.exe",
|
|
265
|
+
["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", archiveCommand],
|
|
158
266
|
{ dryRun }
|
|
159
267
|
)
|
|
160
268
|
}
|