diff --git a/package.json b/package.json index ce47bc03aca..4e91cadbc7e 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "7zip-bin": "^2.0.4", "ansi-escapes": "^1.4.0", "archiver": "^1.3.0", - "archiver-utils": "^1.3.0", "asar-electron-builder": "^0.13.5", "bluebird-lst-c": "^1.0.5", "chalk": "^1.1.3", diff --git a/src/targets/squirrelPack.ts b/src/targets/squirrelPack.ts index d91547f7053..c06c8102b45 100644 --- a/src/targets/squirrelPack.ts +++ b/src/targets/squirrelPack.ts @@ -1,11 +1,11 @@ import * as path from "path" import BluebirdPromise from "bluebird-lst-c" -import { remove, copy, createWriteStream, unlink, ensureDir } from "fs-extra-p" +import { remove, copy, createWriteStream, unlink, ensureDir, stat } from "fs-extra-p" import { spawn, exec, prepareArgs, execWine, debug } from "../util/util" import { WinPackager } from "../winPackager" import { log } from "../util/log" +import { walk, copyFile } from "../util/fs" -const archiverUtil = require("archiver-utils") const archiver = require("archiver") export function convertVersion(version: string): string { @@ -79,7 +79,7 @@ export async function buildInstaller(options: SquirrelOptions, outputDirectory: const setupPath = path.join(outputDirectory, setupExe || `${options.name || options.productName}Setup.exe`) await BluebirdPromise.all([ - pack(options, appOutDir, appUpdate, nupkgPath, version, options.packageCompressionLevel), + pack(options, appOutDir, appUpdate, nupkgPath, version, packager), copy(path.join(options.vendorPath, "Setup.exe"), setupPath), ]) @@ -91,8 +91,7 @@ export async function buildInstaller(options: SquirrelOptions, outputDirectory: embeddedArchive.finalize() await embeddedArchivePromise - const writeZipToSetup = path.join(options.vendorPath, "WriteZipToSetup.exe") - await execWine(writeZipToSetup, [setupPath, embeddedArchiveFile]) + await execWine(path.join(options.vendorPath, "WriteZipToSetup.exe"), [setupPath, embeddedArchiveFile]) await packager.signAndEditResources(setupPath) if (options.msi && process.platform === "win32") { @@ -103,8 +102,8 @@ export async function buildInstaller(options: SquirrelOptions, outputDirectory: } } -async function pack(options: SquirrelOptions, directory: string, updateFile: string, outFile: string, version: string, packageCompressionLevel?: number) { - const archive = archiver("zip", {zlib: {level: packageCompressionLevel == null ? 9 : packageCompressionLevel}}) +async function pack(options: SquirrelOptions, directory: string, updateFile: string, outFile: string, version: string, packager: WinPackager) { + const archive = archiver("zip", {zlib: {level: options.packageCompressionLevel == null ? 9 : options.packageCompressionLevel}}) const archiveOut = createWriteStream(outFile) const archivePromise = new BluebirdPromise(function (resolve, reject) { archive.on("error", reject) @@ -169,7 +168,7 @@ async function pack(options: SquirrelOptions, directory: string, updateFile: str `.replace(/\n/, "\r\n"), {name: "1.psmdcp", prefix: "package/services/metadata/core-properties"}) archive.file(updateFile, {name: "Update.exe", prefix: "lib/net45"}) - encodedZip(archive, directory, "lib/net45") + await encodedZip(archive, directory, "lib/net45", options.vendorPath, packager) await archivePromise } @@ -219,27 +218,32 @@ async function msi(options: SquirrelOptions, nupkgPath: string, setupPath: strin ]) } -function encodedZip(archive: any, dir: string, prefix: string) { - archiverUtil.walkdir(dir, function (error: any, files: any) { - if (error) { - archive.emit("error", error) +async function encodedZip(archive: any, dir: string, prefix: string, vendorPath: string, packager: WinPackager) { + await walk(dir, null, async (file, stats) => { + if (stats.isDirectory()) { return } - for (const file of files) { - if (file.stats.isDirectory()) { - continue - } - - // GBK file name encoding (or Non-English file name) caused a problem - const entryData = { - name: encodeURI(file.relative.replace(/\\/g, "/")).replace(/%5B/g, "[").replace(/%5D/g, "]"), + // GBK file name encoding (or Non-English file name) caused a problem + const relativeSafeFilePath = encodeURI(file.substring(dir.length + 1).replace(/\\/g, "/")).replace(/%5B/g, "[").replace(/%5D/g, "]") + archive._append(file, { + name: relativeSafeFilePath, + prefix: prefix, + stats: stats, + }) + + // createExecutableStubForExe + if (file.endsWith(".exe") && !file.includes("squirrel.exe")) { + const tempFile = await packager.getTempFile("stub.exe") + await copyFile(path.join(vendorPath, "StubExecutable.exe"), tempFile, null, false) + await execWine(path.join(vendorPath, "WriteZipToSetup.exe"), ["--copy-stub-resources", file, tempFile]) + + archive._append(tempFile, { + name: relativeSafeFilePath.substring(0, relativeSafeFilePath.length - 4) + "_ExecutionStub.exe", prefix: prefix, - stats: file.stats, - } - archive._append(file.path, entryData) + stats: await stat(tempFile), + }) } - - archive.finalize() }) + archive.finalize() } \ No newline at end of file diff --git a/src/targets/squirrelWindows.ts b/src/targets/squirrelWindows.ts index ee06516a91f..8a907cd4f5c 100644 --- a/src/targets/squirrelWindows.ts +++ b/src/targets/squirrelWindows.ts @@ -9,9 +9,9 @@ import { buildInstaller, convertVersion, SquirrelOptions } from "./squirrelPack" import { SquirrelWindowsOptions } from "../options/winOptions" import { Target } from "./targetFactory" -const SW_VERSION = "1.5.1" +const SW_VERSION = "1.5.1.3" //noinspection SpellCheckingInspection -const SW_SHA2 = "b9bff7b239d05258170c1c2f096aea0966bea442b61eff71f7333c0096664708" +const SW_SHA2 = "526701c61fffed97f622b110cfd15c4a1197ce082705437e9ef938c0cb8f4172" export default class SquirrelWindowsTarget extends Target { private readonly options: SquirrelWindowsOptions = Object.assign({}, this.packager.platformSpecificBuildOptions, this.packager.config.squirrelWindows) diff --git a/src/util/fs.ts b/src/util/fs.ts index e0caa63cd55..571d29e963d 100644 --- a/src/util/fs.ts +++ b/src/util/fs.ts @@ -39,7 +39,7 @@ export async function exists(file: string): Promise { } } -export async function walk(initialDirPath: string, filter?: Filter, consumer?: (file: string, stat: Stats, parent: string) => any): Promise> { +export async function walk(initialDirPath: string, filter?: Filter | null, consumer?: (file: string, stat: Stats, parent: string) => any): Promise> { const result: Array = [] const queue: Array = [initialDirPath] let addDirToResult = false @@ -89,7 +89,7 @@ const _isUseHardLink = process.platform != "win32" && process.env.USE_HARD_LINKS * Hard links is used if supported and allowed. * File permission is fixed — allow execute for all if owner can, allow read for all if owner can. */ -export function copyFile(src: string, dest: string, stats?: Stats, isUseHardLink = _isUseHardLink): Promise { +export function copyFile(src: string, dest: string, stats?: Stats | null, isUseHardLink = _isUseHardLink): Promise { if (stats != null) { const originalModeNumber = stats.mode const mode = new Mode(stats) diff --git a/test/src/helpers/expectedContents.ts b/test/src/helpers/expectedContents.ts index ddf3598f11b..875c4b07e66 100755 --- a/test/src/helpers/expectedContents.ts +++ b/test/src/helpers/expectedContents.ts @@ -73,6 +73,7 @@ export const expectedWinContents = [ "lib/net45/node.dll", "lib/net45/snapshot_blob.bin", "lib/net45/TestApp.exe", + "lib/net45/TestApp_ExecutionStub.exe", "lib/net45/ui_resources_200_percent.pak", "lib/net45/Update.exe", "lib/net45/views_resources_200_percent.pak", diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts index f42bc03b90d..c9dfda0a2fe 100755 --- a/test/src/helpers/packTester.ts +++ b/test/src/helpers/packTester.ts @@ -369,6 +369,12 @@ async function checkWindowsResult(packager: Packager, checkOptions: AssertPackOp } return `lib/net45/${encodeURI(appInfo.productFilename).replace(/%5B/g, "[").replace(/%5D/g, "]")}.exe` } + else if (it === "lib/net45/TestApp_ExecutionStub.exe") { + if (appInfo.productFilename === "Test App ßW") { + return `lib/net45/Test%20App%20%C3%9FW_ExecutionStub.exe` + } + return `lib/net45/${encodeURI(appInfo.productFilename).replace(/%5B/g, "[").replace(/%5D/g, "]")}_ExecutionStub.exe` + } else { return it }