Skip to content

Commit fda6ee9

Browse files
committed
feat(nsis): custom uninstaller display name in the control panel
1 parent 58c5522 commit fda6ee9

File tree

8 files changed

+35
-20
lines changed

8 files changed

+35
-20
lines changed

docs/Options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ Configuration Options
257257
* <a name="NsisOptions-language"></a>`language` String - [LCID Dec](https://msdn.microsoft.com/en-au/goglobal/bb964664.aspx), defaults to `1033`(`English - United States`).
258258
* <a name="NsisOptions-multiLanguageInstaller"></a>`multiLanguageInstaller` Boolean - *boring installer only.* Whether to create multi-language installer. Defaults to `unicode` option value. [Not all strings are translated](https://github.com/electron-userland/electron-builder/issues/646#issuecomment-238155800).
259259
* <a name="NsisOptions-menuCategory"></a>`menuCategory` = `false` Boolean | String - Whether to create submenu for start menu shortcut and program files directory. If `true`, company name will be used. Or string value.
260+
* <a name="NsisOptions-uninstallDisplayName"></a>`uninstallDisplayName` = `${productName} ${version}` String - The uninstaller display name in the control panel.
260261
* <a name="NsisOptions-artifactName"></a>`artifactName` String - The [artifact file name pattern](https://github.com/electron-userland/electron-builder/wiki/Options#artifact-file-name-pattern). Defaults to `${productName} Setup ${version}.${ext}`.
261262
* <a name="NsisOptions-deleteAppDataOnUninstall"></a>`deleteAppDataOnUninstall` = `false` Boolean - *one-click installer only.* Whether to delete app data on uninstall.
262263
* <a name="NsisOptions-packElevateHelper"></a>`packElevateHelper` = `true` Boolean - Whether to pack the elevate executable (required for electron-updater if per-machine installer used or can be used in the future). Ignored if `perMachine` is set to `true`.

docs/api/electron-builder.md

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@
466466
* [`.getElectronDestDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronDestDir) ⇒ <code>String</code>
467467
* [`.getElectronSrcDir(dist)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronSrcDir) ⇒ <code>String</code>
468468
* [`.expandArtifactNamePattern(targetSpecificOptions, ext, arch, defaultPattern, skipArchIfX64)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandArtifactNamePattern) ⇒ <code>String</code>
469-
* [`.expandMacro(pattern, arch, extra)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
469+
* [`.expandMacro(pattern, arch, extra, isProductNameSanitized)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
470470
* [`.generateName(ext, arch, deployment, classifier)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName) ⇒ <code>String</code>
471471
* [`.generateName2(ext, classifier, deployment)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName2) ⇒ <code>String</code>
472472
* [`.getIconPath()`](#module_electron-builder/out/platformPackager.PlatformPackager+getIconPath) ⇒ <code>Promise&lt; \| String&gt;</code>
@@ -498,7 +498,7 @@
498498
* [`.getElectronDestDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronDestDir) ⇒ <code>String</code>
499499
* [`.getElectronSrcDir(dist)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronSrcDir) ⇒ <code>String</code>
500500
* [`.expandArtifactNamePattern(targetSpecificOptions, ext, arch, defaultPattern, skipArchIfX64)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandArtifactNamePattern) ⇒ <code>String</code>
501-
* [`.expandMacro(pattern, arch, extra)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
501+
* [`.expandMacro(pattern, arch, extra, isProductNameSanitized)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
502502
* [`.generateName(ext, arch, deployment, classifier)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName) ⇒ <code>String</code>
503503
* [`.generateName2(ext, classifier, deployment)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName2) ⇒ <code>String</code>
504504
* [`.getIconPath()`](#module_electron-builder/out/platformPackager.PlatformPackager+getIconPath) ⇒ <code>Promise&lt; \| String&gt;</code>
@@ -585,14 +585,15 @@
585585

586586
<a name="module_electron-builder/out/platformPackager.PlatformPackager+expandMacro"></a>
587587

588-
#### `linuxPackager.expandMacro(pattern, arch, extra)` ⇒ <code>String</code>
588+
#### `linuxPackager.expandMacro(pattern, arch, extra, isProductNameSanitized)` ⇒ <code>String</code>
589589
**Kind**: instance method of [<code>LinuxPackager</code>](#LinuxPackager)
590590

591591
| Param | Type |
592592
| --- | --- |
593593
| pattern | <code>String</code> |
594-
| arch | <code>String</code> \| <code>undefined</code> \| <code>null</code> |
594+
| arch | <code>String</code> \| <code>null</code> |
595595
| extra | <code>any</code> |
596+
| isProductNameSanitized | |
596597

597598
<a name="module_electron-builder/out/platformPackager.PlatformPackager+generateName"></a>
598599

@@ -685,7 +686,7 @@
685686
* [`.getDefaultIcon(ext)`](#module_electron-builder/out/platformPackager.PlatformPackager+getDefaultIcon) ⇒ <code>Promise&lt; \| String&gt;</code>
686687
* [`.dispatchArtifactCreated(file, target, arch, safeArtifactName)`](#module_electron-builder/out/platformPackager.PlatformPackager+dispatchArtifactCreated)
687688
* [`.expandArtifactNamePattern(targetSpecificOptions, ext, arch, defaultPattern, skipArchIfX64)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandArtifactNamePattern) ⇒ <code>String</code>
688-
* [`.expandMacro(pattern, arch, extra)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
689+
* [`.expandMacro(pattern, arch, extra, isProductNameSanitized)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
689690
* [`.generateName(ext, arch, deployment, classifier)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName) ⇒ <code>String</code>
690691
* [`.generateName2(ext, classifier, deployment)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName2) ⇒ <code>String</code>
691692
* [`.getMacOsResourcesDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getMacOsResourcesDir) ⇒ <code>String</code>
@@ -717,7 +718,7 @@
717718
* [`.getDefaultIcon(ext)`](#module_electron-builder/out/platformPackager.PlatformPackager+getDefaultIcon) ⇒ <code>Promise&lt; \| String&gt;</code>
718719
* [`.dispatchArtifactCreated(file, target, arch, safeArtifactName)`](#module_electron-builder/out/platformPackager.PlatformPackager+dispatchArtifactCreated)
719720
* [`.expandArtifactNamePattern(targetSpecificOptions, ext, arch, defaultPattern, skipArchIfX64)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandArtifactNamePattern) ⇒ <code>String</code>
720-
* [`.expandMacro(pattern, arch, extra)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
721+
* [`.expandMacro(pattern, arch, extra, isProductNameSanitized)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
721722
* [`.generateName(ext, arch, deployment, classifier)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName) ⇒ <code>String</code>
722723
* [`.generateName2(ext, classifier, deployment)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName2) ⇒ <code>String</code>
723724
* [`.getMacOsResourcesDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getMacOsResourcesDir) ⇒ <code>String</code>
@@ -822,14 +823,15 @@
822823

823824
<a name="module_electron-builder/out/platformPackager.PlatformPackager+expandMacro"></a>
824825

825-
#### `macPackager.expandMacro(pattern, arch, extra)` ⇒ <code>String</code>
826+
#### `macPackager.expandMacro(pattern, arch, extra, isProductNameSanitized)` ⇒ <code>String</code>
826827
**Kind**: instance method of [<code>MacPackager</code>](#MacPackager)
827828

828829
| Param | Type |
829830
| --- | --- |
830831
| pattern | <code>String</code> |
831-
| arch | <code>String</code> \| <code>undefined</code> \| <code>null</code> |
832+
| arch | <code>String</code> \| <code>null</code> |
832833
| extra | <code>any</code> |
834+
| isProductNameSanitized | |
833835

834836
<a name="module_electron-builder/out/platformPackager.PlatformPackager+generateName"></a>
835837

@@ -916,7 +918,7 @@
916918
* [`.getElectronDestDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronDestDir) ⇒ <code>String</code>
917919
* [`.getElectronSrcDir(dist)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronSrcDir) ⇒ <code>String</code>
918920
* [`.expandArtifactNamePattern(targetSpecificOptions, ext, arch, defaultPattern, skipArchIfX64)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandArtifactNamePattern) ⇒ <code>String</code>
919-
* [`.expandMacro(pattern, arch, extra)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
921+
* [`.expandMacro(pattern, arch, extra, isProductNameSanitized)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
920922
* [`.generateName(ext, arch, deployment, classifier)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName) ⇒ <code>String</code>
921923
* [`.generateName2(ext, classifier, deployment)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName2) ⇒ <code>String</code>
922924
* [`.getIconPath()`](#module_electron-builder/out/platformPackager.PlatformPackager+getIconPath) ⇒ <code>Promise&lt; \| String&gt;</code>
@@ -960,7 +962,7 @@
960962
* [`.getElectronDestDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronDestDir) ⇒ <code>String</code>
961963
* [`.getElectronSrcDir(dist)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronSrcDir) ⇒ <code>String</code>
962964
* [`.expandArtifactNamePattern(targetSpecificOptions, ext, arch, defaultPattern, skipArchIfX64)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandArtifactNamePattern) ⇒ <code>String</code>
963-
* [`.expandMacro(pattern, arch, extra)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
965+
* [`.expandMacro(pattern, arch, extra, isProductNameSanitized)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
964966
* [`.generateName(ext, arch, deployment, classifier)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName) ⇒ <code>String</code>
965967
* [`.generateName2(ext, classifier, deployment)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName2) ⇒ <code>String</code>
966968
* [`.getIconPath()`](#module_electron-builder/out/platformPackager.PlatformPackager+getIconPath) ⇒ <code>Promise&lt; \| String&gt;</code>
@@ -1046,14 +1048,15 @@
10461048

10471049
<a name="module_electron-builder/out/platformPackager.PlatformPackager+expandMacro"></a>
10481050

1049-
#### `platformPackager.expandMacro(pattern, arch, extra)` ⇒ <code>String</code>
1051+
#### `platformPackager.expandMacro(pattern, arch, extra, isProductNameSanitized)` ⇒ <code>String</code>
10501052
**Kind**: instance method of [<code>PlatformPackager</code>](#PlatformPackager)
10511053

10521054
| Param | Type |
10531055
| --- | --- |
10541056
| pattern | <code>String</code> |
1055-
| arch | <code>String</code> \| <code>undefined</code> \| <code>null</code> |
1057+
| arch | <code>String</code> \| <code>null</code> |
10561058
| extra | <code>any</code> |
1059+
| isProductNameSanitized | |
10571060

10581061
<a name="module_electron-builder/out/platformPackager.PlatformPackager+generateName"></a>
10591062

@@ -1776,7 +1779,7 @@
17761779
* [`.getElectronDestDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronDestDir) ⇒ <code>String</code>
17771780
* [`.getElectronSrcDir(dist)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronSrcDir) ⇒ <code>String</code>
17781781
* [`.expandArtifactNamePattern(targetSpecificOptions, ext, arch, defaultPattern, skipArchIfX64)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandArtifactNamePattern) ⇒ <code>String</code>
1779-
* [`.expandMacro(pattern, arch, extra)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
1782+
* [`.expandMacro(pattern, arch, extra, isProductNameSanitized)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
17801783
* [`.generateName(ext, arch, deployment, classifier)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName) ⇒ <code>String</code>
17811784
* [`.generateName2(ext, classifier, deployment)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName2) ⇒ <code>String</code>
17821785
* [`.getMacOsResourcesDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getMacOsResourcesDir) ⇒ <code>String</code>
@@ -1885,7 +1888,7 @@
18851888
* [`.getElectronDestDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronDestDir) ⇒ <code>String</code>
18861889
* [`.getElectronSrcDir(dist)`](#module_electron-builder/out/platformPackager.PlatformPackager+getElectronSrcDir) ⇒ <code>String</code>
18871890
* [`.expandArtifactNamePattern(targetSpecificOptions, ext, arch, defaultPattern, skipArchIfX64)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandArtifactNamePattern) ⇒ <code>String</code>
1888-
* [`.expandMacro(pattern, arch, extra)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
1891+
* [`.expandMacro(pattern, arch, extra, isProductNameSanitized)`](#module_electron-builder/out/platformPackager.PlatformPackager+expandMacro) ⇒ <code>String</code>
18891892
* [`.generateName(ext, arch, deployment, classifier)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName) ⇒ <code>String</code>
18901893
* [`.generateName2(ext, classifier, deployment)`](#module_electron-builder/out/platformPackager.PlatformPackager+generateName2) ⇒ <code>String</code>
18911894
* [`.getMacOsResourcesDir(appOutDir)`](#module_electron-builder/out/platformPackager.PlatformPackager+getMacOsResourcesDir) ⇒ <code>String</code>
@@ -1995,14 +1998,15 @@
19951998

19961999
<a name="module_electron-builder/out/platformPackager.PlatformPackager+expandMacro"></a>
19972000

1998-
#### `winPackager.expandMacro(pattern, arch, extra)` ⇒ <code>String</code>
2001+
#### `winPackager.expandMacro(pattern, arch, extra, isProductNameSanitized)` ⇒ <code>String</code>
19992002
**Kind**: instance method of [<code>WinPackager</code>](#WinPackager)
20002003

20012004
| Param | Type |
20022005
| --- | --- |
20032006
| pattern | <code>String</code> |
2004-
| arch | <code>String</code> \| <code>undefined</code> \| <code>null</code> |
2007+
| arch | <code>String</code> \| <code>null</code> |
20052008
| extra | <code>any</code> |
2009+
| isProductNameSanitized | |
20062010

20072011
<a name="module_electron-builder/out/platformPackager.PlatformPackager+generateName"></a>
20082012

packages/electron-builder/src/options/winOptions.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,12 @@ export interface NsisOptions extends CommonNsisOptions, TargetSpecificOptions {
211211
*/
212212
readonly menuCategory?: boolean | string
213213

214+
/**
215+
* The uninstaller display name in the control panel.
216+
* @default ${productName} ${version}
217+
*/
218+
readonly uninstallDisplayName?: string
219+
214220
/**
215221
* @private
216222
* @default false

packages/electron-builder/src/platformPackager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
377377
})
378378
}
379379

380-
expandMacro(pattern: string, arch: string | n, extra: any = {}): string {
380+
expandMacro(pattern: string, arch?: string | null, extra: any = {}, isProductNameSanitized = true): string {
381381
if (arch == null) {
382382
pattern = pattern
383383
.replace("-${arch}", "")
@@ -390,7 +390,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
390390
return pattern.replace(/\${([_a-zA-Z./*]+)}/g, (match, p1): string => {
391391
switch (p1) {
392392
case "productName":
393-
return appInfo.productFilename
393+
return isProductNameSanitized ? appInfo.productFilename : appInfo.productName
394394

395395
case "arch":
396396
if (arch == null) {

packages/electron-builder/src/targets/nsis.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,8 @@ export class NsisTarget extends Target {
375375
defines.UNINSTALLER_ICON = uninstallerIcon
376376
defines.MUI_UNICON = uninstallerIcon
377377
}
378+
379+
defines.UNINSTALL_DISPLAY_NAME = packager.expandMacro(this.options.uninstallDisplayName || "${productName} ${version}", null, {}, false)
378380
}
379381

380382
private configureDefinesForAllTypeOfInstaller(defines: any) {

packages/electron-builder/templates/nsis/multiUser.nsh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
!define INSTALL_REGISTRY_KEY "Software\${APP_GUID}"
88
!define UNINSTALL_REGISTRY_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_GUID}"
9-
!define UNINSTALL_DISPLAY_NAME "${PRODUCT_NAME} ${VERSION}"
109

1110
# current Install Mode ("all" or "CurrentUser")
1211
Var installMode

test/out/__snapshots__/ExtraBuildTest.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ Object {
127127
"file": "TestApp-1.1.0-x86_64.AppImage",
128128
},
129129
Object {
130-
"arch": 1,
130+
"arch": 0,
131131
"file": "TestApp-1.1.0-ia32.zip",
132132
"safeArtifactName": "TestApp-1.1.0-ia32.zip",
133133
},

test/src/windows/oneClickInstallerTest.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ test.ifAll("multi language license", app({
3535
targets: Platform.WINDOWS.createTarget("nsis"),
3636
config: {
3737
publish: null,
38+
nsis: {
39+
uninstallDisplayName: "Hi!!!",
40+
}
3841
},
3942
}, {
4043
projectDirCreated: projectDir => {

0 commit comments

Comments
 (0)