♻️ Refactor AppLibrary to use TrashCommand

This commit is contained in:
Ben Chatelain 2019-01-02 23:16:45 -08:00
parent 3630df5750
commit ae8d8f5f46
3 changed files with 23 additions and 53 deletions

View file

@ -13,8 +13,8 @@ public protocol ExternalCommand {
var process: Process { get } var process: Process { get }
var stdout: String? { get } var stdout: String { get }
var stderr: String? { get } var stderr: String { get }
var stdoutPipe: Pipe { get } var stdoutPipe: Pipe { get }
var stderrPipe: Pipe { get } var stderrPipe: Pipe { get }
@ -23,19 +23,19 @@ public protocol ExternalCommand {
var failed: Bool { get } var failed: Bool { get }
/// Runs the command. /// Runs the command.
mutating func run() throws func run() throws
} }
/// Common implementation /// Common implementation
extension ExternalCommand { extension ExternalCommand {
public var stdout: String? { get { public var stdout: String { get {
let data = stdoutPipe.fileHandleForReading.readDataToEndOfFile() 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() let data = stderrPipe.fileHandleForReading.readDataToEndOfFile()
return String(data: data, encoding: .utf8) return String(data: data, encoding: .utf8) ?? ""
}} }}
public var exitCode: Int? { get { public var exitCode: Int? { get {
@ -51,7 +51,7 @@ extension ExternalCommand {
}} }}
/// Runs the command. /// Runs the command.
public mutating func run() throws { public func run() throws {
process.standardOutput = stdoutPipe process.standardOutput = stdoutPipe
process.standardError = stderrPipe process.standardError = stderrPipe
process.arguments = arguments process.arguments = arguments

View file

@ -6,7 +6,9 @@
// Copyright © 2019 mas-cli. All rights reserved. // 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 struct TrashCommand: ExternalCommand {
public var binaryPath: String public var binaryPath: String
public var arguments: [String] public var arguments: [String]

View file

@ -22,8 +22,9 @@ public class MasAppLibrary: AppLibrary {
return products return products
}() }()
private let trashCommand: ExternalCommand private var trashCommand: ExternalCommand
/// Designated initializer
public init(trashCommand: ExternalCommand = TrashCommand()) { public init(trashCommand: ExternalCommand = TrashCommand()) {
self.trashCommand = trashCommand self.trashCommand = trashCommand
} }
@ -41,50 +42,17 @@ public class MasAppLibrary: AppLibrary {
/// - Parameter app: App to be removed. /// - Parameter app: App to be removed.
/// - Throws: Error if there is a problem. /// - Throws: Error if there is a problem.
public func uninstallApp(app: SoftwareProduct) throws { public func uninstallApp(app: SoftwareProduct) throws {
let status = trash(path: app.bundlePath) trashCommand.arguments = [app.bundlePath]
if !status { 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 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
}
}
} }