[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/vampirewalk/ObjectGraph-Xcode/master/ObjectGraph/ObjectGraph.m [Back]  [Original]

//
//  ObjectGraph.m
//  ObjectGraph
//
//  Created by vampirewalk on 2015/1/13.
//  Copyright (c) 2015 mocacube. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.

#import "ObjectGraph.h"
#import "VWKShellHandler.h"
#import "VWKWorkspaceManager.h"
#import "VWKProject.h"

static ObjectGraph *sharedPlugin;

static NSString *BIN_PATH = @"/bin";
static NSString *USER_BIN_PATH = @"/usr/bin";
static NSString *USER_LOCAL_BIN_PATH = @"/usr/local/bin";

static NSString *PYTHON_EXECUTABLE = @"python";
static NSString *GRAPHVIZ_EXECUTABLE = @"dot";
static NSString *MOVE_EXECUTABLE = @"mv";
static NSString *OPEN_EXECUTABLE = @"open";

typedef void(^TaskBlock)(NSTask *t, NSString *standardOutputString, NSString *standardErrorString);

@interface ObjectGraph()
@property (nonatomic, strong, readwrite) NSBundle *bundle;
@property (nonatomic, strong) NSMenuItem *drawObjectGraphItem;
@property (nonatomic, strong) NSMenuItem *pathItem;
@property (nonatomic, copy) NSString *sourceCodePath;
@property (nonatomic, copy) TaskBlock getGraphvizExecutablePathBlock;
@property (nonatomic, copy) TaskBlock convertToPDFBlock;
@property (nonatomic, copy) TaskBlock movePDFFileBlock;
@property (nonatomic, copy) TaskBlock moveDOTFileBlock;
@property (nonatomic, copy) TaskBlock openBlock;

@end

@implementation ObjectGraph

+ (void)pluginDidLoad:(NSBundle *)plugin
{
    static dispatch_once_t onceToken;
    NSString *currentApplicationName = [[NSBundle mainBundle] infoDictionary][@"CFBundleName"];
    if ([currentApplicationName isEqual:@"Xcode"]) {
        dispatch_once(&onceToken, ^{
            sharedPlugin = [[self alloc] initWithBundle:plugin];
        });
    }
}

+ (instancetype)sharedPlugin
{
    return sharedPlugin;
}

+ (NSBundle *)pluginBundle
{
    return [NSBundle bundleForClass:self];
}

- (id)initWithBundle:(NSBundle *)plugin
{
    if (self = [super init]) {
        // reference to plugin's bundle, for resource access
        self.bundle = plugin;
        
        [self setDefaultSourceCodePathPath];
        
        [self setupGetGraphvizExecutablePathBlock];
        [self setupConvertToPDFBlock];
        [self setupMovePDFFileBlock];
        [self setupMoveDOTFileBlock];
        [self setupOpenBlock];
        
        
        // Create menu items, initialize UI, etc.
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self addMenuItems];
        }];
    }
    return self;
}

- (void)setDefaultSourceCodePathPath
{
    VWKProject *project = [VWKProject projectForKeyWindow];
    self.sourceCodePath = project.directoryPath;
}


#pragma mark - Menu

- (void)addMenuItems
{
    NSMenuItem *topMenuItem = [[NSApp mainMenu] itemWithTitle:@"Product"];
    if (topMenuItem) {
        NSMenuItem *objectGraphMenu = [[NSMenuItem alloc] initWithTitle:@"ObjectGraph" action:nil keyEquivalent:@""];
        objectGraphMenu.submenu = [[NSMenu alloc] initWithTitle:@"ObjectGraph"];
        
        self.drawObjectGraphItem = [[NSMenuItem alloc] initWithTitle:@"Draw Object Graph" action:@selector(drawObjectGraph) keyEquivalent:@""];
        [self.drawObjectGraphItem setTarget:self];
        
        
        self.pathItem = [[NSMenuItem alloc] initWithTitle:@"Set Source Code PATH..." action:@selector(selectPath) keyEquivalent:@""];
        [self.pathItem setTarget:self];
        
        [[objectGraphMenu submenu] addItem:self.drawObjectGraphItem];
        [[objectGraphMenu submenu] addItem:self.pathItem];
        
        
        [[topMenuItem submenu] insertItem:objectGraphMenu atIndex:[topMenuItem.submenu indexOfItemWithTitle:@"Build For"]];
    }
}

#pragma mark - Menu Actions

// Sample Action, for menu item:
- (void)drawObjectGraph
{
    if([self isValidSourceCodePath])
    {
        self.sourceCodePath = self.projectPath;
    }
    
    NSString *dotFileScriptPath = [[ObjectGraph pluginBundle] pathForResource:@"objc_dep" ofType:@"py"];
    if (dotFileScriptPath.length) {
        [VWKShellHandler runShellCommand:[USER_BIN_PATH stringByAppendingPathComponent:PYTHON_EXECUTABLE]
                                withArgs:@[dotFileScriptPath, _sourceCodePath, @"-o", self.dotFileName]
                               directory:_sourceCodePath
                              completion:self.getGraphvizExecutablePathBlock];
    }
}

- (void)selectPath
{
    NSOpenPanel *oPanel = [NSOpenPanel openPanel];
    [oPanel setCanChooseDirectories:YES];
    [oPanel setCanChooseFiles:NO];
    if ([oPanel runModal] == NSModalResponseOK) {
        NSString *projPath = [[[oPanel URLs] objectAtIndex:0] path];
        self.sourceCodePath = projPath;
    }
}

#pragma mark - Private Method

- (NSString *)dotFileName
{
    VWKProject *project = [VWKProject projectForKeyWindow];
    NSString *dotFileName = [project.projectName stringByAppendingPathExtension:@"dot"];
    return dotFileName;
}

- (NSString *)pdfFileName
{
    VWKProject *project = [VWKProject projectForKeyWindow];
    NSString *pdfFileName = [project.projectName stringByAppendingPathExtension:@"pdf"];
    return pdfFileName;
}

- (NSString *)projectPath
{
    VWKProject *project = [VWKProject projectForKeyWindow];
    NSString *projectPath = project.directoryPath;
    return projectPath;
}

- (BOOL)isValidSourceCodePath
{
    NSFileManager *manager = [NSFileManager defaultManager];
    return _sourceCodePath == nil || ![manager fileExistsAtPath:_sourceCodePath];
}

- (void)setupGetGraphvizExecutablePathBlock
{
    NSDictionary *environmentDict = [[NSProcessInfo processInfo] environment];
    NSString *shellString = [environmentDict objectForKey:@"SHELL"];
    
    NSArray *args = @[@"-l",
                      @"-c",
                      @"which dot", //Assuming git is the launch path you want to run
                      ];
    __weak __typeof(&*self)weakSelf = self;
    self.getGraphvizExecutablePathBlock = ^(NSTask *t,
                               NSString *standardOutputString,
                               NSString *standardErrorString)
    {
        __strong __typeof(&*weakSelf)strongSelf = weakSelf;
        [VWKShellHandler runShellCommand:shellString
                                withArgs:args
                               directory:strongSelf.sourceCodePath
                              completion:strongSelf.convertToPDFBlock];
    };
}

- (void)setupConvertToPDFBlock
{
    __weak __typeof(&*self)weakSelf = self;
    self.convertToPDFBlock = ^(NSTask *t,
                               NSString *standardOutputString,
                               NSString *standardErrorString){
        __strong __typeof(&*weakSelf)strongSelf = weakSelf;
        if (standardOutputString.length > 0) {
            NSString *GRAPHVIZ_EXECUTABLE_PATH = [standardOutputString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
            [VWKShellHandler runShellCommand:GRAPHVIZ_EXECUTABLE_PATH
                                    withArgs:@[@"-Tpdf", strongSelf.dotFileName, @"-o", strongSelf.pdfFileName]
                                   directory:strongSelf.sourceCodePath
                                  completion:strongSelf.movePDFFileBlock];
        }
    };
}

- (void)setupMovePDFFileBlock
{
    __weak __typeof(&*self)weakSelf = self;
    self.movePDFFileBlock = ^(NSTask *t,
                              NSString *standardOutputString,
                              NSString *standardErrorString){
        __strong __typeof(&*weakSelf)strongSelf = weakSelf;
        [VWKShellHandler runShellCommand:[BIN_PATH stringByAppendingPathComponent:MOVE_EXECUTABLE]
                                withArgs:@[strongSelf.pdfFileName, strongSelf.projectPath]
                               directory:strongSelf.sourceCodePath
                              completion:strongSelf.moveDOTFileBlock];
    };
}

- (void)setupMoveDOTFileBlock
{
    __weak __typeof(&*self)weakSelf = self;
    self.moveDOTFileBlock = ^(NSTask *t,
                              NSString *standardOutputString,
                              NSString *standardErrorString){
        __strong __typeof(&*weakSelf)strongSelf = weakSelf;
        [VWKShellHandler runShellCommand:[BIN_PATH stringByAppendingPathComponent:MOVE_EXECUTABLE]
                                withArgs:@[strongSelf.dotFileName, strongSelf.projectPath]
                               directory:strongSelf.sourceCodePath
                              completion:strongSelf.openBlock];
    };
}

- (void)setupOpenBlock
{
    __weak __typeof(&*self)weakSelf = self;
    self.openBlock = ^(NSTask *t,
                       NSString *standardOutputString,
                       NSString *standardErrorString){
        __strong __typeof(&*weakSelf)strongSelf = weakSelf;
        [VWKShellHandler runShellCommand:[USER_BIN_PATH stringByAppendingPathComponent:OPEN_EXECUTABLE]
                                withArgs:@[strongSelf.pdfFileName]
                               directory:strongSelf.projectPath
                              completion:nil];
    };
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end

Web Proxy Viewer  |  New URL  |  Original Page