/* 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 "PerforceActionResolve.h" #import "AppUtils.h" static NSString* kNewLine = @"\n"; @implementation PerforceActionResolve + (void) defaultRun: (NSArray*) depotPaths { NSFileManager* fileManager = [NSFileManager defaultManager]; NSMutableArray* commandAndArgs = [[[NSMutableArray alloc] init] autorelease]; NSString* fileListFile = nil; // // Set up the input files // if ( depotPaths ) { NSMutableString* fileString = [[[NSMutableString alloc] init] autorelease]; int n; int num = [depotPaths count]; for ( n = 0; n < num; n++ ) { [fileString appendString:[depotPaths objectAtIndex:n]]; [fileString appendString:kNewLine]; } NSData* fileListData = [fileString dataUsingEncoding:NSASCIIStringEncoding]; fileListFile = [NSString stringWithFormat:@"%@ResolveFileList.P4Cocoa", GetAppTempPath()]; [fileManager createFileAtPath:fileListFile contents:fileListData attributes:nil]; [commandAndArgs addObject:@"-x"]; [commandAndArgs addObject:fileListFile]; } [commandAndArgs addObject:@"resolve"]; // // Create the task for resolve // NSTask* perforceTask = nil; NSString* p4exe = GetPerforceExecPath(); if ( !p4exe ) return; // special case a single item in the resolve list if ( depotPaths && ([depotPaths count] == 1) ) { NSString* consoleMsg = [NSString stringWithFormat:@"executing p4 resolve %@\n", [depotPaths objectAtIndex:0]]; SendExecutingMessage ([consoleMsg cString]); } else { NSString* consoleMsg = [NSString stringWithString:@"executing p4 resolve\n"]; SendExecutingMessage ([consoleMsg cString]); } NSPipe* standardOutPipe = [NSPipe pipe]; NSPipe* standardErrPipe = [NSPipe pipe]; NSPipe* standardInPipe = [NSPipe pipe]; perforceTask = [[[NSTask alloc] init] autorelease]; [perforceTask setLaunchPath:p4exe]; [perforceTask setStandardOutput:standardOutPipe]; [perforceTask setStandardError:standardErrPipe]; [perforceTask setStandardInput:standardInPipe]; [perforceTask setArguments:commandAndArgs]; NSFileHandle* fileOutput = [standardOutPipe fileHandleForReading]; NSFileHandle* fileError = [standardErrPipe fileHandleForReading]; NSFileHandle* fileInput = [standardInPipe fileHandleForWriting]; // tell p4 to go do its thing [perforceTask launch]; NSData* pipeData = [fileOutput availableData]; BOOL didSomething = NO; BOOL lastActionWasMerge = NO; while ( [pipeData length] > 0 ) { didSomething = YES; // Grab the string from the resolve task and parse it for what to do NSString* outString = [[NSString alloc] initWithData:pipeData encoding:NSUTF8StringEncoding]; NSArray* outStringLines = [outString componentsSeparatedByString:@"\n"]; int count = [outStringLines count]; int n; for ( n = 0; n < count; n++ ) { NSString* aLine = [outStringLines objectAtIndex:n]; NSScanner* lineScanner = [NSScanner scannerWithString:aLine]; BOOL bAsking = NO; // The normal ask bAsking = [lineScanner scanString:@"Accept(a)" intoString:nil]; if ( bAsking == NO ) { [lineScanner setScanLocation:0]; // the ask for binary files bAsking = [lineScanner scanString:@"Accept (at/ay)" intoString:nil]; } if ( bAsking == NO ) { // Sometimes the user is asked to confirm overwrite [lineScanner setScanLocation:0]; if ( [lineScanner scanString:@"This overrides your changes: confirm accept" intoString:nil] == YES ) { // For now assume the user knew what they were doing and just say y. [fileInput writeData:[[NSString stringWithString:@"y\n"] dataUsingEncoding:NSASCIIStringEncoding]]; /* int nButton = NSRunCriticalAlertPanel (@"This overrides your changes", @"Confirm accept (Yes/No)", @"Yes", @"No", nil); if ( nButton == 1 ) { [fileInput writeData:[[NSString stringWithString:@"y\n"] dataUsingEncoding:NSASCIIStringEncoding]]; } else { [fileInput writeData:[[NSString stringWithString:@"n\n"] dataUsingEncoding:NSASCIIStringEncoding]]; } */ } else { if ( [aLine length] > 0 ) { SendOutputMessage ([aLine cString]); SendOutputMessage ("\n"); } lastActionWasMerge = NO; } } else { // Parse the last line for what to do [lineScanner setScanLocation:0]; NSString* actionString = nil; if ( [lineScanner scanUpToString:@":" intoString:&actionString] ) { // Go backward until we find a space int lastIndex = [actionString length] - 1; int startIndex = lastIndex; while ( (lastIndex > 0) && ([actionString characterAtIndex:lastIndex] != ' ') ) { lastIndex--; } int actionLength = startIndex - lastIndex; if ( actionLength > 0 ) { NSString* theAction = [actionString substringWithRange:NSMakeRange(lastIndex + 1, actionLength)]; NSLog (@"TheAction = %@", theAction); if ( [theAction isEqualToString:@"at"] ) { SendOutputMessage ("Accepting theirs\n"); [fileInput writeData:[[NSString stringWithString:@"\n"] dataUsingEncoding:NSASCIIStringEncoding]]; lastActionWasMerge = NO; } else if ( [theAction isEqualToString:@"ay"] ) { SendOutputMessage ("Accepting yours\n"); [fileInput writeData:[[NSString stringWithString:@"\n"] dataUsingEncoding:NSASCIIStringEncoding]]; lastActionWasMerge = NO; } else if ( [theAction isEqualToString:@"am"] ) { SendOutputMessage ("Accepting merge\n"); [fileInput writeData:[[NSString stringWithString:@"\n"] dataUsingEncoding:NSASCIIStringEncoding]]; lastActionWasMerge = NO; } else if ( [theAction isEqualToString:@"ae"] ) { SendOutputMessage ("Accepting edits\n"); [fileInput writeData:[[NSString stringWithString:@"\n"] dataUsingEncoding:NSASCIIStringEncoding]]; lastActionWasMerge = NO; } else if ( [theAction isEqualToString:@"e"] ) { if ( !lastActionWasMerge ) { //SendOutputMessage ("Edit using merge application\n"); [fileInput writeData:[[NSString stringWithString:@"m\n"] dataUsingEncoding:NSASCIIStringEncoding]]; lastActionWasMerge = YES; } else { SendOutputMessage ("Skipping\n"); [fileInput writeData:[[NSString stringWithString:@"s\n"] dataUsingEncoding:NSASCIIStringEncoding]]; } } else { // When in doubt, skip SendOutputMessage ("Skipping\n"); [fileInput writeData:[[NSString stringWithString:@"s\n"] dataUsingEncoding:NSASCIIStringEncoding]]; lastActionWasMerge = NO; } } } } } [outString release]; pipeData = [fileOutput availableData]; } // Process error /* pipeData = [fileError availableData]; while ( [pipeData length] > 0 ) { NSString* errString = [[NSString alloc] initWithData:pipeData encoding:NSUTF8StringEncoding]; SendErrorMessage ([errString cString]); [errString release]; pipeData = [fileError availableData]; } */ pipeData = [fileError readDataToEndOfFile]; if ( [pipeData length] > 0 ) { if ( didSomething ) { SendErrorMessage ("Some of the files chosen had nothing to resolve\n"); } else { SendErrorMessage ("No files to resolve\n"); } } if ( fileListFile ) { [fileManager removeFileAtPath:fileListFile handler:nil]; } } @end