/* Copyright (C) 2002-2003, Jeffrey D. Argast. The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. Permission is hereby granted to use, copy, modify, and distribute this software or portions thereof for any purpose, without fee, subject to these conditions: (1) If any part of the source code is distributed, then this statement must be included, with this copyright and no-warranty notice unaltered. (2) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. */ #import "PerforceAction.h" #import "PerforceDepot.h" #import "PerforceDirectory.h" #import "PerforceChangeList.h" #import "PerforceChangeFile.h" #import "AppUtils.h" #import "AppDefaults.h" #import "MessageDefs.h" #import <unistd.h> static NSString* kNewLine = @"\n"; @implementation PerforceAction + (NSTask*) runCommand: (NSArray*) commandAndArgs stdInString: (NSString*) stdInString owner: (id) owner readSelector: (SEL) readSelector readToEOF:(BOOL)readToEOF sendStdInToConsole:(BOOL)sendStdInToConsole; { NSTask* perforceTask = nil; NSString* p4exe = GetPerforceExecPath(); NSMutableString* consoleMsg = [NSMutableString stringWithCString:"executing p4"]; int numArgs = [commandAndArgs count]; for ( int n = 0; n < numArgs; n++ ) { [consoleMsg appendString:@" "]; [consoleMsg appendString:[commandAndArgs objectAtIndex:n]]; } if ( stdInString && sendStdInToConsole ) { [consoleMsg appendString:@" "]; [consoleMsg appendString:stdInString]; } // append a new line if the last character of the console is not a newline // compare:kNewLine options:0 range:NSMakeRange([consoleMsg length] - 1, 1)] != NSOrderedSame ) if ( [consoleMsg characterAtIndex:[consoleMsg length] - 1] != '\n' ) { [consoleMsg appendString:kNewLine]; } SendExecutingMessage ([consoleMsg cString]); if ( p4exe ) { NSPipe* standardOutPipe = [NSPipe pipe]; NSPipe* standardErrPipe = [NSPipe pipe]; NSPipe* standardInPipe = nil; NSFileHandle* standardIn = nil; perforceTask = [[[NSTask alloc] init] autorelease]; [perforceTask setLaunchPath:p4exe]; [perforceTask setStandardOutput:standardOutPipe]; [perforceTask setStandardError:standardErrPipe]; if ( stdInString ) { standardInPipe = [NSPipe pipe]; standardIn = [standardInPipe fileHandleForWriting]; [perforceTask setStandardInput:standardInPipe]; } [perforceTask setArguments:commandAndArgs]; // tell p4 to go do its thing [perforceTask launch]; // send it data if needed if ( standardInPipe ) { NSData* stdInData = [stdInString dataUsingEncoding:NSASCIIStringEncoding]; // using standard in is slow when writing a large amount of data [standardIn writeData:stdInData]; [standardIn closeFile]; } NSFileHandle* standardOut = [standardOutPipe fileHandleForReading]; if ( readToEOF ) { [[NSNotificationCenter defaultCenter] addObserver:owner selector:readSelector name:NSFileHandleReadToEndOfFileCompletionNotification object:standardOut]; [standardOut readToEndOfFileInBackgroundAndNotify]; } else { [[NSNotificationCenter defaultCenter] addObserver:owner selector:readSelector name:NSFileHandleReadCompletionNotification object:standardOut]; [standardOut readInBackgroundAndNotify]; } } return perforceTask; } static int gNumCriticalActionsRunning = 0; + (void) pushCriticalAction { gNumCriticalActionsRunning++; } + (void) popCriticalAction { gNumCriticalActionsRunning--; } + (BOOL) isCriticalActionRunning { if ( gNumCriticalActionsRunning > 0 ) { return YES; } return NO; } + (NSArray*) runningActions { static NSMutableArray* gRunningActions = nil; if ( !gRunningActions ) { gRunningActions = [[NSMutableArray alloc] init]; } return gRunningActions; } + (void) addAction: (PerforceAction*) perforceAction { NSMutableArray* runningActions = (NSMutableArray*) [PerforceAction runningActions]; [runningActions addObject:perforceAction]; if ( [perforceAction isCriticalAction] ) { [PerforceAction pushCriticalAction]; } SendNotification (kActionListChanged); } + (void) removeAction: (PerforceAction*) perforceAction { NSMutableArray* runningActions = (NSMutableArray*) [PerforceAction runningActions]; [runningActions removeObjectIdenticalTo:perforceAction]; if ( [perforceAction isCriticalAction] ) { [PerforceAction popCriticalAction]; } SendNotification (kActionListChanged); } + (void) abortAllActions { NSArray* runningActions = [NSArray arrayWithArray:[PerforceAction runningActions]]; int n = 0; int num = [runningActions count]; for ( n = 0; n < num; n++ ) { PerforceAction* action = [runningActions objectAtIndex:n]; [action abort]; } } + (void) abortAllOwnersActions: (id) owner { NSMutableArray* runningActions = (NSMutableArray*) [PerforceAction runningActions]; NSMutableArray* toAbort = [[[NSMutableArray alloc] init] autorelease]; int n; int num = [runningActions count]; for ( n = 0; n < num; n++ ) { PerforceAction* action = [runningActions objectAtIndex:n]; if ( [action getOwner] == owner ) { [toAbort addObject:action]; } } num = [toAbort count]; for ( n = 0; n < num; n++ ) { PerforceAction* action = [toAbort objectAtIndex:n]; [action abort]; } } // Standard init method. client and user are not set - (id) init { if (self = [super init]) { fClientName = nil; fUserName = nil; } fWasError = NO; fWasAborted = NO; // NSLog (@"Task init %@", [self description]); // NSLog ([self description]); return self; } // Init with a special client and/or user - (id) initWithClient:(NSString*)client user:(NSString*) user; { if (self = [super init]) { if (client) { fClientName = client; [fClientName retain]; } if (user) { fUserName = user; [fUserName retain]; } } return self; } - (void) dealloc { // NSLog (@"Task dealloc %@", [self description]); // NSLog ([self description]); if ( fPerforceTask ) { //NSLog (@"Perforce task not yet complete. Too many release messages"); [[NSNotificationCenter defaultCenter] removeObserver:self]; [fPerforceTask terminate]; [fPerforceTask release]; } [fClientName release]; [fUserName release]; [fStandardOutput release]; [fStandardError release]; [fStandardInput release]; [fActionDescription release]; [super dealloc]; } - (void) readToEOFNotification:(NSNotification*) aNotification { NSData* data = [[aNotification userInfo] objectForKey:NSFileHandleNotificationDataItem]; fStandardOutput = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; if ( [fStandardOutput length] > 0 ) { [self processOutput:fStandardOutput]; } [self taskDidComplete]; } - (void) readNotification:(NSNotification*) aNotification { NSData* data = [[aNotification userInfo] objectForKey:NSFileHandleNotificationDataItem]; NSString* dataString = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease]; if ( [dataString length] > 0 ) { [self processOutput:dataString]; [[aNotification object] readInBackgroundAndNotify]; } else { [self taskDidComplete]; } } - (void) runAction:(NSArray*)commandAndArgs stdInString:(NSString*)stdInString readToEOF:(BOOL)readToEOF { [self runAction:commandAndArgs stdInString:stdInString readToEOF:readToEOF sendStdInToConsole:YES]; } - (void) runAction:(NSArray*)commandAndArgs stdInString:(NSString*)stdInString readToEOF:(BOOL)readToEOF sendStdInToConsole:(BOOL)sendStdInToConsole { [self retain]; NSMutableString* actionDesc = [[[NSMutableString alloc] init] autorelease]; [actionDesc appendString:@"p4"]; int i; int len = [commandAndArgs count]; for ( i = 0; i < len; i++ ) { [actionDesc appendString:@" "]; [actionDesc appendString:[commandAndArgs objectAtIndex:i]]; } fActionDescription = [actionDesc retain]; if ( readToEOF ) { fPerforceTask = [[PerforceAction runCommand:commandAndArgs stdInString:stdInString owner:self readSelector:@selector(readToEOFNotification:) readToEOF:readToEOF sendStdInToConsole:sendStdInToConsole] retain]; } else { fPerforceTask = [[PerforceAction runCommand:commandAndArgs stdInString:stdInString owner:self readSelector:@selector(readNotification:) readToEOF:readToEOF sendStdInToConsole:sendStdInToConsole] retain]; } [PerforceAction addAction:self]; if ( !fPerforceTask ) { fWasError = YES; [self taskDidComplete]; } } - (void) abort { //NSLog (@"abort called"); fWasAborted = YES; if ( fPerforceTask ) { [fPerforceTask terminate]; } [self taskDidComplete]; } - (BOOL) isCriticalAction { return NO; } - (NSString*) getActionDescription { return fActionDescription; } - (BOOL) wasError { return fWasError; } - (BOOL) wasAborted { return fWasAborted; } - (BOOL) wasSuccess { return (!fWasError && !fWasAborted); } - (NSString*) getOutput { return fStandardOutput; } - (NSString*) getError { return fStandardError; } - (NSString*) getInput { return fStandardInput; } - (id) getOwner { return fOwner; } - (void) processOutput: (NSString*) perforceOutput { SendOutputMessage ([perforceOutput cString]); } - (void) processError: (NSString*) perforceError { SendErrorMessage ([perforceError cString]); } - (void) taskDidComplete { [PerforceAction removeAction:self]; NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; [center removeObserver:self]; if ( fPerforceTask ) { if ( [fPerforceTask isRunning] ) { //NSLog (@"perforce task still running"); [fPerforceTask waitUntilExit]; } fTerminationReturnCode = [fPerforceTask terminationStatus]; //NSLog (@"termination status = %d", fTerminationReturnCode); if ( fTerminationReturnCode != 0 ) { fWasError = YES; } NSPipe* standardErr = [fPerforceTask standardError]; NSFileHandle* stdErr = [standardErr fileHandleForReading]; NSData* nsData; nsData = [stdErr readDataToEndOfFile]; fStandardError = [[NSString alloc] initWithData:nsData encoding:NSASCIIStringEncoding]; [fPerforceTask release]; fPerforceTask = nil; if ( [fStandardError length] > 0 ) { [self processError:fStandardError]; } } [self notifyOwnerTaskIsComplete]; [self autorelease]; } - (void) notifyOwnerTaskIsComplete { [fOwner performSelector:fSelector withObject:self]; } /* // // CLIENTINFO // - (PerforceClient*) clientInfo: (NSString*) clientName { ClientUserClient ui; std::vector<std::string> p4args; std::string commandStr ("client"); p4args.push_back ("-o"); if (clientName) p4args.push_back ([clientName cString]); [self performCommand:commandStr withUI:&ui withArgs:p4args setProtocol:NO]; return ui.getClient(); } // // WHERE // - (NSString*) where:(NSString*) depotFilePath { ClientUserWhere ui; std::vector<std::string> p4args; std::string commandStr ("where"); p4args.push_back ([depotFilePath cString]); [self performCommand:commandStr withUI:&ui withArgs:p4args setProtocol:NO]; return ui.getClientPath(); } */ @end
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 3210 | Paul Ferguson | Initial branch | ||
//guest/jeff_argast/P4Cocoa/source/Perforce/PerforceAction.mm | |||||
#5 | 3147 | Jeff Argast | Testing std in blockage | ||
#4 | 3130 | Jeff Argast |
Added double click support to the depot view and pending changelist view. Added View File In Editor item on the pending changeist context menu. |
||
#3 | 3113 | Jeff Argast |
Reduced the times the depot view completely collapses. Now it won't collapse on refresh views or submit, but still collapses when the defaults change. |
||
#2 | 3111 | Jeff Argast |
Made multiple selection smarter by operating on the entire selection as an atomic operation with the server. Also partially fixed the read only window to not wrap at the window boundary. I did the same for the editable window, but now the problem appears to be that p4 change -o is breaking its output at some character location before the string gets into the editor (at least I think that is the problem). |
||
#1 | 2732 | Jeff Argast | Initial submission of P4Cocoa |