diff --git a/docs/Developer API.md b/docs/Developer API.md
index 9c71a35a123..d28ddeeccbc 100644
--- a/docs/Developer API.md
+++ b/docs/Developer API.md
@@ -61,7 +61,7 @@
electron-builder/out/targets/targetFactory
-electron-builder/out/targets/WebInstaller
+electron-builder/out/targets/WebInstallerTarget
electron-builder/out/util/filter
@@ -2081,12 +2081,38 @@ Portable Specific Options ([portable](#Config-portable})
## electron-builder/out/targets/nsis
* [electron-builder/out/targets/nsis](#module_electron-builder/out/targets/nsis)
+ * [.AppPackageHelper](#AppPackageHelper)
+ * [`.finishBuild()`](#module_electron-builder/out/targets/nsis.AppPackageHelper+finishBuild) ⇒ Promise<any>
+ * [`.packArch(arch, target)`](#module_electron-builder/out/targets/nsis.AppPackageHelper+packArch) ⇒ Promise<string>
* [.NsisTarget](#NsisTarget) ⇐ [Target](#Target)
* [`.build(appOutDir, arch)`](#module_electron-builder/out/targets/nsis.NsisTarget+build) ⇒ Promise<void>
* [`.finishBuild()`](#module_electron-builder/out/targets/nsis.NsisTarget+finishBuild) ⇒ Promise<any>
* [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/nsis.NsisTarget+configureDefines) ⇒ Promise<void>
* [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/nsis.NsisTarget+generateGitHubInstallerName) ⇒ string
+
+
+### AppPackageHelper
+**Kind**: class of [electron-builder/out/targets/nsis](#module_electron-builder/out/targets/nsis)
+
+* [.AppPackageHelper](#AppPackageHelper)
+ * [`.finishBuild()`](#module_electron-builder/out/targets/nsis.AppPackageHelper+finishBuild) ⇒ Promise<any>
+ * [`.packArch(arch, target)`](#module_electron-builder/out/targets/nsis.AppPackageHelper+packArch) ⇒ Promise<string>
+
+
+
+#### `appPackageHelper.finishBuild()` ⇒ Promise<any>
+**Kind**: instance method of [AppPackageHelper](#AppPackageHelper)
+
+
+#### `appPackageHelper.packArch(arch, target)` ⇒ Promise<string>
+**Kind**: instance method of [AppPackageHelper](#AppPackageHelper)
+
+| Param | Type |
+| --- | --- |
+| arch | [Arch](#Arch)
|
+| target | [NsisTarget](#NsisTarget)
|
+
### NsisTarget ⇐ [Target](#Target)
@@ -2306,29 +2332,34 @@ Portable Specific Options ([portable](#Config-portable})
| packager | [PlatformPackager](#PlatformPackager)<any>
|
| cleanupTasks | Array<module:electron-builder/out/targets/targetFactory.__type>
|
-
+
-## electron-builder/out/targets/WebInstaller
+## electron-builder/out/targets/WebInstallerTarget
-* [electron-builder/out/targets/WebInstaller](#module_electron-builder/out/targets/WebInstaller)
- * [.WebInstallerTarget](#WebInstallerTarget) ⇐ module:electron-builder/out/targets/nsis.default
- * [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+configureDefines) ⇒ Promise<void>
- * [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+generateGitHubInstallerName) ⇒ string
+* [electron-builder/out/targets/WebInstallerTarget](#module_electron-builder/out/targets/WebInstallerTarget)
+ * [.WebInstallerTarget](#WebInstallerTarget) ⇐ [NsisTarget](#NsisTarget)
+ * [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+configureDefines) ⇒ Promise<void>
+ * [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+generateGitHubInstallerName) ⇒ string
+ * [`.build(appOutDir, arch)`](#module_electron-builder/out/targets/nsis.NsisTarget+build) ⇒ Promise<void>
+ * [`.finishBuild()`](#module_electron-builder/out/targets/nsis.NsisTarget+finishBuild) ⇒ Promise<any>
-### WebInstallerTarget ⇐ module:electron-builder/out/targets/nsis.default
-**Kind**: class of [electron-builder/out/targets/WebInstaller](#module_electron-builder/out/targets/WebInstaller)
-**Extends**: module:electron-builder/out/targets/nsis.default
+### WebInstallerTarget ⇐ [NsisTarget](#NsisTarget)
+**Kind**: class of [electron-builder/out/targets/WebInstallerTarget](#module_electron-builder/out/targets/WebInstallerTarget)
+**Extends**: [NsisTarget](#NsisTarget)
-* [.WebInstallerTarget](#WebInstallerTarget) ⇐ module:electron-builder/out/targets/nsis.default
- * [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+configureDefines) ⇒ Promise<void>
- * [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+generateGitHubInstallerName) ⇒ string
+* [.WebInstallerTarget](#WebInstallerTarget) ⇐ [NsisTarget](#NsisTarget)
+ * [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+configureDefines) ⇒ Promise<void>
+ * [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+generateGitHubInstallerName) ⇒ string
+ * [`.build(appOutDir, arch)`](#module_electron-builder/out/targets/nsis.NsisTarget+build) ⇒ Promise<void>
+ * [`.finishBuild()`](#module_electron-builder/out/targets/nsis.NsisTarget+finishBuild) ⇒ Promise<any>
-
+
#### `webInstallerTarget.configureDefines(oneClick, defines)` ⇒ Promise<void>
**Kind**: instance method of [WebInstallerTarget](#WebInstallerTarget)
+**Overrides**: [configureDefines](#module_electron-builder/out/targets/nsis.NsisTarget+configureDefines)
**Access**: protected
| Param | Type |
@@ -2336,11 +2367,26 @@ Portable Specific Options ([portable](#Config-portable})
| oneClick | boolean
|
| defines | any
|
-
+
#### `webInstallerTarget.generateGitHubInstallerName()` ⇒ string
**Kind**: instance method of [WebInstallerTarget](#WebInstallerTarget)
+**Overrides**: [generateGitHubInstallerName](#module_electron-builder/out/targets/nsis.NsisTarget+generateGitHubInstallerName)
**Access**: protected
+
+
+#### `webInstallerTarget.build(appOutDir, arch)` ⇒ Promise<void>
+**Kind**: instance method of [WebInstallerTarget](#WebInstallerTarget)
+
+| Param | Type |
+| --- | --- |
+| appOutDir | string
|
+| arch | [Arch](#Arch)
|
+
+
+
+#### `webInstallerTarget.finishBuild()` ⇒ Promise<any>
+**Kind**: instance method of [WebInstallerTarget](#WebInstallerTarget)
## electron-builder/out/util/filter
diff --git a/packages/electron-builder/src/targets/WebInstaller.ts b/packages/electron-builder/src/targets/WebInstallerTarget.ts
similarity index 86%
rename from packages/electron-builder/src/targets/WebInstaller.ts
rename to packages/electron-builder/src/targets/WebInstallerTarget.ts
index 0727e015f37..733c6fbdb32 100644
--- a/packages/electron-builder/src/targets/WebInstaller.ts
+++ b/packages/electron-builder/src/targets/WebInstallerTarget.ts
@@ -1,14 +1,14 @@
import { NsisWebOptions } from "../options/winOptions"
import { computeDownloadUrl, getPublishConfigs, getPublishConfigsForUpdateInfo } from "../publish/PublishManager"
import { WinPackager } from "../winPackager"
-import NsisTarget from "./nsis"
+import { AppPackageHelper, NsisTarget } from "./nsis"
-export default class WebInstallerTarget extends NsisTarget {
- constructor(packager: WinPackager, outDir: string, targetName: string) {
- super(packager, outDir, targetName)
+export class WebInstallerTarget extends NsisTarget {
+ constructor(packager: WinPackager, outDir: string, targetName: string, packageHelper: AppPackageHelper) {
+ super(packager, outDir, targetName, packageHelper)
}
- protected get isWebInstaller(): boolean {
+ get isWebInstaller(): boolean {
return true
}
diff --git a/packages/electron-builder/src/targets/nsis.ts b/packages/electron-builder/src/targets/nsis.ts
index 4249d706fa8..cf70a85a778 100644
--- a/packages/electron-builder/src/targets/nsis.ts
+++ b/packages/electron-builder/src/targets/nsis.ts
@@ -25,16 +25,64 @@ const nsisResourcePathPromise = getBinFromBintray("nsis-resources", "3.0.0", "cd
const USE_NSIS_BUILT_IN_COMPRESSOR = false
-export default class NsisTarget extends Target {
+interface PackageFileInfo {
+ file: string
+}
+
+export class AppPackageHelper {
+ private readonly archToFileInfo = new Map>()
+ private readonly infoToIsDelete = new Map()
+
+ /** @private */
+ refCount = 0
+
+ async packArch(arch: Arch, target: NsisTarget) {
+ let infoPromise = this.archToFileInfo.get(arch)
+ if (infoPromise == null) {
+ infoPromise = subTask(`Packaging NSIS installer for arch ${Arch[arch]}`, target.buildAppPackage(target.archs.get(arch)!, arch))
+ .then(it => {return {file: it} })
+ this.archToFileInfo.set(arch, infoPromise)
+ }
+
+ const info = await infoPromise
+ if (target.isWebInstaller) {
+ this.infoToIsDelete.set(info, false)
+ }
+ else if (!this.infoToIsDelete.has(info)) {
+ this.infoToIsDelete.set(info, true)
+ }
+ return info.file
+ }
+
+ async finishBuild(): Promise {
+ if (--this.refCount > 0) {
+ return
+ }
+
+ const filesToDelete: Array = []
+ for (let [info, isDelete] of this.infoToIsDelete.entries()) {
+ if (isDelete) {
+ filesToDelete.push(info.file)
+ }
+ }
+
+ await BluebirdPromise.map(filesToDelete, it => unlink(it))
+ }
+}
+
+export class NsisTarget extends Target {
readonly options: NsisOptions
- private archs: Map = new Map()
+ /** @private */
+ readonly archs: Map = new Map()
private readonly nsisTemplatesDir = path.join(__dirname, "..", "..", "templates", "nsis")
- constructor(protected readonly packager: WinPackager, readonly outDir: string, targetName: string) {
+ constructor(protected readonly packager: WinPackager, readonly outDir: string, targetName: string, protected readonly packageHelper: AppPackageHelper) {
super(targetName)
+ this.packageHelper.refCount++
+
let options = this.packager.config.nsis || Object.create(null)
if (targetName !== "nsis") {
options = Object.assign(options, (this.packager.config)[targetName === "nsis-web" ? "nsisWeb" : targetName])
@@ -51,7 +99,8 @@ export default class NsisTarget extends Target {
this.archs.set(arch, appOutDir)
}
- private async buildAppPackage(appOutDir: string, arch: Arch) {
+ /** @private */
+ async buildAppPackage(appOutDir: string, arch: Arch) {
await BluebirdPromise.all([
copyFile(path.join(await nsisPathPromise, "elevate.exe"), path.join(appOutDir, "resources", "elevate.exe"), null, false),
copyFile(path.join(await getSignVendorPath(), "windows-10", Arch[arch], "signtool.exe"), path.join(appOutDir, "resources", "signtool.exe"), null, false),
@@ -66,14 +115,11 @@ export default class NsisTarget extends Target {
// noinspection JSUnusedGlobalSymbols
async finishBuild(): Promise {
log("Building NSIS installer")
- const filesToDelete: Array = []
try {
- await this.buildInstaller(filesToDelete)
+ await this.buildInstaller()
}
finally {
- if (filesToDelete.length > 0) {
- await BluebirdPromise.map(filesToDelete, it => unlink(it))
- }
+ await this.packageHelper.finishBuild()
}
}
@@ -85,7 +131,7 @@ export default class NsisTarget extends Target {
return this.name === "portable"
}
- private async buildInstaller(filesToDelete: Array): Promise {
+ private async buildInstaller(): Promise {
const isPortable = this.isPortable
const packager = this.packager
@@ -140,16 +186,13 @@ export default class NsisTarget extends Target {
}
else {
await BluebirdPromise.map(this.archs.keys(), async arch => {
- const file = await subTask(`Packaging NSIS installer for arch ${Arch[arch]}`, this.buildAppPackage(this.archs.get(arch)!, arch))
+ const file = await this.packageHelper.packArch(arch, this, )
defines[arch === Arch.x64 ? "APP_64" : "APP_32"] = file
defines[(arch === Arch.x64 ? "APP_64" : "APP_32") + "_NAME"] = path.basename(file)
if (this.isWebInstaller) {
packager.dispatchArtifactCreated(file, this, arch)
}
- else {
- filesToDelete.push(file)
- }
})
}
@@ -195,7 +238,7 @@ export default class NsisTarget extends Target {
return this.options.unicode == null ? true : this.options.unicode
}
- protected get isWebInstaller(): boolean {
+ get isWebInstaller(): boolean {
return false
}
diff --git a/packages/electron-builder/src/winPackager.ts b/packages/electron-builder/src/winPackager.ts
index 81e3efde76f..e222b9f32db 100644
--- a/packages/electron-builder/src/winPackager.ts
+++ b/packages/electron-builder/src/winPackager.ts
@@ -10,8 +10,9 @@ import { WinBuildOptions } from "./options/winOptions"
import { BuildInfo } from "./packagerApi"
import { PlatformPackager } from "./platformPackager"
import AppXTarget from "./targets/appx"
-import NsisTarget from "./targets/nsis"
+import { AppPackageHelper, NsisTarget } from "./targets/nsis"
import { createCommonTarget } from "./targets/targetFactory"
+import { WebInstallerTarget } from "./targets/WebInstallerTarget"
import { FileCodeSigningInfo, getSignVendorPath, sign, SignOptions } from "./windowsCodeSign"
export class WinPackager extends PlatformPackager {
@@ -94,36 +95,46 @@ export class WinPackager extends PlatformPackager {
}
createTargets(targets: Array, mapper: (name: string, factory: (outDir: string) => Target) => void, cleanupTasks: Array<() => Promise>): void {
+ let helper: AppPackageHelper | null
+ const getHelper = () => {
+ if (helper == null) {
+ helper = new AppPackageHelper()
+ }
+ return helper
+ }
+
for (const name of targets) {
if (name === DIR_TARGET) {
continue
}
- const targetClass: typeof NsisTarget | typeof AppXTarget | null = (() => {
- switch (name) {
- case "nsis":
- case "portable":
- return require("./targets/nsis").default
- case "nsis-web":
- return require("./targets/WebInstaller").default
-
- case "squirrel":
- try {
- return require("electron-builder-squirrel-windows").default
- }
- catch (e) {
- throw new Error(`Module electron-builder-squirrel-windows must be installed in addition to build Squirrel.Windows: ${e.stack || e}`)
- }
-
- case "appx":
- return require("./targets/appx").default
-
- default:
- return null
- }
- })()
-
- mapper(name, outDir => targetClass === null ? createCommonTarget(name, outDir, this) : new (targetClass)(this, outDir, name))
+ if (name === "nsis" || name === "portable") {
+ mapper(name, outDir => new NsisTarget(this, outDir, name, getHelper()))
+ }
+ else if (name === "nsis-web") {
+ mapper(name, outDir => new WebInstallerTarget(this, outDir, name, getHelper()))
+ }
+ else {
+ const targetClass: typeof NsisTarget | typeof AppXTarget | null = (() => {
+ switch (name) {
+ case "squirrel":
+ try {
+ return require("electron-builder-squirrel-windows").default
+ }
+ catch (e) {
+ throw new Error(`Module electron-builder-squirrel-windows must be installed in addition to build Squirrel.Windows: ${e.stack || e}`)
+ }
+
+ case "appx":
+ return require("./targets/appx").default
+
+ default:
+ return null
+ }
+ })()
+
+ mapper(name, outDir => targetClass === null ? createCommonTarget(name, outDir, this) : new (targetClass)(this, outDir, name))
+ }
}
}
diff --git a/test/out/linux/__snapshots__/debTest.js.snap b/test/out/linux/__snapshots__/debTest.js.snap
index 6813ecc0b15..94c929f2f64 100644
--- a/test/out/linux/__snapshots__/debTest.js.snap
+++ b/test/out/linux/__snapshots__/debTest.js.snap
@@ -85,7 +85,6 @@ Object {
"Section": "devel",
"Size": "89541",
"Vendor": "Foo Bar ",
- "Version": "1.1.0-42",
}
`;
@@ -186,7 +185,6 @@ Object {
"Section": "devel",
"Size": "123301",
"Vendor": "Foo Bar ",
- "Version": "1.1.0-42",
}
`;
@@ -275,6 +273,5 @@ Object {
"Section": "devel",
"Size": "123301",
"Vendor": "Foo Bar ",
- "Version": "1.1.0-42",
}
`;
diff --git a/test/out/windows/__snapshots__/portableTest.js.snap b/test/out/windows/__snapshots__/portableTest.js.snap
index b0d9166d30e..f4efe955e23 100644
--- a/test/out/windows/__snapshots__/portableTest.js.snap
+++ b/test/out/windows/__snapshots__/portableTest.js.snap
@@ -15,6 +15,11 @@ Object {
exports[`portable 1`] = `
Object {
"win": Array [
+ Object {
+ "arch": 1,
+ "file": "Test App ßW Setup 1.1.0.exe",
+ "safeArtifactName": "TestApp-Setup-1.1.0.exe",
+ },
Object {
"arch": 1,
"file": "Test App ßW 1.1.0.exe",
diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts
index c50474377e6..f8f4565b087 100755
--- a/test/src/helpers/packTester.ts
+++ b/test/src/helpers/packTester.ts
@@ -229,7 +229,9 @@ async function checkLinuxResult(outDir: string, packager: Packager, arch: Arch,
expect(await getContents(`${outDir}/TestApp_${appInfo.version}_i386.deb`)).toMatchSnapshot()
}
- expect(parseDebControl(await exec("dpkg", ["--info", packageFile]))).toMatchSnapshot()
+ const control = parseDebControl(await exec("dpkg", ["--info", packageFile]))
+ delete control.Version
+ expect(control).toMatchSnapshot()
}
function parseDebControl(info: string): any {
diff --git a/test/src/windows/portableTest.ts b/test/src/windows/portableTest.ts
index bd9c5f81fc2..1c6ac7d684b 100644
--- a/test/src/windows/portableTest.ts
+++ b/test/src/windows/portableTest.ts
@@ -1,15 +1,16 @@
import { Platform } from "electron-builder"
import { app } from "../helpers/packTester"
-test.ifNotCiMac("portable", app({
- targets: Platform.WINDOWS.createTarget(["portable"]),
+// build in parallel - /~https://github.com/electron-userland/electron-builder/issues/1340#issuecomment-286061789
+test.ifAll.ifNotCiMac("portable", app({
+ targets: Platform.WINDOWS.createTarget(["portable", "nsis"]),
config: {
nsis: {
}
}
}))
-test.ifAll.ifNotCiMac("portable - artifactName and request execution level", app({
+test.ifNotCiMac("portable - artifactName and request execution level", app({
targets: Platform.WINDOWS.createTarget(["portable"]),
config: {
"nsis": {