Skip to content
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

Change snapshot name #375

Merged
merged 1 commit into from
Jul 29, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public extension VBVirtualMachine {
}

/// Convenience for ``VMLibraryController/createSavedStatePackage(for:)``.
func createSavedStatePackage(in library: VMLibraryController) throws -> VBSavedStatePackage {
try library.createSavedStatePackage(for: self)
func createSavedStatePackage(in library: VMLibraryController, snapshotName name: String) throws -> VBSavedStatePackage {
try library.createSavedStatePackage(for: self, snapshotName: name)
}
}
14 changes: 2 additions & 12 deletions VirtualCore/Source/Models/SavedState/VBSavedStatePackage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ public final class VBSavedStatePackage: Identifiable, Hashable, Codable {
}

/// Creates a new package on disk for the given virtual machine, initializing the saved state package accordingly.
public convenience init(creatingPackageInDirectoryAt baseURL: URL, model: VBVirtualMachine) throws {
let suffix = DateFormatter.savedStateFileName.string(from: .now)
let url = baseURL.appendingPathComponent("Save-\(suffix)", conformingTo: .virtualBuddySavedState)
public convenience init(creatingPackageInDirectoryAt baseURL: URL, model: VBVirtualMachine, snapshotName: String) throws {
let url = baseURL.appendingPathComponent(snapshotName, conformingTo: .virtualBuddySavedState)
let createdURL = try url.creatingDirectoryIfNeeded()

try self.init(url: createdURL, metadata: VBSavedStateMetadata(model: model))
Expand Down Expand Up @@ -122,15 +121,6 @@ public final class VBSavedStatePackage: Identifiable, Hashable, Codable {
public static func ==(lhs: VBSavedStatePackage, rhs: VBSavedStatePackage) -> Bool { lhs.metadata == rhs.metadata }
}

private extension DateFormatter {
static let savedStateFileName: DateFormatter = {
let f = DateFormatter()
f.calendar = .init(identifier: .gregorian)
f.dateFormat = "yyyy-MM-dd_HH;mm;ss"
return f
}()
}

// MARK: - Validation

extension VBSavedStatePackage {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public extension VMLibraryController {
.creatingDirectoryIfNeeded()
}

func createSavedStatePackage(for model: VBVirtualMachine) throws -> VBSavedStatePackage {
func createSavedStatePackage(for model: VBVirtualMachine, snapshotName name: String) throws -> VBSavedStatePackage {
let baseURL = try model.savedStatesDirectoryURLCreatingIfNeeded(in: self)

return try VBSavedStatePackage(creatingPackageInDirectoryAt: baseURL, model: model)
return try VBSavedStatePackage(creatingPackageInDirectoryAt: baseURL, model: model, snapshotName: name)
}

func virtualMachine(with uuid: UUID) throws -> VBVirtualMachine {
Expand Down
4 changes: 2 additions & 2 deletions VirtualCore/Source/Virtualization/VMController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,14 @@ public final class VMController: ObservableObject {
}

@available(macOS 14.0, *)
public func saveState() async throws {
public func saveState(snapshotName name: String) async throws {
try await updatingState {
let instance = try ensureInstance()
let vm = try instance.virtualMachine

state = .savingState(vm)

let package = try await instance.saveState()
let package = try await instance.saveState(snapshotName: name)

state = .stateSaveCompleted(vm, package)

Expand Down
4 changes: 2 additions & 2 deletions VirtualCore/Source/Virtualization/VMInstance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ public final class VMInstance: NSObject, ObservableObject {

@available(macOS 14.0, *)
@discardableResult
func saveState() async throws -> VBSavedStatePackage {
func saveState(snapshotName name: String) async throws -> VBSavedStatePackage {
logger.debug(#function)

let vm = try ensureVM()
Expand All @@ -312,7 +312,7 @@ public final class VMInstance: NSObject, ObservableObject {

logger.debug("VM paused, requesting state save")

let package = try virtualMachineModel.createSavedStatePackage(in: library)
let package = try virtualMachineModel.createSavedStatePackage(in: library, snapshotName: name)

logger.debug("VM state package will be written to \(package.url.path)")

Expand Down
80 changes: 62 additions & 18 deletions VirtualUI/Source/Session/Components/VirtualMachineControls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protocol VirtualMachineStateController: ObservableObject {
func resume() async throws

@available(macOS 14.0, *)
func saveState() async throws
func saveState(snapshotName: String) async throws

var virtualMachineModel: VBVirtualMachine { get }
}
Expand All @@ -29,7 +29,9 @@ struct VirtualMachineControls<Controller: VirtualMachineStateController>: View {
@EnvironmentObject private var controller: Controller

@State private var actionTask: Task<Void, Never>?

@State private var isPopoverPresented = false
@State private var textFieldContent = ""

var body: some View {
Group {
switch controller.state {
Expand All @@ -50,31 +52,63 @@ struct VirtualMachineControls<Controller: VirtualMachineStateController>: View {
if #available(macOS 14.0, *), controller.virtualMachineModel.supportsStateRestoration {
Button {
runToolbarAction {
try await controller.saveState()
textFieldContent = "Save-" + DateFormatter.savedStateFileName.string(from: .now)
isPopoverPresented = true
}
} label: {
Image(systemName: "tray.and.arrow.down")
}
.help("Save current state")
}
.popover(isPresented: $isPopoverPresented) {
VStack {
Text("Save current state")
.font(.headline)
TextField("Name current state", text: $textFieldContent)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.top, 15)
.padding(.bottom, 15)

HStack {
Spacer()

Button("Cancel") {
isPopoverPresented = false
}
.padding(.trailing, 8)
.keyboardShortcut(.cancelAction)

Button("Save") {
isPopoverPresented = false

Task {
try await controller.saveState(snapshotName: textFieldContent)
}
}
.keyboardShortcut(.defaultAction)
}
}
.frame(width: 300)
.padding()
}

Button {
runToolbarAction {
try await controller.pause()
Button {
runToolbarAction {
try await controller.pause()
}
} label: {
Image(systemName: "pause")
}
} label: {
Image(systemName: "pause")
}
.help("Pause")
.help("Pause")

Button {
runToolbarAction {
try await controller.stop()
Button {
runToolbarAction {
try await controller.stop()
}
} label: {
Image(systemName: "power")
}
} label: {
Image(systemName: "power")
.help("Shut down")
}
.help("Shut down")
}
}
.symbolVariant(.fill)
Expand All @@ -96,6 +130,16 @@ struct VirtualMachineControls<Controller: VirtualMachineStateController>: View {
}
}

private extension DateFormatter {
static let savedStateFileName: DateFormatter = {
let f = DateFormatter()
f.calendar = .init(identifier: .gregorian)
f.dateFormat = "yyyy-MM-dd_HH;mm;ss"
return f
}()
}


#if DEBUG
private final class PreviewVirtualMachineStateController: VirtualMachineStateController {
@MainActor
Expand Down Expand Up @@ -131,7 +175,7 @@ private final class PreviewVirtualMachineStateController: VirtualMachineStateCon

@available(macOS 14.0, *)
@MainActor
func saveState() async throws {
func saveState(snapshotName: String) async throws {
state = .paused(.preview)
}

Expand Down