Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow custom makensis and logging #6024

Merged
merged 13 commits into from Aug 9, 2021
5 changes: 5 additions & 0 deletions .changeset/old-planes-look.md
@@ -0,0 +1,5 @@
---
"app-builder-lib": minor
---

feat: allowing custom makensis url to be specified and adding flag to enable debug logging for NSIS scripts
66 changes: 65 additions & 1 deletion packages/app-builder-lib/scheme.json
Expand Up @@ -3447,6 +3447,38 @@
"description": "Whether to create start menu shortcut.",
"type": "boolean"
},
"customNsisBinary": {
"description": "Allows providing the URL configuration for `makensis`.",
"type": [
"null",
"object"
],
"properties": {
"url": {
"description": "URL to download from",
"type": "string"
},
"checksum": {
"description": "SHA256 to validate downloaded `makensis`",
"type": [
"null",
"string"
]
},
"version": {
"description": "Version of `makensis` (used for caching)",
"type": [
"null",
"string"
]
}
}
},
"debugLogging": {
"default": false,
"description": "Enables `LogText` to be used in `nsh` scripts",
"type": "boolean"
},
"deleteAppDataOnUninstall": {
"default": false,
"description": "*one-click installer only.* Whether to delete app data on uninstall.",
Expand Down Expand Up @@ -3748,6 +3780,38 @@
"description": "Whether to create start menu shortcut.",
"type": "boolean"
},
"customNsisBinary": {
"description": "Allows providing the URL configuration for `makensis`.",
"type": [
"null",
"object"
],
"properties": {
"url": {
"description": "URL to download from",
"type": "string"
},
"checksum": {
"description": "SHA256 to validate downloaded `makensis`",
"type": [
"null",
"string"
]
},
"version": {
"description": "Version of `makensis` (used for caching)",
"type": [
"null",
"string"
]
}
}
},
"debugLogging": {
"default": false,
"description": "Enables `LogText` to be used in `nsh` scripts",
"type": "boolean"
},
"deleteAppDataOnUninstall": {
"default": false,
"description": "*one-click installer only.* Whether to delete app data on uninstall.",
Expand Down Expand Up @@ -6578,4 +6642,4 @@
}
},
"type": "object"
}
}
5 changes: 5 additions & 0 deletions packages/app-builder-lib/src/binDownload.ts
Expand Up @@ -10,6 +10,11 @@ export function download(url: string, output: string, checksum?: string | null):
return executeAppBuilder(args) as Promise<any>
}

export function getBinFromCustomLoc(name: string, version: string, binariesLocUrl: string, checksum: string): Promise<string> {
const dirName = `${name}-${version}`
return getBin(dirName, binariesLocUrl, checksum)
}

export function getBinFromUrl(name: string, version: string, checksum: string): Promise<string> {
const dirName = `${name}-${version}`
let url: string
Expand Down
7 changes: 6 additions & 1 deletion packages/app-builder-lib/src/targets/nsis/NsisTarget.ts
Expand Up @@ -23,7 +23,7 @@ import { addCustomMessageFileInclude, createAddLangsMacro, LangConfigurator } fr
import { computeLicensePage } from "./nsisLicense"
import { NsisOptions, PortableOptions } from "./nsisOptions"
import { NsisScriptGenerator } from "./nsisScriptGenerator"
import { AppPackageHelper, nsisTemplatesDir, NSIS_PATH, UninstallerReader } from "./nsisUtil"
import { AppPackageHelper, nsisTemplatesDir, NSIS_PATH, UninstallerReader, NsisTargetOptions } from "./nsisUtil"

const debug = _debug("electron-builder:nsis")

Expand Down Expand Up @@ -62,6 +62,8 @@ export class NsisTarget extends Target {
if (deps != null && deps["electron-squirrel-startup"] != null) {
log.warn('"electron-squirrel-startup" dependency is not required for NSIS')
}

NsisTargetOptions.resolve(this.options)
}

build(appOutDir: string, arch: Arch) {
Expand Down Expand Up @@ -189,6 +191,9 @@ export class NsisTarget extends Target {

APP_PACKAGE_NAME: appInfo.name,
}
if (options.debugLogging) {
defines.ENABLE_LOGGING = null
}
if (uninstallAppKey !== guid) {
defines.UNINSTALL_REGISTRY_KEY_2 = `Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${guid}`
}
Expand Down
36 changes: 36 additions & 0 deletions packages/app-builder-lib/src/targets/nsis/nsisOptions.ts
@@ -1,6 +1,28 @@
import { TargetSpecificOptions } from "../../core"
import { CommonWindowsInstallerConfiguration } from "../.."

interface CustomNsisBinary {
/**
* @private
* @default https://github.com/electron-userland/electron-builder-binaries/releases/download
*/

readonly url: string | null

/**
* @private
* @default o+YZsXHp8LNihhuk7JsCDhdIgx0MKKK+1b3sGD+4zX5djZULe4/4QMcAsfQ+0r+a8FnwBt7BVBHkIkJHjKQ0sg==
*/

readonly checksum?: string | null

/**
* @private
* @default 3.0.4.2
*/

readonly version?: string | null
}
export interface CommonNsisOptions {
/**
* Whether to create [Unicode installer](http://nsis.sourceforge.net/Docs/Chapter1.html#intro-unicode).
Expand All @@ -24,6 +46,20 @@ export interface CommonNsisOptions {
* @default false
*/
readonly useZip?: boolean

/**
* @private
*/
readonly customNsisBinary?: CustomNsisBinary | null

/**
* Whether or not to enable NSIS logging for debugging.
* Note: Requires a debug-enabled NSIS build.
* electron-builder's included `makensis` only supports building debug-enabled NSIS installers on Windows currently
* https://github.com/electron-userland/electron-builder/issues/5119#issuecomment-811353612
* @private
*/
readonly debugLogging?: boolean | null
}

export interface NsisOptions extends CommonNsisOptions, CommonWindowsInstallerConfiguration, TargetSpecificOptions {
Expand Down
25 changes: 22 additions & 3 deletions packages/app-builder-lib/src/targets/nsis/nsisUtil.ts
@@ -1,22 +1,41 @@
import { Arch, log } from "builder-util"
import { PackageFileInfo } from "builder-util-runtime"
import { getBinFromUrl } from "../../binDownload"
import { getBinFromUrl, getBinFromCustomLoc } from "../../binDownload"
import { copyFile } from "builder-util/out/fs"
import * as path from "path"
import { getTemplatePath } from "../../util/pathManager"
import { NsisTarget } from "./NsisTarget"
import * as fs from "fs/promises"
import * as zlib from "zlib"
import { NsisOptions } from "./nsisOptions"

export const nsisTemplatesDir = getTemplatePath("nsis")

export const NsisTargetOptions = (() => {
let _resolve: (options: NsisOptions) => any
const promise = new Promise<NsisOptions>(resolve => (_resolve = resolve))
return {
then: (callback: (options: NsisOptions) => any): Promise<string> => promise.then(callback),
resolve: (options: NsisOptions): any => _resolve(options),
}
})()

export const NSIS_PATH = () => {
const custom = process.env.ELECTRON_BUILDER_NSIS_DIR
if (custom != null && custom.length > 0) {
return Promise.resolve(custom.trim())
}
// noinspection SpellCheckingInspection
return getBinFromUrl("nsis", "3.0.4.1", "VKMiizYdmNdJOWpRGz4trl4lD++BvYP2irAXpMilheUP0pc93iKlWAoP843Vlraj8YG19CVn0j+dCo/hURz9+Q==")
return NsisTargetOptions.then((options: NsisOptions) => {
if (options.customNsisBinary) {
const { checksum, url, version } = options.customNsisBinary
if (checksum && url) {
const binaryVersion = version || checksum.substr(0, 8)
return getBinFromCustomLoc("nsis", binaryVersion, url, checksum)
}
}
// noinspection SpellCheckingInspection
return getBinFromUrl("nsis", "3.0.4.2", "o+YZsXHp8LNihhuk7JsCDhdIgx0MKKK+1b3sGD+4zX5djZULe4/4QMcAsfQ+0r+a8FnwBt7BVBHkIkJHjKQ0sg==")
Copy link
Collaborator Author

@mmaietta mmaietta Jul 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@develar I tried to update to 3.0.5.0 that is uploaded in electron-builder-binaries, but that throws CI errors:

    Command line defined: "UNINSTALLER_OUT_FILE=C:\Users\RUNNER~1\AppData\Local\Temp\et-d8d6360ca6c99632f01b203b451e295c\t-oEMxqx\test-project-0\dist\__uninstaller-nsis-TestApp.exe"
    Processing config: C:\Users\runneradmin\AppData\Local\electron-builder\Cache\nsis\nsis-3.0.5.0\nsisconf.nsh
    Processing script file: "<stdin>" (ACP)

    Error output:
    Bad text encoding
    Error in macro MUI_LANGUAGEEX on macroline 13
    Error in macro MUI_LANGUAGE on macroline 4
    Error in macro addLangs on macroline 5
    Error in script "<stdin>" on line 112 -- aborting creation process

I couldn't easily identify why (MUI_LANGUAGEEX is no where in the codebase AFAICT) and 3.0.4.2 seems to have the log and max string length compiler flags enabled, so I'm just upgrading to that patch version here.

Copy link
Collaborator Author

@mmaietta mmaietta Jul 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@develar it happens here AFAICT
LoadLanguageFile "${LangDir}\${NLFID}.nlf"
https://github.com/electron-userland/electron-builder-binaries/blob/ec807af771a341b93d122734a9a1d6d2ae9bf90a/nsis/Contrib/Modern%20UI%202/Localization.nsh#L42

My best guess is that this file is no longer valid for newer versions of makensis:
https://github.com/electron-userland/electron-builder-binaries/blob/master/nsis-lang-fixes/SimpChinese.nlf

Alternatively, we could upgrade to makensis 3.0.6.1, but I'm struggling to figure out how to compile it for both windows & mac on my hackintosh.

})
}

export class AppPackageHelper {
Expand Down
14 changes: 14 additions & 0 deletions packages/app-builder-lib/templates/nsis/common.nsh
Expand Up @@ -99,3 +99,17 @@ Name "${PRODUCT_NAME}"

${StdUtils.ExecShellAsUser} $0 "$launchLink" "open" "$startAppArgs"
!macroend

!define LogSet "!insertmacro LogSetMacro"
!macro LogSetMacro SETTING
!ifdef ENABLE_LOGGING
LogSet ${SETTING}
!endif
!macroend

!define LogText "!insertmacro LogTextMacro"
!macro LogTextMacro INPUT_TEXT
!ifdef ENABLE_LOGGING
LogText ${INPUT_TEXT}
!endif
!macroend
3 changes: 3 additions & 0 deletions packages/app-builder-lib/templates/nsis/installer.nsi
Expand Up @@ -40,6 +40,9 @@ Var oldMenuDirectory
!endif

Function .onInit
SetOutPath $INSTDIR
${LogSet} on

!ifmacrodef preInit
!insertmacro preInit
!endif
Expand Down
3 changes: 3 additions & 0 deletions packages/app-builder-lib/templates/nsis/uninstaller.nsh
@@ -1,4 +1,7 @@
Function un.onInit
SetOutPath $INSTDIR
${LogSet} on

!insertmacro check64BitAndSetRegView

${IfNot} ${Silent}
Expand Down
28 changes: 28 additions & 0 deletions test/src/windows/assistedInstallerTest.ts
Expand Up @@ -117,6 +117,34 @@ test.ifAll.ifNotCiMac("assisted, MUI_HEADER as option", () => {
)
})

test.ifNotCiMac(
"custom makensis.exe",
app({
targets: nsisTarget,
config: {
nsis: {
customNsisBinary: {
url: "https://github.com/electron-userland/electron-builder-binaries/releases/download/nsis-3.0.4.1/nsis-3.0.4.1.7z",
version: "3.0.4.1",
checksum: "VKMiizYdmNdJOWpRGz4trl4lD++BvYP2irAXpMilheUP0pc93iKlWAoP843Vlraj8YG19CVn0j+dCo/hURz9+Q==",
},
},
},
})
)

test.ifNotCiMac(
"debug logging enabled",
app({
targets: nsisTarget,
config: {
nsis: {
debugLogging: true,
},
},
})
)

test.ifNotCiMac(
"assisted, only perMachine",
app({
Expand Down