Skip to content

Commit

Permalink
feat(nsis): MUI_HEADERIMAGE electron-userland#525
Browse files Browse the repository at this point in the history
  • Loading branch information
develar committed Jun 24, 2016
1 parent 26c89f0 commit 5fc6bf6
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
vendor/**/* filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.keychain filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text
1 change: 1 addition & 0 deletions .idea/dictionaries/develar.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ See [NSIS target notes](https://github.com/electron-userland/electron-builder/wi
| perMachine | <a name="NsisOptions-perMachine"></a>Mark "all users" (per-machine) as default. Not recommended. Defaults to `false`.
| allowElevation | <a name="NsisOptions-allowElevation"></a>Allow requesting for elevation. If false, user will have to restart installer with elevated permissions. Defaults to `true`.
| oneClick | <a name="NsisOptions-oneClick"></a>One-click installation. Defaults to `true`.
| installerHeader | <a name="NsisOptions-installerHeader"></a>*boring installer only.* `MUI_HEADERIMAGE`, relative to the project directory. Defaults to `build/installerHeader.bmp`

<a name="LinuxBuildOptions"></a>
### `.build.linux`
Expand Down
5 changes: 5 additions & 0 deletions src/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ export interface NsisOptions {
One-click installation. Defaults to `true`.
*/
readonly oneClick?: boolean | null

/*
*boring installer only.* `MUI_HEADERIMAGE`, relative to the project directory. Defaults to `build/installerHeader.bmp`
*/
readonly installerHeader?: string | null
}

/*
Expand Down
4 changes: 3 additions & 1 deletion src/platformPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export interface PackagerOptions {
* Application `package.json` will be still read, but options specified in this object will override.
*/
readonly appMetadata?: AppMetadata

readonly effectiveOptionComputed?: (options: any) => boolean
}

export interface BuildInfo {
Expand All @@ -70,7 +72,7 @@ export class Target {
}

export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions> {
protected readonly options: PackagerOptions
readonly options: PackagerOptions

readonly projectDir: string
readonly buildResourcesDir: string
Expand Down
33 changes: 27 additions & 6 deletions src/targets/nsis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ const ELECTRON_BUILDER_NS_UUID = "50e065bc-3134-11e6-9bab-38c9862bdaf3"
const nsisPathPromise = getBin("nsis", NSIS_VERSION, `https://dl.bintray.com/electron-userland/bin/${NSIS_VERSION}.7z`, NSIS_SHA2)

export default class NsisTarget extends Target {
private readonly nsisOptions: NsisOptions
private readonly options: NsisOptions

constructor(private packager: WinPackager) {
super("nsis")

this.nsisOptions = packager.info.devMetadata.build.nsis || Object.create(null)
this.options = packager.info.devMetadata.build.nsis || Object.create(null)
}

async build(arch: Arch, outDir: string, appOutDir: string) {
Expand All @@ -43,7 +43,7 @@ export default class NsisTarget extends Target {
// const archiveFile = path.join(this.outDir, `.${packager.metadata.name}-${packager.metadata.version}${archSuffix}.7z`)
const archiveFile = path.join(outDir, `app.7z`)

const guid = this.nsisOptions.guid || await BluebirdPromise.promisify(uuid5)({namespace: ELECTRON_BUILDER_NS_UUID, name: appInfo.id})
const guid = this.options.guid || await BluebirdPromise.promisify(uuid5)({namespace: ELECTRON_BUILDER_NS_UUID, name: appInfo.id})
const productName = appInfo.productName
const defines: any = {
APP_ID: appInfo.id,
Expand All @@ -60,14 +60,31 @@ export default class NsisTarget extends Target {
COMPANY_NAME: appInfo.companyName,
}

if (this.nsisOptions.perMachine === true) {
let installerHeader = this.options.installerHeader
if (installerHeader === undefined) {
const resourceList = await packager.resourceList
if (resourceList.includes("installerHeader.bmp")) {
installerHeader = path.join(packager.buildResourcesDir, "installerHeader.bmp")
}
}
else {
installerHeader = path.resolve(packager.projectDir, installerHeader)
}

if (installerHeader != null) {
defines.MUI_HEADERIMAGE = null
defines.MUI_HEADERIMAGE_RIGHT = null
defines.MUI_HEADERIMAGE_BITMAP = installerHeader
}

if (this.options.perMachine === true) {
defines.MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS = null
}
else {
defines.MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER = null
}

if (this.nsisOptions.allowElevation !== false) {
if (this.options.allowElevation !== false) {
defines.MULTIUSER_INSTALLMODE_ALLOW_ELEVATION = null
}

Expand Down Expand Up @@ -102,14 +119,18 @@ export default class NsisTarget extends Target {

await subTask("Packing app into 7z archive", archiveApp(packager.devMetadata.build.compression, "7z", archiveFile, appOutDir, true))

const oneClick = this.nsisOptions.oneClick !== false
const oneClick = this.options.oneClick !== false
if (oneClick) {
defines.ONE_CLICK = null
}

debug(defines)
debug(commands)

if (this.packager.options.effectiveOptionComputed != null && this.packager.options.effectiveOptionComputed([defines, commands])) {
return
}

await subTask(`Executing makensis`, NsisTarget.executeMakensis(defines, commands))
await packager.sign(installerPath)

Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/test-app-one/installerHeader.bmp
Git LFS file not shown
2 changes: 1 addition & 1 deletion test/src/helpers/packTester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ async function packAndCheck(projectDir: string, packagerOptions: PackagerOptions

const platformToTarget = await packager.build()

if (packagerOptions.platformPackagerFactory != null) {
if (packagerOptions.platformPackagerFactory != null || packagerOptions.effectiveOptionComputed != null) {
return
}

Expand Down
90 changes: 78 additions & 12 deletions test/src/winPackagerTest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Platform, Arch, BuildInfo, PackagerOptions } from "out"
import test from "./helpers/avaEx"
import { assertPack, platform, modifyPackageJson, signed } from "./helpers/packTester"
import { move, outputFile } from "fs-extra-p"
import { outputFile, rename } from "fs-extra-p"
import * as path from "path"
import { WinPackager } from "out/winPackager"
import { Promise as BluebirdPromise } from "bluebird"
Expand Down Expand Up @@ -48,10 +48,76 @@ test.ifNotCiOsx("nsis boring", () => assertPack("test-app-one", _signed({
}
))

// test.ifNotCiOsx("win 32", () => assertPack("test-app-one", signed({
// targets: Platform.WINDOWS.createTarget(null, Arch.ia32),
// })
// ))
test.ifNotCiOsx("nsis boring", () => assertPack("test-app-one", _signed({
targets: Platform.WINDOWS.createTarget(["nsis"]),
devMetadata: {
build: {
nsis: {
oneClick: false,
}
}
}
}), {
useTempDir: true,
}
))

test.ifNotCiOsx("nsis boring, MUI_HEADER", () => {
let installerHeaderPath: string | null = null
return assertPack("test-app-one", {
targets: Platform.WINDOWS.createTarget(["nsis"]),
devMetadata: {
build: {
nsis: {
oneClick: false,
}
}
},
effectiveOptionComputed: options => {
const defines = options[0]
assertThat(defines.MUI_HEADERIMAGE).isEqualTo(null)
assertThat(defines.MUI_HEADERIMAGE_BITMAP).isEqualTo(installerHeaderPath)
assertThat(defines.MUI_HEADERIMAGE_RIGHT).isEqualTo(null)
// speedup, do not build - another MUI_HEADER test will test build
return true
}
}, {
tempDirCreated: projectDir => {
installerHeaderPath = path.join(projectDir, "build", "installerHeader.bmp")
return rename(path.join(projectDir, "installerHeader.bmp"), installerHeaderPath)
}
}
)
})

test.ifNotCiOsx("nsis boring, MUI_HEADER as option", () => {
let installerHeaderPath: string | null = null
return assertPack("test-app-one", {
targets: Platform.WINDOWS.createTarget(["nsis"]),
devMetadata: {
build: {
nsis: {
oneClick: false,
installerHeader: "foo.bmp"
}
}
},
effectiveOptionComputed: options => {
const defines = options[0]
assertThat(defines.MUI_HEADERIMAGE).isEqualTo(null)
assertThat(defines.MUI_HEADERIMAGE_BITMAP).isEqualTo(installerHeaderPath)
assertThat(defines.MUI_HEADERIMAGE_RIGHT).isEqualTo(null)
// test that we can build such installer
return false
}
}, {
tempDirCreated: projectDir => {
installerHeaderPath = path.join(projectDir, "foo.bmp")
return rename(path.join(projectDir, "installerHeader.bmp"), installerHeaderPath)
}
}
)
})

// very slow
test.ifWinCi("delta and msi", () => assertPack("test-app-one", {
Expand Down Expand Up @@ -95,17 +161,17 @@ test("detect install-spinner, certificateFile/password", () => {
targets: Platform.WINDOWS.createTarget(),
platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingWinPackager(packager, cleanupTasks),
devMetadata: {
build: {
win: {
certificatePassword: "pass",
}
build: {
win: {
certificatePassword: "pass",
}
}
}
}, {
tempDirCreated: it => {
loadingGifPath = path.join(it, "build", "install-spinner.gif")
return BluebirdPromise.all([
move(path.join(it, "install-spinner.gif"), loadingGifPath),
rename(path.join(it, "install-spinner.gif"), loadingGifPath),
modifyPackageJson(it, data => {
data.build.win = {
certificateFile: "secretFile",
Expand All @@ -123,7 +189,7 @@ test("detect install-spinner, certificateFile/password", () => {
})

test.ifNotCiOsx("icon < 256", (t: any) => t.throws(assertPack("test-app-one", platform(Platform.WINDOWS), {
tempDirCreated: projectDir => move(path.join(projectDir, "build", "incorrect.ico"), path.join(projectDir, "build", "icon.ico"), {clobber: true})
tempDirCreated: projectDir => rename(path.join(projectDir, "build", "incorrect.ico"), path.join(projectDir, "build", "icon.ico"))
}), /Windows icon size must be at least 256x256, please fix ".+/))

test.ifNotCiOsx("icon not an image", (t: any) => t.throws(assertPack("test-app-one", platform(Platform.WINDOWS), {
Expand All @@ -137,7 +203,7 @@ test.ifOsx("custom icon", () => {
platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingWinPackager(packager, cleanupTasks)
}, {
tempDirCreated: projectDir => BluebirdPromise.all([
move(path.join(projectDir, "build", "icon.ico"), path.join(projectDir, "customIcon.ico")),
rename(path.join(projectDir, "build", "icon.ico"), path.join(projectDir, "customIcon.ico")),
modifyPackageJson(projectDir, data => {
data.build.win = {
icon: "customIcon"
Expand Down

0 comments on commit 5fc6bf6

Please sign in to comment.