Skip to content

Commit

Permalink
Update error output formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanbaird committed Sep 14, 2023
1 parent 2d9acfa commit cc2c669
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 15 deletions.
11 changes: 10 additions & 1 deletion Sources/Backend/FileManagement/FileVerifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ struct FileVerifier {
case isNotDirectory(String)
case invalidPathExtension(String, FileType?)

var message: FormattedText {
var errorMessage: FormattedText {
switch self {
case .alreadyExists(let path):
return "'\(path, color: .yellow)' already exists"
Expand All @@ -89,6 +89,15 @@ struct FileVerifier {
return start + " for unknown output type"
}
}

var fix: FormattedText? {
if case .invalidPathExtension(_, let outputType) = self {
if let type = outputType?.preferredFilenameExtension {
return "Use path extension '\(type, color: .green, style: .bold)'"
}
}
return nil
}
}

/// The options that specify the verifications to perform.
Expand Down
2 changes: 1 addition & 1 deletion Sources/Backend/ImageProcessing/Iconset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ extension Iconset {
private enum IconValidationError: String, FormattedError {
case invalidDimensions = "Image width and height must be equal."

var message: FormattedText {
var errorMessage: FormattedText {
"\("Invalid icon", color: .red)\(rawValue, style: .bold)"
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Backend/ImageProcessing/ProcessingError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ enum ImageProcessingError: String, FormattedError {
case pdfDocumentError = "Error with PDF document."
case svgCreationError = "Error creating image data from SVG."

var message: FormattedText {
var errorMessage: FormattedText {
"\("Could not process image", color: .red)\(rawValue, style: .bold)"
}
}
29 changes: 25 additions & 4 deletions Sources/Backend/Runners/MainRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// createicns
//

import Darwin

/// The main runner that encapsulates the behavior of the command, delegating
/// parts of its execution to additional sub-runners.
public struct MainRunner: Runner {
Expand Down Expand Up @@ -40,10 +42,29 @@ public struct MainRunner: Runner {
}
}

public func run() throws {
try validate()
for runner in runners {
try runner.run()
public func run() {
do {
try validate()
for runner in runners {
try runner.run()
}
} catch {
exit(with: error)
}
}

func exit(with error: Error) -> Never {
let box = FormattedErrorBox(error: error)
let errorText = FormattedText("error:", color: .red, style: .bold)
.appending(" ")
.appending(box.errorMessage)
print(errorText)
if let fix = box.fix {
let fixText = FormattedText("fix:", color: .green, style: .bold)
.appending(" ")
.appending(fix)
print(fixText)
}
Darwin.exit(EXIT_FAILURE)
}
}
44 changes: 38 additions & 6 deletions Sources/Backend/Utilities/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,48 @@ import Foundation
/// An error type that is displayed in a formatted representation when printed
/// to a command line interface.
public protocol FormattedError: Error, TextOutputStreamable {
/// The formatted message to display.
/// The formatted error message to display.
///
/// If one of either standard output or standard error does not point to a
/// terminal, the message is displayed without formatting.
var message: FormattedText { get }
/// If one of either standard output or standard error does not point to
/// a terminal, the message is displayed without formatting.
var errorMessage: FormattedText { get }

/// An optional formatted message to display that describes how the user
/// can remedy this error.
///
/// If one of either standard output or standard error does not point to
/// a terminal, the message is displayed without formatting.
var fix: FormattedText? { get }
}

extension FormattedError {
public var fix: FormattedText? { nil }
}

extension FormattedError {
public func write<Target: TextOutputStream>(to target: inout Target) {
message.write(to: &target)
errorMessage.write(to: &target)
}
}

// MARK: FormattedErrorBox

/// A formatted error type that wraps another error.
struct FormattedErrorBox: FormattedError {
let error: any Error

var errorMessage: FormattedText {
if let error = error as? FormattedError {
return error.errorMessage
}
return FormattedText(contentsOf: error.localizedDescription)
}

var fix: FormattedText? {
if let error = error as? FormattedError {
return error.fix
}
return nil
}
}

Expand All @@ -34,7 +66,7 @@ struct ContextualDataError: FormattedError {
/// A string describing the context in which this error occurred.
let context: String

var message: FormattedText {
var errorMessage: FormattedText {
var message = FormattedText(context + ":", color: .yellow, style: .bold)
if let string = String(data: data, encoding: .utf8) {
message.append(" \("An error occurred with the following data:", color: .red) \(string)")
Expand Down
4 changes: 2 additions & 2 deletions Sources/Frontend/CreateICNS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ struct CreateICNS: ParsableCommand {

@OptionGroup var options: Options

func run() throws {
try MainRunner(
func run() {
MainRunner(
input: options.input,
output: options.output,
type: options.type,
Expand Down

0 comments on commit cc2c669

Please sign in to comment.