scripting: add an install command for macOS guests - #7863
Merged
Merged
Conversation
This was referenced Sep 11, 2026
VMDisplayAppleWindowController.windowDidLoad shows a confirmation sheet before calling requestInstallVM, so a macOS install cannot be driven from a script without someone clicking OK. This does not remove the sheet. It guards a genuinely destructive action (it erases the primary drive) and a GUI user who opens a VM that happens to carry an IPSW should keep being asked. It is also structurally unavailable to a script: showConfirmAlert calls beginSheetModal(for: window!), so it needs a window, and the scripted `start` verb calls data.run(...), which loads the window controller and raises the sheet in the first place. So this adds a separate `install` verb that goes straight to installVM(with:) and never opens a window. The confirmation moves rather than disappearing: asking for `install` is the confirmation, which is why the sdef entry says DESTRUCTIVE in as many words. This matches the CONTRIBUTING.md guidance about putting things most users do not need into the scripting interface rather than the UI. It also clears the IPSW on success, as the GUI does in didCompleteInstallation. That clearing lives in the window controller's delegate callback, and a scripted install has no window, so without it the IPSW outlives the install and the next `start` that does open a display window asks "Would you like to install macOS?" over a guest that is already installed. Measured before the fix: the registry still held the IPSW after a completed scripted install. Two guards, because installVM returns silently when the VM is not stopped and calling it unguarded would report success having done nothing: a VM with no IPSW configured, and a VM that is not stopped, each fail with an error naming the cause. Verified against main on Xcode 26.6 / Apple Silicon: no confirmation sheet at any point, a macOS 26.6.2 install run to completion (21 GB, framework returned success), the IPSW cleared from the registry afterwards, and a subsequent `start` opening a display window with no reinstall prompt and the guest booting to Setup Assistant. UTMScripting.swift gains the install() method that bridge-gen.sh generates for this sdef change. Refs utmapp#6092 Assisted-by: Claude:claude-opus-5
A macOS install takes several minutes, well past the default two minute Apple Event timeout. A plain `install` therefore failed with -1712 while the installation kept running, and a script reacting to that error by retrying or starting the VM would race the install. `install` now returns as soon as the installation starts, and the new `query install` verb reports whether it is still running and how far it has progressed, or raises the error if it failed. The installation only counts as finished once the VM has stopped by itself, so the VM can be started right away. Other verbs fail with a clear error while an installation started from a script is in progress. This includes `start`, which would otherwise open a window that asks to install macOS again. As in the GUI, `stop` cancels the installation. Assisted-by: Claude:claude-opus-5
osy
force-pushed
the
scripting-install-command
branch
from
September 19, 2026 14:49
0c07c9f to
5d395ab
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #6092 and #7862.
What is blocked
VMDisplayAppleWindowController.windowDidLoadshows a confirmation sheet before callingrequestInstallVM, so a macOS install cannot be driven from a script without someone clicking OK.This does not remove the sheet
That is deliberate. It guards a genuinely destructive action — it erases the primary drive — and a GUI user who opens a VM that happens to carry an IPSW should keep being asked.
It is also structurally unavailable to a script:
showConfirmAlertcallsbeginSheetModal(for: window!), so it needs a window. The scriptedstartverb callsdata.run(...), which loads the window controller — that is what raises the sheet in the first place.So this adds a separate verb that goes straight to
installVM(with:)and never opens a window. The confirmation moves rather than disappearing: asking forinstallis the confirmation, which is why the sdef entry says DESTRUCTIVE in as many words. This seemed to match the guidance in CONTRIBUTING.md about putting things most users do not need into the scripting interface rather than the UI.It also clears the IPSW on success
As the GUI does in
didCompleteInstallation. That clearing lives in the window controller's delegate callback, and a scripted install has no window — so without it the IPSW outlives the install, and the nextstartthat does open a display window asks "Would you like to install macOS?" over a guest that is already installed. Measured before the fix: the registry still held the IPSW after a completed scripted install.Two guards
installVMreturns silently when the VM is not stopped, so calling it unguarded would report success having done nothing. Both cases were exercised:installa Linux VMinstalla running VMTesting
Built against
mainfrom a clean baseline, Xcode 26.6, macOS arm64. This branch applies and builds independently of #7862.installresolves as a verbinstall virtual machinestartInstall timeline, macOS 26.6.2 (25G83):
No generated-code changes are needed for this one.