mirror of
https://github.com/cirruslabs/tart.git
synced 2026-10-06 14:11:16 +02:00
* feat: Add disk image format selection with ASIF support * fixed goreleaser-pro * Fix ASIF disk format compatibility issues - Use .uncached caching mode for ASIF disks to avoid Virtualization framework compatibility issues - Improve caching mode selection logic for better maintainability - Fix compiler warning by changing var to let for attachment variable This resolves VM startup failures when using ASIF disk format by ensuring proper disk attachment configuration. * Update goreleaser installation to use tap-specific formula Change from 'brew install --cask goreleaser-pro' to 'brew install --cask goreleaser/tap/goreleaser-pro' for proper installation from the official goreleaser tap. * Remove VS Code configuration and add to gitignore - Remove .vscode/launch.json from repository - Add .vscode/ to .gitignore to prevent VS Code settings from being tracked * Implement ASIF disk resize using diskutil - Add support for resizing ASIF disk images using diskutil image resize - Detect disk format from VM config and route to appropriate resize method - Use diskutil image info to get current ASIF disk size and validate resize - Remove restriction that prevented ASIF disk resizing in Set command - Add FailedToResizeDisk error case for proper error handling - Maintain backward compatibility with raw disk resizing - Add comprehensive size validation to prevent data loss * Update Sources/tart/Commands/Create.swift Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com> * Update Sources/tart/DiskImageFormat.swift Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com> * Update Sources/tart/DiskImageFormat.swift Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com> * Fix test naming and remove redundant test cases - Rename testFormatArgument to testCaseInsensitivity for clarity - Remove redundant 'raw' and 'invalid' test cases already covered in testFormatFromString - Remove testFormatDescriptions test as it's not very useful Addresses review comment: https://github.com/cirruslabs/tart/pull/1094#discussion_r2152093510 * Remove canCreate property and simplify DiskImageFormat - Remove canCreate property since it's the same as isSupported - Remove description property entirely as it's not used - Fix displayName for RAW format (remove UDIF reference) - Remove checkDiskutilASIFSupport helper function Addresses review comments: - https://github.com/cirruslabs/tart/pull/1094#discussion_r2152109450 - https://github.com/cirruslabs/tart/pull/1094#discussion_r2152115610 - https://github.com/cirruslabs/tart/pull/1094#discussion_r2152124330 * Update Create command validation and help text - Simplify ArgumentParser help text to let it show possible values automatically - Remove canCreate validation since property was removed - Simplify error message for unsupported disk formats Addresses review comment: https://github.com/cirruslabs/tart/pull/1094#discussion_r2152113480 * Add disk format validation to Run command - Add validation to ensure ASIF disk format is supported on current system - Check disk format compatibility before attempting to run VM Addresses review comment: https://github.com/cirruslabs/tart/pull/1094#discussion_r2152109450 * Use proper namespaced constant for OCI label - Add diskFormatLabelAnnotation constant in Manifest.swift - Use org.cirruslabs.tart.disk.format namespace for consistency - Use variable shadowing instead of new variable name for labels Addresses review comment: https://github.com/cirruslabs/tart/pull/1094#discussion_r2152163515 * Remove special ASIF caching mode - Remove .uncached caching mode for ASIF disks - Use default caching logic for all disk formats - Testing shows .cached mode works fine on macOS 26.0 Addresses review comment: https://github.com/cirruslabs/tart/pull/1094#discussion_r2152133589 * Improve code structure in VMDirectory - Use guard let instead of nested if let for better readability - Reduce nesting in resizeASIFDisk function - Improve error handling flow Addresses review comment: https://github.com/cirruslabs/tart/pull/1094#discussion_r2152141916 * diskFormatLabel * reverted caching mode * Use PropertyListDecoder --------- Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com>
83 lines
2.6 KiB
Swift
83 lines
2.6 KiB
Swift
import ArgumentParser
|
|
import Dispatch
|
|
import Foundation
|
|
import SwiftUI
|
|
import Virtualization
|
|
|
|
struct Create: AsyncParsableCommand {
|
|
static var configuration = CommandConfiguration(abstract: "Create a VM")
|
|
|
|
@Argument(help: "VM name")
|
|
var name: String
|
|
|
|
@Option(help: ArgumentHelp("create a macOS VM using path to the IPSW file or URL (or \"latest\", to fetch the latest supported IPSW automatically)", valueName: "path"), completion: .file())
|
|
var fromIPSW: String?
|
|
|
|
@Flag(help: "create a Linux VM")
|
|
var linux: Bool = false
|
|
|
|
@Option(help: ArgumentHelp("Disk size in GB"))
|
|
var diskSize: UInt16 = 50
|
|
|
|
@Option(help: ArgumentHelp("Disk image format", discussion: "ASIF format provides better performance but requires macOS 26 Tahoe or later"))
|
|
var diskFormat: DiskImageFormat = .raw
|
|
|
|
func validate() throws {
|
|
if fromIPSW == nil && !linux {
|
|
throw ValidationError("Please specify either a --from-ipsw or --linux option!")
|
|
}
|
|
#if arch(x86_64)
|
|
if fromIPSW != nil {
|
|
throw ValidationError("Only Linux VMs are supported on Intel!")
|
|
}
|
|
#endif
|
|
|
|
// Validate disk format support
|
|
if !diskFormat.isSupported {
|
|
throw ValidationError("Disk format '\(diskFormat.rawValue)' is not supported on this system.")
|
|
}
|
|
}
|
|
|
|
func run() async throws {
|
|
let tmpVMDir = try VMDirectory.temporary()
|
|
|
|
// Lock the temporary VM directory to prevent it's garbage collection
|
|
let tmpVMDirLock = try FileLock(lockURL: tmpVMDir.baseURL)
|
|
try tmpVMDirLock.lock()
|
|
|
|
try await withTaskCancellationHandler(operation: {
|
|
#if arch(arm64)
|
|
if let fromIPSW = fromIPSW {
|
|
let ipswURL: URL
|
|
|
|
if fromIPSW == "latest" {
|
|
defaultLogger.appendNewLine("Looking up the latest supported IPSW...")
|
|
|
|
let image = try await withCheckedThrowingContinuation { continuation in
|
|
VZMacOSRestoreImage.fetchLatestSupported() { result in
|
|
continuation.resume(with: result)
|
|
}
|
|
}
|
|
|
|
ipswURL = image.url
|
|
} else if fromIPSW.starts(with: "http://") || fromIPSW.starts(with: "https://") {
|
|
ipswURL = URL(string: fromIPSW)!
|
|
} else {
|
|
ipswURL = URL(fileURLWithPath: NSString(string: fromIPSW).expandingTildeInPath)
|
|
}
|
|
|
|
_ = try await VM(vmDir: tmpVMDir, ipswURL: ipswURL, diskSizeGB: diskSize, diskFormat: diskFormat)
|
|
}
|
|
#endif
|
|
|
|
if linux {
|
|
_ = try await VM.linux(vmDir: tmpVMDir, diskSizeGB: diskSize, diskFormat: diskFormat)
|
|
}
|
|
|
|
try VMStorageLocal().move(name, from: tmpVMDir)
|
|
}, onCancel: {
|
|
try? FileManager.default.removeItem(at: tmpVMDir.baseURL)
|
|
})
|
|
}
|
|
}
|