P4Functionality.mm #1

  • //
  • guest/
  • jaime_rios/
  • XcodePerforcePlugin/
  • XcodePerforcePlugin/
  • P4Functionality.mm
  • View
  • Commits
  • Open Download .zip Download (10 KB)
// 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.