mirror of
https://github.com/utmapp/UTM.git
synced 2026-10-12 02:24:01 +00:00
Merge pull request #7862 from meisenbarth/scripting-macos-create
scripting: allow creating macOS VMs with the Apple backend
This commit is contained in:
@@ -31,6 +31,11 @@
|
||||
</property>
|
||||
</class-extension>
|
||||
|
||||
<enumeration name="operating system" code="ApOe" description="Guest operating system for an Apple virtual machine.">
|
||||
<enumerator name="linux" code="ApOl" description="Linux guest."/>
|
||||
<enumerator name="macOS" code="ApOm" description="macOS guest (Apple silicon only)."/>
|
||||
</enumeration>
|
||||
|
||||
<enumeration name="backend" code="VmEb" description="Backend type.">
|
||||
<enumerator name="apple" code="ApPl" description="Apple Virtualization.framework backend."/>
|
||||
<enumerator name="qemu" code="QeMu" description="QEMU backend."/>
|
||||
@@ -713,6 +718,12 @@
|
||||
description="List of display configuration.">
|
||||
<type type="apple display configuration" list="yes"/>
|
||||
</property>
|
||||
|
||||
<property name="os" code="ApOs" type="operating system"
|
||||
description="Guest operating system. Only used when creating; defaults to Linux."/>
|
||||
|
||||
<property name="macRecoveryIpsw" code="ApIp" type="file"
|
||||
description="IPSW recovery image used to install macOS. Required when os is macOS."/>
|
||||
</record-type>
|
||||
|
||||
<record-type name="apple directory share configuration" code="ApDs" description="Apple directory share configuration.">
|
||||
|
||||
@@ -51,6 +51,12 @@ import ScriptingBridge
|
||||
case detailed = 0x6c776474 /* 'lwdt' */
|
||||
}
|
||||
|
||||
// MARK: UTMScriptingOperatingSystem
|
||||
@objc public enum UTMScriptingOperatingSystem : AEKeyword {
|
||||
case linux = 0x41704f6c /* 'ApOl' */
|
||||
case macOS = 0x41704f6d /* 'ApOm' */
|
||||
}
|
||||
|
||||
// MARK: UTMScriptingBackend
|
||||
@objc public enum UTMScriptingBackend : AEKeyword {
|
||||
case apple = 0x4170506c /* 'ApPl' */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Virtualization
|
||||
|
||||
@MainActor
|
||||
@objc(UTMScriptingCreateCommand)
|
||||
@@ -103,12 +104,49 @@ class UTMScriptingCreateCommand: NSCreateCommand, UTMScriptable {
|
||||
throw ScriptingError.nameNotSpecified
|
||||
}
|
||||
let config = UTMAppleConfiguration()
|
||||
config.system.boot = try UTMAppleConfigurationBoot(for: .linux)
|
||||
// enumerations arrive as an AEKeyword and not a string
|
||||
var bootOS = UTMAppleConfigurationBoot.OperatingSystem.linux
|
||||
if let osKeyword = record["os"] as? AEKeyword {
|
||||
guard let scriptingOS = UTMScriptingOperatingSystem(rawValue: osKeyword) else {
|
||||
throw ScriptingError.operatingSystemNotSupported
|
||||
}
|
||||
switch scriptingOS {
|
||||
case .linux: bootOS = .linux
|
||||
case .macOS: bootOS = .macOS
|
||||
}
|
||||
}
|
||||
config.system.boot = try UTMAppleConfigurationBoot(for: bootOS)
|
||||
var macGuestMajorVersion = 0
|
||||
if bootOS == .macOS {
|
||||
guard let ipsw = record["macRecoveryIpsw"] as? URL else {
|
||||
throw ScriptingError.macRecoveryIpswNotSpecified
|
||||
}
|
||||
config.system.boot.macRecoveryIpswURL = ipsw
|
||||
#if arch(arm64)
|
||||
// the hardware model must match the IPSW the caller chose
|
||||
let image = try await VZMacOSRestoreImage.image(from: ipsw)
|
||||
guard let model = image.mostFeaturefulSupportedConfiguration?.hardwareModel else {
|
||||
throw ScriptingError.ipswNotSupported
|
||||
}
|
||||
config.system.macPlatform = UTMAppleConfigurationMacPlatform(newHardware: model)
|
||||
macGuestMajorVersion = image.operatingSystemVersion.majorVersion
|
||||
#else
|
||||
throw ScriptingError.operatingSystemNotSupported
|
||||
#endif
|
||||
}
|
||||
config.virtualization.hasBalloon = true
|
||||
config.virtualization.hasEntropy = true
|
||||
config.networks = [UTMAppleConfigurationNetwork()]
|
||||
// remove any display devices
|
||||
config.displays = []
|
||||
if bootOS == .macOS {
|
||||
// macOS is not usable headless so it gets the same devices as the wizard
|
||||
config.displays = [UTMAppleConfigurationDisplay(width: 1920, height: 1200)]
|
||||
config.virtualization.hasAudio = true
|
||||
config.virtualization.keyboard = .generic
|
||||
config.virtualization.pointer = macGuestMajorVersion >= 13 ? .trackpad : .mouse
|
||||
} else {
|
||||
// remove any display devices
|
||||
config.displays = []
|
||||
}
|
||||
// add a default serial device
|
||||
var serial = UTMAppleConfigurationSerial()
|
||||
serial.mode = .ptty
|
||||
@@ -131,6 +169,9 @@ class UTMScriptingCreateCommand: NSCreateCommand, UTMScriptable {
|
||||
case configurationNotFound
|
||||
case nameNotSpecified
|
||||
case architectureNotSpecified
|
||||
case operatingSystemNotSupported
|
||||
case macRecoveryIpswNotSpecified
|
||||
case ipswNotSupported
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
@@ -140,6 +181,9 @@ class UTMScriptingCreateCommand: NSCreateCommand, UTMScriptable {
|
||||
case .configurationNotFound: return NSLocalizedString("A valid configuration must be specified.", comment: "UTMScriptingAppDelegate")
|
||||
case .nameNotSpecified: return NSLocalizedString("No name specified in the configuration.", comment: "UTMScriptingAppDelegate")
|
||||
case .architectureNotSpecified: return NSLocalizedString("No architecture specified in the configuration.", comment: "UTMScriptingAppDelegate")
|
||||
case .operatingSystemNotSupported: return NSLocalizedString("The specified operating system is not supported on your machine.", comment: "UTMScriptingAppDelegate")
|
||||
case .macRecoveryIpswNotSpecified: return NSLocalizedString("An IPSW recovery image must be specified to create a macOS virtual machine.", comment: "UTMScriptingAppDelegate")
|
||||
case .ipswNotSupported: return NSLocalizedString("Your machine does not support running this IPSW.", comment: "UTMScriptingAppDelegate")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user