8000 macOS: Add shared directory mount tag customization by tmc · Pull Request #7051 · utmapp/UTM · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

macOS: Add shared directory mount tag customization #7051

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Configuration/UTMAppleConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ final class UTMAppleConfiguration: UTMConfiguration {
@Published private var _networks: [UTMAppleConfigurationNetwork] = [.init()]

@Published private var _serials: [UTMAppleConfigurationSerial] = []

/// Custom mount tag for shared directories
@Published private var _sharedDirectoryMountTag: String?

/// Set to true to request guest tools install. Not saved.
@Published var isGuestToolsInstallRequested: Bool = false
Expand All @@ -55,6 +58,7 @@ final class UTMAppleConfiguration: UTMConfiguration {
case serials = "Serial"
case backend = "Backend"
case configurationVersion = "ConfigurationVersion"
case sharedDirectoryMountTag = "SharedDirectoryMountTag"
}

init() {
Expand All @@ -81,6 +85,7 @@ final class UTMAppleConfiguration: UTMConfiguration {
_drives = try values.decode([UTMAppleConfigurationDrive].self, forKey: .drives)
_networks = try values.decode([UTMAppleConfigurationNetwork].self, forKey: .networks)
_serials = try values.decode([UTMAppleConfigurationSerial].self, forKey: .serials)
_sharedDirectoryMountTag = try values.decodeIfPresent(String.self, forKey: .sharedDirectoryMountTag)
}

func encode(to encoder: Encoder) throws {
Expand All @@ -94,6 +99,7 @@ final class UTMAppleConfiguration: UTMConfiguration {
try container.encode(_serials, forKey: .serials)
try container.encode(UTMBackend.apple, forKey: .backend)
try container.encode(Self.currentVersion, forKey: .configurationVersion)
try container.encodeIfPresent(_sharedDirectoryMountTag, forKey: .sharedDirectoryMountTag)
}
}

Expand Down Expand Up @@ -311,12 +317,32 @@ extension UTMAppleConfiguration {
}

var shareDirectoryTag: String {
if let customTag = _sharedDirectoryMountTag, !customTag.isEmpty {
return customTag
}
if #available(macOS 13, *), system.boot.operatingSystem == .macOS {
return VZVirtioFileSystemDeviceConfiguration.macOSGuestAutomountTag
} else {
return "share"
}
}

/// Get or set the custom mount tag for shared directories.
/// Only applies when the guest OS is macOS and the host is running macOS 13 or later.
var sharedDirectoryMountTag: String? {
get {
if #available(macOS 13, *), system.boot.operatingSystem == .macOS {
return _sharedDirectoryMountTag
}
return nil
}
set {
if #available(macOS 13, *), system.boot.operatingSystem == .macOS {
let trimmed = newValue?.trimmingCharacters(in: .whitespacesAndNewlines)
_sharedDirectoryMountTag = trimmed?.isEmpty == true ? nil : trimmed
}
}
}
}

// MARK: - Saving data
Expand Down
114 changes: 79 additions & 35 deletions Platform/macOS/VMConfigAppleSharingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,56 +23,100 @@ struct VMConfigAppleSharingView: View {
@State private var selectedID: UUID?
@State private var isImporterPresented: Bool = false
@State private var isAddReadOnly: Bool = false

@State private var mountTag: String = ""

var body: some View {

Form {
if config.system.boot.operatingSystem == .macOS {
Text("Shared directories in macOS VMs are only available in macOS 13 and later.")
}
Table(config.sharedDirectories, selection: $selectedID) {
TableColumn("Shared Path") { share in
Text(share.directoryURL?.path ?? "")
}
TableColumn("Read Only?") { share in
Toggle("", isOn: .constant(share.isReadOnly))
.disabled(true)
}
}.frame(minHeight: 300)
HStack {
Spacer()
Button("Delete") {
config.sharedDirectories.removeAll { share in
share.id == selectedID
VStack(alignment: .leading, spacing: 16.0) {
if #available(macOS 13.0, *) {
// Information text
VStack(alignment: .leading, spacing: 8) {
Text("Shared directories in macOS VMs are only available in macOS 13 and later.")
.padding(.top, 4)
LabeledContent("(Advanced) Custom mount tag") {
TextField("", text: $mountTag)
.textFieldStyle(.roundedBorder)
.frame(width: 300)
.onChange(of: mountTag) { newValue in
config.sharedDirectoryMountTag = newValue.isEmpty ? nil : newValue
}
}
.help("The name that shared directories will use when mounted in the guest. Useful when applications have issues with spaces in paths.")
.onAppear {
mountTag = config.sharedDirectoryMountTag ?? ""
}
Text("note: This disable automatic mounting. You must use `mountfs_virtio tag path` in the guset.")
.font(.caption)
.foregroundColor(.secondary)

Text("e.g. $ mkdir ~/shared; mountfs_virtio \(mountTag.isEmpty ? "tag" : mountTag) ~/shared")
.font(.caption)
.foregroundColor(.secondary)
}
}.disabled(selectedID == nil)
Button("Add") {
isImporterPresented.toggle()
}
}.fileImporter(isPresented: $isImporterPresented, allowedContentTypes: [.folder]) { result in
data.busyWorkAsync {
let url = try result.get()
if await config.sharedDirectories.contains(where: { existing in
url == existing.directoryURL
}) {
throw NSLocalizedString("This directory is already being shared.", comment: "VMConfigAppleSharingView")
// Table section
VStack(alignment: .leading, spacing: 9.0) {
Table(config.sharedDirectories, selection: $selectedID) {
TableColumn("Shared Path") { share in
Text(share.directoryURL?.path ?? "")
}
TableColumn("Read Only?") { share in
Toggle("", isOn: .constant(share.isReadOnly))
.disabled(true)
.labelsHidden()
}
}
await MainActor.run {
config.sharedDirectories.append(UTMAppleConfigurationSharedDirectory(directoryURL: url, isReadOnly: isAddReadOnly))
.frame(minHeight: 200)
// Buttons
HStack {
Spacer()
Button("Delete") {
config.sharedDirectories.removeAll { share in
share.id == selectedID
}
}
.disabled(selectedID == nil)
.buttonStyle(.bordered)

Button("Add") {
isImporterPresented.toggle()
}
.buttonStyle(.bordered)
}
.fileImporter(
isPresented: $isImporterPresented,
allowedContentTypes: [.folder]
) { result in
data.busyWorkAsync {
let url = try result.get()
if await config.sharedDirectories.contains(where: { existing in
url == existing.directoryURL
}) {
throw NSLocalizedString("This directory is already being shared.", comment: "VMConfigAppleSharingView")
}
await MainActor.run {
config.sharedDirectories.append(UTMAppleConfigurationSharedDirectory(directoryURL: url, isReadOnly: isAddReadOnly))
}
}
}
// Read only toggle
HStack {
Spacer()
Toggle("Add read only", isOn: $isAddReadOnly)
}
}
}
HStack {
Spacer()
Toggle("Add read only", isOn: $isAddReadOnly)
}
.padding([.horizontal, .bottom], 9.0)
}
}

}

@available(macOS 12, *)
struct VMConfigAppleSharingView_Previews: PreviewProvider {
@State static private var config = UTMAppleConfiguration()

static var previews: some View {
VMConfigAppleSharingView(config: config)
}
Expand Down
0