<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** #50020 # What this does Adds **Rtools** as a Windows Fleet-maintained app. One of the 11 apps split out of #48501 that failed the FMA validator; #50016 shipped the 6 that passed. ## Why it was failing The install script hit the validator's 10-minute `executeScript` cap exactly: ``` 20:41:22 INFO msg="Executing install script..." app=Rtools 20:51:22 ERROR msg="Error executing install script: exit status 1" # exactly 10:00 later 20:51:22 WARN msg="failed to remove rtools45-6768-6492.exe: ... Access is denied." ``` The locked installer in the temp dir shows a process was still alive. `Start-Process -Wait` waits for the process *and all of its descendants*, which is the same root cause as the other install-timeout apps in this batch. Rtools is also the one app in the batch where a **slow unpack** is a plausible second cause — the installer is ~460 MB and expands a full toolchain. So rather than assume, the script now waits on the installer process alone with a 480s cap (under the caller's 10-minute budget) and logs elapsed time plus Add/Remove Programs registration state on every poll. If the cap is reached: - **registered** → the install finished and only a lingering child remains, so it stops that process and succeeds; - **not registered** → the unpack genuinely didn't finish, and it fails with that stated explicitly. Either way the CI log now says which one happened instead of just timing out. ## Notes - **Identity verified against the installer**, not winget metadata. The setup stub's PE version resource reads `CompanyName: The R Foundation`, `ProductName: Rtools`. Inno derives `VersionInfoCompany` from `AppPublisher`, so the ARP publisher is `The R Foundation` — which is what the exists query uses. - **Versioned ARP name.** The registry `DisplayName` is `Rtools 4.5 (6768-6492)`, so the input uses `fuzzy_match_name` and the exists query is `name LIKE 'Rtools %'`. - Installs to `C:\rtools45`, not Program Files, so the validator's "no changes detected in `C:\Program Files`" line is an expected warning, not a failure. - Ships a new catalog icon and website asset. # Checklist for submitter - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. - [x] Timeouts are implemented and retries are limited to avoid infinite loops ## Testing - [x] FMA CI validator (install → detect → uninstall) **passes** on the SYSTEM-context Windows runner — [run 30384196159](https://github.com/fleetdm/fleet/actions/runs/30384196159) (`All checks passed`) - [x] Generated output verified locally: manifest SHA matches the winget manifest, exists/patched queries checked against the installer's PE version resource, `apps.json` is valid JSON with a description filled in. - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Rtools as a supported Windows application. * Added installation and uninstallation support with silent setup and silent removal. * Added Rtools version metadata, installer verification, and Developer tools categorization. * Added a dedicated Rtools icon for software listings. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
76 lines
2.5 KiB
PowerShell
76 lines
2.5 KiB
PowerShell
# Learn more about .exe install scripts:
|
|
# http://fleetdm.com/learn-more-about/exe-install-scripts
|
|
|
|
$exeFilePath = "${env:INSTALLER_PATH}"
|
|
|
|
# Rtools unpacks a large toolchain (~460 MB) to C:\rtools45, not Program Files.
|
|
# -Wait waits on descendants, so wait on the installer process alone and log
|
|
# progress to tell a slow unpack apart from a stuck one.
|
|
$installTimeoutSeconds = 480
|
|
$pollSeconds = 15
|
|
|
|
$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
|
$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
|
|
|
function Test-RtoolsRegistered {
|
|
$null -ne (Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |
|
|
ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |
|
|
Where-Object { $_.DisplayName -like "Rtools*" } |
|
|
Select-Object -First 1)
|
|
}
|
|
|
|
try {
|
|
|
|
$process = Start-Process -FilePath "$exeFilePath" `
|
|
-ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" `
|
|
-PassThru
|
|
# Keeps .ExitCode readable after the process ends.
|
|
$null = $process.Handle
|
|
|
|
$elapsed = 0
|
|
while (-not $process.HasExited -and ($elapsed -lt $installTimeoutSeconds)) {
|
|
Start-Sleep -Seconds $pollSeconds
|
|
$elapsed += $pollSeconds
|
|
Write-Host "Installing... ($elapsed seconds, registered: $(Test-RtoolsRegistered))"
|
|
}
|
|
|
|
if (-not $process.HasExited) {
|
|
# Registered means the install finished and only a lingering child remains.
|
|
if (Test-RtoolsRegistered) {
|
|
Write-Host "Installer still running after ${installTimeoutSeconds}s but Rtools is registered; stopping the lingering process."
|
|
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
|
|
Start-Sleep -Seconds 2
|
|
Exit 0
|
|
}
|
|
|
|
Write-Host "Installer did not finish within ${installTimeoutSeconds}s and Rtools is not registered."
|
|
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
|
|
Exit 1
|
|
}
|
|
|
|
$exitCode = $process.ExitCode
|
|
Write-Host "Install exit code: $exitCode"
|
|
|
|
# The parent can exit while a descendant is still writing the ARP entry.
|
|
$settle = 0
|
|
while (-not (Test-RtoolsRegistered) -and ($settle -lt 90)) {
|
|
Start-Sleep -Seconds $pollSeconds
|
|
$settle += $pollSeconds
|
|
Write-Host "Waiting for Rtools to register... ($settle seconds)"
|
|
}
|
|
|
|
if (-not (Test-RtoolsRegistered)) {
|
|
Write-Host "Rtools did not register in Add/Remove Programs."
|
|
Exit 1
|
|
}
|
|
|
|
# 3010 (reboot required) and 1641 (reboot initiated) are successful installs.
|
|
if ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }
|
|
|
|
Exit $exitCode
|
|
|
|
} catch {
|
|
Write-Host "Error: $_"
|
|
Exit 1
|
|
}
|