Nucleic: Gitea Runner macOS VM Support
This commit is contained in:
@@ -155,12 +155,10 @@ public struct IPSWProvider: Sendable {
|
||||
// not a Swift error — when handed a non-file or missing path, and an
|
||||
// ObjC exception cannot be caught here. So the existence check is not
|
||||
// politeness; it is the only thing standing between a typo and a crash.
|
||||
var isDirectory: ObjCBool = false
|
||||
guard FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory),
|
||||
!isDirectory.boolValue
|
||||
else {
|
||||
throw CoreError.notFound("restore image not found at \(url.path)")
|
||||
}
|
||||
// The size and magic-byte checks alongside it cover the other way this
|
||||
// call goes wrong: handed a partial download it neither fails nor
|
||||
// reports progress, it simply stops responding.
|
||||
try IPSWFile.validate(path: url.path)
|
||||
|
||||
do {
|
||||
return try await VZMacOSRestoreImage.image(from: url)
|
||||
|
||||
@@ -6,10 +6,16 @@ import Virtualization
|
||||
public enum ImageBuildStage: Sendable, Equatable {
|
||||
/// Downloading the IPSW.
|
||||
case downloadingIPSW(fraction: Double)
|
||||
/// Reading the restore image and deriving a hardware configuration.
|
||||
/// Working out which file the operator meant and whether it is usable.
|
||||
case preparing
|
||||
/// Inside `VZMacOSRestoreImage.image(from:)`, which reports no progress of
|
||||
/// its own and is the longest silent stretch of a local-IPSW build.
|
||||
case loadingRestoreImage
|
||||
/// Creating the disk, NVRAM, and bundle metadata.
|
||||
case creatingBundle
|
||||
case creatingBundle(diskGB: Int)
|
||||
/// An out-of-band remark about the stage in flight — printed on its own
|
||||
/// line rather than replacing the status line.
|
||||
case note(String)
|
||||
/// `VZMacOSInstaller` is writing macOS onto the disk.
|
||||
case installing(fraction: Double)
|
||||
/// First boot; waiting for Setup Assistant, a DHCP lease, and SSH.
|
||||
@@ -89,7 +95,28 @@ public struct ImageBuilder: Sendable {
|
||||
let provider = IPSWProvider(downloadDirectory: store.ipswDir)
|
||||
let restoreImage: VZMacOSRestoreImage
|
||||
if let ipswPath {
|
||||
progress?(.downloadingIPSW(fraction: 1.0))
|
||||
progress?(.preparing)
|
||||
progress?(.loadingRestoreImage)
|
||||
|
||||
// Reading a 21 GB archive's metadata takes a while and the
|
||||
// framework says nothing while it does. A build that looks frozen
|
||||
// is the single most-reported symptom of this command, so say out
|
||||
// loud what the other likely explanation is rather than letting the
|
||||
// operator guess.
|
||||
let watchdog = Task {
|
||||
try? await Task.sleep(for: .seconds(60))
|
||||
// Cancelling is how a *fast* load ends this task, and a
|
||||
// cancelled sleep returns rather than throwing past `try?` — so
|
||||
// without this the note prints on every quick failure, which is
|
||||
// precisely when it is misleading.
|
||||
guard !Task.isCancelled else { return }
|
||||
progress?(
|
||||
.note(
|
||||
"still loading — a truncated or partially downloaded .ipsw can block here; "
|
||||
+ "verify the download completed"))
|
||||
}
|
||||
defer { watchdog.cancel() }
|
||||
|
||||
restoreImage = try await provider.load(localPath: ipswPath)
|
||||
} else {
|
||||
progress?(.downloadingIPSW(fraction: 0))
|
||||
@@ -100,8 +127,7 @@ public struct ImageBuilder: Sendable {
|
||||
}
|
||||
|
||||
// 2/3. Hardware model and bundle.
|
||||
progress?(.preparing)
|
||||
progress?(.creatingBundle)
|
||||
progress?(.creatingBundle(diskGB: config.guest.diskGB))
|
||||
let bundle = try await createBundle(name: name, restoreImage: restoreImage, config: config)
|
||||
|
||||
// 4. Install.
|
||||
|
||||
Reference in New Issue
Block a user