I have a situation where I need to pipe my console output for several external processes.
Some of these should be "silent" (i.e. the console output gets piped to a variable for parsing of the data) while one of them should be displayed in an NSTextField as a progress indicator for the user.
Since this is rather a big chunk of code, I'd like to write the function so that I can give it a destination parameter, but I'm still pretty new at this and I can't quite make it work.
Here is what I have so far:
func pipeOutput(task: Process, destination: String) {
let pipe = Pipe()
task.standardError = pipe
task.standardOutput = pipe
let outHandle = pipe.fileHandleForReading
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) {
destination += ("\(str)")
let range = NSRange(location:destination.count,length:0)
destination.scrollRangeToVisible(range)
}
outHandle.waitForDataInBackgroundAndNotify()
}
else {
print("EOF on stderr from process")
NotificationCenter.default.removeObserver(obs1!)
}
}
var obs2 : NSObjectProtocol!
obs2 = NotificationCenter.default
.addObserver(
forName: Process.didTerminateNotification,
object: task, queue: nil) {
notification -> Void in
print("terminated")
NotificationCenter.default.removeObserver(obs2!)
}
}
I only need the
let range = NSRange(location:destination.count,length:0) destination.scrollRangeToVisible(range)
part when the destination
is the NSTextField. In the other cases, I just need destination += ("\(str)")
I assume it would require writing a method along the lines of:
func getOutputDestination(processType: String) -> String {
let process = processType
switch process {
case "silent" :
outputDestination = "outputString"
default :
outputDestination = "textField"
where "textField" =
outputTextDisplay.string += ("\(str)")
let range = NSRange(location:outputTextDisplay.string.count,length:0)
outputTextDisplay.scrollRangeToVisible(range)
}
return outputDestination
}
And then somehow designating the various external processes as "silent" or otherwise. But I'm not quite sure how to get it to work.
How do I make this happen?