mirror of
https://github.com/utmapp/UTM.git
synced 2026-10-12 02:24:01 +00:00
Merge pull request #6977 from naveenrajm7/script-sandbox-path
scripting : add vm registry suite
This commit is contained in:
@@ -564,6 +564,10 @@
|
||||
<record-type name="qemu argument" code="QeAr" description="QEMU argument configuration.">
|
||||
<property name="argument string" code="ArSt" type="text"
|
||||
description="The QEMU argument as a string."/>
|
||||
<property name="file urls" code="FlUr"
|
||||
description="Optional URLs associated with this argument.">
|
||||
<type type="file" list="yes"/>
|
||||
</property>
|
||||
</record-type>
|
||||
|
||||
<record-type name="apple configuration" code="ApCf" description="Apple virtual machine configuration.">
|
||||
@@ -714,4 +718,27 @@
|
||||
<direct-parameter description="The USB device to disconnect." type="usb device"/>
|
||||
</command>
|
||||
</suite>
|
||||
|
||||
<suite name="UTM Registry Suite" code="UTMr" description="UTM virtual machine registry suite. Use this to update virtual machine registry.">
|
||||
<access-group identifier="com.utmapp.UTM.vm-access" />
|
||||
|
||||
<class-extension extends="virtual machine" description="Virtual machine registry.">
|
||||
<property name="registry" code="ReGs" access="r"
|
||||
description="The registry of the virtual machine.">
|
||||
<type type="file" list="yes"/>
|
||||
</property>
|
||||
|
||||
<responds-to command="update registry">
|
||||
<cocoa method="updateRegistry:"/>
|
||||
</responds-to>
|
||||
</class-extension>
|
||||
|
||||
<command name="update registry" code="UTMrUpDt" description="Update the registry of the virtual machine.">
|
||||
<direct-parameter description="Virtual machine to update." type="virtual machine"/>
|
||||
<parameter name="with" code="UpRg" description="The registry to update the virtual machine. Currently you can only change the shared directory with this!">
|
||||
<cocoa key="newRegistry"/>
|
||||
<type type="file" list="yes"/>
|
||||
</parameter>
|
||||
</command>
|
||||
</suite>
|
||||
</dictionary>
|
||||
|
||||
@@ -194,6 +194,10 @@ extension UTMScriptingConfigImpl {
|
||||
var serializedArgument: [AnyHashable: Any] = [
|
||||
"argumentString": argument.string
|
||||
]
|
||||
// Only add fileUrls if it is not nil and contains URLs
|
||||
if let fileUrls = argument.fileUrls, !fileUrls.isEmpty {
|
||||
serializedArgument["fileUrls"] = fileUrls.map({ $0 as AnyHashable })
|
||||
}
|
||||
|
||||
return serializedArgument
|
||||
}
|
||||
@@ -526,7 +530,10 @@ extension UTMScriptingConfigImpl {
|
||||
let additionalArguments = records.compactMap { record -> QEMUArgument? in
|
||||
guard let argumentString = record["argumentString"] as? String else { return nil }
|
||||
var argument = QEMUArgument(argumentString)
|
||||
|
||||
// fileUrls are used as required resources by QEMU.
|
||||
if let fileUrls = record["fileUrls"] as? [URL] {
|
||||
argument.fileUrls = fileUrls
|
||||
}
|
||||
return argument
|
||||
}
|
||||
// Update entire additional arguments with new one.
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// Copyright © 2025 naveenrajm7. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc extension UTMScriptingVirtualMachineImpl {
|
||||
@objc var registry: [URL] {
|
||||
let wrapper = UTMScriptingRegistryEntryImpl(vm.registryEntry)
|
||||
return wrapper.serializeRegistry()
|
||||
}
|
||||
|
||||
@objc func updateRegistry(_ command: NSScriptCommand) {
|
||||
let newRegistry = command.evaluatedArguments?["newRegistry"] as? [URL]
|
||||
withScriptCommand(command) { [self] in
|
||||
guard let newRegistry = newRegistry else {
|
||||
throw ScriptingError.invalidParameter
|
||||
}
|
||||
let wrapper = UTMScriptingRegistryEntryImpl(vm.registryEntry)
|
||||
try await wrapper.updateRegistry(from: newRegistry, qemuProcess)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
class UTMScriptingRegistryEntryImpl {
|
||||
private(set) var registry: UTMRegistryEntry
|
||||
|
||||
init(_ registry: UTMRegistryEntry) {
|
||||
self.registry = registry
|
||||
}
|
||||
|
||||
func serializeRegistry() -> [URL] {
|
||||
return registry.sharedDirectories.compactMap { $0.url }
|
||||
}
|
||||
|
||||
func updateRegistry(from fileUrls: [URL], _ system: UTMQemuSystem?) async throws {
|
||||
// Clear all shared directories, we add all directories here
|
||||
registry.removeAllSharedDirectories()
|
||||
|
||||
// Add urls to the registry
|
||||
for url in fileUrls {
|
||||
// Start scoped access
|
||||
let isScopedAccess = url.startAccessingSecurityScopedResource()
|
||||
defer {
|
||||
if isScopedAccess {
|
||||
url.stopAccessingSecurityScopedResource()
|
||||
}
|
||||
}
|
||||
|
||||
// Get bookmark from UTM process
|
||||
let standardBookmark = try url.bookmarkData()
|
||||
let system = system ?? UTMProcess()
|
||||
let (success, bookmark, path) = await system.accessData(withBookmark: standardBookmark, securityScoped: false)
|
||||
guard let bookmark = bookmark, let _ = path, success else {
|
||||
throw UTMQemuVirtualMachineError.accessDriveImageFailed
|
||||
}
|
||||
|
||||
// Store bookmark in registry
|
||||
let file = UTMRegistryEntry.File(dummyFromPath: url.path, remoteBookmark: bookmark)
|
||||
registry.appendSharedDirectory(file)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -90,6 +90,12 @@ class UTMScriptingVirtualMachineImpl: NSObject, UTMScriptable {
|
||||
}
|
||||
}
|
||||
|
||||
var qemuProcess: UTMQemuSystem? {
|
||||
get async {
|
||||
await (vm as? UTMQemuVirtualMachine)?.system
|
||||
}
|
||||
}
|
||||
|
||||
override var objectSpecifier: NSScriptObjectSpecifier? {
|
||||
let appDescription = NSApplication.classDescription() as! NSScriptClassDescription
|
||||
return NSUniqueIDSpecifier(containerClassDescription: appDescription,
|
||||
|
||||
Reference in New Issue
Block a user