mirror of https://github.com/cirruslabs/tart.git
Use separate exception codes for better Sentry grouping (#363)
This commit is contained in:
parent
9cdb7087f2
commit
1380ece108
|
|
@ -19,7 +19,7 @@ struct IP: AsyncParsableCommand {
|
|||
let vmMACAddress = MACAddress(fromString: vmConfig.macAddress.string)!
|
||||
|
||||
guard let ipViaDHCP = try await IP.resolveIP(vmMACAddress, secondsToWait: wait) else {
|
||||
throw RuntimeError("no IP address found, is your VM running?")
|
||||
throw RuntimeError.NoIPAddressFound("no IP address found, is your VM running?")
|
||||
}
|
||||
|
||||
let arpCache = try ARPCache()
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ struct Login: AsyncParsableCommand {
|
|||
credentialsProviders: [credentialsProvider])
|
||||
try await registry.ping()
|
||||
} catch {
|
||||
throw RuntimeError("invalid credentials: \(error)")
|
||||
throw RuntimeError.InvalidCredentials("invalid credentials: \(error)")
|
||||
}
|
||||
|
||||
try KeychainCredentialsProvider().store(host: host, user: user, password: password)
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ struct Run: AsyncParsableCommand {
|
|||
}
|
||||
|
||||
if try !FileLock(lockURL: additionalDiskAttachment.url).trylock() {
|
||||
throw RuntimeError("disk \(additionalDiskAttachment.url.path) seems to be already in use, "
|
||||
throw RuntimeError.DiskAlreadyInUse("disk \(additionalDiskAttachment.url.path) seems to be already in use, "
|
||||
+ "unmount it first in Finder")
|
||||
}
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@ struct Run: AsyncParsableCommand {
|
|||
// [1]: https://man.openbsd.org/fcntl
|
||||
let lock = try PIDLock(lockURL: vmDir.configURL)
|
||||
if try !lock.trylock() {
|
||||
throw RuntimeError("Virtual machine \"\(name)\" is already running!", exitCode: 2)
|
||||
throw RuntimeError.VMAlreadyRunning("VM \"\(name)\" is already running!")
|
||||
}
|
||||
|
||||
let task = Task {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ struct Stop: AsyncParsableCommand {
|
|||
// Find the VM's PID
|
||||
var pid = try lock.pid()
|
||||
if pid == 0 {
|
||||
throw RuntimeError("VM \(name) is not running", exitCode: 2)
|
||||
throw RuntimeError.VMNotRunning("VM \"\(name)\" is not running")
|
||||
}
|
||||
|
||||
// Try to gracefully terminate the VM
|
||||
|
|
@ -54,7 +54,7 @@ struct Stop: AsyncParsableCommand {
|
|||
if ret != 0 {
|
||||
let details = Errno(rawValue: CInt(errno))
|
||||
|
||||
throw RuntimeError("failed to forcefully terminate the VM \(name): \(details)")
|
||||
throw RuntimeError.VMTerminationFailed("failed to forcefully terminate the VM \"\(name)\": \(details)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ struct RemoteName: Comparable, Hashable, CustomStringConvertible {
|
|||
try ParseTreeWalker().walk(referenceCollector, try parser.root())
|
||||
|
||||
if let error = errorCollector.error {
|
||||
throw RuntimeError("failed to parse remote name: \(error)")
|
||||
throw RuntimeError.FailedToParseRemoteName("\(error)")
|
||||
}
|
||||
|
||||
host = referenceCollector.host!
|
||||
|
|
@ -120,7 +120,7 @@ struct RemoteName: Comparable, Hashable, CustomStringConvertible {
|
|||
} else if reference.starts(with: ":") {
|
||||
self.reference = Reference(tag: String(reference.dropFirst(1)))
|
||||
} else {
|
||||
throw RuntimeError("failed to parse remote name: unknown reference format")
|
||||
throw RuntimeError.FailedToParseRemoteName("unknown reference format")
|
||||
}
|
||||
} else {
|
||||
self.reference = Reference(tag: "latest")
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class PIDLock {
|
|||
|
||||
let details = Errno(rawValue: CInt(errno))
|
||||
|
||||
throw RuntimeError("\(message): \(details)")
|
||||
throw RuntimeError.PIDLockFailed("\(message): \(details)")
|
||||
}
|
||||
|
||||
return (true, result)
|
||||
|
|
|
|||
|
|
@ -106,8 +106,8 @@ struct Root: AsyncParsableCommand {
|
|||
|
||||
print(error)
|
||||
|
||||
if let runtimeError = error as? RuntimeError {
|
||||
Foundation.exit(runtimeError.exitCode)
|
||||
if let errorWithExitCode = error as? HasExitCode {
|
||||
Foundation.exit(errorWithExitCode.exitCode)
|
||||
}
|
||||
|
||||
Foundation.exit(1)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ extension URL {
|
|||
let times = [accessDate.asTimeval(), modificationDate.asTimeval()]
|
||||
let ret = utimes(path, times)
|
||||
if ret != 0 {
|
||||
throw RuntimeError("utimes(2) failed: \(ret.explanation())")
|
||||
throw RuntimeError.FailedToUpdateAccessDate("utimes(2) failed: \(ret.explanation())")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ struct VMDirectory: Prunable {
|
|||
|
||||
func initialize(overwrite: Bool = false) throws {
|
||||
if !overwrite && initialized {
|
||||
throw RuntimeError("VM directory is already initialized, preventing overwrite")
|
||||
throw RuntimeError.VMDirectoryAlreadyInitialized("VM directory is already initialized, preventing overwrite")
|
||||
}
|
||||
|
||||
try FileManager.default.createDirectory(at: baseURL, withIntermediateDirectories: true, attributes: nil)
|
||||
|
|
@ -53,11 +53,11 @@ struct VMDirectory: Prunable {
|
|||
|
||||
func validate() throws {
|
||||
if !FileManager.default.fileExists(atPath: baseURL.path) {
|
||||
throw RuntimeError("the specified VM does not exist")
|
||||
throw RuntimeError.VMDoesNotExist(name: baseURL.lastPathComponent)
|
||||
}
|
||||
|
||||
if !initialized {
|
||||
throw RuntimeError("VM is missing some of its files (\(configURL.lastPathComponent),"
|
||||
throw RuntimeError.VMMissingFiles("VM is missing some of its files (\(configURL.lastPathComponent),"
|
||||
+ " \(diskURL.lastPathComponent) or \(nvramURL.lastPathComponent))")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class VMStorageHelper {
|
|||
return try closure()
|
||||
} catch {
|
||||
if error.isFileNotFound() {
|
||||
throw RuntimeError("source VM \"\(name)\" not found, is it listed in \"tart list\"?")
|
||||
throw RuntimeError.VMDoesNotExist(name: name)
|
||||
}
|
||||
|
||||
throw error
|
||||
|
|
@ -40,17 +40,66 @@ extension Error {
|
|||
}
|
||||
}
|
||||
|
||||
class RuntimeError: Error, CustomStringConvertible {
|
||||
let message: String
|
||||
let exitCode: Int32
|
||||
enum RuntimeError : Error {
|
||||
case VMDoesNotExist(name: String)
|
||||
case VMMissingFiles(_ message: String)
|
||||
case VMNotRunning(_ message: String)
|
||||
case VMAlreadyRunning(_ message: String)
|
||||
case NoIPAddressFound(_ message: String)
|
||||
case DiskAlreadyInUse(_ message: String)
|
||||
case FailedToUpdateAccessDate(_ message: String)
|
||||
case PIDLockFailed(_ message: String)
|
||||
case FailedToParseRemoteName(_ message: String)
|
||||
case VMTerminationFailed(_ message: String)
|
||||
case InvalidCredentials(_ message: String)
|
||||
case VMDirectoryAlreadyInitialized(_ message: String)
|
||||
}
|
||||
|
||||
init(_ message: String, exitCode: Int32 = 1) {
|
||||
self.message = message
|
||||
self.exitCode = exitCode
|
||||
protocol HasExitCode {
|
||||
var exitCode: Int32 { get }
|
||||
}
|
||||
|
||||
extension RuntimeError : CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .VMDoesNotExist(let name):
|
||||
return "the specified VM \"\(name)\" does not exist"
|
||||
case .VMMissingFiles(let message):
|
||||
return message
|
||||
case .VMNotRunning(let message):
|
||||
return message
|
||||
case .VMAlreadyRunning(let message):
|
||||
return message
|
||||
case .NoIPAddressFound(let message):
|
||||
return message
|
||||
case .DiskAlreadyInUse(let message):
|
||||
return message
|
||||
case .FailedToUpdateAccessDate(let message):
|
||||
return message
|
||||
case .PIDLockFailed(let message):
|
||||
return message
|
||||
case .FailedToParseRemoteName(let cause):
|
||||
return "failed to parse remote name: \(cause)"
|
||||
case .VMTerminationFailed(let message):
|
||||
return message
|
||||
case .InvalidCredentials(let message):
|
||||
return message
|
||||
case .VMDirectoryAlreadyInitialized(let message):
|
||||
return message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
message
|
||||
extension RuntimeError : HasExitCode {
|
||||
var exitCode: Int32 {
|
||||
switch self {
|
||||
case .VMNotRunning:
|
||||
return 2
|
||||
case .VMAlreadyRunning:
|
||||
return 2
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +109,7 @@ class RuntimeError: Error, CustomStringConvertible {
|
|||
extension RuntimeError : CustomNSError {
|
||||
var errorUserInfo: [String : Any] {
|
||||
[
|
||||
NSDebugDescriptionErrorKey: message,
|
||||
NSDebugDescriptionErrorKey: description,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue