fix: 使用IExpress生成可安装分发包

This commit is contained in:
yu 2026-10-27 16:53:03 +08:00
parent 442eeaf9c1
commit dd27ec27f2

View File

@ -14,7 +14,8 @@ const productFolderName = `RPA-Studio-${version}-win-x64`;
const productFolder = path.join(releaseRoot, productFolderName);
const zipPath = path.join(releaseRoot, `${productFolderName}.zip`);
const setupPath = path.join(releaseRoot, `RPA-Studio-Setup-${version}-win-x64.exe`);
const setupArchive = path.join(releaseRoot, `${productFolderName}.7z`);
const installerPayload = path.join(releaseRoot, ".installer-payload");
const installerSed = path.join(releaseRoot, ".installer.sed");
function assertInsideRelease(target) {
const relative = path.relative(releaseRoot, path.resolve(target));
@ -29,7 +30,7 @@ function run(command, args) {
}
fs.mkdirSync(releaseRoot, { recursive: true });
for (const target of [productFolder, zipPath, setupPath, setupArchive]) {
for (const target of [productFolder, zipPath, setupPath, installerPayload, installerSed]) {
assertInsideRelease(target);
fs.rmSync(target, { recursive: true, force: true });
}
@ -144,16 +145,38 @@ zip.writeZip(zipPath);
const zipSha256 = createHash("sha256").update(fs.readFileSync(zipPath)).digest("hex");
let setupSha256 = "";
const sevenZip = "C:/Program Files/7-Zip/7z.exe";
const sfxModule = "C:/Program Files/7-Zip/7z.sfx";
if (fs.existsSync(sevenZip) && fs.existsSync(sfxModule)) {
console.log("[package] setup sfx");
const archived = spawnSync(sevenZip, ["a", "-t7z", setupArchive, ".", "-mx=9"], { cwd: productFolder, stdio: "inherit" });
if (archived.status !== 0) throw new Error(`7-Zip 打包失败,退出码 ${archived.status}`);
const config = Buffer.from(`;!@Install@!UTF-8!\nTitle=\"RPA Studio ${version}\"\nBeginPrompt=\"将 RPA Studio 安装到当前用户并创建桌面快捷方式?\"\nRunProgram=\"安装到本机.cmd\"\nGUIMode=\"1\"\n;!@InstallEnd@!\n`, "utf8");
fs.writeFileSync(setupPath, Buffer.concat([fs.readFileSync(sfxModule), config, fs.readFileSync(setupArchive)]));
setupSha256 = createHash("sha256").update(fs.readFileSync(setupPath)).digest("hex");
}
const iexpress = path.join(process.env.SystemRoot || "C:/Windows", "System32", "iexpress.exe");
if (!fs.existsSync(iexpress)) throw new Error(`找不到 Windows IExpress:${iexpress}`);
console.log("[package] setup iexpress");
fs.mkdirSync(installerPayload, { recursive: true });
fs.copyFileSync(zipPath, path.join(installerPayload, "payload.zip"));
fs.writeFileSync(path.join(installerPayload, "install.cmd"), [
"@echo off",
"chcp 65001 >nul",
"set \"TARGET=%LOCALAPPDATA%\\Programs\\RPA Studio\"",
"set \"STAGE=%TEMP%\\RPA-Studio-Install-%RANDOM%\"",
"powershell -NoProfile -ExecutionPolicy Bypass -Command \"Expand-Archive -LiteralPath '%~dp0payload.zip' -DestinationPath '%STAGE%' -Force\"",
`robocopy "%STAGE%\\${productFolderName}" "%TARGET%" /E /R:2 /W:1 /NFL /NDL /NJH /NJS /NP >nul`,
"powershell -NoProfile -ExecutionPolicy Bypass -Command \"$w=New-Object -ComObject WScript.Shell;$s=$w.CreateShortcut([IO.Path]::Combine([Environment]::GetFolderPath('Desktop'),'RPA Studio.lnk'));$s.TargetPath=[IO.Path]::Combine($env:LOCALAPPDATA,'Programs','RPA Studio','RPA Studio.exe');$s.WorkingDirectory=[IO.Path]::Combine($env:LOCALAPPDATA,'Programs','RPA Studio');$s.Save()\"",
"start \"RPA Studio\" \"%TARGET%\\RPA Studio.exe\"",
"rmdir /s /q \"%STAGE%\"",
"exit /b 0"
].join("\r\n"), "utf8");
const sourceDir = `${installerPayload.replace(/\//g, "\\")}\\`;
fs.writeFileSync(installerSed, [
"[Version]", "Class=IEXPRESS", "SEDVersion=3", "[Options]", "PackagePurpose=InstallApp", "ShowInstallProgramWindow=1",
"HideExtractAnimation=0", "UseLongFileName=1", "InsideCompressed=0", "CAB_FixedSize=0", "CAB_ResvCodeSigning=0",
"RebootMode=N", "InstallPrompt=%InstallPrompt%", "DisplayLicense=", "FinishMessage=%FinishMessage%",
`TargetName=${setupPath}`, `FriendlyName=RPA Studio ${version}`, "AppLaunched=install.cmd", "PostInstallCmd=<None>",
"AdminQuietInstCmd=install.cmd", "UserQuietInstCmd=install.cmd", "SourceFiles=SourceFiles", "[Strings]",
`InstallPrompt=Install RPA Studio ${version} for the current Windows user?`, "FinishMessage=RPA Studio installation completed.",
"FILE0=payload.zip", "FILE1=install.cmd", "[SourceFiles]", `SourceFiles0=${sourceDir}`, "[SourceFiles0]", "%FILE0%=", "%FILE1%=", ""
].join("\r\n"), "utf8");
const builtSetup = spawnSync(iexpress, ["/N", installerSed], { cwd: releaseRoot, stdio: "inherit", windowsHide: true });
if (builtSetup.status !== 0 || !fs.existsSync(setupPath)) throw new Error(`IExpress 安装包生成失败,退出码 ${builtSetup.status}`);
setupSha256 = createHash("sha256").update(fs.readFileSync(setupPath)).digest("hex");
fs.rmSync(installerPayload, { recursive: true, force: true });
fs.rmSync(installerSed, { force: true });
const sums = [`${zipSha256} ${path.basename(zipPath)}`];
if (setupSha256) sums.push(`${setupSha256} ${path.basename(setupPath)}`);
fs.writeFileSync(path.join(releaseRoot, "SHA256SUMS.txt"), `${sums.join("\r\n")}\r\n`, "utf8");