electron-forge-maker-innosetup 0.3.3 → 1.0.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/README.md +29 -43
- package/dist/MakerInnosetup.d.ts +119 -50
- package/dist/MakerInnosetup.d.ts.map +1 -0
- package/dist/MakerInnosetup.js +448 -428
- package/dist/MakerInnosetup.js.map +1 -0
- package/dist/errors.d.ts +56 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +87 -0
- package/dist/errors.js.map +1 -0
- package/dist/generator.d.ts +125 -42
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +435 -407
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -1
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +32 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +55 -0
- package/dist/logger.js.map +1 -0
- package/dist/parser.d.ts +49 -26
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +590 -400
- package/dist/parser.js.map +1 -0
- package/dist/types.d.ts +605 -618
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +37 -1
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/path.d.ts +46 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +122 -0
- package/dist/utils/path.js.map +1 -0
- package/package.json +21 -7
package/dist/MakerInnosetup.js
CHANGED
|
@@ -32,324 +32,396 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
-
};
|
|
38
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
37
|
};
|
|
41
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.InnoScriptParser = exports.InnoScriptGenerator = void 0;
|
|
43
39
|
const path = __importStar(require("path"));
|
|
44
40
|
const fs = __importStar(require("fs"));
|
|
45
41
|
const child_process_1 = require("child_process");
|
|
46
42
|
const maker_base_1 = __importDefault(require("@electron-forge/maker-base"));
|
|
43
|
+
const types_1 = require("./types");
|
|
47
44
|
const generator_1 = require("./generator");
|
|
48
45
|
const parser_1 = require("./parser");
|
|
46
|
+
const errors_1 = require("./errors");
|
|
47
|
+
const logger_1 = require("./logger");
|
|
48
|
+
const path_1 = require("./utils/path");
|
|
49
|
+
/** 默认编译超时时间(5 分钟) */
|
|
50
|
+
const DEFAULT_COMPILE_TIMEOUT = 300000;
|
|
51
|
+
/** 默认的 Inno Setup 编译器搜索路径 */
|
|
52
|
+
const DEFAULT_COMPILER_PATHS = [
|
|
53
|
+
// 内置便携版(相对于 dist 目录)
|
|
54
|
+
path.join(__dirname, "..", "vendor", "innosetup", "ISCC.exe"),
|
|
55
|
+
path.join(__dirname, "..", "vendor", "ISCC.exe"),
|
|
56
|
+
// 内置便携版(相对于 src 目录 - 用于开发环境)
|
|
57
|
+
path.join(__dirname, "..", "..", "vendor", "innosetup", "ISCC.exe"),
|
|
58
|
+
path.join(__dirname, "..", "..", "vendor", "ISCC.exe"),
|
|
59
|
+
// 系统安装路径
|
|
60
|
+
"C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe",
|
|
61
|
+
"C:\\Program Files\\Inno Setup 6\\ISCC.exe",
|
|
62
|
+
"C:\\Program Files (x86)\\Inno Setup 5\\ISCC.exe",
|
|
63
|
+
"C:\\Program Files\\Inno Setup 5\\ISCC.exe",
|
|
64
|
+
];
|
|
49
65
|
/**
|
|
50
|
-
* Electron Forge
|
|
66
|
+
* Electron Forge 的 Inno Setup Maker
|
|
67
|
+
*
|
|
68
|
+
* 使用 Inno Setup 编译器(ISCC.exe)创建 Windows 安装程序
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* import { MakerInnosetup } from 'electron-forge-maker-innosetup';
|
|
73
|
+
*
|
|
74
|
+
* // 在 forge.config.ts 中
|
|
75
|
+
* const config: ForgeConfig = {
|
|
76
|
+
* makers: [
|
|
77
|
+
* new MakerInnosetup({
|
|
78
|
+
* appName: 'My App',
|
|
79
|
+
* appVersion: '1.0.0',
|
|
80
|
+
* setupIconFile: './assets/icon.ico',
|
|
81
|
+
* config: {
|
|
82
|
+
* Setup: {
|
|
83
|
+
* AppName: 'My App',
|
|
84
|
+
* AppVersion: '1.0.0',
|
|
85
|
+
* DefaultDirName: '{autopf}\\MyApp',
|
|
86
|
+
* OutputDir: './out/installer',
|
|
87
|
+
* },
|
|
88
|
+
* },
|
|
89
|
+
* }),
|
|
90
|
+
* ],
|
|
91
|
+
* };
|
|
92
|
+
* ```
|
|
51
93
|
*/
|
|
52
94
|
class MakerInnosetup extends maker_base_1.default {
|
|
53
95
|
/**
|
|
54
|
-
*
|
|
96
|
+
* 从配置获取项目目录,若未配置则使用当前工作目录
|
|
55
97
|
*/
|
|
56
98
|
getProjectDir() {
|
|
57
|
-
return this.config
|
|
99
|
+
return this.config.paths?.projectDir ?? process.cwd();
|
|
58
100
|
}
|
|
59
101
|
/**
|
|
60
|
-
*
|
|
102
|
+
* 从配置获取构建目录
|
|
61
103
|
*/
|
|
62
104
|
getBuildDir() {
|
|
63
|
-
return this.config
|
|
105
|
+
return this.config.paths?.buildDir;
|
|
64
106
|
}
|
|
65
107
|
/**
|
|
66
|
-
*
|
|
108
|
+
* 从配置获取资源目录,若未配置则使用默认值 "assets"
|
|
67
109
|
*/
|
|
68
110
|
getAssetsDir() {
|
|
69
|
-
return this.config
|
|
111
|
+
return this.config.paths?.assetsDir ?? "assets";
|
|
70
112
|
}
|
|
71
113
|
constructor(config = {}, platforms) {
|
|
72
114
|
// 默认启用相对路径解析
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
115
|
+
const finalConfig = {
|
|
116
|
+
resolveRelativePaths: true,
|
|
117
|
+
...config,
|
|
118
|
+
};
|
|
119
|
+
super(finalConfig, platforms);
|
|
77
120
|
this.name = "innosetup";
|
|
78
121
|
this.defaultPlatforms = ["win32"];
|
|
79
122
|
this.scriptGenerator = new generator_1.InnoScriptGenerator();
|
|
80
123
|
}
|
|
81
124
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* @param
|
|
85
|
-
* @returns
|
|
125
|
+
* 从 ISS 文件创建 MakerInnosetupConfig
|
|
126
|
+
*
|
|
127
|
+
* @param issFilePath - ISS 文件路径
|
|
128
|
+
* @returns 解析后的配置对象
|
|
129
|
+
*/
|
|
130
|
+
static fromIssFile(issFilePath) {
|
|
131
|
+
const config = parser_1.InnoScriptParser.parseFile(issFilePath);
|
|
132
|
+
return {
|
|
133
|
+
config,
|
|
134
|
+
scriptPath: issFilePath,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 从 ISS 内容字符串创建 MakerInnosetupConfig
|
|
139
|
+
*
|
|
140
|
+
* @param issContent - ISS 文件内容
|
|
141
|
+
* @returns 解析后的配置对象
|
|
142
|
+
*/
|
|
143
|
+
static fromIssContent(issContent) {
|
|
144
|
+
const config = parser_1.InnoScriptParser.parse(issContent);
|
|
145
|
+
return { config };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 检查当前平台是否支持
|
|
149
|
+
*
|
|
150
|
+
* @returns 当前平台是否为 Windows
|
|
151
|
+
*/
|
|
152
|
+
isSupportedOnCurrentPlatform() {
|
|
153
|
+
return process.platform === "win32";
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* 创建安装程序
|
|
157
|
+
*
|
|
158
|
+
* @param options - Electron Forge Maker 选项
|
|
159
|
+
* @returns 生成的安装程序文件路径数组
|
|
160
|
+
*/
|
|
161
|
+
async make(options) {
|
|
162
|
+
const { appName, dir, makeDir, targetArch, packageJSON } = options;
|
|
163
|
+
const appVersion = packageJSON.version ?? "1.0.0";
|
|
164
|
+
const archId = (0, types_1.getArchIdentifier)(targetArch);
|
|
165
|
+
// 验证平台
|
|
166
|
+
if (!this.isSupportedOnCurrentPlatform()) {
|
|
167
|
+
throw new errors_1.PlatformNotSupportedError(process.platform);
|
|
168
|
+
}
|
|
169
|
+
// 设置构建目录用于路径解析
|
|
170
|
+
this.config.paths = {
|
|
171
|
+
...this.config.paths,
|
|
172
|
+
buildDir: dir,
|
|
173
|
+
};
|
|
174
|
+
(0, logger_1.log)("正在创建 Inno Setup 安装程序: %s %s (%s)", appName, appVersion, targetArch);
|
|
175
|
+
(0, logger_1.logPath)("项目目录: %s", this.getProjectDir());
|
|
176
|
+
(0, logger_1.logPath)("构建目录: %s", this.getBuildDir());
|
|
177
|
+
// 查找编译器
|
|
178
|
+
const compilerPath = this.findInnosetupCompiler();
|
|
179
|
+
(0, logger_1.logCompile)("使用 Inno Setup 编译器: %s", compilerPath);
|
|
180
|
+
// 确定输出目录
|
|
181
|
+
const baseOutputDir = this.config.outputDir ?? path.join(makeDir, "innosetup.windows");
|
|
182
|
+
const outputDir = path.join(baseOutputDir, archId);
|
|
183
|
+
(0, path_1.ensureDir)(outputDir);
|
|
184
|
+
(0, logger_1.log)("输出目录: %s", outputDir);
|
|
185
|
+
// 生成或使用现有脚本
|
|
186
|
+
let scriptPath;
|
|
187
|
+
// actualOutputDir 用于查找生成的安装程序
|
|
188
|
+
let actualOutputDir = outputDir;
|
|
189
|
+
if (this.config.scriptPath) {
|
|
190
|
+
scriptPath = this.resolvePath(this.config.scriptPath, this.getProjectDir());
|
|
191
|
+
(0, logger_1.log)("使用自定义脚本: %s", scriptPath);
|
|
192
|
+
// 解析脚本以获取输出目录
|
|
193
|
+
try {
|
|
194
|
+
const parsedConfig = parser_1.InnoScriptParser.parseFile(scriptPath);
|
|
195
|
+
if (parsedConfig.Setup.OutputDir) {
|
|
196
|
+
actualOutputDir = path.isAbsolute(parsedConfig.Setup.OutputDir)
|
|
197
|
+
? parsedConfig.Setup.OutputDir
|
|
198
|
+
: path.resolve(path.dirname(scriptPath), parsedConfig.Setup.OutputDir);
|
|
199
|
+
(0, logger_1.log)("脚本定义的 OutputDir: %s", actualOutputDir);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
(0, logger_1.logCompile)("解析脚本 OutputDir 失败: %s", err);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
// 生成脚本
|
|
208
|
+
const defaultConfig = this.generateDefaultConfig(dir, appName, appVersion, targetArch, outputDir);
|
|
209
|
+
const finalConfig = this.mergeConfig(defaultConfig, this.config.config);
|
|
210
|
+
// 解析配置中的路径
|
|
211
|
+
this.resolveConfigPaths(finalConfig, dir);
|
|
212
|
+
// 添加任务(桌面图标等)
|
|
213
|
+
this.addTasks(finalConfig, appName);
|
|
214
|
+
// 生成并保存脚本
|
|
215
|
+
const scriptContent = this.scriptGenerator.generate(finalConfig);
|
|
216
|
+
scriptPath = path.join(makeDir, `${appName}-setup.iss`);
|
|
217
|
+
this.scriptGenerator.saveToFile(scriptContent, scriptPath);
|
|
218
|
+
(0, logger_1.log)("已生成 Inno Setup 脚本: %s", scriptPath);
|
|
219
|
+
// 使用配置中的 OutputDir(如果有)
|
|
220
|
+
if (finalConfig.Setup.OutputDir) {
|
|
221
|
+
actualOutputDir = finalConfig.Setup.OutputDir;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// 编译
|
|
225
|
+
(0, logger_1.logCompile)("正在编译安装程序...");
|
|
226
|
+
await this.compileScript(scriptPath, compilerPath);
|
|
227
|
+
// 查找生成的安装程序
|
|
228
|
+
const installerPaths = this.findInstaller(actualOutputDir, appName, appVersion, archId);
|
|
229
|
+
// 输出成功信息
|
|
230
|
+
(0, logger_1.log)("✓ 安装程序创建成功!");
|
|
231
|
+
for (const installerPath of installerPaths) {
|
|
232
|
+
const stats = fs.statSync(installerPath);
|
|
233
|
+
const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
|
|
234
|
+
(0, logger_1.log)(" 文件: %s", installerPath);
|
|
235
|
+
(0, logger_1.log)(" 大小: %s MB", sizeMB);
|
|
236
|
+
}
|
|
237
|
+
return installerPaths;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* 查找 Inno Setup 编译器
|
|
241
|
+
*
|
|
242
|
+
* 按以下顺序查找:
|
|
243
|
+
* 1. 配置中指定的路径
|
|
244
|
+
* 2. 环境变量 INNOSETUP_PATH
|
|
245
|
+
* 3. 默认搜索路径
|
|
246
|
+
*
|
|
247
|
+
* @returns 编译器路径
|
|
248
|
+
* @throws CompilerNotFoundError 如果找不到编译器
|
|
86
249
|
*/
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
250
|
+
findInnosetupCompiler() {
|
|
251
|
+
// 首先检查配置路径
|
|
252
|
+
if (this.config.innosetupPath) {
|
|
253
|
+
if ((0, path_1.fileExists)(this.config.innosetupPath)) {
|
|
254
|
+
return this.config.innosetupPath;
|
|
255
|
+
}
|
|
90
256
|
}
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
257
|
+
// 检查环境变量
|
|
258
|
+
const envPath = process.env.INNOSETUP_PATH;
|
|
259
|
+
if (envPath && (0, path_1.fileExists)(envPath)) {
|
|
260
|
+
return envPath;
|
|
94
261
|
}
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
262
|
+
// 搜索默认路径
|
|
263
|
+
for (const searchPath of DEFAULT_COMPILER_PATHS) {
|
|
264
|
+
if ((0, path_1.fileExists)(searchPath)) {
|
|
265
|
+
(0, logger_1.logCompile)("找到内置 Inno Setup: %s", searchPath);
|
|
266
|
+
return searchPath;
|
|
267
|
+
}
|
|
98
268
|
}
|
|
99
|
-
|
|
100
|
-
const base = baseDir || this.getProjectDir();
|
|
101
|
-
return path.resolve(base, pathStr);
|
|
269
|
+
throw new errors_1.CompilerNotFoundError([this.config.innosetupPath, process.env.INNOSETUP_PATH, ...DEFAULT_COMPILER_PATHS].filter(Boolean));
|
|
102
270
|
}
|
|
103
271
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* @param
|
|
107
|
-
* @
|
|
272
|
+
* 解析相对于基础目录的路径
|
|
273
|
+
*
|
|
274
|
+
* @param input - 输入路径
|
|
275
|
+
* @param baseDir - 基础目录
|
|
276
|
+
* @returns 解析后的绝对路径
|
|
108
277
|
*/
|
|
109
|
-
|
|
110
|
-
if (!
|
|
111
|
-
return
|
|
278
|
+
resolvePath(input, baseDir) {
|
|
279
|
+
if (!input) {
|
|
280
|
+
return "";
|
|
112
281
|
}
|
|
113
|
-
|
|
282
|
+
// 如果禁用了相对路径解析则直接返回
|
|
283
|
+
if (this.config.resolveRelativePaths === false) {
|
|
284
|
+
return input;
|
|
285
|
+
}
|
|
286
|
+
// 已经是绝对路径,规范化分隔符
|
|
287
|
+
if (path.isAbsolute(input)) {
|
|
288
|
+
return path.normalize(input);
|
|
289
|
+
}
|
|
290
|
+
// 解析相对路径并规范化
|
|
291
|
+
return path.normalize(path.resolve(baseDir, input));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 解析字符串中的路径占位符
|
|
295
|
+
*
|
|
296
|
+
* 支持的占位符:
|
|
297
|
+
* - {project} - 项目根目录
|
|
298
|
+
* - {build} - 构建输出目录
|
|
299
|
+
* - {assets} - 资源文件目录
|
|
300
|
+
*
|
|
301
|
+
* @param input - 输入字符串
|
|
302
|
+
* @returns 替换占位符后的字符串
|
|
303
|
+
*/
|
|
304
|
+
resolvePathPlaceholders(input) {
|
|
305
|
+
let result = input;
|
|
114
306
|
const projectDir = this.getProjectDir();
|
|
115
307
|
const buildDir = this.getBuildDir();
|
|
116
308
|
const assetsDir = this.getAssetsDir();
|
|
117
309
|
// {project} - 项目根目录
|
|
118
|
-
|
|
310
|
+
result = result.replace(/\{project\}/g, projectDir);
|
|
119
311
|
// {build} - 构建输出目录
|
|
120
312
|
if (buildDir) {
|
|
121
|
-
|
|
313
|
+
result = result.replace(/\{build\}/g, buildDir);
|
|
122
314
|
}
|
|
123
315
|
// {assets} - 资源目录
|
|
124
316
|
const assetsPath = path.resolve(projectDir, assetsDir);
|
|
125
|
-
|
|
126
|
-
return
|
|
317
|
+
result = result.replace(/\{assets\}/g, assetsPath);
|
|
318
|
+
return result;
|
|
127
319
|
}
|
|
128
320
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* @param
|
|
321
|
+
* 解析配置中的所有路径
|
|
322
|
+
*
|
|
323
|
+
* @param config - Inno Setup 配置
|
|
324
|
+
* @param appDir - 应用目录
|
|
132
325
|
*/
|
|
133
326
|
resolveConfigPaths(config, appDir) {
|
|
134
|
-
if (this.config
|
|
327
|
+
if (this.config.resolveRelativePaths === false) {
|
|
135
328
|
return;
|
|
136
329
|
}
|
|
137
330
|
const projectDir = this.getProjectDir();
|
|
138
|
-
// 解析 Setup
|
|
331
|
+
// 解析 Setup 节中的路径字段
|
|
139
332
|
if (config.Setup) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (config.Setup.WizardImageFile) {
|
|
158
|
-
config.Setup.WizardImageFile = this.resolvePath(this.resolvePathPlaceholders(config.Setup.WizardImageFile), projectDir);
|
|
159
|
-
}
|
|
160
|
-
// WizardSmallImageFile
|
|
161
|
-
if (config.Setup.WizardSmallImageFile) {
|
|
162
|
-
config.Setup.WizardSmallImageFile = this.resolvePath(this.resolvePathPlaceholders(config.Setup.WizardSmallImageFile), projectDir);
|
|
333
|
+
const pathFields = [
|
|
334
|
+
"SetupIconFile",
|
|
335
|
+
"LicenseFile",
|
|
336
|
+
"InfoBeforeFile",
|
|
337
|
+
"InfoAfterFile",
|
|
338
|
+
"WizardImageFile",
|
|
339
|
+
"WizardSmallImageFile",
|
|
340
|
+
];
|
|
341
|
+
for (const field of pathFields) {
|
|
342
|
+
const value = config.Setup[field];
|
|
343
|
+
if (value && typeof value === "string") {
|
|
344
|
+
const resolved = this.resolvePathPlaceholders(value);
|
|
345
|
+
config.Setup = {
|
|
346
|
+
...config.Setup,
|
|
347
|
+
[field]: this.resolvePath(resolved, projectDir),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
163
350
|
}
|
|
164
351
|
}
|
|
165
|
-
// 解析 Languages
|
|
352
|
+
// 解析 Languages 节中的路径
|
|
166
353
|
if (config.Languages) {
|
|
167
|
-
config.Languages.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
!
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
lang.InfoAfterFile = this.resolvePath(this.resolvePathPlaceholders(lang.InfoAfterFile), projectDir);
|
|
354
|
+
config.Languages = config.Languages.map((lang) => {
|
|
355
|
+
const resolved = { ...lang };
|
|
356
|
+
const langPathFields = ["LicenseFile", "InfoBeforeFile", "InfoAfterFile"];
|
|
357
|
+
for (const field of langPathFields) {
|
|
358
|
+
const value = resolved[field];
|
|
359
|
+
if (value && !value.startsWith("compiler:")) {
|
|
360
|
+
const resolvedPath = this.resolvePathPlaceholders(value);
|
|
361
|
+
resolved[field] = this.resolvePath(resolvedPath, projectDir);
|
|
362
|
+
}
|
|
177
363
|
}
|
|
364
|
+
return resolved;
|
|
178
365
|
});
|
|
179
366
|
}
|
|
180
|
-
// 解析 Files
|
|
367
|
+
// 解析 Files 节中的路径
|
|
181
368
|
if (config.Files) {
|
|
182
|
-
config.Files.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const resolvedBase = this.resolvePath(basePath, appDir);
|
|
196
|
-
sourcePath = resolvedBase ? resolvedBase + wildcard : sourcePath;
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
sourcePath = this.resolvePath(sourcePath, appDir);
|
|
200
|
-
}
|
|
201
|
-
file.Source = sourcePath;
|
|
202
|
-
}
|
|
203
|
-
else if (sourcePath) {
|
|
204
|
-
// 是 Inno Setup 常量,保持不变
|
|
205
|
-
file.Source = sourcePath;
|
|
206
|
-
}
|
|
369
|
+
config.Files = config.Files.map((file) => {
|
|
370
|
+
if (!file.Source)
|
|
371
|
+
return file;
|
|
372
|
+
const sourcePath = this.resolvePathPlaceholders(file.Source);
|
|
373
|
+
// 跳过 Inno Setup 常量
|
|
374
|
+
if ((0, path_1.isInnoSetupConstant)(sourcePath)) {
|
|
375
|
+
return { ...file, Source: sourcePath };
|
|
376
|
+
}
|
|
377
|
+
// 处理通配符
|
|
378
|
+
if (sourcePath.includes("*") || sourcePath.includes("?")) {
|
|
379
|
+
const { basePath, wildcard } = (0, path_1.splitWildcardPath)(sourcePath);
|
|
380
|
+
const resolvedBase = this.resolvePath(basePath, appDir);
|
|
381
|
+
return { ...file, Source: resolvedBase + wildcard };
|
|
207
382
|
}
|
|
383
|
+
return { ...file, Source: this.resolvePath(sourcePath, appDir) };
|
|
208
384
|
});
|
|
209
385
|
}
|
|
210
386
|
}
|
|
211
387
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
* @
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
scriptPath: issFilePath,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* 从 ISS 脚本内容解析配置
|
|
225
|
-
* @param issContent ISS 脚本内容
|
|
226
|
-
* @returns MakerInnosetupConfig 配置对象
|
|
227
|
-
*/
|
|
228
|
-
static fromIssContent(issContent) {
|
|
229
|
-
const config = parser_1.InnoScriptParser.parse(issContent);
|
|
230
|
-
return {
|
|
231
|
-
config: config,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* 检查是否支持当前平台
|
|
236
|
-
*/
|
|
237
|
-
isSupportedOnCurrentPlatform() {
|
|
238
|
-
return process.platform === "win32";
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* 查找 Innosetup 编译器路径
|
|
242
|
-
*/
|
|
243
|
-
findInnosetupCompiler() {
|
|
244
|
-
if (this.config.innosetupPath) {
|
|
245
|
-
return this.config.innosetupPath;
|
|
246
|
-
}
|
|
247
|
-
// 1. 优先查找内置的便携版(相对于包的位置)
|
|
248
|
-
const builtinPaths = [
|
|
249
|
-
// 相对于 dist 目录
|
|
250
|
-
path.join(__dirname, "..", "vendor", "innosetup", "ISCC.exe"),
|
|
251
|
-
path.join(__dirname, "..", "vendor", "ISCC.exe"),
|
|
252
|
-
// 相对于 src 目录
|
|
253
|
-
path.join(__dirname, "..", "..", "vendor", "innosetup", "ISCC.exe"),
|
|
254
|
-
path.join(__dirname, "..", "..", "vendor", "ISCC.exe"),
|
|
255
|
-
];
|
|
256
|
-
for (const builtinPath of builtinPaths) {
|
|
257
|
-
if (fs.existsSync(builtinPath)) {
|
|
258
|
-
console.log(`Using bundled Innosetup: ${builtinPath}`);
|
|
259
|
-
return builtinPath;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
// 2. 尝试从环境变量中查找
|
|
263
|
-
if (process.env.INNOSETUP_PATH &&
|
|
264
|
-
fs.existsSync(process.env.INNOSETUP_PATH)) {
|
|
265
|
-
return process.env.INNOSETUP_PATH;
|
|
266
|
-
}
|
|
267
|
-
// 3. 查找系统安装的 Innosetup
|
|
268
|
-
const systemPaths = [
|
|
269
|
-
"C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe",
|
|
270
|
-
"C:\\Program Files\\Inno Setup 6\\ISCC.exe",
|
|
271
|
-
"C:\\Program Files (x86)\\Inno Setup 5\\ISCC.exe",
|
|
272
|
-
"C:\\Program Files\\Inno Setup 5\\ISCC.exe",
|
|
273
|
-
];
|
|
274
|
-
for (const systemPath of systemPaths) {
|
|
275
|
-
if (fs.existsSync(systemPath)) {
|
|
276
|
-
return systemPath;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
throw new Error("Innosetup compiler not found. Please:\n" +
|
|
280
|
-
"1. Place Innosetup portable in vendor/innosetup/ directory, or\n" +
|
|
281
|
-
"2. Install Innosetup to system, or\n" +
|
|
282
|
-
"3. Set INNOSETUP_PATH environment variable, or\n" +
|
|
283
|
-
"4. Set innosetupPath in config.");
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* 根据架构获取架构标识符
|
|
287
|
-
*/
|
|
288
|
-
getArchIdentifier(arch) {
|
|
289
|
-
switch (arch) {
|
|
290
|
-
case "x64":
|
|
291
|
-
return "x64";
|
|
292
|
-
case "ia32":
|
|
293
|
-
case "x86":
|
|
294
|
-
return "x86";
|
|
295
|
-
case "arm64":
|
|
296
|
-
return "arm64";
|
|
297
|
-
default:
|
|
298
|
-
return arch;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* 根据架构获取 ArchitecturesAllowed 配置
|
|
303
|
-
*/
|
|
304
|
-
getArchitecturesAllowed(arch) {
|
|
305
|
-
switch (arch) {
|
|
306
|
-
case "x64":
|
|
307
|
-
return "x64compatible";
|
|
308
|
-
case "ia32":
|
|
309
|
-
case "x86":
|
|
310
|
-
return "x86compatible";
|
|
311
|
-
case "arm64":
|
|
312
|
-
return "arm64";
|
|
313
|
-
default:
|
|
314
|
-
return arch;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* 生成默认配置
|
|
388
|
+
* 生成默认的 Inno Setup 配置
|
|
389
|
+
*
|
|
390
|
+
* @param appDir - 应用目录
|
|
391
|
+
* @param appName - 应用名称
|
|
392
|
+
* @param appVersion - 应用版本
|
|
393
|
+
* @param arch - 目标架构
|
|
394
|
+
* @param outputDir - 输出目录
|
|
395
|
+
* @returns 默认配置对象
|
|
319
396
|
*/
|
|
320
397
|
generateDefaultConfig(appDir, appName, appVersion, arch, outputDir) {
|
|
321
398
|
const exeName = `${appName}.exe`;
|
|
322
|
-
const archId =
|
|
399
|
+
const archId = (0, types_1.getArchIdentifier)(arch);
|
|
323
400
|
const outputName = `${appName}-${appVersion}-${archId}-setup`;
|
|
401
|
+
const setup = {
|
|
402
|
+
AppName: this.config.appName ?? appName,
|
|
403
|
+
AppVersion: this.config.appVersion ?? appVersion,
|
|
404
|
+
AppPublisher: this.config.appPublisher ?? "",
|
|
405
|
+
AppId: this.config.appId ?? `{{${appName}}}`,
|
|
406
|
+
DefaultDirName: `{autopf}\\${appName}`,
|
|
407
|
+
DefaultGroupName: appName,
|
|
408
|
+
OutputDir: outputDir,
|
|
409
|
+
OutputBaseFilename: outputName,
|
|
410
|
+
Compression: "lzma2",
|
|
411
|
+
SolidCompression: true,
|
|
412
|
+
ArchitecturesAllowed: (0, types_1.getArchitecturesAllowed)(arch),
|
|
413
|
+
ArchitecturesInstallIn64BitMode: arch === "x64" ? "x64compatible" : "",
|
|
414
|
+
SetupIconFile: this.config.setupIconFile ?? "",
|
|
415
|
+
UninstallDisplayIcon: `{app}\\${exeName}`,
|
|
416
|
+
LicenseFile: this.config.licenseFile ?? "",
|
|
417
|
+
PrivilegesRequired: "admin",
|
|
418
|
+
WizardStyle: "modern",
|
|
419
|
+
};
|
|
324
420
|
return {
|
|
325
|
-
Setup:
|
|
326
|
-
AppName: this.config.appName || appName,
|
|
327
|
-
AppVersion: this.config.appVersion || appVersion,
|
|
328
|
-
AppPublisher: this.config.appPublisher || "",
|
|
329
|
-
AppId: this.config.appId || `{{${appName}}}`,
|
|
330
|
-
DefaultDirName: `{autopf}\\${appName}`,
|
|
331
|
-
DefaultGroupName: appName,
|
|
332
|
-
OutputDir: outputDir,
|
|
333
|
-
OutputBaseFilename: outputName,
|
|
334
|
-
Compression: "lzma2",
|
|
335
|
-
SolidCompression: true,
|
|
336
|
-
ArchitecturesAllowed: this.getArchitecturesAllowed(arch),
|
|
337
|
-
ArchitecturesInstallIn64BitMode: arch === "x64" ? "x64compatible" : "",
|
|
338
|
-
SetupIconFile: this.config.setupIconFile || "",
|
|
339
|
-
UninstallDisplayIcon: `{app}\\${exeName}`,
|
|
340
|
-
LicenseFile: this.config.licenseFile || "",
|
|
341
|
-
PrivilegesRequired: "admin",
|
|
342
|
-
WizardStyle: "modern",
|
|
343
|
-
},
|
|
421
|
+
Setup: setup,
|
|
344
422
|
Languages: [
|
|
345
|
-
{
|
|
346
|
-
|
|
347
|
-
MessagesFile: "compiler:Default.isl",
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
Name: "chinesesimplified",
|
|
351
|
-
MessagesFile: "compiler:Languages\\ChineseSimplified.isl",
|
|
352
|
-
},
|
|
423
|
+
{ Name: "english", MessagesFile: "compiler:Default.isl" },
|
|
424
|
+
{ Name: "chinesesimplified", MessagesFile: "compiler:Languages\\ChineseSimplified.isl" },
|
|
353
425
|
],
|
|
354
426
|
Tasks: [],
|
|
355
427
|
Files: [
|
|
@@ -360,103 +432,102 @@ class MakerInnosetup extends maker_base_1.default {
|
|
|
360
432
|
},
|
|
361
433
|
],
|
|
362
434
|
Icons: [
|
|
363
|
-
{
|
|
364
|
-
|
|
365
|
-
Filename: `{app}\\${exeName}`,
|
|
366
|
-
},
|
|
367
|
-
{
|
|
368
|
-
Name: `{group}\\Uninstall ${appName}`,
|
|
369
|
-
Filename: "{uninstallexe}",
|
|
370
|
-
},
|
|
435
|
+
{ Name: `{group}\\${appName}`, Filename: `{app}\\${exeName}` },
|
|
436
|
+
{ Name: `{group}\\卸载 ${appName}`, Filename: "{uninstallexe}" },
|
|
371
437
|
],
|
|
372
438
|
Run: [
|
|
373
439
|
{
|
|
374
440
|
Filename: `{app}\\${exeName}`,
|
|
375
|
-
Description:
|
|
441
|
+
Description: `启动 ${appName}`,
|
|
376
442
|
Flags: "nowait postinstall skipifsilent",
|
|
377
443
|
},
|
|
378
444
|
],
|
|
379
445
|
};
|
|
380
446
|
}
|
|
381
447
|
/**
|
|
382
|
-
*
|
|
448
|
+
* 合并用户配置与默认配置
|
|
449
|
+
*
|
|
450
|
+
* @param defaultConfig - 默认配置
|
|
451
|
+
* @param userConfig - 用户配置
|
|
452
|
+
* @returns 合并后的配置
|
|
383
453
|
*/
|
|
384
454
|
mergeConfig(defaultConfig, userConfig) {
|
|
385
455
|
if (!userConfig) {
|
|
386
456
|
return defaultConfig;
|
|
387
457
|
}
|
|
388
458
|
return {
|
|
389
|
-
Defines: userConfig.Defines
|
|
459
|
+
Defines: userConfig.Defines ?? defaultConfig.Defines,
|
|
390
460
|
Setup: { ...defaultConfig.Setup, ...userConfig.Setup },
|
|
391
|
-
Languages: userConfig.Languages
|
|
392
|
-
Tasks: userConfig.Tasks
|
|
393
|
-
Types: userConfig.Types
|
|
394
|
-
Components: userConfig.Components
|
|
395
|
-
Files: userConfig.Files
|
|
396
|
-
Dirs: userConfig.Dirs
|
|
397
|
-
Icons: userConfig.Icons
|
|
398
|
-
INI: userConfig.INI
|
|
399
|
-
InstallDelete: userConfig.InstallDelete
|
|
400
|
-
UninstallDelete: userConfig.UninstallDelete
|
|
401
|
-
Registry: userConfig.Registry
|
|
402
|
-
Run: userConfig.Run
|
|
403
|
-
UninstallRun: userConfig.UninstallRun
|
|
404
|
-
Messages: userConfig.Messages
|
|
405
|
-
CustomMessages: userConfig.CustomMessages
|
|
406
|
-
Code: userConfig.Code
|
|
461
|
+
Languages: userConfig.Languages ?? defaultConfig.Languages,
|
|
462
|
+
Tasks: userConfig.Tasks ?? defaultConfig.Tasks,
|
|
463
|
+
Types: userConfig.Types ?? defaultConfig.Types,
|
|
464
|
+
Components: userConfig.Components ?? defaultConfig.Components,
|
|
465
|
+
Files: userConfig.Files ?? defaultConfig.Files,
|
|
466
|
+
Dirs: userConfig.Dirs ?? defaultConfig.Dirs,
|
|
467
|
+
Icons: userConfig.Icons ?? defaultConfig.Icons,
|
|
468
|
+
INI: userConfig.INI ?? defaultConfig.INI,
|
|
469
|
+
InstallDelete: userConfig.InstallDelete ?? defaultConfig.InstallDelete,
|
|
470
|
+
UninstallDelete: userConfig.UninstallDelete ?? defaultConfig.UninstallDelete,
|
|
471
|
+
Registry: userConfig.Registry ?? defaultConfig.Registry,
|
|
472
|
+
Run: userConfig.Run ?? defaultConfig.Run,
|
|
473
|
+
UninstallRun: userConfig.UninstallRun ?? defaultConfig.UninstallRun,
|
|
474
|
+
Messages: userConfig.Messages ?? defaultConfig.Messages,
|
|
475
|
+
CustomMessages: userConfig.CustomMessages ?? defaultConfig.CustomMessages,
|
|
476
|
+
Code: userConfig.Code ?? defaultConfig.Code,
|
|
407
477
|
};
|
|
408
478
|
}
|
|
409
479
|
/**
|
|
410
|
-
*
|
|
480
|
+
* 添加桌面图标和快速启动任务
|
|
481
|
+
*
|
|
482
|
+
* @param config - Inno Setup 配置
|
|
483
|
+
* @param appName - 应用名称
|
|
411
484
|
*/
|
|
412
485
|
addTasks(config, appName) {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
!hasDesktopTask &&
|
|
421
|
-
!hasDesktopIcon) {
|
|
422
|
-
config.Tasks.push({
|
|
486
|
+
const tasks = [...(config.Tasks ?? [])];
|
|
487
|
+
const icons = [...(config.Icons ?? [])];
|
|
488
|
+
// 检查是否已存在桌面图标任务
|
|
489
|
+
const hasDesktopTask = tasks.some((t) => t.Name === "desktopicon");
|
|
490
|
+
const hasDesktopIcon = icons.some((i) => i.Name.includes("{autodesktop}") && i.Tasks === "desktopicon");
|
|
491
|
+
if (this.config.createDesktopIcon !== false && !hasDesktopTask && !hasDesktopIcon) {
|
|
492
|
+
tasks.push({
|
|
423
493
|
Name: "desktopicon",
|
|
424
|
-
Description: "
|
|
425
|
-
GroupDescription: "
|
|
494
|
+
Description: "创建桌面图标(&D)",
|
|
495
|
+
GroupDescription: "附加图标:",
|
|
426
496
|
Flags: "unchecked",
|
|
427
497
|
});
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
});
|
|
434
|
-
}
|
|
498
|
+
icons.push({
|
|
499
|
+
Name: `{autodesktop}\\${appName}`,
|
|
500
|
+
Filename: `{app}\\${appName}.exe`,
|
|
501
|
+
Tasks: "desktopicon",
|
|
502
|
+
});
|
|
435
503
|
}
|
|
436
|
-
//
|
|
437
|
-
const hasQuickLaunchTask =
|
|
438
|
-
const hasQuickLaunchIcon =
|
|
439
|
-
if (this.config.createQuickLaunchIcon &&
|
|
440
|
-
|
|
441
|
-
!hasQuickLaunchIcon) {
|
|
442
|
-
config.Tasks.push({
|
|
504
|
+
// 检查是否已存在快速启动任务
|
|
505
|
+
const hasQuickLaunchTask = tasks.some((t) => t.Name === "quicklaunchicon");
|
|
506
|
+
const hasQuickLaunchIcon = icons.some((i) => i.Name.includes("Quick Launch") && i.Tasks === "quicklaunchicon");
|
|
507
|
+
if (this.config.createQuickLaunchIcon && !hasQuickLaunchTask && !hasQuickLaunchIcon) {
|
|
508
|
+
tasks.push({
|
|
443
509
|
Name: "quicklaunchicon",
|
|
444
|
-
Description: "
|
|
445
|
-
GroupDescription: "
|
|
510
|
+
Description: "创建快速启动图标(&Q)",
|
|
511
|
+
GroupDescription: "附加图标:",
|
|
446
512
|
Flags: "unchecked",
|
|
447
513
|
});
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
Tasks: "quicklaunchicon",
|
|
454
|
-
});
|
|
455
|
-
}
|
|
514
|
+
icons.push({
|
|
515
|
+
Name: `{userappdata}\\Microsoft\\Internet Explorer\\Quick Launch\\${appName}`,
|
|
516
|
+
Filename: `{app}\\${appName}.exe`,
|
|
517
|
+
Tasks: "quicklaunchicon",
|
|
518
|
+
});
|
|
456
519
|
}
|
|
520
|
+
config.Tasks = tasks;
|
|
521
|
+
config.Icons = icons;
|
|
457
522
|
}
|
|
458
523
|
/**
|
|
459
|
-
*
|
|
524
|
+
* 编译 ISS 脚本
|
|
525
|
+
*
|
|
526
|
+
* @param scriptPath - 脚本文件路径
|
|
527
|
+
* @param compilerPath - 编译器路径
|
|
528
|
+
* @returns 编译输出
|
|
529
|
+
* @throws CompilationError 编译失败
|
|
530
|
+
* @throws CompilationTimeoutError 编译超时
|
|
460
531
|
*/
|
|
461
532
|
async compileScript(scriptPath, compilerPath) {
|
|
462
533
|
return new Promise((resolve, reject) => {
|
|
@@ -464,44 +535,45 @@ class MakerInnosetup extends maker_base_1.default {
|
|
|
464
535
|
if (this.config.isccOptions) {
|
|
465
536
|
args.push(...this.config.isccOptions);
|
|
466
537
|
}
|
|
467
|
-
const
|
|
468
|
-
stdio: "pipe",
|
|
469
|
-
});
|
|
538
|
+
const timeout = this.config.compileTimeout ?? DEFAULT_COMPILE_TIMEOUT;
|
|
470
539
|
let output = "";
|
|
471
540
|
let errorOutput = "";
|
|
472
541
|
let isResolved = false;
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
if (!
|
|
476
|
-
isResolved = false;
|
|
477
|
-
console.error("Innosetup compilation timeout, killing process...");
|
|
542
|
+
let iscc = null;
|
|
543
|
+
const cleanup = () => {
|
|
544
|
+
if (iscc && !iscc.killed) {
|
|
478
545
|
try {
|
|
479
546
|
iscc.kill("SIGKILL");
|
|
480
547
|
}
|
|
481
|
-
catch
|
|
482
|
-
|
|
548
|
+
catch {
|
|
549
|
+
// 忽略终止进程时的错误
|
|
483
550
|
}
|
|
484
|
-
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
const timeoutHandle = setTimeout(() => {
|
|
554
|
+
if (!isResolved) {
|
|
555
|
+
isResolved = true;
|
|
556
|
+
cleanup();
|
|
557
|
+
reject(new errors_1.CompilationTimeoutError(timeout));
|
|
485
558
|
}
|
|
486
559
|
}, timeout);
|
|
487
|
-
|
|
560
|
+
try {
|
|
561
|
+
iscc = (0, child_process_1.spawn)(compilerPath, args, { stdio: "pipe" });
|
|
562
|
+
}
|
|
563
|
+
catch (err) {
|
|
488
564
|
clearTimeout(timeoutHandle);
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
catch (e) { }
|
|
495
|
-
};
|
|
496
|
-
iscc.stdout.on("data", (data) => {
|
|
565
|
+
reject(new Error(`启动 Inno Setup 编译器失败: ${err instanceof Error ? err.message : String(err)}`));
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
iscc.stdout?.on("data", (data) => {
|
|
497
569
|
const text = data.toString();
|
|
498
570
|
output += text;
|
|
499
|
-
|
|
571
|
+
(0, logger_1.logCompile)("%s", text.trim());
|
|
500
572
|
});
|
|
501
|
-
iscc.stderr
|
|
573
|
+
iscc.stderr?.on("data", (data) => {
|
|
502
574
|
const text = data.toString();
|
|
503
575
|
errorOutput += text;
|
|
504
|
-
|
|
576
|
+
(0, logger_1.logCompile)("错误: %s", text.trim());
|
|
505
577
|
});
|
|
506
578
|
iscc.on("close", (code) => {
|
|
507
579
|
if (isResolved)
|
|
@@ -513,121 +585,69 @@ class MakerInnosetup extends maker_base_1.default {
|
|
|
513
585
|
}
|
|
514
586
|
else {
|
|
515
587
|
cleanup();
|
|
516
|
-
reject(new
|
|
588
|
+
reject(new errors_1.CompilationError(code ?? 1, errorOutput || output));
|
|
517
589
|
}
|
|
518
590
|
});
|
|
519
591
|
iscc.on("error", (err) => {
|
|
520
592
|
if (isResolved)
|
|
521
593
|
return;
|
|
522
594
|
isResolved = true;
|
|
595
|
+
clearTimeout(timeoutHandle);
|
|
523
596
|
cleanup();
|
|
524
|
-
reject(new Error(
|
|
597
|
+
reject(new Error(`运行 Inno Setup 编译器失败: ${err.message}`));
|
|
525
598
|
});
|
|
526
|
-
// 处理进程意外退出
|
|
527
|
-
process.on("exit", cleanup);
|
|
528
|
-
process.on("SIGINT", cleanup);
|
|
529
|
-
process.on("SIGTERM", cleanup);
|
|
530
599
|
});
|
|
531
600
|
}
|
|
532
601
|
/**
|
|
533
|
-
*
|
|
602
|
+
* 查找生成的安装程序文件
|
|
603
|
+
*
|
|
604
|
+
* @param searchDir - 搜索目录
|
|
605
|
+
* @param appName - 应用名称
|
|
606
|
+
* @param appVersion - 应用版本
|
|
607
|
+
* @param archId - 架构标识
|
|
608
|
+
* @returns 安装程序文件路径数组
|
|
609
|
+
* @throws InstallerNotFoundError 如果找不到安装程序
|
|
534
610
|
*/
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
const compilerPath = this.findInnosetupCompiler();
|
|
549
|
-
console.log(`Using Innosetup compiler: ${compilerPath}`);
|
|
550
|
-
// 确定输出目录:根据架构生成子目录
|
|
551
|
-
// 格式: makeDir/innosetup.windows/x64 或 makeDir/innosetup.windows/arm64
|
|
552
|
-
const baseOutputDir = this.config.outputDir || path.join(makeDir, "innosetup.windows");
|
|
553
|
-
const outputDir = path.join(baseOutputDir, archId);
|
|
554
|
-
// 确保输出目录存在
|
|
555
|
-
if (!fs.existsSync(outputDir)) {
|
|
556
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
557
|
-
}
|
|
558
|
-
console.log(`Output directory: ${outputDir}`);
|
|
559
|
-
// 生成或使用脚本
|
|
560
|
-
let scriptPath;
|
|
561
|
-
let finalConfig;
|
|
562
|
-
let actualOutputDir = outputDir; // 实际的输出目录
|
|
563
|
-
if (this.config.scriptPath) {
|
|
564
|
-
// 使用用户提供的脚本
|
|
565
|
-
scriptPath = this.resolvePath(this.config.scriptPath, this.getProjectDir());
|
|
566
|
-
console.log(`Using custom script: ${scriptPath}`);
|
|
567
|
-
// 解析脚本以获取实际的输出目录
|
|
568
|
-
try {
|
|
569
|
-
const parsedConfig = parser_1.InnoScriptParser.parseFile(scriptPath);
|
|
570
|
-
if (parsedConfig.Setup?.OutputDir) {
|
|
571
|
-
// 如果脚本中定义了输出目录,使用绝对路径
|
|
572
|
-
const scriptOutputDir = parsedConfig.Setup.OutputDir;
|
|
573
|
-
actualOutputDir = path.isAbsolute(scriptOutputDir)
|
|
574
|
-
? scriptOutputDir
|
|
575
|
-
: path.resolve(path.dirname(scriptPath), scriptOutputDir);
|
|
576
|
-
console.log(`Script defines OutputDir: ${actualOutputDir}`);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
catch (err) {
|
|
580
|
-
console.warn(`Failed to parse script for OutputDir: ${err}`);
|
|
581
|
-
// 继续使用默认的 outputDir
|
|
611
|
+
findInstaller(searchDir, appName, appVersion, archId) {
|
|
612
|
+
(0, logger_1.log)("在目录中搜索安装程序: %s", searchDir);
|
|
613
|
+
// 尝试预期的文件名格式
|
|
614
|
+
const expectedNames = [
|
|
615
|
+
`${appName}-${appVersion}-${archId}-setup.exe`, // 默认格式
|
|
616
|
+
`${appName}_${appVersion}.exe`, // 用户自定义格式
|
|
617
|
+
`${appName}-${appVersion}.exe`, // 无架构格式
|
|
618
|
+
];
|
|
619
|
+
for (const expectedName of expectedNames) {
|
|
620
|
+
const expectedPath = path.join(searchDir, expectedName);
|
|
621
|
+
if ((0, path_1.fileExists)(expectedPath)) {
|
|
622
|
+
(0, logger_1.log)("找到安装程序: %s", expectedPath);
|
|
623
|
+
return [expectedPath];
|
|
582
624
|
}
|
|
583
625
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
}
|
|
599
|
-
// 编译安装包
|
|
600
|
-
console.log("Compiling installer...");
|
|
601
|
-
await this.compileScript(scriptPath, compilerPath);
|
|
602
|
-
// 查找生成的安装包
|
|
603
|
-
// 如果使用自定义脚本,在实际输出目录中查找
|
|
604
|
-
const searchDir = actualOutputDir;
|
|
605
|
-
console.log(`Searching for installer in: ${searchDir}`);
|
|
606
|
-
// 尝试匹配输出文件名模式
|
|
607
|
-
const outputPattern = `${appName}-${appVersion}-${archId}-setup.exe`;
|
|
608
|
-
const outputPath = path.join(searchDir, outputPattern);
|
|
609
|
-
if (fs.existsSync(outputPath)) {
|
|
610
|
-
console.log(`Installer created successfully: ${outputPath}`);
|
|
611
|
-
return [outputPath];
|
|
612
|
-
}
|
|
613
|
-
// 如果没找到,尝试查找所有 exe 文件
|
|
614
|
-
if (fs.existsSync(searchDir)) {
|
|
615
|
-
const files = fs.readdirSync(searchDir);
|
|
616
|
-
const exeFiles = files
|
|
617
|
-
.filter((f) => f.endsWith(".exe"))
|
|
618
|
-
.map((f) => path.join(searchDir, f));
|
|
626
|
+
// 搜索目录中的 .exe 文件
|
|
627
|
+
const searchInDir = (dir) => {
|
|
628
|
+
if (!(0, path_1.fileExists)(dir))
|
|
629
|
+
return [];
|
|
630
|
+
const files = fs.readdirSync(dir);
|
|
631
|
+
return files.filter((f) => f.endsWith(".exe")).map((f) => path.join(dir, f));
|
|
632
|
+
};
|
|
633
|
+
// 先在当前目录搜索
|
|
634
|
+
let exeFiles = searchInDir(searchDir);
|
|
635
|
+
// 如果没找到,尝试搜索子目录 (如 innosetup.windows/x64)
|
|
636
|
+
if (exeFiles.length === 0) {
|
|
637
|
+
const subDir = path.join(searchDir, "innosetup.windows", archId);
|
|
638
|
+
(0, logger_1.log)("尝试搜索子目录: %s", subDir);
|
|
639
|
+
exeFiles = searchInDir(subDir);
|
|
619
640
|
if (exeFiles.length > 0) {
|
|
620
|
-
|
|
641
|
+
(0, logger_1.log)("在子目录中找到安装程序: %s", exeFiles[0]);
|
|
621
642
|
return exeFiles;
|
|
622
643
|
}
|
|
623
644
|
}
|
|
624
|
-
|
|
645
|
+
else {
|
|
646
|
+
(0, logger_1.log)("找到安装程序: %s", exeFiles[0]);
|
|
647
|
+
return exeFiles;
|
|
648
|
+
}
|
|
649
|
+
throw new errors_1.InstallerNotFoundError(searchDir);
|
|
625
650
|
}
|
|
626
651
|
}
|
|
627
652
|
exports.default = MakerInnosetup;
|
|
628
|
-
|
|
629
|
-
__exportStar(require("./types"), exports);
|
|
630
|
-
var generator_2 = require("./generator");
|
|
631
|
-
Object.defineProperty(exports, "InnoScriptGenerator", { enumerable: true, get: function () { return generator_2.InnoScriptGenerator; } });
|
|
632
|
-
var parser_2 = require("./parser");
|
|
633
|
-
Object.defineProperty(exports, "InnoScriptParser", { enumerable: true, get: function () { return parser_2.InnoScriptParser; } });
|
|
653
|
+
//# sourceMappingURL=MakerInnosetup.js.map
|