I'm writing a Swift command line tool that uses NSTask
to interact with git
. In the simplest scenario I want to run three commands: init
, add .
, and commit -m Initial Commit
. I intend to use a separate NSTask
for each command, and want to house each command in its own function - returning true
if the task succeeded or false
if it didn't. This set-up would allow my main
function to look like this:
func main() {
if runInit() {
if runStage() {
if runCommit() {
NSLog("success!")
}
}
}
}
To accomplish this each of the three functions must do the following before returning (i) launch the task (ii) wait for it to complete, (iii) obtain whatever is in stdout
, and (iv) set the return value (true
or false
). Here's what I've got for the commit stage:
func runCommit() -> Bool {
var retval = false
var commitTask = NSTask()
commitTask.standardOutput = NSPipe()
commitTask.launchPath = gitPath
commitTask.arguments = ["commit", "-m", "Initial Commit"]
commitTask.currentDirectoryPath = demoProjectURL.path!
commitTask.standardOutput.fileHandleForReading.readToEndOfFileInBackgroundAndNotify()
nc.addObserverForName(NSFileHandleReadToEndOfFileCompletionNotification,
object: commitTask.standardOutput.fileHandleForReading,
queue: nil) { (note) -> Void in
// get the output, log it, then...
if commitTask.terminationStatus == EXIT_SUCCESS {
retval = true
}
}
commitTask.launch()
commitTask.waitUntilExit()
return retval
}
My question is essentially about how waitUntilExit
works, particularly in conjunction with the notification I sign up for to enable me to get the output. Apple's docs say:
This method first checks to see if the receiver is still running using isRunning. Then it polls the current run loop using NSDefaultRunLoopMode until the task completes.
I'm a bit out of my depth when it comes to run loop mechanics, and was wondering what this means in this context - can I safely assume that my notification block will always be executed before the enclosing function returns?