diff --git a/MasKit/ExternalCommands/ExternalCommand.swift b/MasKit/ExternalCommands/ExternalCommand.swift index 4ffb767..df50e13 100644 --- a/MasKit/ExternalCommands/ExternalCommand.swift +++ b/MasKit/ExternalCommands/ExternalCommand.swift @@ -13,8 +13,8 @@ public protocol ExternalCommand { var process: Process { get } - var stdout: String? { get } - var stderr: String? { get } + var stdout: String { get } + var stderr: String { get } var stdoutPipe: Pipe { get } var stderrPipe: Pipe { get } @@ -23,19 +23,19 @@ public protocol ExternalCommand { var failed: Bool { get } /// Runs the command. - mutating func run() throws + func run() throws } /// Common implementation extension ExternalCommand { - public var stdout: String? { get { + public var stdout: String { get { let data = stdoutPipe.fileHandleForReading.readDataToEndOfFile() - return String(data: data, encoding: .utf8) + return String(data: data, encoding: .utf8) ?? "" }} - public var stderr: String? { get { + public var stderr: String { get { let data = stderrPipe.fileHandleForReading.readDataToEndOfFile() - return String(data: data, encoding: .utf8) + return String(data: data, encoding: .utf8) ?? "" }} public var exitCode: Int? { get { @@ -51,7 +51,7 @@ extension ExternalCommand { }} /// Runs the command. - public mutating func run() throws { + public func run() throws { process.standardOutput = stdoutPipe process.standardError = stderrPipe process.arguments = arguments diff --git a/MasKit/ExternalCommands/TrashCommand.swift b/MasKit/ExternalCommands/TrashCommand.swift index 2e0c74d..ddad5eb 100644 --- a/MasKit/ExternalCommands/TrashCommand.swift +++ b/MasKit/ExternalCommands/TrashCommand.swift @@ -6,7 +6,9 @@ // Copyright © 2019 mas-cli. All rights reserved. // -/// CLI command +/// Wrapper for the external trash command. Relies on the "trash" command +/// from Homebrew. Trash requires el_capitan or higher for core bottles: +/// https://github.com/Homebrew/homebrew-core/blob/master/Formula/trash.rb public struct TrashCommand: ExternalCommand { public var binaryPath: String public var arguments: [String] diff --git a/MasKit/MasAppLibrary.swift b/MasKit/MasAppLibrary.swift index b03066b..dfaf02f 100644 --- a/MasKit/MasAppLibrary.swift +++ b/MasKit/MasAppLibrary.swift @@ -22,8 +22,9 @@ public class MasAppLibrary: AppLibrary { return products }() - private let trashCommand: ExternalCommand + private var trashCommand: ExternalCommand + /// Designated initializer public init(trashCommand: ExternalCommand = TrashCommand()) { self.trashCommand = trashCommand } @@ -41,50 +42,17 @@ public class MasAppLibrary: AppLibrary { /// - Parameter app: App to be removed. /// - Throws: Error if there is a problem. public func uninstallApp(app: SoftwareProduct) throws { - let status = trash(path: app.bundlePath) - if !status { + trashCommand.arguments = [app.bundlePath] + do { + try trashCommand.run() + } catch { + printError("Unable to launch trash command") + throw MASError.uninstallFailed + } + if trashCommand.failed { + let reason = trashCommand.process.terminationReason + printError("Uninstall failed: (\(reason)) \(trashCommand.stderr)") throw MASError.uninstallFailed } } - - /// Runs the trash command in another process. Relies on the "trash" command - /// from Homebrew. Trash requires el_capitan or higher for core bottles: - /// https://github.com/Homebrew/homebrew-core/blob/master/Formula/trash.rb - /// - /// - Parameter path: Absolute path to the application bundle to uninstall. - /// - Returns: true on success; fail on error - func trash(path: String) -> Bool { - let binaryPath = "/usr/local/bin/trash" - let process = Process() - let stdout = Pipe() - let stderr = Pipe() - - process.standardOutput = stdout - process.standardError = stderr - process.arguments = [path] - - if #available(OSX 10.13, *) { - process.executableURL = URL(fileURLWithPath: binaryPath) - do { - try process.run() - } catch { - printError("Unable to launch trash command") - return false - } - } else { - process.launchPath = binaryPath - process.launch() - } - - process.waitUntilExit() - - if process.terminationStatus == 0 { - return true - } else { - let reason = process.terminationReason - let output = stderr.fileHandleForReading.readDataToEndOfFile() - printError("Uninstall failed: \(reason)\n\(String(data: output, encoding: .utf8)!)") - return false - } - } }