mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-14 19:27:01 -04:00
fix(windows): #399 ignore stale App Paths values in the install-folder fallback
The App Paths directory search doesn't check that lightcraft.exe exists, and when the old installers' unquoted path is gone, Windows Installer falls back to the text before the first space: a deleted C:\Program Files\LightCraft\lightcraft.exe resolved to C:\, so an upgrade would install into the drive root. Gate the fallback on a second search of the same value with a FileSearch for lightcraft.exe. The install-folder test gains legacy-folder-deleted (failed before this fix) and legacy-exe-deleted cases, and removes its empty parent registry key. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
32a358180c
commit
a82ecb3753
2 files changed
+31
-9
No files matched your search
@@ -51,9 +51,19 @@
|
||||
<RegistrySearch Id="LegacyInstallFolder" Root="HKLM"
|
||||
Key="Software\Microsoft\Windows\CurrentVersion\App Paths\lightcraft.exe" Type="file" />
|
||||
</Property>
|
||||
<!-- That directory search doesn't check the executable exists, and when its unquoted path is
|
||||
gone it falls back to the text before the first space: a deleted
|
||||
"C:\Program Files\LightCraft\lightcraft.exe" yields "C:\". Only use the folder when this
|
||||
search, which does require lightcraft.exe, finds it too. -->
|
||||
<Property Id="LEGACYINSTALLEXE">
|
||||
<RegistrySearch Id="LegacyInstallExe" Root="HKLM"
|
||||
Key="Software\Microsoft\Windows\CurrentVersion\App Paths\lightcraft.exe" Type="file">
|
||||
<FileSearch Id="LegacyInstallExeFile" Name="lightcraft.exe" />
|
||||
</RegistrySearch>
|
||||
</Property>
|
||||
<SetProperty Id="INSTALLFOLDER" Action="SetInstallFolderFromAppPaths" Value="[LEGACYINSTALLFOLDER]"
|
||||
After="SetINSTALLFOLDER" Sequence="both"
|
||||
Condition="LEGACYINSTALLFOLDER AND NOT PREVIOUSINSTALLFOLDER AND NOT INSTALLFOLDER" />
|
||||
Condition="LEGACYINSTALLFOLDER AND LEGACYINSTALLEXE AND NOT PREVIOUSINSTALLFOLDER AND NOT INSTALLFOLDER" />
|
||||
<StandardDirectory Id="ProgramMenuFolder" />
|
||||
|
||||
<Feature Id="Main" Title="LightCraft" Level="1">
|
||||
|
||||
@@ -12,7 +12,8 @@ $ErrorActionPreference = 'Stop'
|
||||
$PSNativeCommandUseErrorActionPreference = $false
|
||||
$id = [Guid]::NewGuid().ToString('N')
|
||||
$root = Join-Path ([IO.Path]::GetTempPath()) "lightcraft-install-folder-$id"
|
||||
$key = "Software\LightCraftInstallerTests\$id"
|
||||
$testsKey = 'Software\LightCraftInstallerTests'
|
||||
$key = "$testsKey\$id"
|
||||
$product = [Guid]::NewGuid().ToString('B')
|
||||
$upgrade = [Guid]::NewGuid().ToString('B')
|
||||
$view = if ($Arch -eq 'x86') { [Microsoft.Win32.RegistryView]::Registry32 } else { [Microsoft.Win32.RegistryView]::Registry64 }
|
||||
@@ -72,20 +73,25 @@ try {
|
||||
$legacy = Join-Path $root 'legacy app café'
|
||||
$modern = Join-Path $root 'remembered app'
|
||||
$explicit = Join-Path $root 'explicit app'
|
||||
New-Item -ItemType Directory -Path $legacy, $modern, $explicit | Out-Null
|
||||
[IO.File]::WriteAllText((Join-Path $legacy 'lightcraft.exe'), 'test placeholder; never executed')
|
||||
$emptied = Join-Path $root 'emptied app'
|
||||
New-Item -ItemType Directory -Path $legacy, $modern, $explicit, $emptied | Out-Null
|
||||
$legacyExe = Join-Path $legacy 'lightcraft.exe'
|
||||
[IO.File]::WriteAllText($legacyExe, 'test placeholder; never executed')
|
||||
$programFiles = if ($Arch -eq 'x86' -and ${env:ProgramFiles(x86)}) { ${env:ProgramFiles(x86)} } else { $env:ProgramFiles }
|
||||
$cases = @(
|
||||
@{ Name = 'fresh'; Expected = (Join-Path $programFiles 'LightCraft') },
|
||||
@{ Name = 'legacy-app-paths'; Legacy = $true; Expected = $legacy },
|
||||
@{ Name = 'legacy-app-paths'; Legacy = $legacyExe; Expected = $legacy },
|
||||
# A stale unquoted path with a space used to resolve to the parent of the text before the space.
|
||||
@{ Name = 'legacy-folder-deleted'; Legacy = (Join-Path $root 'deleted app\lightcraft.exe'); Expected = (Join-Path $programFiles 'LightCraft') },
|
||||
@{ Name = 'legacy-exe-deleted'; Legacy = (Join-Path $emptied 'lightcraft.exe'); Expected = (Join-Path $programFiles 'LightCraft') },
|
||||
@{ Name = 'remembered-folder'; Modern = $true; Expected = $modern },
|
||||
@{ Name = 'remembered-beats-legacy'; Modern = $true; Legacy = $true; Expected = $modern },
|
||||
@{ Name = 'explicit-beats-legacy'; Legacy = $true; Explicit = $true; Expected = $explicit },
|
||||
@{ Name = 'explicit-beats-both'; Modern = $true; Legacy = $true; Explicit = $true; Expected = $explicit }
|
||||
@{ Name = 'remembered-beats-legacy'; Modern = $true; Legacy = $legacyExe; Expected = $modern },
|
||||
@{ Name = 'explicit-beats-legacy'; Legacy = $legacyExe; Explicit = $true; Expected = $explicit },
|
||||
@{ Name = 'explicit-beats-both'; Modern = $true; Legacy = $legacyExe; Explicit = $true; Expected = $explicit }
|
||||
)
|
||||
foreach ($case in $cases) {
|
||||
$registry.DeleteSubKeyTree($key, $false)
|
||||
if ($case.Legacy) { Set-TestValue 'Software\Microsoft\Windows\CurrentVersion\App Paths\lightcraft.exe' '' (Join-Path $legacy 'lightcraft.exe') }
|
||||
if ($case.Legacy) { Set-TestValue 'Software\Microsoft\Windows\CurrentVersion\App Paths\lightcraft.exe' '' $case.Legacy }
|
||||
if ($case.Modern) { Set-TestValue 'Software\LightCraft' 'InstallFolder' "$modern\" }
|
||||
$arguments = @('/i', "`"$msi`"")
|
||||
if ($case.Explicit) { $arguments += "INSTALLFOLDER=`"$explicit`"" }
|
||||
@@ -108,6 +114,12 @@ try {
|
||||
if ($installed) { Invoke-Msi @('/x', $product) (Join-Path $root 'cleanup.log') -AllowAbsent }
|
||||
} finally {
|
||||
$registry.DeleteSubKeyTree($key, $false)
|
||||
$tests = $registry.OpenSubKey($testsKey)
|
||||
if ($tests) {
|
||||
$empty = $tests.SubKeyCount -eq 0 -and $tests.ValueCount -eq 0
|
||||
$tests.Dispose()
|
||||
if ($empty) { $registry.DeleteSubKey($testsKey, $false) }
|
||||
}
|
||||
$registry.Dispose()
|
||||
# Keep logs on failure; they explain MSI failures that otherwise only report an exit code.
|
||||
if ($passed) { Remove-Item -Recurse -Force $root } else { Write-Output "Test artifacts retained: $root" }
|
||||
|
||||
Reference in new issue
Block a user