NsisComposer.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. import { relative, resolve, win32 } from 'path';
  2. import { readdirAsync, lstatAsync } from 'fs-extra-promise';
  3. import { fixWindowsVersion } from '../util';
  4. export interface INsisComposerOptions {
  5. // Basic.
  6. appName: string;
  7. companyName: string;
  8. description: string;
  9. version: string;
  10. copyright: string;
  11. icon: string;
  12. unIcon: string;
  13. // Compression.
  14. compression: 'zlib' | 'bzip2' | 'lzma';
  15. solid: boolean;
  16. languages: string[];
  17. // Output.
  18. output: string;
  19. }
  20. export class NsisComposer {
  21. public static DIVIDER = '################################################################################';
  22. protected fixedVersion: string;
  23. constructor(protected options: INsisComposerOptions) {
  24. if(!this.options.appName) {
  25. this.options.appName = 'NO_APPNAME';
  26. }
  27. if(!this.options.companyName) {
  28. this.options.companyName = 'NO_COMPANYNAME';
  29. }
  30. if(!this.options.description) {
  31. this.options.description = 'NO_DESCRIPTION';
  32. }
  33. if(!this.options.version) {
  34. this.options.version = 'NO_VERSION';
  35. }
  36. if(!this.options.copyright) {
  37. this.options.copyright = 'NO_COPYRIGHT';
  38. }
  39. this.options.compression = this.options.compression || 'lzma';
  40. this.options.solid = this.options.solid ? true : false;
  41. this.options.languages = this.options.languages && this.options.languages.length > 0 ? this.options.languages : [ 'English' ];
  42. this.fixedVersion = fixWindowsVersion(this.options.version);
  43. }
  44. public async make(): Promise<string> {
  45. return `
  46. ${ NsisComposer.DIVIDER }
  47. #
  48. # Generated by nsis-gen.
  49. #
  50. ${ NsisComposer.DIVIDER }
  51. ${ await this.makeGeneralSection() }
  52. ${ await this.makeModernUISection() }
  53. ${ await this.makeVersionSection() }
  54. ${ await this.makeHookSection() }
  55. ${ await this.makeInstallSection() }
  56. ${ await this.makeUninstallSection() }
  57. `;
  58. }
  59. protected async makeGeneralSection(): Promise<string> {
  60. return `${ NsisComposer.DIVIDER }
  61. #
  62. # General
  63. #
  64. ${ NsisComposer.DIVIDER }
  65. Unicode true
  66. Name "${ this.options.appName }"
  67. Caption "${ this.options.appName }"
  68. BrandingText "${ this.options.appName } ${ this.fixedVersion }"
  69. ${
  70. this.options.icon
  71. ? `Icon "${ win32.normalize(resolve(this.options.icon)) }"`
  72. : ''
  73. }
  74. ${
  75. this.options.unIcon
  76. ? `UninstallIcon "${ win32.normalize(resolve(this.options.unIcon)) }"`
  77. : ''
  78. }
  79. SetCompressor ${ this.options.solid ? '/SOLID' : '' } ${ this.options.compression }
  80. OutFile "${ win32.normalize(resolve(this.options.output)) }"
  81. InstallDir "$LOCALAPPDATA\\${ this.options.appName }"
  82. InstallDirRegKey HKCU "Software\\${ this.options.appName }" "InstallDir"
  83. RequestExecutionLevel user
  84. XPStyle on`;
  85. }
  86. protected async makeModernUISection(): Promise<string> {
  87. return `${ NsisComposer.DIVIDER }
  88. #
  89. # Modern UI
  90. #
  91. ${ NsisComposer.DIVIDER }
  92. !include "MUI2.nsh"
  93. !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU"
  94. !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\\${ this.options.appName }"
  95. !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "StartMenuFolder"
  96. !define MUI_FINISHPAGE_RUN "$INSTDIR\\${ this.options.appName }.exe"
  97. Var StartMenuFolder
  98. !insertmacro MUI_PAGE_WELCOME
  99. !insertmacro MUI_PAGE_DIRECTORY
  100. !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder
  101. !insertmacro MUI_PAGE_INSTFILES
  102. !insertmacro MUI_PAGE_FINISH
  103. !insertmacro MUI_UNPAGE_WELCOME
  104. !insertmacro MUI_UNPAGE_CONFIRM
  105. !insertmacro MUI_UNPAGE_INSTFILES
  106. !insertmacro MUI_UNPAGE_FINISH
  107. ${
  108. this.options.languages.map((language) => {
  109. return `!insertmacro MUI_LANGUAGE "${ language }"`;
  110. }).join('\n')
  111. }
  112. ${
  113. this.options.languages.length > 1
  114. ? `!insertmacro MUI_RESERVEFILE_LANGDLL`
  115. : ''
  116. }`;
  117. }
  118. protected async makeVersionSection(): Promise<string> {
  119. return `${ NsisComposer.DIVIDER }
  120. #
  121. # Versions
  122. #
  123. ${ NsisComposer.DIVIDER }
  124. VIProductVersion "${ this.fixedVersion }"
  125. VIAddVersionKey /LANG=0 "ProductName" "${ this.options.appName }"
  126. VIAddVersionKey /LANG=0 "CompanyName" "${ this.options.companyName }"
  127. VIAddVersionKey /LANG=0 "FileDescription" "${ this.options.description }"
  128. VIAddVersionKey /LANG=0 "FileVersion" "${ this.fixedVersion }"
  129. VIAddVersionKey /LANG=0 "LegalCopyright" "${ this.options.copyright }"`;
  130. }
  131. protected async makeHookSection(): Promise<string> {
  132. return `${ NsisComposer.DIVIDER }
  133. #
  134. # Hooks
  135. #
  136. ${ NsisComposer.DIVIDER }
  137. Function .onInit
  138. ${
  139. this.options.languages.length > 1
  140. ? `!insertmacro MUI_LANGDLL_DISPLAY`
  141. : ''
  142. }
  143. FunctionEnd`;
  144. }
  145. protected async makeInstallSection(): Promise<string> {
  146. return `${ NsisComposer.DIVIDER }
  147. #
  148. # Install
  149. #
  150. ${ NsisComposer.DIVIDER }
  151. Section -Install
  152. SetShellVarContext current
  153. SetOverwrite ifnewer
  154. WriteRegStr HKCU "Software\\${ this.options.appName }" "InstallDir" "$INSTDIR"
  155. ${ await this.makeInstallerFiles() }
  156. !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
  157. CreateDirectory "$SMPROGRAMS\\$StartMenuFolder"
  158. CreateShortcut "$SMPROGRAMS\\$StartMenuFolder\\${ this.options.appName }.lnk" "$INSTDIR\\${ this.options.appName }.exe"
  159. CreateShortcut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe"
  160. !insertmacro MUI_STARTMENU_WRITE_END
  161. WriteUninstaller "$INSTDIR\\Uninstall.exe"
  162. SectionEnd`;
  163. }
  164. protected async makeUninstallSection(): Promise<string> {
  165. return `${ NsisComposer.DIVIDER }
  166. #
  167. # Uninstall
  168. #
  169. ${ NsisComposer.DIVIDER }
  170. Section Uninstall
  171. # FIXME: Remove only files installed.
  172. RMDir /r "$INSTDIR"
  173. !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder
  174. Delete "$SMPROGRAMS\\$StartMenuFolder\\${ this.options.appName }.lnk"
  175. Delete "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk"
  176. RMDir "$SMPROGRAMS\\$StartMenuFolder"
  177. DeleteRegKey HKCU "Software\\${ this.options.appName }"
  178. SectionEnd`;
  179. }
  180. protected async makeInstallerFiles(): Promise<string> {
  181. return `SetOutPath "$INSTDIR"
  182. FILE /r .\\*.*`;
  183. }
  184. }