diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4f35374..036068e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -131,10 +131,10 @@ jobs: sudo apt-get update sudo apt-get install -y libsecret-1-dev - - name: Install NSIS + - name: Install Inno Setup if: runner.os == 'Windows' shell: pwsh - run: choco install nsis -y --no-progress + run: choco install innosetup -y --no-progress - name: Install dependencies run: bun install --frozen-lockfile diff --git a/assets/installer/windows.iss b/assets/installer/windows.iss new file mode 100644 index 0000000..982f8da --- /dev/null +++ b/assets/installer/windows.iss @@ -0,0 +1,85 @@ +; Inno Setup script for Aryx +; Metadata values are passed via /D preprocessor defines from the build script. + +#ifndef PRODUCT_NAME + #define PRODUCT_NAME "Aryx" +#endif +#ifndef PRODUCT_VERSION + #define PRODUCT_VERSION "0.0.0" +#endif +#ifndef PRODUCT_PUBLISHER + #define PRODUCT_PUBLISHER "David Kaya" +#endif +#ifndef SOURCE_DIR + #error "SOURCE_DIR must be defined (path to the packaged app directory)." +#endif +#ifndef OUTPUT_DIR + #error "OUTPUT_DIR must be defined (path to the output directory)." +#endif +#ifndef OUTPUT_FILENAME + #error "OUTPUT_FILENAME must be defined (output installer filename without extension)." +#endif + +#ifndef ICON_PATH + #define ICON_PATH SOURCE_DIR + "\" + PRODUCT_NAME + ".exe" +#endif + +[Setup] +AppId={{B8A3E7F1-4D2C-4A9B-8E6F-1C3D5A7B9E0F} +AppName={#PRODUCT_NAME} +AppVersion={#PRODUCT_VERSION} +AppPublisher={#PRODUCT_PUBLISHER} +AppSupportURL=https://github.com/davidkaya/aryx +DefaultDirName={localappdata}\Programs\{#PRODUCT_NAME} +DefaultGroupName={#PRODUCT_NAME} +PrivilegesRequired=lowest +OutputDir={#OUTPUT_DIR} +OutputBaseFilename={#OUTPUT_FILENAME} +Compression=lzma2/ultra64 +SolidCompression=yes +SetupIconFile={#ICON_PATH} +UninstallDisplayIcon={app}\{#PRODUCT_NAME}.exe +WizardStyle=modern +DisableProgramGroupPage=yes +CloseApplications=force +RestartApplications=no + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Files] +Source: "{#SOURCE_DIR}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs + +[Icons] +Name: "{group}\{#PRODUCT_NAME}"; Filename: "{app}\{#PRODUCT_NAME}.exe" +Name: "{autodesktop}\{#PRODUCT_NAME}"; Filename: "{app}\{#PRODUCT_NAME}.exe"; Tasks: desktopicon + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Run] +Filename: "{app}\{#PRODUCT_NAME}.exe"; Description: "{cm:LaunchProgram,{#PRODUCT_NAME}}"; Flags: nowait postinstall skipifsilent + +[UninstallDelete] +Type: filesandordirs; Name: "{app}" + +[Code] +procedure CurStepChanged(CurStep: TSetupStep); +var + ResultCode: Integer; +begin + if CurStep = ssInstall then + begin + Exec('taskkill', '/F /IM {#PRODUCT_NAME}.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + end; +end; + +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +var + ResultCode: Integer; +begin + if CurUninstallStep = usUninstall then + begin + Exec('taskkill', '/F /IM {#PRODUCT_NAME}.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + end; +end; diff --git a/assets/installer/windows.nsi b/assets/installer/windows.nsi deleted file mode 100644 index 8c83760..0000000 --- a/assets/installer/windows.nsi +++ /dev/null @@ -1,112 +0,0 @@ -!include "MUI2.nsh" - -;--- Product metadata (passed via /D defines from the build script) --- -!ifndef PRODUCT_NAME - !define PRODUCT_NAME "Aryx" -!endif -!ifndef PRODUCT_VERSION - !define PRODUCT_VERSION "0.0.0" -!endif -!ifndef PRODUCT_PUBLISHER - !define PRODUCT_PUBLISHER "David Kaya" -!endif -!ifndef SOURCE_DIR - !error "SOURCE_DIR must be defined (path to the packaged app directory)." -!endif -!ifndef OUTPUT_PATH - !error "OUTPUT_PATH must be defined (path to the output installer .exe)." -!endif - -;--- Installer attributes --- -Name "${PRODUCT_NAME}" -OutFile "${OUTPUT_PATH}" -InstallDir "$LOCALAPPDATA\Programs\${PRODUCT_NAME}" -InstallDirRegKey HKCU "Software\${PRODUCT_NAME}" "InstallDir" -RequestExecutionLevel user -SetCompressor /SOLID lzma - -;--- Version info embedded in the installer EXE --- -VIProductVersion "${PRODUCT_VERSION}.0" -VIAddVersionKey "ProductName" "${PRODUCT_NAME}" -VIAddVersionKey "ProductVersion" "${PRODUCT_VERSION}" -VIAddVersionKey "FileDescription" "${PRODUCT_NAME} Setup" -VIAddVersionKey "FileVersion" "${PRODUCT_VERSION}" -VIAddVersionKey "CompanyName" "${PRODUCT_PUBLISHER}" -VIAddVersionKey "LegalCopyright" "Copyright ${PRODUCT_PUBLISHER}" - -;--- MUI configuration --- -!define MUI_ABORTWARNING - -;--- Installer pages --- -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!define MUI_FINISHPAGE_RUN "$INSTDIR\${PRODUCT_NAME}.exe" -!insertmacro MUI_PAGE_FINISH - -;--- Uninstaller pages --- -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - -;--- Language --- -!insertmacro MUI_LANGUAGE "English" - -;--- Installer section --- -Section "Install" - ; Close any running instance - ExecWait 'taskkill /F /IM ${PRODUCT_NAME}.exe' $0 - - SetOutPath "$INSTDIR" - File /r "${SOURCE_DIR}\*.*" - - ; Write uninstaller - WriteUninstaller "$INSTDIR\Uninstall.exe" - - ; Start Menu shortcut - CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}" - CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_NAME}.exe" - CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall ${PRODUCT_NAME}.lnk" "$INSTDIR\Uninstall.exe" - - ; Desktop shortcut - CreateShortcut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_NAME}.exe" - - ; Add/Remove Programs registry entry - WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "DisplayName" "${PRODUCT_NAME}" - WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "UninstallString" '"$INSTDIR\Uninstall.exe"' - WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "QuietUninstallString" '"$INSTDIR\Uninstall.exe" /S' - WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "InstallLocation" "$INSTDIR" - WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "DisplayIcon" "$INSTDIR\${PRODUCT_NAME}.exe" - WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "Publisher" "${PRODUCT_PUBLISHER}" - WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "DisplayVersion" "${PRODUCT_VERSION}" - WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "NoModify" 1 - WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "NoRepair" 1 - - ; Store install directory for future upgrades - WriteRegStr HKCU "Software\${PRODUCT_NAME}" "InstallDir" "$INSTDIR" -SectionEnd - -;--- Uninstaller section --- -Section "Uninstall" - ; Close any running instance - ExecWait 'taskkill /F /IM ${PRODUCT_NAME}.exe' $0 - - ; Remove application files - RMDir /r "$INSTDIR" - - ; Remove shortcuts - RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}" - Delete "$DESKTOP\${PRODUCT_NAME}.lnk" - - ; Remove registry entries - DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" - DeleteRegKey HKCU "Software\${PRODUCT_NAME}" -SectionEnd diff --git a/scripts/create-installer.ts b/scripts/create-installer.ts index 22bb614..7bcee49 100644 --- a/scripts/create-installer.ts +++ b/scripts/create-installer.ts @@ -62,13 +62,13 @@ async function readVersion(): Promise { return packageJson.version; } -// --- Windows: NSIS installer --- +// --- Windows: Inno Setup installer --- -async function resolveNsisPath(): Promise { +async function resolveInnoSetupCompilerPath(): Promise { const candidates = [ - 'C:\\Program Files (x86)\\NSIS\\makensis.exe', - 'C:\\Program Files\\NSIS\\makensis.exe', - 'makensis', + 'C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe', + 'C:\\Program Files\\Inno Setup 6\\ISCC.exe', + 'iscc', ]; for (const candidate of candidates) { @@ -77,21 +77,25 @@ async function resolveNsisPath(): Promise { } } - return 'makensis'; + return 'iscc'; } async function createWindowsInstaller(version: string): Promise { - const nsisScript = join(installerAssetsDirectory, 'windows.nsi'); - const makensisPath = await resolveNsisPath(); + const issScript = join(installerAssetsDirectory, 'windows.iss'); + const isccPath = await resolveInnoSetupCompilerPath(); + const outputFilename = releaseTarget.installerAssetName.replace(/\.exe$/, ''); + const iconPath = join(repositoryRoot, 'assets', 'icons', 'windows', 'icon.ico'); await runCommand( - makensisPath, + isccPath, [ `/DPRODUCT_NAME=${productName}`, `/DPRODUCT_VERSION=${version}`, `/DSOURCE_DIR=${packagedAppDirectory}`, - `/DOUTPUT_PATH=${installerOutputPath}`, - nsisScript, + `/DOUTPUT_DIR=${releaseRootDirectory}`, + `/DOUTPUT_FILENAME=${outputFilename}`, + `/DICON_PATH=${iconPath}`, + issScript, ], repositoryRoot, );