//
// CommandRunner.swift
// zhengyh
//
// Created by zhengyh on 2019/5/9.
// Copyright © 2019 zhengyh. All rights reserved.
//
import Cocoa
class CommandRunner: NSObject {
/** 同步執行
* command: shell 命令內容
* returns: 命令行執行結果,積壓在一起返回
*
* 使用示例
let (res, rev) = CommandRunner.sync(command: "ls -l")
print(rev)
*/
static func sync(command: String) -> (Int, String) {
let utf8Command = "export LANG=en_US.UTF-8\n" + command
return sync(shellPath: "/bin/bash", arguments: ["-c", utf8Command])
}
/** 同步執行
* shellPath: 命令行啓動路徑
* arguments: 命令行參數
* returns: 命令行執行結果,積壓在一起返回
*
* 使用示例
let (res, rev) = CommandRunner.sync(shellPath: "/usr/sbin/system_profiler", arguments: ["SPHardwareDataType"])
print(rev)
*/
static func sync(shellPath: String, arguments: [String]? = nil) -> (Int, String) {
let task = Process()
let pipe = Pipe()
var environment = ProcessInfo.processInfo.environment
environment["PATH"] = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
task.environment = environment
if arguments != nil {
task.arguments = arguments!
}
task.launchPath = shellPath
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = String(data: data, encoding: String.Encoding.utf8)!
task.waitUntilExit()
pipe.fileHandleForReading.closeFile()
return (Int(task.terminationStatus), output)
}
/** 異步執行
* command: shell 命令內容
* output: 每行的輸出內容實時回調(主線程回調)
* terminate: 命令執行結束狀態(主線程回調)
*
* 使用示例
CommandRunner.async(command: "ls -l",
output: {[weak self] (str) in
self?.appendLog(str: str)
},
terminate: {[weak self] (code) in
self?.appendLog(str: "end \(code)")
})
*/
static func async(command: String,
output: ((String) -> Void)? = nil,
terminate: ((Int) -> Void)? = nil) {
let utf8Command = "export LANG=en_US.UTF-8\n" + command
async(shellPath: "/bin/bash", arguments: ["-c", utf8Command], output:output, terminate:terminate)
}
/** 異步執行
* shellPath: 命令行啓動路徑
* arguments: 命令行參數
* output: 每行的輸出內容實時回調(主線程回調)
* terminate: 命令執行結束狀態(主線程回調)
*
* 使用示例
CommandRunner.async(shellPath: "/usr/sbin/system_profiler",
arguments: ["SPHardwareDataType"],
output: {[weak self] (str) in
self?.appendLog(str: str)
},
terminate: {[weak self] (code) in
self?.appendLog(str: "end \(code)")
})
*/
static func async(shellPath: String,
arguments: [String]? = nil,
output: ((String) -> Void)? = nil,
terminate: ((Int) -> Void)? = nil) {
DispatchQueue.global().async {
let task = Process()
let pipe = Pipe()
let outHandle = pipe.fileHandleForReading
var environment = ProcessInfo.processInfo.environment
environment["PATH"] = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
task.environment = environment
if arguments != nil {
task.arguments = arguments!
}
task.launchPath = shellPath
task.standardOutput = pipe
outHandle.waitForDataInBackgroundAndNotify()
var obs1 : NSObjectProtocol!
obs1 = NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable,
object: outHandle, queue: nil) { notification -> Void in
let data = outHandle.availableData
if data.count > 0 {
if let str = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
DispatchQueue.main.async {
output?(str as String)
}
}
outHandle.waitForDataInBackgroundAndNotify()
} else {
NotificationCenter.default.removeObserver(obs1)
pipe.fileHandleForReading.closeFile()
}
}
var obs2 : NSObjectProtocol!
obs2 = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification,
object: task, queue: nil) { notification -> Void in
DispatchQueue.main.async {
terminate?(Int(task.terminationStatus))
}
NotificationCenter.default.removeObserver(obs2)
}
task.launch()
task.waitUntilExit()
}
}
}