From 89e06acc72315dcf6ac75c03fcaee502be5d7f30 Mon Sep 17 00:00:00 2001 From: Kare Morstol Date: Fri, 25 Sep 2015 02:18:05 +0200 Subject: [PATCH] Give 'run' and 'runAsync' much nicer errors when running inaccessible executables. - add ShellError.InAccessibleExecutable - add ShellError.errorcode - add exit(ErrorType) --- SwiftShell/Command.swift | 56 +++++++++++++++++++++++++-- SwiftShell2.xcodeproj/project.pbxproj | 2 +- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/SwiftShell/Command.swift b/SwiftShell/Command.swift index 85ef988..66deeab 100644 --- a/SwiftShell/Command.swift +++ b/SwiftShell/Command.swift @@ -20,6 +20,16 @@ Print message to standard error and halt execution. exit(errorcode) } +@noreturn public func exit (error: ErrorType) { + if let shellerror = error as? ShellError { + exit(errormessage: shellerror, errorcode: shellerror.errorcode) + } else { + let nserror = error as NSError + exit(errormessage: nserror, errorcode: Int32(nserror.code)) + } +} + + /** If `executable` is not a path and a path for an executable file of that name can be found, return that path. Otherwise just return `executable`. @@ -58,7 +68,11 @@ extension ShellContextType { let output = NSPipe () task.standardOutput = output task.standardError = output - task.launch() + do { + try task.launchThrowably() + } catch { + exit(error) + } task.waitUntilExit() var outputstring = output.fileHandleForReading.read(encoding: self.encoding) @@ -93,13 +107,37 @@ public enum ShellError: ErrorType, Equatable { /** Exit code was not zero. */ case ReturnedErrorCode (errorcode: Int32) - // case InAccessibleExecutable (path: String) + case InAccessibleExecutable (path: String) + + var errorcode: Int32 { + switch self { + case .ReturnedErrorCode(let code): + return code + case .InAccessibleExecutable: + return EXIT_FAILURE + } + } +} + +extension ShellError: CustomStringConvertible { + public var description: String { + switch self { + case .InAccessibleExecutable(let path): + return "Could not execute file at path '\(path)'." + case .ReturnedErrorCode(let code): + return "Command returned with error code \(code)." + } + } } public func == (e1: ShellError, e2: ShellError) -> Bool { switch (e1, e2) { case (.ReturnedErrorCode(let c1), .ReturnedErrorCode(let c2)): return c1 == c2 + case (.InAccessibleExecutable(let c1), .InAccessibleExecutable(let c2)): + return c1 == c2 + default: + return false } } @@ -110,6 +148,14 @@ extension NSTask { throw ShellError.ReturnedErrorCode(errorcode: self.terminationStatus) } } + + public func launchThrowably() throws { + do { + try launchWithNSError() + } catch { + throw ShellError.InAccessibleExecutable(path: self.launchPath!) + } + } } @@ -132,7 +178,11 @@ public struct AsyncShellTask { task.standardError = errorpipe self.stderror = errorpipe.fileHandleForReading - task.launch() + do { + try task.launchThrowably() + } catch { + exit(error) + } } /** diff --git a/SwiftShell2.xcodeproj/project.pbxproj b/SwiftShell2.xcodeproj/project.pbxproj index f16caf3..e1156a9 100644 --- a/SwiftShell2.xcodeproj/project.pbxproj +++ b/SwiftShell2.xcodeproj/project.pbxproj @@ -42,7 +42,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - BA1362171BADCA0C009ACCC9 /* CatchingFire.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CatchingFire.swift; sourceTree = ""; }; + BA1362171BADCA0C009ACCC9 /* CatchingFire.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CatchingFire.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; BA2E3B151B5C34DD001ED175 /* SwiftShell.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftShell.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BA2E3B1A1B5C34DD001ED175 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; BA2E3B1F1B5C34DD001ED175 /* SwiftShellTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftShellTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };