"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SquirrelBuilder = exports.convertVersion = void 0; const builder_util_1 = require("builder-util"); const fs_1 = require("builder-util/out/fs"); const archive_1 = require("app-builder-lib/out/targets/archive"); const wine_1 = require("app-builder-lib/out/wine"); const fs_extra_1 = require("fs-extra"); const path = require("path"); const archiver = require("archiver"); const fs = require("fs/promises"); function convertVersion(version) { const parts = version.split("-"); const mainVersion = parts.shift(); if (parts.length > 0) { return [mainVersion, parts.join("-").replace(/\./g, "")].join("-"); } else { return mainVersion; } } exports.convertVersion = convertVersion; function syncReleases(outputDirectory, options) { builder_util_1.log.info("syncing releases to build delta package"); const args = (0, wine_1.prepareWindowsExecutableArgs)(["-u", options.remoteReleases, "-r", outputDirectory], path.join(options.vendorPath, "SyncReleases.exe")); if (options.remoteToken) { args.push("-t", options.remoteToken); } return (0, builder_util_1.spawn)(process.platform === "win32" ? path.join(options.vendorPath, "SyncReleases.exe") : "mono", args); } class SquirrelBuilder { constructor(options, outputDirectory, packager) { this.options = options; this.outputDirectory = outputDirectory; this.packager = packager; } async buildInstaller(outFileNames, appOutDir, outDir, arch) { const packager = this.packager; const dirToArchive = await packager.info.tempDirManager.createTempDir({ prefix: "squirrel-windows" }); const outputDirectory = this.outputDirectory; const options = this.options; const appUpdate = path.join(dirToArchive, "Update.exe"); await Promise.all([ (0, fs_1.copyFile)(path.join(options.vendorPath, "Update.exe"), appUpdate).then(() => packager.sign(appUpdate)), Promise.all([ fs.rm(`${outputDirectory.replace(/\\/g, "/")}/*-full.nupkg`, { recursive: true, force: true }), fs.rm(path.join(outputDirectory, "RELEASES"), { recursive: true, force: true }), ]).then(() => fs.mkdir(outputDirectory, { recursive: true })), ]); if ((0, builder_util_1.isEmptyOrSpaces)(options.description)) { options.description = options.productName; } if (options.remoteReleases) { await syncReleases(outputDirectory, options); } const version = convertVersion(options.version); const nupkgPath = path.join(outputDirectory, outFileNames.packageFile); const setupPath = path.join(outputDirectory, outFileNames.setupFile); await Promise.all([ pack(options, appOutDir, appUpdate, nupkgPath, version, packager), (0, fs_1.copyFile)(path.join(options.vendorPath, "Setup.exe"), setupPath), (0, fs_1.copyFile)(options.loadingGif ? path.resolve(packager.projectDir, options.loadingGif) : path.join(options.vendorPath, "install-spinner.gif"), path.join(dirToArchive, "background.gif")), ]); // releasify can be called only after pack nupkg and nupkg must be in the final output directory (where other old version nupkg can be located) await this.releasify(nupkgPath, outFileNames.packageFile).then(it => (0, fs_extra_1.writeFile)(path.join(dirToArchive, "RELEASES"), it)); const embeddedArchiveFile = await this.createEmbeddedArchiveFile(nupkgPath, dirToArchive); await (0, wine_1.execWine)(path.join(options.vendorPath, "WriteZipToSetup.exe"), null, [setupPath, embeddedArchiveFile]); await packager.signAndEditResources(setupPath, arch, outDir); if (options.msi && process.platform === "win32") { const outFile = outFileNames.setupFile.replace(".exe", ".msi"); await msi(options, nupkgPath, setupPath, outputDirectory, outFile); // rcedit can only edit .exe resources await packager.sign(path.join(outputDirectory, outFile)); } } async releasify(nupkgPath, packageName) { const args = ["--releasify", nupkgPath, "--releaseDir", this.outputDirectory]; const out = (await execSw(this.options, args)).trim(); if (builder_util_1.debug.enabled) { (0, builder_util_1.debug)(`Squirrel output: ${out}`); } const lines = out.split("\n"); for (let i = lines.length - 1; i > -1; i--) { const line = lines[i]; if (line.includes(packageName)) { return line.trim(); } } throw new Error(`Invalid output, cannot find last release entry, output: ${out}`); } async createEmbeddedArchiveFile(nupkgPath, dirToArchive) { const embeddedArchiveFile = await this.packager.getTempFile("setup.zip"); const path7za = await (0, builder_util_1.getPath7za)(); await (0, builder_util_1.exec)(path7za, (0, archive_1.compute7zCompressArgs)("zip", { isRegularFile: true, compression: this.packager.compression, }).concat(embeddedArchiveFile, "."), { cwd: dirToArchive, }); await (0, builder_util_1.exec)(path7za, (0, archive_1.compute7zCompressArgs)("zip", { isRegularFile: true, compression: "store" /* nupkg is already compressed */, }).concat(embeddedArchiveFile, nupkgPath)); return embeddedArchiveFile; } } exports.SquirrelBuilder = SquirrelBuilder; async function pack(options, directory, updateFile, outFile, version, packager) { // SW now doesn't support 0-level nupkg compressed files. It means that we are forced to use level 1 if store level requested. const archive = archiver("zip", { zlib: { level: Math.max(1, options.packageCompressionLevel == null ? 9 : options.packageCompressionLevel) } }); const archiveOut = (0, fs_extra_1.createWriteStream)(outFile); const archivePromise = new Promise((resolve, reject) => { archive.on("error", reject); archiveOut.on("error", reject); archiveOut.on("close", resolve); }); archive.pipe(archiveOut); const author = options.authors; const copyright = options.copyright || `Copyright © ${new Date().getFullYear()} ${author}`; const nuspecContent = ` ${options.appId} ${version} ${options.productName} ${author} ${options.iconUrl} false ${options.description} ${copyright}${options.extraMetadataSpecs || ""} `; (0, builder_util_1.debug)(`Created NuSpec file:\n${nuspecContent}`); archive.append(nuspecContent.replace(/\n/, "\r\n"), { name: `${options.name}.nuspec` }); //noinspection SpellCheckingInspection archive.append(` `.replace(/\n/, "\r\n"), { name: ".rels", prefix: "_rels" }); //noinspection SpellCheckingInspection archive.append(` `.replace(/\n/, "\r\n"), { name: "[Content_Types].xml" }); archive.append(` ${author} ${options.description} ${options.appId} ${version} ${options.productName} NuGet, Version=2.8.50926.602, Culture=neutral, PublicKeyToken=null;Microsoft Windows NT 6.2.9200.0;.NET Framework 4 `.replace(/\n/, "\r\n"), { name: "1.psmdcp", prefix: "package/services/metadata/core-properties" }); archive.file(updateFile, { name: "Update.exe", prefix: "lib/net45" }); await encodedZip(archive, directory, "lib/net45", options.vendorPath, packager); await archivePromise; } async function execSw(options, args) { return (0, builder_util_1.exec)(process.platform === "win32" ? path.join(options.vendorPath, "Update.com") : "mono", (0, wine_1.prepareWindowsExecutableArgs)(args, path.join(options.vendorPath, "Update-Mono.exe")), { env: { ...process.env, SZA_PATH: await (0, builder_util_1.getPath7za)(), }, }); } async function msi(options, nupkgPath, setupPath, outputDirectory, outFile) { const args = ["--createMsi", nupkgPath, "--bootstrapperExe", setupPath]; await execSw(options, args); //noinspection SpellCheckingInspection await (0, builder_util_1.exec)(path.join(options.vendorPath, "candle.exe"), ["-nologo", "-ext", "WixNetFxExtension", "-out", "Setup.wixobj", "Setup.wxs"], { cwd: outputDirectory, }); //noinspection SpellCheckingInspection await (0, builder_util_1.exec)(path.join(options.vendorPath, "light.exe"), ["-ext", "WixNetFxExtension", "-sval", "-out", outFile, "Setup.wixobj"], { cwd: outputDirectory, }); //noinspection SpellCheckingInspection await Promise.all([ (0, fs_extra_1.unlink)(path.join(outputDirectory, "Setup.wxs")), (0, fs_extra_1.unlink)(path.join(outputDirectory, "Setup.wixobj")), (0, fs_extra_1.unlink)(path.join(outputDirectory, outFile.replace(".msi", ".wixpdb"))).catch((e) => (0, builder_util_1.debug)(e.toString())), ]); } async function encodedZip(archive, dir, prefix, vendorPath, packager) { await (0, fs_1.walk)(dir, null, { isIncludeDir: true, consume: async (file, stats) => { if (stats.isDirectory()) { return; } const relativeSafeFilePath = file.substring(dir.length + 1).replace(/\\/g, "/"); archive._append(file, { name: relativeSafeFilePath, prefix, stats, }); // createExecutableStubForExe // https://github.com/Squirrel/Squirrel.Windows/pull/1051 Only generate execution stubs for the top-level executables if (file.endsWith(".exe") && !file.includes("squirrel.exe") && !relativeSafeFilePath.includes("/")) { const tempFile = await packager.getTempFile("stub.exe"); await (0, fs_1.copyFile)(path.join(vendorPath, "StubExecutable.exe"), tempFile); await (0, wine_1.execWine)(path.join(vendorPath, "WriteZipToSetup.exe"), null, ["--copy-stub-resources", file, tempFile]); await packager.sign(tempFile); archive._append(tempFile, { name: relativeSafeFilePath.substring(0, relativeSafeFilePath.length - 4) + "_ExecutionStub.exe", prefix, stats: await (0, fs_extra_1.stat)(tempFile), }); } }, }); archive.finalize(); } //# sourceMappingURL=squirrelPack.js.map