Files
SideStore/Shared/Errors/ProcessError.swift

89 lines
3.6 KiB
Swift
Raw Normal View History

//
// ProcessError.swift
// AltPackage
//
// Created by Riley Testut on 9/1/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import Foundation
extension ProcessError
{
enum Code: Int, ALTErrorCode
{
typealias Error = ProcessError
case failed
case timedOut
case unexpectedOutput
case terminated
}
static func failed(executableURL: URL, exitCode: Int32, output: String?, file: StaticString = #file, line: Int = #line) -> ProcessError {
ProcessError(code: .failed, executableURL: executableURL, exitCode: exitCode, output: output, sourceFile: file, sourceLine: UInt(line))
}
static func timedOut(executableURL: URL, exitCode: Int32? = nil, output: String? = nil, file: StaticString = #file, line: Int = #line) -> ProcessError {
ProcessError(code: .timedOut, executableURL: executableURL, exitCode: exitCode, output: output, sourceFile: file, sourceLine: UInt(line))
}
static func unexpectedOutput(executableURL: URL, output: String, exitCode: Int32? = nil, file: StaticString = #file, line: Int = #line) -> ProcessError {
ProcessError(code: .unexpectedOutput, executableURL: executableURL, exitCode: exitCode, output: output, sourceFile: file, sourceLine: UInt(line))
}
static func terminated(executableURL: URL, exitCode: Int32, output: String, file: StaticString = #file, line: Int = #line) -> ProcessError {
ProcessError(code: .terminated, executableURL: executableURL, exitCode: exitCode, output: output, sourceFile: file, sourceLine: UInt(line))
}
}
struct ProcessError: ALTLocalizedError
{
let code: Code
var errorTitle: String?
var errorFailure: String?
@UserInfoValue var executableURL: URL?
@UserInfoValue var exitCode: Int32?
@UserInfoValue var output: String?
var sourceFile: StaticString?
var sourceLine: UInt?
var errorFailureReason: String {
switch self.code
{
case .failed:
guard let exitCode else { return String(format: NSLocalizedString("%@ failed.", comment: ""), self.processName) }
let baseMessage = String(format: NSLocalizedString("%@ failed with code %@.", comment: ""), self.processName, NSNumber(value: exitCode))
guard let lastLine = self.lastOutputLine else { return baseMessage }
let failureReason = baseMessage + " " + lastLine
return failureReason
case .timedOut: return String(format: NSLocalizedString("%@ timed out.", comment: ""), self.processName)
case .terminated: return String(format: NSLocalizedString("%@ unexpectedly quit.", comment: ""), self.processName)
case .unexpectedOutput:
let baseMessage = String(format: NSLocalizedString("%@ returned unexpected output.", comment: ""), self.processName)
guard let lastLine = self.lastOutputLine else { return baseMessage }
let failureReason = baseMessage + " " + lastLine
return failureReason
}
}
private var processName: String {
guard let executableName = self.executableURL?.lastPathComponent else { return NSLocalizedString("The process", comment: "") }
return String(format: NSLocalizedString("The process '%@'", comment: ""), executableName)
}
private var lastOutputLine: String? {
guard let output else { return nil }
let lastLine = output.components(separatedBy: .newlines).last(where: { !$0.isEmpty })
return lastLine
}
}