#import "MyTask.h"
//see Apple code example moriaty
@implementation MyTask
-(id)initForController:(id) control {
self = [super init];
if (self != nil) {
controller = control;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(checkTaskStatus:)
name:NSTaskDidTerminateNotification
object:nil];
}
return self;
}
#pragma mark current state
- (void)checkTaskStatus:(NSNotification *)aNotification {
if(![myTask isRunning]) {
int status = [[aNotification object] terminationStatus];
if (status)
NSLog(@"Task succeeded.");
else
NSLog(@"Task stopped.");
}
}
#pragma mark task
-(BOOL) startTask:(NSString *) command inWorkingDirectory:(NSURL *) url withOptions:(NSArray *) options {
NSMutableArray *allOptions = [[NSMutableArray alloc] initWithCapacity:2+[options count]];
[allOptions addObject:command];
[allOptions addObject:url];
[allOptions addObjectsFromArray:options];
BOOL succes = [self startTask:allOptions];
[allOptions release];
return succes;
}
-(BOOL) startTask:(NSArray *) options{
if ([options count] < 2)
return NO;
//options:
//0, NSString = shell command
//1, NSURL = working directory
//2 - count-2 = arguments
NSString *command = [options objectAtIndex:0];
NSString *workingDirectory = [[options objectAtIndex:1] path];
BOOL succes = NO;
//check if file is valid path
BOOL isDir = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath:workingDirectory isDirectory:&isDir] & (isDir)) {
[controller processStarted];
//create task
myTask = [[NSTask alloc] init];
[myTask setCurrentDirectoryPath:workingDirectory];
[myTask setLaunchPath:command];
//set arguments
NSArray *args = [options subarrayWithRange:NSMakeRange(2, [options count]-2)];
[myTask setArguments:args];
//pipes -> log
NSPipe *outputPipe = [NSPipe pipe];
[myTask setStandardOutput:outputPipe];
[myTask setStandardError:outputPipe];
NSPipe *inputPipe = [NSPipe pipe];
[myTask setStandardInput:inputPipe];
//pipes -> filehandles
readHandle = [outputPipe fileHandleForReading];
writeHandle = [inputPipe fileHandleForWriting];
//observe change to output of task, so that they can be collected
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(readFromTask:)
name:NSFileHandleReadCompletionNotification
object:readHandle];
// We tell the file handle to go ahead and read in the background asynchronously, and notify
// us via the callback registered above when we signed up as an observer. The file handle will
// send a NSFileHandleReadCompletionNotification when it has data that is available.
[readHandle readInBackgroundAndNotify];
// launch the task asynchronously
[myTask launch];
succes = YES;
}
return succes;
}
-(BOOL) stopTask {
if ([myTask isRunning]) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:readHandle];
[myTask terminate];
NSData *data = nil;
while ((data = [readHandle availableData]) && [data length]) {
[controller appendOutput: [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]];
}
}
[myTask release];
[controller processFinished];
controller = nil;
return YES;
}
#pragma mark input/output
-(void) readFromTask: (NSNotification *)aNotification{
NSData *data = [[aNotification userInfo] objectForKey:NSFileHandleNotificationDataItem];
if ([data length]) {
// Send the data on to the controller; we can't just use +stringWithUTF8String: here because -[data bytes] is not necessarily a properly terminated string.
// -initWithData:encoding: on the other hand checks -[data length]
[controller appendOutput: [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]];
// we need to schedule the file handle go read more data in the background again.
[[aNotification object] readInBackgroundAndNotify];
} else {
[self stopTask]; //no more data
}
}
-(void) writeToTask:(NSString *) output{
[writeHandle writeData:[output dataUsingEncoding:NSUTF8StringEncoding]];
}
#pragma mark cleanup
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSTaskDidTerminateNotification object:nil];
[super dealloc];
}