diff --git a/docs/Options.md b/docs/Options.md index 3a2da9eedb6..4166ccccea6 100644 --- a/docs/Options.md +++ b/docs/Options.md @@ -168,6 +168,7 @@ NSIS only, [in progress](https://github.com/electron-userland/electron-builder/i | **ext** | The extension (minus the leading period). e.g. `png` | **name** | The name. e.g. `PNG` | description | *windows-only.* The description. +| icon | *windows-only.* The path to icon (`.ico`), relative to `build` (build resources directory). Defaults to `${ext}.ico`. ## `.directories` diff --git a/src/metadata.ts b/src/metadata.ts index c5b933b535b..58f54449e4b 100755 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -493,6 +493,11 @@ export interface FileAssociation { *windows-only.* The description. */ readonly description?: string + + /* + *windows-only.* The path to icon (`.ico`), relative to `build` (build resources directory). Defaults to `${ext}.ico`. + */ + readonly icon?: string } /* diff --git a/src/targets/nsis.ts b/src/targets/nsis.ts index c6abfd75ab0..a64b500442d 100644 --- a/src/targets/nsis.ts +++ b/src/targets/nsis.ts @@ -1,5 +1,5 @@ import { WinPackager } from "../winPackager" -import { Arch, NsisOptions } from "../metadata" +import { Arch, NsisOptions, FileAssociation } from "../metadata" import { exec, debug, doSpawn, handleProcess, use } from "../util/util" import * as path from "path" import { Promise as BluebirdPromise } from "bluebird" @@ -30,10 +30,17 @@ export default class NsisTarget extends Target { private readonly nsisTemplatesDir = path.join(__dirname, "..", "..", "templates", "nsis") + private readonly fileAssociations: Array + constructor(private packager: WinPackager, private outDir: string) { super("nsis") this.options = packager.info.devMetadata.build.nsis || Object.create(null) + + // CFBundleTypeName + // https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-101685 + // CFBundleTypeExtensions + this.fileAssociations = asArray(packager.devMetadata.build.fileAssociations).concat(asArray(packager.platformSpecificBuildOptions.fileAssociations)) } async build(arch: Arch, appOutDir: string) { @@ -221,24 +228,26 @@ export default class NsisTarget extends Target { const binDir = process.platform === "darwin" ? "mac" : (process.platform === "win32" ? "Bin" : "linux") const nsisPath = await nsisPathPromise - const packager = this.packager - // CFBundleTypeName - // https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-101685 - // CFBundleTypeExtensions - const fileAssociations = asArray(packager.devMetadata.build.fileAssociations).concat(asArray(packager.platformSpecificBuildOptions.fileAssociations)) - let script = originalScript const customInclude = await this.getResource(this.options.include, "installer.nsh") if (customInclude != null) { script = `!include "${customInclude}"\n!addincludedir "${this.packager.buildResourcesDir}"\n${script}` } - if (fileAssociations.length !== 0) { + if (this.fileAssociations.length !== 0) { script = "!include FileAssociation.nsh\n" + script if (isInstaller) { let registerFileAssociationsScript = "" - for (let item of fileAssociations) { - const icon = '"$INSTDIR\\${APP_EXECUTABLE_FILENAME},0"' + for (let item of this.fileAssociations) { + const customIcon = await this.getResource(item.icon, `${normalizeExt(item.ext)}.ico`) + let installedIconPath = "${APP_EXECUTABLE_FILENAME},0" + if (customIcon != null) { + installedIconPath = `resources\\${path.basename(customIcon)}` + //noinspection SpellCheckingInspection + registerFileAssociationsScript += ` File "/oname=${installedIconPath}" "${customIcon}"\n` + } + + const icon = `"$INSTDIR\\${installedIconPath}"` const commandText = `"Open with ${this.packager.appInfo.productName}"` const command = '"$INSTDIR\\${APP_EXECUTABLE_FILENAME} $\\"%1$\\""' registerFileAssociationsScript += ` !insertmacro APP_ASSOCIATE "${normalizeExt(item.ext)}" "${item.name}" "${item.description || ""}" ${icon} ${commandText} ${command}\n` @@ -247,7 +256,7 @@ export default class NsisTarget extends Target { } else { let unregisterFileAssociationsScript = "" - for (let item of fileAssociations) { + for (let item of this.fileAssociations) { unregisterFileAssociationsScript += ` !insertmacro APP_UNASSOCIATE "${normalizeExt(item.ext)}" "${item.name}"\n` } script = `!macro unregisterFileAssociations\n${unregisterFileAssociationsScript}!macroend\n${script}` diff --git a/test/src/nsisTest.ts b/test/src/nsisTest.ts index b80d1664822..72695c35640 100644 --- a/test/src/nsisTest.ts +++ b/test/src/nsisTest.ts @@ -28,6 +28,11 @@ test.ifDevOrLinuxCi("perMachine, no run after finish", app({ }, } } +}, { + projectDirCreated: projectDir => { + let headerIconPath = path.join(projectDir, "build", "foo.ico") + return copy(getTestAsset("headerIcon.ico"), headerIconPath) + }, })) test.ifNotCiOsx("boring", app({