qemu: migrate legacy QEMU config

This commit is contained in:
osy 2022-06-18 00:11:36 -07:00
parent 300ef18fcc
commit 6c8c6d8dc6
13 changed files with 367 additions and 0 deletions

View File

@ -89,3 +89,20 @@ class UTMConfigurationInfo: Codable, ObservableObject {
try container.encode(uuid, forKey: .uuid)
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMConfigurationInfo {
convenience init(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
name = oldConfig.name
notes = oldConfig.notes
if let uuidString = oldConfig.systemUUID, let uuid = UUID(uuidString: uuidString) {
self.uuid = uuid
}
isIconCustom = oldConfig.iconCustom
dataURL = oldConfig.existingPath
icon = oldConfig.icon
}
}

View File

@ -74,3 +74,21 @@ class UTMConfigurationTerminal: Codable, Identifiable, ObservableObject {
try container.encodeIfPresent(resizeCommand, forKey: .resizeCommand)
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMConfigurationTerminal {
convenience init(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
foregroundColor = oldConfig.consoleTextColor
backgroundColor = oldConfig.consoleBackgroundColor
if let fontStr = oldConfig.consoleFont {
font = QEMUTerminalFont(rawValue: fontStr)
}
if let fontSizeNum = oldConfig.consoleFontSize {
fontSize = fontSizeNum.intValue
}
resizeCommand = oldConfig.consoleResizeCommand
}
}

View File

@ -67,6 +67,10 @@ class UTMQemuConfiguration: Codable, ObservableObject {
case configurationVersion = "ConfigurationVersion"
}
init() {
reset()
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let backend = try values.decodeIfPresent(UTMBackend.self, forKey: .backend) ?? .qemu
@ -147,6 +151,33 @@ extension UTMQemuConfiguration {
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfiguration {
convenience init(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
information = .init(migrating: oldConfig)
system = .init(migrating: oldConfig)
qemu = .init(migrating: oldConfig)
input = .init(migrating: oldConfig)
sharing = .init(migrating: oldConfig)
if let display = UTMQemuConfigurationDisplay(migrating: oldConfig) {
displays = [display]
}
drives = (0..<oldConfig.countDrives).map({ i in UTMQemuConfigurationDrive(migrating: oldConfig, at: i) })
if let network = UTMQemuConfigurationNetwork(migrating: oldConfig) {
networks = [network]
}
if let serial = UTMQemuConfigurationSerial(migrating: oldConfig) {
serials = [serial]
}
if let _sound = UTMQemuConfigurationSound(migrating: oldConfig) {
sound = [_sound]
}
}
}
// MARK: UserInfo key constant
// TODO: maybe move this elsewhere as it is shared by both backend configs

View File

@ -89,3 +89,36 @@ extension UTMQemuConfigurationDisplay {
}
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationDisplay {
convenience init?(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
guard !oldConfig.displayConsoleOnly else {
return nil
}
if let hardwareStr = oldConfig.displayCard {
hardware = AnyQEMUConstant(rawValue: hardwareStr)!
}
isDynamicResolution = oldConfig.displayFitScreen
isNativeResolution = oldConfig.displayRetina
if let upscaler = convertScaler(from: oldConfig.displayUpscaler) {
upscalingFilter = upscaler
}
if let downscaler = convertScaler(from: oldConfig.displayDownscaler) {
downscalingFilter = downscaler
}
}
private func convertScaler(from str: String?) -> QEMUScaler? {
if str == "linear" {
return .linear
} else if str == "nearest" {
return .nearest
} else {
return nil
}
}
}

View File

@ -97,3 +97,63 @@ extension UTMQemuConfigurationDrive {
}
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationDrive {
convenience init(migrating oldConfig: UTMLegacyQemuConfiguration, at index: Int) {
self.init()
imageName = oldConfig.driveName(for: index)
imageType = convertImageType(from: oldConfig.driveImageType(for: index))
interface = convertInterface(from: oldConfig.driveInterfaceType(for: index))
isRemovable = oldConfig.driveRemovable(for: index)
}
private func convertImageType(from type: UTMDiskImageType) -> QEMUDriveImageType {
switch type {
case .none:
return .none
case .disk:
return .disk
case .CD:
return .cd
case .BIOS:
return .bios
case .kernel:
return .linuxKernel
case .initrd:
return .linuxInitrd
case .DTB:
return .linuxDtb
case .max:
return .none
@unknown default:
return .none
}
}
private func convertInterface(from str: String?) -> QEMUDriveInterface {
if str == "ide" {
return .ide
} else if str == "scsi" {
return .scsi
} else if str == "sd" {
return .sd
} else if str == "mtd" {
return .mtd
} else if str == "floppy" {
return .floppy
} else if str == "pflash" {
return .pflash
} else if str == "virtio" {
return .virtio
} else if str == "nvme" {
return .nvme
} else if str == "usb" {
return .usb
} else {
return .none
}
}
}

View File

@ -68,3 +68,23 @@ extension UTMQemuConfigurationInput {
}
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationInput {
convenience init(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
if oldConfig.inputLegacy {
usbBusSupport = .disabled
} else if oldConfig.usb3Support {
usbBusSupport = .usb3_0
} else {
usbBusSupport = .usb2_0
}
if let sharingNum = oldConfig.usbRedirectionMaximumDevices {
hasUsbSharing = true
maximumUsbShare = sharingNum.intValue
}
}
}

View File

@ -174,3 +174,51 @@ extension UTMQemuConfigurationNetwork {
#endif
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationNetwork {
convenience init?(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
guard oldConfig.networkEnabled else {
return nil
}
guard let oldMode = convertMode(from: oldConfig.networkMode) else {
return nil
}
mode = oldMode
if let hardwareStr = oldConfig.networkCard {
hardware = AnyQEMUConstant(rawValue: hardwareStr)!
}
if let macString = oldConfig.networkCardMac {
macAddress = macString
}
isIsolateFromHost = oldConfig.networkIsolate
bridgeInterface = oldConfig.networkBridgeInterface
vlanGuestAddress = oldConfig.networkAddress
vlanGuestAddressIPv6 = oldConfig.networkAddressIPv6
vlanHostAddress = oldConfig.networkHost
vlanHostAddressIPv6 = oldConfig.networkHostIPv6
vlanDhcpStartAddress = oldConfig.networkDhcpStart
vlanDhcpDomain = oldConfig.networkDhcpDomain
vlanDnsServerAddress = oldConfig.networkDnsServer
vlanDnsServerAddressIPv6 = oldConfig.networkDnsServerIPv6
vlanDnsSearchDomain = oldConfig.networkDnsSearch
portForward = oldConfig.portForwards().map({ old in UTMQemuConfigurationPortForward(migrating: old) })
}
private func convertMode(from str: String?) -> QEMUNetworkMode? {
if str == "emulated" {
return .emulated
} else if str == "shared" {
return .shared
} else if str == "host" {
return .host
} else if str == "bridged" {
return .bridged
} else {
return nil
}
}
}

View File

@ -33,3 +33,33 @@ struct UTMQemuConfigurationPortForward: Codable {
/// Guest port where connection is coming from.
var guestPort: Int = 0
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationPortForward {
init(migrating oldForward: UTMLegacyQemuConfigurationPortForward) {
self.init()
if let oldProtocol = convertProtocol(from: oldForward.protocol) {
`protocol` = oldProtocol
}
hostAddress = oldForward.hostAddress
if let portNum = oldForward.guestPort {
hostPort = portNum.intValue
}
guestAddress = oldForward.guestAddress
if let portNum = oldForward.guestPort {
guestPort = portNum.intValue
}
}
private func convertProtocol(from str: String?) -> QEMUNetworkProtocol? {
if str == "tcp" {
return .tcp
} else if str == "udp" {
return .udp
} else {
return nil
}
}
}

View File

@ -119,3 +119,22 @@ extension UTMQemuConfigurationQEMU {
#endif
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationQEMU {
convenience init(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
hasDebugLog = oldConfig.debugLogEnabled
hasUefiBoot = oldConfig.systemBootUefi
hasRNGDevice = oldConfig.systemRngEnabled
hasHypervisor = oldConfig.useHypervisor
hasRTCLocalTime = oldConfig.rtcUseLocalTime
hasPS2Controller = oldConfig.forcePs2Controller
machinePropertyOverride = oldConfig.systemMachineProperties
if let oldAddArgs = oldConfig.systemArguments {
additionalArguments = oldAddArgs
}
}
}

View File

@ -92,3 +92,16 @@ extension UTMQemuConfigurationSerial {
}
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationSerial {
convenience init?(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
guard oldConfig.displayConsoleOnly else {
return nil
}
terminal = UTMConfigurationTerminal(migrating: oldConfig)
}
}

View File

@ -71,3 +71,17 @@ extension UTMQemuConfigurationSharing {
}
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationSharing {
convenience init(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
if oldConfig.shareDirectoryEnabled {
directoryShareMode = .webdav
}
isDirectoryShareReadOnly = oldConfig.shareDirectoryReadOnly
hasClipboardSharing = oldConfig.shareClipboardEnabled
}
}

View File

@ -65,3 +65,18 @@ extension UTMQemuConfigurationSound {
}
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationSound {
convenience init?(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
guard oldConfig.soundEnabled else {
return nil
}
if let hardwareStr = oldConfig.soundCard {
hardware = AnyQEMUConstant(rawValue: hardwareStr)!
}
}
}

View File

@ -87,3 +87,52 @@ class UTMQemuConfigurationSystem: Codable, ObservableObject {
try container.encode(jitCacheSize, forKey: .jitCacheSize)
}
}
// MARK: - Conversion of old config format
@available(iOS 13, macOS 11, *)
extension UTMQemuConfigurationSystem {
convenience init(migrating oldConfig: UTMLegacyQemuConfiguration) {
self.init()
if let archStr = oldConfig.systemArchitecture, let arch = QEMUArchitecture(rawValue: archStr) {
architecture = arch
}
if let targetStr = oldConfig.systemTarget {
target = AnyQEMUConstant(rawValue: targetStr)!
}
if let cpuStr = oldConfig.systemCPU {
cpu = AnyQEMUConstant(rawValue: cpuStr)!
}
if let cpuCountNum = oldConfig.systemCPUCount {
cpuCount = cpuCountNum.intValue
}
if let oldFlags = oldConfig.systemCPUFlags {
for oldFlag in oldFlags {
var newFlag = oldFlag
let isAdd: Bool
if oldFlag.starts(with: "-") {
newFlag.removeFirst()
isAdd = false
} else if oldFlag.starts(with: "+") {
newFlag.removeFirst()
isAdd = true
} else {
isAdd = true
}
let flag = AnyQEMUConstant(rawValue: newFlag)!
if isAdd {
cpuFlagsAdd.append(flag)
} else {
cpuFlagsRemove.append(flag)
}
}
}
isForceMulticore = oldConfig.systemForceMulticore
if let memoryNum = oldConfig.systemMemory {
memorySize = memoryNum.intValue
}
if let jitCacheNum = oldConfig.systemJitCacheSize {
jitCacheSize = jitCacheNum.intValue
}
}
}