Skip to content

Commit

Permalink
fix(nsis): build portable in parallel to nsis
Browse files Browse the repository at this point in the history
Close #1340
  • Loading branch information
develar committed Apr 8, 2017
1 parent 3f8caab commit 918a317
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 68 deletions.
76 changes: 61 additions & 15 deletions docs/Developer API.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
<dd></dd>
<dt><a href="#module_electron-builder/out/targets/targetFactory">electron-builder/out/targets/targetFactory</a></dt>
<dd></dd>
<dt><a href="#module_electron-builder/out/targets/WebInstaller">electron-builder/out/targets/WebInstaller</a></dt>
<dt><a href="#module_electron-builder/out/targets/WebInstallerTarget">electron-builder/out/targets/WebInstallerTarget</a></dt>
<dd></dd>
<dt><a href="#module_electron-builder/out/util/filter">electron-builder/out/util/filter</a></dt>
<dd></dd>
Expand Down Expand Up @@ -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) ⇒ <code>Promise&lt;any&gt;</code>
* [`.packArch(arch, target)`](#module_electron-builder/out/targets/nsis.AppPackageHelper+packArch) ⇒ <code>Promise&lt;string&gt;</code>
* [.NsisTarget](#NsisTarget) ⇐ <code>[Target](#Target)</code>
* [`.build(appOutDir, arch)`](#module_electron-builder/out/targets/nsis.NsisTarget+build) ⇒ <code>Promise&lt;void&gt;</code>
* [`.finishBuild()`](#module_electron-builder/out/targets/nsis.NsisTarget+finishBuild) ⇒ <code>Promise&lt;any&gt;</code>
* [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/nsis.NsisTarget+configureDefines) ⇒ <code>Promise&lt;void&gt;</code>
* [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/nsis.NsisTarget+generateGitHubInstallerName) ⇒ <code>string</code>

<a name="AppPackageHelper"></a>

### AppPackageHelper
**Kind**: class of <code>[electron-builder/out/targets/nsis](#module_electron-builder/out/targets/nsis)</code>

* [.AppPackageHelper](#AppPackageHelper)
* [`.finishBuild()`](#module_electron-builder/out/targets/nsis.AppPackageHelper+finishBuild) ⇒ <code>Promise&lt;any&gt;</code>
* [`.packArch(arch, target)`](#module_electron-builder/out/targets/nsis.AppPackageHelper+packArch) ⇒ <code>Promise&lt;string&gt;</code>

<a name="module_electron-builder/out/targets/nsis.AppPackageHelper+finishBuild"></a>

#### `appPackageHelper.finishBuild()` ⇒ <code>Promise&lt;any&gt;</code>
**Kind**: instance method of <code>[AppPackageHelper](#AppPackageHelper)</code>
<a name="module_electron-builder/out/targets/nsis.AppPackageHelper+packArch"></a>

#### `appPackageHelper.packArch(arch, target)` ⇒ <code>Promise&lt;string&gt;</code>
**Kind**: instance method of <code>[AppPackageHelper](#AppPackageHelper)</code>

| Param | Type |
| --- | --- |
| arch | <code>[Arch](#Arch)</code> |
| target | <code>[NsisTarget](#NsisTarget)</code> |

<a name="NsisTarget"></a>

### NsisTarget ⇐ <code>[Target](#Target)</code>
Expand Down Expand Up @@ -2306,41 +2332,61 @@ Portable Specific Options ([portable](#Config-portable})
| packager | <code>[PlatformPackager](#PlatformPackager)&lt;any&gt;</code> |
| cleanupTasks | <code>Array&lt;module:electron-builder/out/targets/targetFactory.__type&gt;</code> |

<a name="module_electron-builder/out/targets/WebInstaller"></a>
<a name="module_electron-builder/out/targets/WebInstallerTarget"></a>

## electron-builder/out/targets/WebInstaller
## electron-builder/out/targets/WebInstallerTarget

* [electron-builder/out/targets/WebInstaller](#module_electron-builder/out/targets/WebInstaller)
* [.WebInstallerTarget](#WebInstallerTarget) ⇐ <code>module:electron-builder/out/targets/nsis.default</code>
* [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+configureDefines) ⇒ <code>Promise&lt;void&gt;</code>
* [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+generateGitHubInstallerName) ⇒ <code>string</code>
* [electron-builder/out/targets/WebInstallerTarget](#module_electron-builder/out/targets/WebInstallerTarget)
* [.WebInstallerTarget](#WebInstallerTarget) ⇐ <code>[NsisTarget](#NsisTarget)</code>
* [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+configureDefines) ⇒ <code>Promise&lt;void&gt;</code>
* [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+generateGitHubInstallerName) ⇒ <code>string</code>
* [`.build(appOutDir, arch)`](#module_electron-builder/out/targets/nsis.NsisTarget+build) ⇒ <code>Promise&lt;void&gt;</code>
* [`.finishBuild()`](#module_electron-builder/out/targets/nsis.NsisTarget+finishBuild) ⇒ <code>Promise&lt;any&gt;</code>

<a name="WebInstallerTarget"></a>

### WebInstallerTarget ⇐ <code>module:electron-builder/out/targets/nsis.default</code>
**Kind**: class of <code>[electron-builder/out/targets/WebInstaller](#module_electron-builder/out/targets/WebInstaller)</code>
**Extends**: <code>module:electron-builder/out/targets/nsis.default</code>
### WebInstallerTarget ⇐ <code>[NsisTarget](#NsisTarget)</code>
**Kind**: class of <code>[electron-builder/out/targets/WebInstallerTarget](#module_electron-builder/out/targets/WebInstallerTarget)</code>
**Extends**: <code>[NsisTarget](#NsisTarget)</code>

* [.WebInstallerTarget](#WebInstallerTarget) ⇐ <code>module:electron-builder/out/targets/nsis.default</code>
* [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+configureDefines) ⇒ <code>Promise&lt;void&gt;</code>
* [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+generateGitHubInstallerName) ⇒ <code>string</code>
* [.WebInstallerTarget](#WebInstallerTarget) ⇐ <code>[NsisTarget](#NsisTarget)</code>
* [`.configureDefines(oneClick, defines)`](#module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+configureDefines) ⇒ <code>Promise&lt;void&gt;</code>
* [`.generateGitHubInstallerName()`](#module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+generateGitHubInstallerName) ⇒ <code>string</code>
* [`.build(appOutDir, arch)`](#module_electron-builder/out/targets/nsis.NsisTarget+build) ⇒ <code>Promise&lt;void&gt;</code>
* [`.finishBuild()`](#module_electron-builder/out/targets/nsis.NsisTarget+finishBuild) ⇒ <code>Promise&lt;any&gt;</code>

<a name="module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+configureDefines"></a>
<a name="module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+configureDefines"></a>

#### `webInstallerTarget.configureDefines(oneClick, defines)` ⇒ <code>Promise&lt;void&gt;</code>
**Kind**: instance method of <code>[WebInstallerTarget](#WebInstallerTarget)</code>
**Overrides**: <code>[configureDefines](#module_electron-builder/out/targets/nsis.NsisTarget+configureDefines)</code>
**Access**: protected

| Param | Type |
| --- | --- |
| oneClick | <code>boolean</code> |
| defines | <code>any</code> |

<a name="module_electron-builder/out/targets/WebInstaller.WebInstallerTarget+generateGitHubInstallerName"></a>
<a name="module_electron-builder/out/targets/WebInstallerTarget.WebInstallerTarget+generateGitHubInstallerName"></a>

#### `webInstallerTarget.generateGitHubInstallerName()` ⇒ <code>string</code>
**Kind**: instance method of <code>[WebInstallerTarget](#WebInstallerTarget)</code>
**Overrides**: <code>[generateGitHubInstallerName](#module_electron-builder/out/targets/nsis.NsisTarget+generateGitHubInstallerName)</code>
**Access**: protected
<a name="module_electron-builder/out/targets/nsis.NsisTarget+build"></a>

#### `webInstallerTarget.build(appOutDir, arch)` ⇒ <code>Promise&lt;void&gt;</code>
**Kind**: instance method of <code>[WebInstallerTarget](#WebInstallerTarget)</code>

| Param | Type |
| --- | --- |
| appOutDir | <code>string</code> |
| arch | <code>[Arch](#Arch)</code> |

<a name="module_electron-builder/out/targets/nsis.NsisTarget+finishBuild"></a>

#### `webInstallerTarget.finishBuild()` ⇒ <code>Promise&lt;any&gt;</code>
**Kind**: instance method of <code>[WebInstallerTarget](#WebInstallerTarget)</code>
<a name="module_electron-builder/out/util/filter"></a>

## electron-builder/out/util/filter
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}

Expand Down
73 changes: 58 additions & 15 deletions packages/electron-builder/src/targets/nsis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Arch, Promise<PackageFileInfo>>()
private readonly infoToIsDelete = new Map<PackageFileInfo, boolean>()

/** @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<any> {
if (--this.refCount > 0) {
return
}

const filesToDelete: Array<string> = []
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<Arch, string> = new Map()
/** @private */
readonly archs: Map<Arch, string> = 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, (<any>this.packager.config)[targetName === "nsis-web" ? "nsisWeb" : targetName])
Expand All @@ -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),
Expand All @@ -66,14 +115,11 @@ export default class NsisTarget extends Target {
// noinspection JSUnusedGlobalSymbols
async finishBuild(): Promise<any> {
log("Building NSIS installer")
const filesToDelete: Array<string> = []
try {
await this.buildInstaller(filesToDelete)
await this.buildInstaller()
}
finally {
if (filesToDelete.length > 0) {
await BluebirdPromise.map(filesToDelete, it => unlink(it))
}
await this.packageHelper.finishBuild()
}
}

Expand All @@ -85,7 +131,7 @@ export default class NsisTarget extends Target {
return this.name === "portable"
}

private async buildInstaller(filesToDelete: Array<string>): Promise<any> {
private async buildInstaller(): Promise<any> {
const isPortable = this.isPortable

const packager = this.packager
Expand Down Expand Up @@ -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)
}
})
}

Expand Down Expand Up @@ -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
}

Expand Down
63 changes: 37 additions & 26 deletions packages/electron-builder/src/winPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<WinBuildOptions> {
Expand Down Expand Up @@ -94,36 +95,46 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
}

createTargets(targets: Array<string>, mapper: (name: string, factory: (outDir: string) => Target) => void, cleanupTasks: Array<() => Promise<any>>): 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 (<any>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 (<any>targetClass)(this, outDir, name))
}
}
}

Expand Down
3 changes: 0 additions & 3 deletions test/out/linux/__snapshots__/debTest.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ Object {
"Section": "devel",
"Size": "89541",
"Vendor": "Foo Bar <foo@example.com>",
"Version": "1.1.0-42",
}
`;

Expand Down Expand Up @@ -186,7 +185,6 @@ Object {
"Section": "devel",
"Size": "123301",
"Vendor": "Foo Bar <foo@example.com>",
"Version": "1.1.0-42",
}
`;

Expand Down Expand Up @@ -275,6 +273,5 @@ Object {
"Section": "devel",
"Size": "123301",
"Vendor": "Foo Bar <foo@example.com>",
"Version": "1.1.0-42",
}
`;
5 changes: 5 additions & 0 deletions test/out/windows/__snapshots__/portableTest.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading

0 comments on commit 918a317

Please sign in to comment.