Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d5154348f6 |
@@ -1,16 +1,36 @@
|
||||
# Build the Testium installer from testium.iss (needs Inno Setup 6 / ISCC.exe).
|
||||
# Build the Windows installer: PyInstaller one-folder build (fast start) + Inno Setup.
|
||||
# Install ISCC without admin: winget install --id JRSoftware.InnoSetup -e
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$repoRoot = Resolve-Path (Join-Path $scriptDir '..\..')
|
||||
$pyiDir = Join-Path $repoRoot 'package\pyinstaller'
|
||||
|
||||
# The PyInstaller exe must exist first.
|
||||
$exe = Join-Path $scriptDir '..\pyinstaller\dist\testium.exe'
|
||||
if (-not (Test-Path $exe)) {
|
||||
throw "PyInstaller build not found: $exe`nRun package\pyinstaller\build first."
|
||||
# Locate PyInstaller: PATH first, then the known project venvs.
|
||||
$pyi = (Get-Command pyinstaller.exe -ErrorAction SilentlyContinue).Source
|
||||
if (-not $pyi) {
|
||||
foreach ($p in @(
|
||||
(Join-Path $repoRoot 'test\tmp\testium_venv\Scripts\pyinstaller.exe'),
|
||||
(Join-Path $repoRoot 'test\tmp\.venv\Scripts\pyinstaller.exe'))) {
|
||||
if (Test-Path $p) { $pyi = $p; break }
|
||||
}
|
||||
}
|
||||
if (-not $pyi) { throw "pyinstaller.exe not found (PATH or project venv)." }
|
||||
|
||||
# One-folder PyInstaller build => dist\testium\testium.exe + dist\testium\_internal\.
|
||||
Write-Host "Building one-folder exe with: $pyi"
|
||||
Remove-Item -Recurse -Force (Join-Path $pyiDir 'build'), (Join-Path $pyiDir 'dist') -ErrorAction SilentlyContinue
|
||||
Push-Location $pyiDir
|
||||
try {
|
||||
$env:TESTIUM_ONEDIR = '1'
|
||||
& $pyi 'testium.spec'
|
||||
if ($LASTEXITCODE -ne 0) { throw "pyinstaller failed with exit code $LASTEXITCODE" }
|
||||
} finally {
|
||||
Remove-Item Env:\TESTIUM_ONEDIR -ErrorAction SilentlyContinue
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Locate ISCC.exe: PATH, then the usual install dirs.
|
||||
# Locate ISCC: PATH, then the usual install dirs.
|
||||
$iscc = (Get-Command ISCC.exe -ErrorAction SilentlyContinue).Source
|
||||
if (-not $iscc) {
|
||||
foreach ($p in @(
|
||||
|
||||
@@ -49,9 +49,12 @@ Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
; PATH off by default: the exe is windowed (console=False), so CLI shows no output.
|
||||
Name: "addtopath"; Description: "Ajouter Testium au PATH (usage en ligne de commande)"; Flags: unchecked
|
||||
; Shown only if another version is already installed; unchecked => keep it.
|
||||
Name: "removeold"; Description: "Désinstaller les autres versions de Testium déjà installées"; Check: OtherVersionsExist; Flags: unchecked
|
||||
|
||||
[Files]
|
||||
Source: "..\pyinstaller\dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||
; One-folder build: the exe plus its _internal\ tree (fast startup, no re-extract).
|
||||
Source: "..\pyinstaller\dist\testium\*"; DestDir: "{app}"; Flags: recursesubdirs ignoreversion
|
||||
; Ship the .ico so shortcuts/uninstall reference it directly, not the embedded one.
|
||||
Source: "..\testium.ico"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
@@ -67,6 +70,54 @@ Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}
|
||||
[Code]
|
||||
const
|
||||
EnvKey = 'Environment';
|
||||
UninstallRoot = 'Software\Microsoft\Windows\CurrentVersion\Uninstall';
|
||||
AppGuid = '{B7E6F1C2-9A4D-4E3B-8F71-7C2D5A6E0B14}';
|
||||
|
||||
// Inno's uninstall subkey for *this* version: "{AppId}_is1".
|
||||
function CurrentUninstallSubkey(): string;
|
||||
begin
|
||||
Result := AppGuid + '_{#MyAppVersion}_is1';
|
||||
end;
|
||||
|
||||
// Uninstall subkeys of every installed Testium version except this one.
|
||||
function OtherTestiumSubkeys(): TArrayOfString;
|
||||
var
|
||||
names: TArrayOfString;
|
||||
i: Integer;
|
||||
prefix, cur: string;
|
||||
begin
|
||||
SetArrayLength(Result, 0);
|
||||
prefix := Uppercase(AppGuid + '_');
|
||||
cur := Uppercase(CurrentUninstallSubkey());
|
||||
if RegGetSubkeyNames(HKEY_CURRENT_USER, UninstallRoot, names) then
|
||||
for i := 0 to GetArrayLength(names) - 1 do
|
||||
if (Pos(prefix, Uppercase(names[i])) = 1) and (Uppercase(names[i]) <> cur) then
|
||||
begin
|
||||
SetArrayLength(Result, GetArrayLength(Result) + 1);
|
||||
Result[GetArrayLength(Result) - 1] := names[i];
|
||||
end;
|
||||
end;
|
||||
|
||||
// Drives the "removeold" task: only offered when another version exists.
|
||||
function OtherVersionsExist(): Boolean;
|
||||
begin
|
||||
Result := GetArrayLength(OtherTestiumSubkeys()) > 0;
|
||||
end;
|
||||
|
||||
// Silently run each other version's uninstaller.
|
||||
procedure RemoveOtherVersions();
|
||||
var
|
||||
subs: TArrayOfString;
|
||||
i, rc: Integer;
|
||||
cmd: string;
|
||||
begin
|
||||
subs := OtherTestiumSubkeys();
|
||||
for i := 0 to GetArrayLength(subs) - 1 do
|
||||
if RegQueryStringValue(HKEY_CURRENT_USER, UninstallRoot + '\' + subs[i],
|
||||
'UninstallString', cmd) and (cmd <> '') then
|
||||
Exec(RemoveQuotes(cmd), '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART',
|
||||
'', SW_HIDE, ewWaitUntilTerminated, rc);
|
||||
end;
|
||||
|
||||
// True if Param is not already a full segment of the per-user PATH.
|
||||
function NeedsAddPath(Param: string): Boolean;
|
||||
@@ -97,6 +148,8 @@ begin
|
||||
Path := Path + ExpandConstant('{app}');
|
||||
RegWriteStringValue(HKEY_CURRENT_USER, EnvKey, 'Path', Path);
|
||||
end;
|
||||
if WizardIsTaskSelected('removeold') then
|
||||
RemoveOtherVersions();
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@@ -79,26 +79,60 @@ a = Analysis(
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='testium',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
# UPX is CPU+IO heavy for a marginal size gain — build_all --ram sets
|
||||
# TESTIUM_NO_UPX=1 to skip it (much faster on slow/flash storage).
|
||||
upx=not os.environ.get("TESTIUM_NO_UPX"),
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
ico='../testium.ico'
|
||||
)
|
||||
# TESTIUM_ONEDIR=1 => one-folder build (fast startup), used by the Windows
|
||||
# installer; default one-file keeps the Linux build_all portable binary.
|
||||
ONEDIR = bool(os.environ.get("TESTIUM_ONEDIR"))
|
||||
# UPX skipped via TESTIUM_NO_UPX (build_all --ram) — slow for a marginal gain.
|
||||
_upx = not os.environ.get("TESTIUM_NO_UPX")
|
||||
|
||||
if ONEDIR:
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='testium',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=_upx,
|
||||
upx_exclude=[],
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
ico='../testium.ico'
|
||||
)
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=_upx,
|
||||
upx_exclude=[],
|
||||
name='testium',
|
||||
)
|
||||
else:
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='testium',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=_upx,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
ico='../testium.ico'
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user