// Created by Jaime O. Rios #import "P4Functionality.h" #import "P4XcodeHelper.h" #import <string> #import <algorithm> // http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c static std::string exec(const char* cmd) { auto pipe = popen(cmd, "r"); if (!pipe) { return std::string("ERROR"); } char buffer[128]; auto result = std::string(""); auto error = 0; auto errNo = 0; while(!feof(pipe)) { auto stringBuf = fgets(buffer, 128, pipe); if( stringBuf != nullptr) { result += buffer; } else { error = ferror(pipe); errNo = errno; (void)error; (void)errNo; perror("Error "); } } pclose(pipe); return result; } static void remove_newline(std::string& str) { auto newline = std::string("\n"); auto found = str.find_last_not_of(newline); if (found!=std::string::npos) { str.erase(found+1); } else { str.clear(); } } @implementation P4Functionality - (instancetype)init { self = [super init]; if (self) { _userHomePathSettings = @".bash_login"; [self updateP4Status]; [self updateP4VCStatus]; _P4CONFIG_Set = NO; _p4ClientName = nil; } return self; } - (void)updateP4Status { _p4Path = [self getPathToCommandLineApp:(const char*)"which p4"]; _p4Installed = _p4Path != nil ? YES : NO; } - (void)updateP4VCStatus { _p4vcPath = [self getPathToCommandLineApp:(const char*)"which p4vc"]; _p4vcInstalled = _p4Path != nil ? YES : NO; } - (NSString*)getPathToCommandLineApp:(const char*)string { NSString* commandPath = nil; auto command = std::string(string); auto returnVal = exec(command.c_str()); if (returnVal.length()) { remove_newline(returnVal); commandPath = [NSString stringWithCString:returnVal.c_str() encoding:NSASCIIStringEncoding]; } return commandPath; } - (void)checkSettings { [self p4ClientSet]; } /** Precondition(s): - _p4Path and _userHomePathSettings must be non-nil and valid Postcondition(s): - Returns p4 command return string - Returns empty std::string on error */ - (std::string)execP4CommandForProjectAtPath:(std::string)p4Command workingPath:(const char*)workingPath { if (_p4Path == nil || _userHomePathSettings == nil) { return std::string(""); } auto userSettingsFile = [_userHomePathSettings cStringUsingEncoding:NSASCIIStringEncoding]; auto p4Path = [_p4Path cStringUsingEncoding:NSASCIIStringEncoding]; auto command = std::string(""); command = "source ~/"; command += userSettingsFile; command += "; "; command += "cd "; command += workingPath; command += "; "; command += p4Path; command += p4Command; return exec(command.c_str()); } - (BOOL)p4ClientSet { BOOL commandSuccess = NO; if (_p4Path == nil) { [self updateP4Status]; } if (_p4vcPath == nil) { [self updateP4VCStatus]; } if(_p4Path != nil) { auto projectURL = [P4XcodeHelper currentProjectURL]; if(projectURL != nil) { auto projectPath = [[projectURL path] cStringUsingEncoding:NSASCIIStringEncoding]; auto p4Command = std::string(" set | grep P4CLIENT"); auto returnVal = [self execP4CommandForProjectAtPath:p4Command workingPath:projectPath]; if (returnVal.length()) { _P4CONFIG_Set = YES; _p4ClientName = [NSString stringWithCString:returnVal.c_str() encoding:NSASCIIStringEncoding]; commandSuccess = YES; } } } if(commandSuccess == NO) { _P4CONFIG_Set = NO; auto noClientName = std::string("No client name defined"); _p4ClientName = [NSString stringWithCString:noClientName.c_str() encoding:NSASCIIStringEncoding]; } return commandSuccess; } - (NSString*)p4CheckOutCurrentFile { NSString* checkoutSuccess = nil; if (_p4Path == nil || _p4ClientName == nil) { [self checkSettings]; } if (_p4Path != nil && _p4ClientName != nil) { IDESourceCodeDocument *currentSourceCodeDocument = [P4XcodeHelper currentSourceCodeDocument]; NSString *filePath = [[currentSourceCodeDocument fileURL] path]; if (filePath) { NSString* fileName = [filePath lastPathComponent]; NSString* parentFolder = [filePath stringByDeletingLastPathComponent]; auto workingFolder = [parentFolder cStringUsingEncoding:NSASCIIStringEncoding]; auto p4Command = std::string(" edit "); p4Command += [fileName cStringUsingEncoding:NSASCIIStringEncoding]; auto returnVal = [self execP4CommandForProjectAtPath:p4Command workingPath:workingFolder]; checkoutSuccess = [NSString stringWithCString:returnVal.c_str() encoding:NSASCIIStringEncoding]; } } return checkoutSuccess; } - (NSString*)p4Add { NSString* addFileSuccess = nil; if (_p4Path == nil || _p4ClientName == nil) { [self checkSettings]; } if (_p4Path != nil && _p4ClientName != nil) { IDESourceCodeDocument *currentSourceCodeDocument = [P4XcodeHelper currentSourceCodeDocument]; NSString *filePath = [[currentSourceCodeDocument fileURL] path]; if (filePath) { NSString* parentFolder = [filePath stringByDeletingLastPathComponent]; NSString* fileName = [filePath lastPathComponent]; auto workingFolder = [parentFolder cStringUsingEncoding:NSASCIIStringEncoding]; auto p4Command = std::string(" add "); p4Command += [fileName cStringUsingEncoding:NSASCIIStringEncoding]; auto returnVal = [self execP4CommandForProjectAtPath:p4Command workingPath:workingFolder]; addFileSuccess = [NSString stringWithCString:returnVal.c_str() encoding:NSASCIIStringEncoding]; } } return addFileSuccess; } - (NSString*)p4Info { NSString* p4InfoResult = nil; if (_p4Path == nil) { [self checkSettings]; } if (_p4Path != nil) { IDESourceCodeDocument *currentSourceCodeDocument = [P4XcodeHelper currentSourceCodeDocument]; NSString *filePath = [[currentSourceCodeDocument fileURL] path]; if (filePath) { NSString* parentFolder = [filePath stringByDeletingLastPathComponent]; auto workingFolder = [parentFolder cStringUsingEncoding:NSASCIIStringEncoding]; auto p4Command = std::string(" info"); auto returnVal = [self execP4CommandForProjectAtPath:p4Command workingPath:workingFolder]; p4InfoResult = [NSString stringWithCString:returnVal.c_str() encoding:NSASCIIStringEncoding]; } } return p4InfoResult; } - (void)p4vcRevGraph { if (_p4vcPath == nil || _p4ClientName == nil) { [self checkSettings]; } if (_p4vcPath != nil && _p4ClientName != nil) { IDESourceCodeDocument *currentSourceCodeDocument = [P4XcodeHelper currentSourceCodeDocument]; NSString *filePath = [[currentSourceCodeDocument fileURL] path]; if (filePath) { std::string command(""); std::string returnVal(""); NSString* parentFolder = [filePath stringByDeletingLastPathComponent]; NSString* fileName = [filePath lastPathComponent]; command = "source ~/"; command += [_userHomePathSettings cStringUsingEncoding:NSASCIIStringEncoding]; command += "; cd "; command += [parentFolder cStringUsingEncoding:NSASCIIStringEncoding]; command += "; "; command += [_p4vcPath cStringUsingEncoding:NSASCIIStringEncoding]; command += " revgraph "; command += [fileName cStringUsingEncoding:NSASCIIStringEncoding]; returnVal = exec(command.c_str()); NSLog(@"Return value: %s\n", returnVal.c_str()); } } } - (void)p4vcTimeLapse { if (_p4vcPath == nil || _p4ClientName == nil) { [self checkSettings]; } if (_p4vcPath != nil && _p4ClientName != nil) { IDESourceCodeDocument *currentSourceCodeDocument = [P4XcodeHelper currentSourceCodeDocument]; NSString *filePath = [[currentSourceCodeDocument fileURL] path]; if (filePath) { std::string command(""); std::string returnVal(""); NSString* parentFolder = [filePath stringByDeletingLastPathComponent]; NSString* fileName = [filePath lastPathComponent]; command = "source ~/"; command += [_userHomePathSettings cStringUsingEncoding:NSASCIIStringEncoding]; command += "; cd "; command += [parentFolder cStringUsingEncoding:NSASCIIStringEncoding]; command += "; "; command += [_p4vcPath cStringUsingEncoding:NSASCIIStringEncoding]; command += " timelapse "; command += [fileName cStringUsingEncoding:NSASCIIStringEncoding]; returnVal = exec(command.c_str()); NSLog(@"Return value: %s\n", returnVal.c_str()); } } } @end
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#10 | 20141 | Jaime Rios | Merging using M_robc_apple-to_jaime_rios_XcodePerforcePlugin | ||
#9 | 16809 | Jaime Rios | Minor editing changes | ||
#8 | 16549 | Jaime Rios | Added debugging code to see paths exported by Xcode; modified MD readme file to include preferred location of p4 and p4vc binaries | ||
#7 | 15948 | Jaime Rios | Added p4vc submit functionality; violated rule 0; updated plist for xcode 7 uuid; fixed errors encountered by xcode related to optionals and interoperability with Obj-C++ code. | ||
#6 | 11740 | Jaime Rios | Updated readme text with additional known issues; refactored p4 revert function; added perforce icon to alert message. | ||
#5 | 11739 | Jaime Rios |
Merging //guest/matt_attaway/XcodePerforcePlugin/... to //guest/jaime_rios/XcodePerforcePlugin/... |
||
#4 | 11737 | Jaime Rios | Minor change to error checking in debug mode; updated readme document with information pertaining to how to set up settings for workspace and edited MD markup formating. | ||
#3 | 11733 | Jaime Rios | Refactored code to have more functionality within Swift code; fixed perforce connection bugs. | ||
#2 | 11714 | Jaime Rios | Added unit tests; fixed bugs found during testing; added Jon Reid's XcodeCoverage files http://qualitycoding.org/xcode-code-coverage/ modified project to produce code coverage reports. | ||
#1 | 11694 | Jaime Rios | Initial add of XcodePerforcePlugin project to guest depot. |