mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-06 19:58:43 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c1852f79f | ||
|
|
d7d1b33a53 |
@@ -131,6 +131,11 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libsecret-1-dev
|
sudo apt-get install -y libsecret-1-dev
|
||||||
|
|
||||||
|
- name: Install Inno Setup
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
shell: pwsh
|
||||||
|
run: choco install innosetup -y --no-progress
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bun install --frozen-lockfile
|
run: bun install --frozen-lockfile
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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
|
|
||||||
+34
-33
@@ -5,6 +5,7 @@ import {
|
|||||||
cp,
|
cp,
|
||||||
mkdir,
|
mkdir,
|
||||||
readFile,
|
readFile,
|
||||||
|
rename,
|
||||||
symlink,
|
symlink,
|
||||||
writeFile,
|
writeFile,
|
||||||
} from 'node:fs/promises';
|
} from 'node:fs/promises';
|
||||||
@@ -61,13 +62,13 @@ async function readVersion(): Promise<string> {
|
|||||||
return packageJson.version;
|
return packageJson.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Windows: NSIS installer ---
|
// --- Windows: Inno Setup installer ---
|
||||||
|
|
||||||
async function resolveNsisPath(): Promise<string> {
|
async function resolveInnoSetupCompilerPath(): Promise<string> {
|
||||||
const candidates = [
|
const candidates = [
|
||||||
'C:\\Program Files (x86)\\NSIS\\makensis.exe',
|
'C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe',
|
||||||
'C:\\Program Files\\NSIS\\makensis.exe',
|
'C:\\Program Files\\Inno Setup 6\\ISCC.exe',
|
||||||
'makensis',
|
'iscc',
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
@@ -76,21 +77,25 @@ async function resolveNsisPath(): Promise<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'makensis';
|
return 'iscc';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createWindowsInstaller(version: string): Promise<void> {
|
async function createWindowsInstaller(version: string): Promise<void> {
|
||||||
const nsisScript = join(installerAssetsDirectory, 'windows.nsi');
|
const issScript = join(installerAssetsDirectory, 'windows.iss');
|
||||||
const makensisPath = await resolveNsisPath();
|
const isccPath = await resolveInnoSetupCompilerPath();
|
||||||
|
const outputFilename = releaseTarget.installerAssetName.replace(/\.exe$/, '');
|
||||||
|
const iconPath = join(repositoryRoot, 'assets', 'icons', 'windows', 'icon.ico');
|
||||||
|
|
||||||
await runCommand(
|
await runCommand(
|
||||||
makensisPath,
|
isccPath,
|
||||||
[
|
[
|
||||||
`/DPRODUCT_NAME=${productName}`,
|
`/DPRODUCT_NAME=${productName}`,
|
||||||
`/DPRODUCT_VERSION=${version}`,
|
`/DPRODUCT_VERSION=${version}`,
|
||||||
`/DSOURCE_DIR=${packagedAppDirectory}`,
|
`/DSOURCE_DIR=${packagedAppDirectory}`,
|
||||||
`/DOUTPUT_PATH=${installerOutputPath}`,
|
`/DOUTPUT_DIR=${releaseRootDirectory}`,
|
||||||
nsisScript,
|
`/DOUTPUT_FILENAME=${outputFilename}`,
|
||||||
|
`/DICON_PATH=${iconPath}`,
|
||||||
|
issScript,
|
||||||
],
|
],
|
||||||
repositoryRoot,
|
repositoryRoot,
|
||||||
);
|
);
|
||||||
@@ -107,29 +112,25 @@ async function createMacInstaller(): Promise<void> {
|
|||||||
const appBundlePath = join(packagedAppDirectory, appBundleName);
|
const appBundlePath = join(packagedAppDirectory, appBundleName);
|
||||||
const createDmg = join(repositoryRoot, 'node_modules', '.bin', 'create-dmg');
|
const createDmg = join(repositoryRoot, 'node_modules', '.bin', 'create-dmg');
|
||||||
|
|
||||||
try {
|
// create-dmg outputs to the destination directory with a generated filename.
|
||||||
await runCommand(
|
// We use --no-version-in-filename so the output is "<AppName>.dmg", then
|
||||||
createDmg,
|
// rename it to the expected installer asset name.
|
||||||
[
|
await runCommand(
|
||||||
'--overwrite',
|
createDmg,
|
||||||
'--window-size', '600', '400',
|
[
|
||||||
'--icon-size', '100',
|
'--overwrite',
|
||||||
'--icon', appBundleName, '150', '200',
|
'--no-version-in-filename',
|
||||||
'--app-drop-link', '450', '200',
|
'--no-code-sign',
|
||||||
installerOutputPath,
|
appBundlePath,
|
||||||
appBundlePath,
|
releaseRootDirectory,
|
||||||
],
|
],
|
||||||
repositoryRoot,
|
repositoryRoot,
|
||||||
);
|
);
|
||||||
} catch {
|
|
||||||
// create-dmg exits with code 2 when code signing fails (expected without
|
|
||||||
// a Developer ID certificate) but still produces a valid DMG. Check
|
|
||||||
// whether the output file was created before treating this as an error.
|
|
||||||
if (!(await pathExists(installerOutputPath))) {
|
|
||||||
throw new Error('Failed to create DMG — output file was not produced.');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('DMG created (code signing skipped — ad-hoc only).');
|
// Rename from the generated name ("Aryx.dmg") to the platform-specific asset name
|
||||||
|
const generatedDmgPath = join(releaseRootDirectory, `${productName}.dmg`);
|
||||||
|
if (generatedDmgPath !== installerOutputPath) {
|
||||||
|
await rename(generatedDmgPath, installerOutputPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user