From d5c6b4068e74437c20d4e782238986f8ded7b585 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sun, 2 Mar 2014 16:00:30 +0100 Subject: [PATCH 01/15] Make the scripting generation separate since both gitx and GitX use it. --- GitX.xcodeproj/project.pbxproj | 72 +++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index 5301ed124..62f16c23d 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -6,6 +6,20 @@ objectVersion = 46; objects = { +/* Begin PBXAggregateTarget section */ + 4D3F252B18C37D2E000922D9 /* Generate Scripting Header */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 4D3F252C18C37D2E000922D9 /* Build configuration list for PBXAggregateTarget "Generate Scripting Header" */; + buildPhases = ( + 4D3F252F18C37D5A000922D9 /* Generate Scripting Header */, + ); + dependencies = ( + ); + name = "Generate Scripting Header"; + productName = "Generate Scripting Header"; + }; +/* End PBXAggregateTarget section */ + /* Begin PBXBuildFile section */ 0A6858C711F7EA8A00AC2BE4 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A6858C611F7EA8A00AC2BE4 /* CoreServices.framework */; }; 2682AABB1929140E00271A4D /* GTOID+JavaScript.m in Sources */ = {isa = PBXBuildFile; fileRef = 2682AABA1929140E00271A4D /* GTOID+JavaScript.m */; }; @@ -279,6 +293,20 @@ remoteGlobalIDString = 88F05A6B16011E5400B7AD1D; remoteInfo = ObjectiveGitTests; }; + 4D3F253018C37D9A000922D9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4D3F252B18C37D2E000922D9; + remoteInfo = "Generate Scripting Header"; + }; + 4D3F253218C37D9F000922D9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4D3F252B18C37D2E000922D9; + remoteInfo = "Generate Scripting Header"; + }; 551BF174112F3F3500265053 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -1051,11 +1079,11 @@ 8D11072E0486CEB800E47090 /* Frameworks */, F580E6BD0E73329C009E2D3F /* CopyFiles */, F5CF04A20EAE696C00D75C81 /* Copy HTML files */, - D81E15ED121CE83D00269E61 /* Scripting Bridge Header Script */, ); buildRules = ( ); dependencies = ( + 4D3F253118C37D9A000922D9 /* PBXTargetDependency */, 4A8F6B4A14A9B6B80002F4D7 /* PBXTargetDependency */, 4A68AD7114A00534006DE321 /* PBXTargetDependency */, 4A68AD7314A00534006DE321 /* PBXTargetDependency */, @@ -1078,6 +1106,7 @@ buildRules = ( ); dependencies = ( + 4D3F253318C37D9F000922D9 /* PBXTargetDependency */, 4A467EF01546D1F300F8902B /* PBXTargetDependency */, ); name = "cli tool"; @@ -1124,6 +1153,7 @@ 8D1107260486CEB800E47090 /* GitX */, 913D5E480E55644600CECEA2 /* cli tool */, 551BF110112F371800265053 /* gitx_askpasswd */, + 4D3F252B18C37D2E000922D9 /* Generate Scripting Header */, ); }; /* End PBXProject section */ @@ -1260,7 +1290,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - D81E15ED121CE83D00269E61 /* Scripting Bridge Header Script */ = { + 4D3F252F18C37D5A000922D9 /* Generate Scripting Header */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1268,14 +1298,13 @@ inputPaths = ( "$(SRCROOT)/GitX.sdef", ); - name = "Scripting Bridge Header Script "; + name = "Generate Scripting Header"; outputPaths = ( "$(SRCROOT)/GitX.h", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Build the scripting bridge header GitX.h if the GitX.sdef file changes\necho \"Trying to build scripting definitions from $CONFIGURATION_BUILD_DIR/GitX.app\"\nif [ -e \"$CONFIGURATION_BUILD_DIR/GitX.app\" ]; then\n\techo -n \"generating...\"\n\tsdef \"$CONFIGURATION_BUILD_DIR/GitX.app\" | sdp -fh --basename GitX\n\techo \" done.\"\nelse\n\techo \"warning: Scripting definitions weren't generated.\"\nfi"; - showEnvVarsInLog = 0; + shellScript = "# Build the scripting bridge header GitX.h if the GitX.sdef file changes\nsdp -fh --basename GitX $SRCROOT/GitX.sdef\n"; }; F5CF04A20EAE696C00D75C81 /* Copy HTML files */ = { isa = PBXShellScriptBuildPhase; @@ -1439,6 +1468,16 @@ name = MGScopeBar.framework; targetProxy = 4A8F6B4914A9B6B80002F4D7 /* PBXContainerItemProxy */; }; + 4D3F253118C37D9A000922D9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4D3F252B18C37D2E000922D9 /* Generate Scripting Header */; + targetProxy = 4D3F253018C37D9A000922D9 /* PBXContainerItemProxy */; + }; + 4D3F253318C37D9F000922D9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4D3F252B18C37D2E000922D9 /* Generate Scripting Header */; + targetProxy = 4D3F253218C37D9F000922D9 /* PBXContainerItemProxy */; + }; 551BF175112F3F3500265053 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 551BF110112F371800265053 /* gitx_askpasswd */; @@ -1607,6 +1646,20 @@ }; name = Release; }; + 4D3F252D18C37D2E000922D9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 4D3F252E18C37D2E000922D9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; 551BF113112F371800265053 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1680,6 +1733,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 4D3F252C18C37D2E000922D9 /* Build configuration list for PBXAggregateTarget "Generate Scripting Header" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4D3F252D18C37D2E000922D9 /* Debug */, + 4D3F252E18C37D2E000922D9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 551BF119112F373E00265053 /* Build configuration list for PBXNativeTarget "gitx_askpasswd" */ = { isa = XCConfigurationList; buildConfigurations = ( From db77353b4fd06111d6645d40550b822f650d0d69 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sun, 2 Mar 2014 16:09:57 +0100 Subject: [PATCH 02/15] Update the Core Suite. --- GitX.h | 25 ++++++++-- GitX.sdef | 137 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 144 insertions(+), 18 deletions(-) diff --git a/GitX.h b/GitX.h index e293d0e17..c3b3dc134 100644 --- a/GitX.h +++ b/GitX.h @@ -8,6 +8,19 @@ @class GitXApplication, GitXDocument, GitXWindow; +enum GitXSaveOptions { + GitXSaveOptionsYes = 'yes ' /* Save the file. */, + GitXSaveOptionsNo = 'no ' /* Do not save the file. */, + GitXSaveOptionsAsk = 'ask ' /* Ask the user whether or not to save the file. */ +}; +typedef enum GitXSaveOptions GitXSaveOptions; + +enum GitXPrintingErrorHandling { + GitXPrintingErrorHandlingStandard = 'lwst' /* Standard PostScript error handling */, + GitXPrintingErrorHandlingDetailed = 'lwdt' /* print a detailed report of PostScript errors */ +}; +typedef enum GitXPrintingErrorHandling GitXPrintingErrorHandling; + /* @@ -24,8 +37,9 @@ @property (readonly) BOOL frontmost; // Is this the active application? @property (copy, readonly) NSString *version; // The version number of the application. -- (void) open:(NSArray *)x; // Open a document. -- (void) quit; // Quit the application. +- (id) open:(id)x; // Open a document. +- (void) print:(id)x withProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. +- (void) quitSaving:(GitXSaveOptions)saving; // Quit the application. - (BOOL) exists:(id)x; // Verify that an object exists. - (void) showDiff:(NSString *)x; // Show the supplied diff output in a GitX window. - (void) initRepository:(NSURL *)x NS_RETURNS_NOT_RETAINED; // Create a git repository at the given filesystem URL. @@ -37,9 +51,11 @@ @interface GitXDocument : SBObject @property (copy, readonly) NSString *name; // Its name. +@property (readonly) BOOL modified; // Has it been modified since the last save? @property (copy, readonly) NSURL *file; // Its location on disk, if it has one. -- (void) close; // Close a document. +- (void) closeSaving:(GitXSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) printWithProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. - (void) delete; // Delete an object. - (void) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy an object. - (void) moveTo:(SBObject *)to; // Move an object to a new location. @@ -63,7 +79,8 @@ @property BOOL zoomed; // Is the window zoomed right now? @property (copy, readonly) GitXDocument *document; // The document whose contents are displayed in the window. -- (void) close; // Close a document. +- (void) closeSaving:(GitXSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) printWithProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. - (void) delete; // Delete an object. - (void) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy an object. - (void) moveTo:(SBObject *)to; // Move an object to a new location. diff --git a/GitX.sdef b/GitX.sdef index 445b9f0e1..c14c19e66 100644 --- a/GitX.sdef +++ b/GitX.sdef @@ -1,28 +1,117 @@ - - + - + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + @@ -31,12 +120,14 @@ + - + + @@ -47,12 +138,14 @@ - + + + @@ -70,7 +163,8 @@ - + + @@ -89,10 +183,13 @@ - + - + + + + @@ -102,12 +199,21 @@ + + + + + + + + + @@ -145,14 +251,17 @@ - - - + + + + + + + - From dfff7570367ae80ec5b33e8baad4a62ff85fb07f Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sun, 2 Mar 2014 18:10:57 +0100 Subject: [PATCH 03/15] Useless function. --- Classes/gitx.m | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Classes/gitx.m b/Classes/gitx.m index 701299675..24602690e 100644 --- a/Classes/gitx.m +++ b/Classes/gitx.m @@ -325,14 +325,6 @@ void handleGitXSearch(NSURL *repositoryURL, NSMutableArray *arguments) } -NSMutableArray *argumentsArray() -{ - NSMutableArray *arguments = [[[NSProcessInfo processInfo] arguments] mutableCopy]; - [arguments removeObjectAtIndex:0]; // url to executable path is not needed - - return arguments; -} - int main(int argc, const char** argv) { @autoreleasepool { @@ -352,9 +344,12 @@ int main(int argc, const char** argv) // gitx can be used to pipe diff output to be displayed in GitX if (!isatty(STDIN_FILENO) && fdopen(STDIN_FILENO, "r")) handleSTDINDiff(); - + + + NSMutableArray *arguments = [[[NSProcessInfo processInfo] arguments] mutableCopy]; + [arguments removeObjectAtIndex:0]; // url to executable path is not needed + // From this point, we require a working directory and the arguments - NSMutableArray *arguments = argumentsArray(); NSURL *wdURL = workingDirectoryURL(arguments); if (!wdURL) { From fe48930094f8319d37406d4797080c4c71f2863c Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sun, 2 Mar 2014 18:15:20 +0100 Subject: [PATCH 04/15] Beef up how `gitx` detects the working directory to use. --- Classes/gitx.m | 104 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 28 deletions(-) diff --git a/Classes/gitx.m b/Classes/gitx.m index 24602690e..1448d922a 100644 --- a/Classes/gitx.m +++ b/Classes/gitx.m @@ -11,7 +11,6 @@ #import "GitXScriptingConstants.h" #import "GitX.h" #import "PBHistorySearchController.h" -#import "GitRepoFinder.h" #pragma mark Commands handled locally @@ -283,46 +282,95 @@ void handleGitXSearch(NSURL *repositoryURL, NSMutableArray *arguments) #pragma mark - #pragma mark main - -#define kGitDirPrefix @"--git-dir=" +#define kGitDirPrefix @"--git-dir" NSURL *workingDirectoryURL(NSMutableArray *arguments) { - // path to git repository has been explicitly passed? - if ([arguments count] && [[arguments objectAtIndex:0] hasPrefix:kGitDirPrefix]) { - NSString *path = [[[arguments objectAtIndex:0] substringFromIndex:[kGitDirPrefix length]] stringByStandardizingPath]; + NSString *workingDirectory = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"]; + + // First check our arguments for a --git-dir option + for (NSUInteger i = 0; i < [arguments count]; i++) { + NSString *argument = [arguments objectAtIndex:i]; + NSString *path = nil; + + if (![argument hasPrefix:kGitDirPrefix]) { + // That's not a --git-dir argument, don't bother + continue; + } + + BOOL isInlinePath = NO; + if ([argument hasPrefix:kGitDirPrefix @"="]) { + // We're looking at a --git-dir=, extract the argument + path = [argument substringFromIndex:[kGitDirPrefix length] + 1]; + isInlinePath = YES; + } else { + // We're looking at a --git-dir [arg], next argument is our path + path = [arguments objectAtIndex:i + 1]; + } + + // We might be looking at a filesystem path, try to standardize it + if (!([path hasPrefix:@"/"] || [path hasPrefix:@"~"])) { + path = [workingDirectory stringByAppendingPathComponent:path]; + } + path = [path stringByStandardizingPath]; - // the path must exist and point to a directory + // The path must exist and point to a directory BOOL isDirectory = YES; - if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory] || !isDirectory) { - if (!isDirectory) - printf("Fatal: --git-dir path does not point to a directory.\n"); - else - printf("Fatal: --git-dir path does not exist.\n"); - printf("Cannot open git repository at path: '%s'\n", [path UTF8String]); + BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]; + if (!exists) { + printf("Fatal: --git-dir path does not exist.\n"); exit(2); + } else if (!isDirectory) { + printf("Fatal: --git-dir path does not point to a directory.\n"); + exit(2); + } else { + [arguments removeObjectAtIndex:i]; + if (!isInlinePath) { + [arguments removeObjectAtIndex:i]; + } + + // Create and return corresponding NSURL + NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES]; + if (!url) { + printf("Unable to create url to path: %s\n", [path UTF8String]); + exit(2); + } + + return url; } + } - // remove the git-dir argument - [arguments removeObjectAtIndex:0]; + // No --git-dir option, let's use the first thing that looks like a path + for (NSUInteger i = 0; i < [arguments count]; i++) { + NSString *path = [arguments objectAtIndex:i]; - // create and return corresponding NSURL - NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES]; - if (!url) { - printf("Unable to create url to path: %s\n", [path UTF8String]); - exit(2); - } + // We might be looking at a filesystem path, try to standardize it + if (!([path hasPrefix:@"/"] || [path hasPrefix:@"~"])) { + path = [workingDirectory stringByAppendingPathComponent:path]; + } + path = [path stringByStandardizingPath]; - return url; - } + // The path must exist and point to a directory + BOOL isDirectory = YES; + BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]; + if (exists && isDirectory) { + [arguments removeObjectAtIndex:i]; + + // Create and return corresponding NSURL + NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES]; + if (!url) { + printf("Unable to create url to path: %s\n", [path UTF8String]); + exit(2); + } - // otherwise, determine current working directory - NSString *pwd = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"]; + return url; + } - NSURL* pwdURL = [NSURL fileURLWithPath:pwd]; - NSURL* repoURL = [GitRepoFinder workDirForURL:pwdURL]; - return repoURL; + // Let's try our luck with the next argument + } + // Still no path found, let's default to our current working directory + return [NSURL fileURLWithPath:workingDirectory]; } int main(int argc, const char** argv) From c3bb10a44599a7c3b3854ea25523953df31d737c Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 12:44:52 +0100 Subject: [PATCH 05/15] Rewrite GitRepoFinder a little. Renamed to PBRepositoryFinder and cleaned up its methods. --- .../PBRepositoryDocumentController.m | 1 - Classes/git/PBGitRepository.m | 5 +- .../{GitRepoFinder.h => PBRepositoryFinder.h} | 4 +- Classes/git/PBRepositoryFinder.m | 83 +++++++++++++++++++ GitX.xcodeproj/project.pbxproj | 16 ++-- 5 files changed, 96 insertions(+), 13 deletions(-) rename Classes/git/{GitRepoFinder.h => PBRepositoryFinder.h} (73%) create mode 100644 Classes/git/PBRepositoryFinder.m diff --git a/Classes/Controllers/PBRepositoryDocumentController.m b/Classes/Controllers/PBRepositoryDocumentController.m index 980bc87a0..55c450228 100644 --- a/Classes/Controllers/PBRepositoryDocumentController.m +++ b/Classes/Controllers/PBRepositoryDocumentController.m @@ -11,7 +11,6 @@ #import "PBGitRevList.h" #import "PBEasyPipe.h" #import "PBGitBinary.h" -#import "GitRepoFinder.h" #import diff --git a/Classes/git/PBGitRepository.m b/Classes/git/PBGitRepository.m index 2ad0a6418..ec1fd8e23 100644 --- a/Classes/git/PBGitRepository.m +++ b/Classes/git/PBGitRepository.m @@ -21,7 +21,8 @@ #import "GitXScriptingConstants.h" #import "PBHistorySearchController.h" #import "PBGitRepositoryWatcher.h" -#import "GitRepoFinder.h" +#import "PBRepositoryFinder.h" +#import "PBGitSubmodule.h" #import "PBGitHistoryList.h" @@ -157,7 +158,7 @@ - (void)showWindows NSString *path = [[eventRecord paramDescriptorForKeyword:typeFileURL] stringValue]; if (path) { NSURL *workingDirectory = [NSURL URLWithString:path]; - if ([[GitRepoFinder gitDirForURL:workingDirectory] isEqual:[self fileURL]]) { + if ([[PBRepositoryFinder gitDirForURL:workingDirectory] isEqual:[self fileURL]]) { NSAppleEventDescriptor *argumentsList = [eventRecord paramDescriptorForKeyword:kGitXAEKeyArgumentsList]; [self handleGitXScriptingArguments:argumentsList inWorkingDirectory:workingDirectory]; diff --git a/Classes/git/GitRepoFinder.h b/Classes/git/PBRepositoryFinder.h similarity index 73% rename from Classes/git/GitRepoFinder.h rename to Classes/git/PBRepositoryFinder.h index 05b87cb5a..5c0d514a5 100644 --- a/Classes/git/GitRepoFinder.h +++ b/Classes/git/PBRepositoryFinder.h @@ -1,5 +1,5 @@ // -// GitRepoFinder.h +// PBRepositoryFinder.h // GitX // // Created by Rowan James on 13/11/2012. @@ -8,7 +8,7 @@ #import -@interface GitRepoFinder : NSObject +@interface PBRepositoryFinder : NSObject + (NSURL*)workDirForURL:(NSURL*)fileURL; + (NSURL*)gitDirForURL:(NSURL*)fileURL; diff --git a/Classes/git/PBRepositoryFinder.m b/Classes/git/PBRepositoryFinder.m new file mode 100644 index 000000000..19f608906 --- /dev/null +++ b/Classes/git/PBRepositoryFinder.m @@ -0,0 +1,83 @@ +// +// PBRepositoryFinder.m +// GitX +// +// Created by Rowan James on 13/11/2012. +// +// + +#import "PBRepositoryFinder.h" + +@implementation PBRepositoryFinder + ++ (NSURL *)workDirForURL:(NSURL *)fileURL; +{ + if (!fileURL.isFileURL) { + return nil; + } + + git_repository *repo = NULL; + git_repository_open_ext(&repo, fileURL.path.UTF8String, GIT_REPOSITORY_OPEN_CROSS_FS, NULL); + if (!repo) { + return NULL; + } + + const char *workdir = git_repository_workdir(repo); + NSURL *result = nil; + if (workdir) { + result = [NSURL fileURLWithPath:[NSString stringWithUTF8String:workdir]]; + } + + git_repository_free(repo); repo = nil; + return result; +} + ++ (NSURL *)gitDirForURL:(NSURL *)fileURL +{ + if (!fileURL.isFileURL) + { + return nil; + } + git_buf path_buffer = {NULL, 0, 0}; + int gitResult = git_repository_discover(&path_buffer, + [fileURL.path UTF8String], + GIT_REPOSITORY_OPEN_CROSS_FS, + nil); + + NSData *repoPathBuffer = nil; + if (path_buffer.ptr) { + repoPathBuffer = [NSData dataWithBytes:path_buffer.ptr length:path_buffer.asize]; + git_buf_free(&path_buffer); + } + + if (gitResult == GIT_OK && repoPathBuffer.length) + { + NSString* repoPath = [NSString stringWithUTF8String:repoPathBuffer.bytes]; + BOOL isDirectory; + if ([[NSFileManager defaultManager] fileExistsAtPath:repoPath + isDirectory:&isDirectory] && isDirectory) + { + NSURL* result = [NSURL fileURLWithPath:repoPath + isDirectory:isDirectory]; + return result; + } + } + return nil; +} + ++ (NSURL *)fileURLForURL:(NSURL *)inputURL +{ + NSURL* gitDir = [self gitDirForURL:inputURL]; + if (!gitDir) { + return nil; // not a Git directory at all + } + + NSURL *workDir = [self workDirForURL:inputURL]; + if (workDir) { + return workDir; // root of this working copy or deepest submodule + } + + return gitDir; // bare repo +} + +@end diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index 62f16c23d..c6bbfc80c 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -150,8 +150,8 @@ 4A8F6B4C14A9B6C90002F4D7 /* MGScopeBar.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A8F6B4714A9B6110002F4D7 /* MGScopeBar.framework */; }; 4A90A73514A9D24300D0DA02 /* GitX.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 4A90A73414A9D24300D0DA02 /* GitX.sdef */; }; 4AAAFDDA14A010DD008FC9B5 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A68AD6714A0050F006DE321 /* Sparkle.framework */; }; - 4AB057E31652652000DE751D /* GitRepoFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AB057E21652652000DE751D /* GitRepoFinder.m */; }; - 4AB057E41652652000DE751D /* GitRepoFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AB057E21652652000DE751D /* GitRepoFinder.m */; }; + 4AB057E31652652000DE751D /* PBRepositoryFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AB057E21652652000DE751D /* PBRepositoryFinder.m */; }; + 4AB057E41652652000DE751D /* PBRepositoryFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AB057E21652652000DE751D /* PBRepositoryFinder.m */; }; 4AB71FF814B7EDD400F1DFFC /* RJModalRepoSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AB71FF714B7EDD400F1DFFC /* RJModalRepoSheet.m */; }; 4AC42F7D16BFBADA007CCA3A /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A40159814067B7A00DB9C07 /* AppKit.framework */; }; 551BF176112F3F4B00265053 /* gitx_askpasswd in Resources */ = {isa = PBXBuildFile; fileRef = 551BF111112F371800265053 /* gitx_askpasswd */; }; @@ -559,8 +559,8 @@ 4A90A72C14A9C12F00D0DA02 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = SOURCE_ROOT; }; 4A90A73314A9D1E800D0DA02 /* GitX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GitX.h; sourceTree = SOURCE_ROOT; }; 4A90A73414A9D24300D0DA02 /* GitX.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = GitX.sdef; sourceTree = SOURCE_ROOT; }; - 4AB057E11652652000DE751D /* GitRepoFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GitRepoFinder.h; sourceTree = ""; }; - 4AB057E21652652000DE751D /* GitRepoFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GitRepoFinder.m; sourceTree = ""; }; + 4AB057E11652652000DE751D /* PBRepositoryFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBRepositoryFinder.h; sourceTree = ""; }; + 4AB057E21652652000DE751D /* PBRepositoryFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBRepositoryFinder.m; sourceTree = ""; usesTabs = 0; }; 4AB71FF614B7EDD400F1DFFC /* RJModalRepoSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RJModalRepoSheet.h; sourceTree = ""; }; 4AB71FF714B7EDD400F1DFFC /* RJModalRepoSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RJModalRepoSheet.m; sourceTree = ""; }; 551BF111112F371800265053 /* gitx_askpasswd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gitx_askpasswd; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -933,8 +933,8 @@ 4A5D768414A9A9CC00DF6C68 /* PBGitXProtocol.m */, 643952751603EF9B00BB7AFF /* PBGitSVSubmoduleItem.h */, 643952761603EF9B00BB7AFF /* PBGitSVSubmoduleItem.m */, - 4AB057E11652652000DE751D /* GitRepoFinder.h */, - 4AB057E21652652000DE751D /* GitRepoFinder.m */, + 4AB057E11652652000DE751D /* PBRepositoryFinder.h */, + 4AB057E21652652000DE751D /* PBRepositoryFinder.m */, 2682AAB91929140E00271A4D /* GTOID+JavaScript.h */, 2682AABA1929140E00271A4D /* GTOID+JavaScript.m */, ); @@ -1424,7 +1424,7 @@ 4A5D777514A9AEB000DF6C68 /* PBSourceViewRemote.m in Sources */, 4AB71FF814B7EDD400F1DFFC /* RJModalRepoSheet.m in Sources */, 643952771603EF9B00BB7AFF /* PBGitSVSubmoduleItem.m in Sources */, - 4AB057E31652652000DE751D /* GitRepoFinder.m in Sources */, + 4AB057E31652652000DE751D /* PBRepositoryFinder.m in Sources */, 4A2125A417C0C78A00B5B582 /* NSColor+RGB.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1436,7 +1436,7 @@ 4A5D773A14A9A9F600DF6C68 /* gitx.m in Sources */, 4A5D773C14A9AA2F00DF6C68 /* PBGitBinary.m in Sources */, 4A5D773D14A9AA3700DF6C68 /* PBEasyPipe.m in Sources */, - 4AB057E41652652000DE751D /* GitRepoFinder.m in Sources */, + 4AB057E41652652000DE751D /* PBRepositoryFinder.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From d45a73bfa224f4f26cbd8e75794fd7c9f629d634 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 13:05:56 +0100 Subject: [PATCH 06/15] More work on working directory detection. Here are the steps it goes through : 1. If `--git-dir` is provided and points to a repository, return that. If it's not a repo, inform the user and exit. Handles `gitx --git-dir=path` or `gitx --git-dir path`. 2. Loops through the rest of the arguments for something that resolves to a repository. Handles `gitx ..`, `gitx path/to/submodule`. 3. Try to find a repository starting from the current working directory. Handles `gitx`. 4. Inform user that we couldn't find a repository and exit. I'm not yet sure about step 2, because it somewhat conflicts with the current behavior if there's a directory with the same name as a branch. You'd end up resolving `branchname` as a repository (either as itself if it is one, or as your CWD) and cause the GitX window to reopen instead of filtering on the `branch name` branch. --- Classes/gitx.m | 91 ++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/Classes/gitx.m b/Classes/gitx.m index 1448d922a..3681931b3 100644 --- a/Classes/gitx.m +++ b/Classes/gitx.m @@ -8,6 +8,7 @@ #import "PBGitBinary.h" #import "PBEasyPipe.h" +#import "PBRepositoryFinder.h" #import "GitXScriptingConstants.h" #import "GitX.h" #import "PBHistorySearchController.h" @@ -284,6 +285,26 @@ void handleGitXSearch(NSURL *repositoryURL, NSMutableArray *arguments) #define kGitDirPrefix @"--git-dir" +NSURL *checkWorkingDirectoryPath(NSString *path) +{ + NSString *workingDirectory = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"]; + + // We might be looking at a filesystem path, try to standardize it + if (!([path hasPrefix:@"/"] || [path hasPrefix:@"~"])) { + path = [workingDirectory stringByAppendingPathComponent:path]; + } + path = [path stringByStandardizingPath]; + + // The path must exist and point to a directory + BOOL isDirectory = YES; + BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]; + if (!exists || !isDirectory) { + return nil; + } + + return [NSURL fileURLWithPath:path]; +} + NSURL *workingDirectoryURL(NSMutableArray *arguments) { NSString *workingDirectory = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"]; @@ -308,69 +329,45 @@ void handleGitXSearch(NSURL *repositoryURL, NSMutableArray *arguments) path = [arguments objectAtIndex:i + 1]; } - // We might be looking at a filesystem path, try to standardize it - if (!([path hasPrefix:@"/"] || [path hasPrefix:@"~"])) { - path = [workingDirectory stringByAppendingPathComponent:path]; - } - path = [path stringByStandardizingPath]; + NSURL *url = checkWorkingDirectoryPath(path); - // The path must exist and point to a directory - BOOL isDirectory = YES; - BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]; - if (!exists) { - printf("Fatal: --git-dir path does not exist.\n"); - exit(2); - } else if (!isDirectory) { - printf("Fatal: --git-dir path does not point to a directory.\n"); + // Let's check that this points to a repository + url = [PBRepositoryFinder workDirForURL:url]; + if (!url) { + NSLog(@"Fatal: --git-dir \"%@\" does not look like a valid repository.", argument); exit(2); - } else { - [arguments removeObjectAtIndex:i]; - if (!isInlinePath) { - [arguments removeObjectAtIndex:i]; - } - - // Create and return corresponding NSURL - NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES]; - if (!url) { - printf("Unable to create url to path: %s\n", [path UTF8String]); - exit(2); - } + } - return url; + // Valid --git-dir found, let's drop parsed arguments + [arguments removeObjectAtIndex:i]; + if (!isInlinePath) { + [arguments removeObjectAtIndex:i]; } + + return url; } // No --git-dir option, let's use the first thing that looks like a path for (NSUInteger i = 0; i < [arguments count]; i++) { NSString *path = [arguments objectAtIndex:i]; - // We might be looking at a filesystem path, try to standardize it - if (!([path hasPrefix:@"/"] || [path hasPrefix:@"~"])) { - path = [workingDirectory stringByAppendingPathComponent:path]; - } - path = [path stringByStandardizingPath]; - - // The path must exist and point to a directory - BOOL isDirectory = YES; - BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]; - if (exists && isDirectory) { - [arguments removeObjectAtIndex:i]; + // Stop processing arguments willy-nilly, we'll just give the CWD a spin. + // The user might be trying todo a `gitx log -- path` or something. + if ([path isEqualToString:@"--"]) break; - // Create and return corresponding NSURL - NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES]; - if (!url) { - printf("Unable to create url to path: %s\n", [path UTF8String]); - exit(2); - } + // Let's check that path and find the closest repository + NSURL *url = checkWorkingDirectoryPath(path); + url = [PBRepositoryFinder fileURLForURL:url]; + if (!url) continue; // Invalid path, let's ignore it - return url; - } + // Valid repository found, lets' drop parsed argument + [arguments removeObjectAtIndex:i]; - // Let's try our luck with the next argument + return url; } // Still no path found, let's default to our current working directory - return [NSURL fileURLWithPath:workingDirectory]; + return [PBRepositoryFinder fileURLForURL:[NSURL fileURLWithPath:workingDirectory]]; } int main(int argc, const char** argv) From 6f7cf0eb8d6ba54ebd42c777c1a8a912c1284139 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 14:15:51 +0100 Subject: [PATCH 07/15] Create an Info.plist file for `gitx` and put it in the binary. --- GitX.entitlements | 19 ++++++++++++++++++- GitX.xcodeproj/project.pbxproj | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/GitX.entitlements b/GitX.entitlements index 0c67376eb..a37421b9f 100644 --- a/GitX.entitlements +++ b/GitX.entitlements @@ -1,5 +1,22 @@ - + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + net.phere.gitx-cli + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${CURRENT_PROJECT_VERSION} + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index c6bbfc80c..b37abfddf 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -563,6 +563,7 @@ 4AB057E21652652000DE751D /* PBRepositoryFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBRepositoryFinder.m; sourceTree = ""; usesTabs = 0; }; 4AB71FF614B7EDD400F1DFFC /* RJModalRepoSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RJModalRepoSheet.h; sourceTree = ""; }; 4AB71FF714B7EDD400F1DFFC /* RJModalRepoSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RJModalRepoSheet.m; sourceTree = ""; }; + 4DC1853818E6F93200E8DB8F /* Info-gitx.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-gitx.plist"; sourceTree = ""; }; 551BF111112F371800265053 /* gitx_askpasswd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gitx_askpasswd; sourceTree = BUILT_PRODUCTS_DIR; }; 643952751603EF9B00BB7AFF /* PBGitSVSubmoduleItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitSVSubmoduleItem.h; sourceTree = ""; }; 643952761603EF9B00BB7AFF /* PBGitSVSubmoduleItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitSVSubmoduleItem.m; sourceTree = ""; }; @@ -720,6 +721,7 @@ 4A5D75B514A9A90500DF6C68 /* source.css */, 4A5D75B714A9A90500DF6C68 /* UpdateKey.pem */, 4A5D75B914A9A90500DF6C68 /* XIBs */, + 4DC1853818E6F93200E8DB8F /* Info-gitx.plist */, ); path = Resources; sourceTree = ""; @@ -1692,8 +1694,10 @@ 913D5E4B0E55644600CECEA2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CREATE_INFOPLIST_SECTION_IN_BINARY = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GitX_Prefix.pch; + INFOPLIST_FILE = "Resources/Info-gitx.plist"; INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = gitx; SKIP_INSTALL = YES; @@ -1703,8 +1707,10 @@ 913D5E4C0E55644600CECEA2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CREATE_INFOPLIST_SECTION_IN_BINARY = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GitX_Prefix.pch; + INFOPLIST_FILE = "Resources/Info-gitx.plist"; INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = gitx; SKIP_INSTALL = YES; From 04c86ed77b9bf996e0fe660ad242beec83889b31 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 14:16:40 +0100 Subject: [PATCH 08/15] Use the version from `gitx` Info.plist. --- Classes/gitx.m | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Classes/gitx.m b/Classes/gitx.m index 3681931b3..46162b71a 100644 --- a/Classes/gitx.m +++ b/Classes/gitx.m @@ -87,13 +87,8 @@ void usage(char const *programName) void version_info() { - NSString *version = [[[NSBundle bundleForClass:[PBGitBinary class]] infoDictionary] valueForKey:@"CFBundleVersion"]; - NSString *gitVersion = [[[NSBundle bundleForClass:[PBGitBinary class]] infoDictionary] valueForKey:@"CFBundleGitVersion"]; - printf("GitX version %s (%s)\n", [version UTF8String], [gitVersion UTF8String]); - if ([PBGitBinary path]) - printf("Using git found at %s, version %s\n", [[PBGitBinary path] UTF8String], [[PBGitBinary version] UTF8String]); - else - printf("GitX cannot find a git binary\n"); + NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + printf("GitX version %s\n", [version UTF8String]); exit(1); } From 0908ab6eee8bcad762e8f871b3709c4d4440e837 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 14:18:47 +0100 Subject: [PATCH 09/15] Add AppleScript support to perform diffs and use that in `gitx`. This allows us to stop depending on `git` for the CLI tool. --- Classes/Util/NSApplication+GitXScripting.m | 29 +++++++++++++-- Classes/gitx.m | 42 ++++------------------ GitX.h | 1 + GitX.sdef | 13 +++++++ GitX.xcodeproj/project.pbxproj | 4 --- 5 files changed, 47 insertions(+), 42 deletions(-) diff --git a/Classes/Util/NSApplication+GitXScripting.m b/Classes/Util/NSApplication+GitXScripting.m index 4b190748c..dd54d9cb5 100644 --- a/Classes/Util/NSApplication+GitXScripting.m +++ b/Classes/Util/NSApplication+GitXScripting.m @@ -11,8 +11,8 @@ #import "PBDiffWindowController.h" #import "PBGitRepository.h" #import "PBCloneRepositoryPanel.h" - -#import +#import "PBGitBinary.h" +#import "PBEasyPipe.h" @implementation NSApplication (GitXScripting) @@ -27,6 +27,31 @@ - (void)showDiffScriptCommand:(NSScriptCommand *)command } } +- (void)performDiffScriptCommand:(NSScriptCommand *)command +{ + NSURL *repositoryURL = command.directParameter; + NSArray *diffOptions = command.arguments[@"diffOptions"]; + + diffOptions = [[NSArray arrayWithObjects:@"diff", @"--no-ext-diff", nil] arrayByAddingObjectsFromArray:diffOptions]; + + int retValue = 1; + NSString *diffOutput = [PBEasyPipe outputForCommand:[PBGitBinary path] withArgs:diffOptions inDir:[repositoryURL path] retValue:&retValue]; + if (retValue) { + // if there is an error diffOutput should have the error output from git + if (diffOutput) + NSLog(@"%s\n", [diffOutput UTF8String]); + else + NSLog(@"Invalid diff command [%d]\n", retValue); + return; + } + + if (diffOutput) { + PBDiffWindowController *diffController = [[PBDiffWindowController alloc] initWithDiff:diffOutput]; + [diffController showWindow:self]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + } +} + - (void)initRepositoryScriptCommand:(NSScriptCommand *)command { NSError *error = nil; diff --git a/Classes/gitx.m b/Classes/gitx.m index 46162b71a..2da5c8512 100644 --- a/Classes/gitx.m +++ b/Classes/gitx.m @@ -6,8 +6,6 @@ // Copyright 2008 __MyCompanyName__. All rights reserved. // -#import "PBGitBinary.h" -#import "PBEasyPipe.h" #import "PBRepositoryFinder.h" #import "GitXScriptingConstants.h" #import "GitX.h" @@ -92,17 +90,6 @@ void version_info() exit(1); } -void git_path() -{ - if (![PBGitBinary path]) - exit(101); - - NSString *path = [[PBGitBinary path] stringByDeletingLastPathComponent]; - printf("%s\n", [path UTF8String]); - exit(0); -} - - #pragma mark - #pragma mark Commands sent to GitX @@ -121,21 +108,8 @@ void handleSTDINDiff() void handleDiffWithArguments(NSURL *repositoryURL, NSArray *arguments) { - arguments = [[NSArray arrayWithObjects:@"diff", @"--no-ext-diff", nil] arrayByAddingObjectsFromArray:arguments]; - - int retValue = 1; - NSString *diffOutput = [PBEasyPipe outputForCommand:[PBGitBinary path] withArgs:arguments inDir:[repositoryURL path] retValue:&retValue]; - if (retValue) { - // if there is an error diffOutput should have the error output from git - if (diffOutput) - printf("%s\n", [diffOutput UTF8String]); - else - printf("Invalid diff command [%d]\n", retValue); - exit(3); - } - GitXApplication *gitXApp = [SBApplication applicationWithBundleIdentifier:kGitXBundleIdentifier]; - [gitXApp showDiff:diffOutput]; + [gitXApp performDiffIn:repositoryURL withOptions:arguments]; exit(0); } @@ -372,15 +346,11 @@ int main(int argc, const char** argv) usage(argv[0]); if (argc >= 2 && (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-v"))) version_info(); - if (argc >= 2 && !strcmp(argv[1], "--git-path")) - git_path(); - - // From here on everything needs to access git, so make sure it's installed - if (![PBGitBinary path]) { - printf("%s\n", [[PBGitBinary notFoundError] cStringUsingEncoding:NSUTF8StringEncoding]); - exit(2); - } - + if (argc >= 2 && !strcmp(argv[1], "--git-path")) { + printf("gitx now uses libgit2 to work."); + exit(1); + } + // gitx can be used to pipe diff output to be displayed in GitX if (!isatty(STDIN_FILENO) && fdopen(STDIN_FILENO, "r")) handleSTDINDiff(); diff --git a/GitX.h b/GitX.h index c3b3dc134..ecde8d7a3 100644 --- a/GitX.h +++ b/GitX.h @@ -42,6 +42,7 @@ typedef enum GitXPrintingErrorHandling GitXPrintingErrorHandling; - (void) quitSaving:(GitXSaveOptions)saving; // Quit the application. - (BOOL) exists:(id)x; // Verify that an object exists. - (void) showDiff:(NSString *)x; // Show the supplied diff output in a GitX window. +- (void) performDiffIn:(NSURL *)x withOptions:(NSArray *)withOptions; // Perform a diff operation in a repository. - (void) initRepository:(NSURL *)x NS_RETURNS_NOT_RETAINED; // Create a git repository at the given filesystem URL. - (void) cloneRepository:(NSString *)x to:(NSURL *)to isBare:(BOOL)isBare; // Clone a repository. diff --git a/GitX.sdef b/GitX.sdef index c14c19e66..53be7d866 100644 --- a/GitX.sdef +++ b/GitX.sdef @@ -269,9 +269,19 @@ + + + + + + + + + + @@ -296,6 +306,9 @@ + + + diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index b37abfddf..ddf2e8cb7 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -139,8 +139,6 @@ 4A5D773914A9A9CC00DF6C68 /* PBSourceViewItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5D76DF14A9A9CC00DF6C68 /* PBSourceViewItem.m */; }; 4A5D773A14A9A9F600DF6C68 /* gitx.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5D768614A9A9CC00DF6C68 /* gitx.m */; }; 4A5D773B14A9A9F900DF6C68 /* gitx_askpasswd_main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5D768714A9A9CC00DF6C68 /* gitx_askpasswd_main.m */; }; - 4A5D773C14A9AA2F00DF6C68 /* PBGitBinary.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5D764F14A9A9CC00DF6C68 /* PBGitBinary.m */; }; - 4A5D773D14A9AA3700DF6C68 /* PBEasyPipe.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5D76B214A9A9CC00DF6C68 /* PBEasyPipe.m */; }; 4A5D777314A9AEB000DF6C68 /* PBSourceViewAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5D776D14A9AEB000DF6C68 /* PBSourceViewAction.m */; }; 4A5D777414A9AEB000DF6C68 /* PBSourceViewBadge.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5D776F14A9AEB000DF6C68 /* PBSourceViewBadge.m */; }; 4A5D777514A9AEB000DF6C68 /* PBSourceViewRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5D777214A9AEB000DF6C68 /* PBSourceViewRemote.m */; }; @@ -1436,8 +1434,6 @@ buildActionMask = 2147483647; files = ( 4A5D773A14A9A9F600DF6C68 /* gitx.m in Sources */, - 4A5D773C14A9AA2F00DF6C68 /* PBGitBinary.m in Sources */, - 4A5D773D14A9AA3700DF6C68 /* PBEasyPipe.m in Sources */, 4AB057E41652652000DE751D /* PBRepositoryFinder.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From 8b85e4a47ae5df924216ef92bb7f6483ce7238a5 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 17:14:04 +0100 Subject: [PATCH 10/15] Catch the exceptions NSTask has a tendency to throw. --- Classes/Util/PBEasyPipe.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Classes/Util/PBEasyPipe.m b/Classes/Util/PBEasyPipe.m index 1cdd7cbcb..76bdc7056 100644 --- a/Classes/Util/PBEasyPipe.m +++ b/Classes/Util/PBEasyPipe.m @@ -93,8 +93,14 @@ + (NSString*) outputForCommand:(NSString *) cmd [inHandle writeData:[input dataUsingEncoding:NSUTF8StringEncoding]]; [inHandle closeFile]; } - - [task launch]; + + @try { + [task launch]; + } + @catch (NSException *exception) { + if (ret) *ret = -1; + return nil; + } NSData* data = [handle readDataToEndOfFile]; NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; From ac0f40694ece44b083c39ee1647a82783df554a4 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 19:10:08 +0100 Subject: [PATCH 11/15] Open repositories through AppleEvents. --- Classes/Controllers/ApplicationController.m | 15 ++++++++++ Classes/gitx.m | 32 ++------------------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/Classes/Controllers/ApplicationController.m b/Classes/Controllers/ApplicationController.m index 8225ab685..9242d56bd 100644 --- a/Classes/Controllers/ApplicationController.m +++ b/Classes/Controllers/ApplicationController.m @@ -7,6 +7,7 @@ // #import "ApplicationController.h" +#import "PBRepositoryDocumentController.h" #import "PBGitRevisionCell.h" #import "PBGitWindowController.h" #import "PBServicesController.h" @@ -67,6 +68,20 @@ - (void)registerServices } } +- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename { + NSURL *repository = [NSURL fileURLWithPath:filename]; + NSError *error = nil; + NSDocument *doc = [[PBRepositoryDocumentController sharedDocumentController] openDocumentWithContentsOfURL:repository + display:YES + error:&error]; + if (!doc) { + NSLog(@"Error opening repository \"%@\": %@", repository.path, error); + return NO; + } + + return YES; +} + - (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender { if(!started || [[[NSDocumentController sharedDocumentController] documents] count]) diff --git a/Classes/gitx.m b/Classes/gitx.m index 2da5c8512..879e2c44a 100644 --- a/Classes/gitx.m +++ b/Classes/gitx.m @@ -116,35 +116,9 @@ void handleDiffWithArguments(NSURL *repositoryURL, NSArray *arguments) void handleOpenRepository(NSURL *repositoryURL, NSMutableArray *arguments) { - // if there are command line arguments send them to GitX through an Apple Event - // the recordDescriptor will be stored in keyAEPropData inside the openDocument or openApplication event - NSAppleEventDescriptor *recordDescriptor = nil; - if ([arguments count]) { - recordDescriptor = [NSAppleEventDescriptor recordDescriptor]; - - NSAppleEventDescriptor *listDescriptor = [NSAppleEventDescriptor listDescriptor]; - uint listIndex = 1; // AppleEvent list descriptor's are one based - for (NSString *argument in arguments) - [listDescriptor insertDescriptor:[NSAppleEventDescriptor descriptorWithString:argument] atIndex:listIndex++]; - - [recordDescriptor setParamDescriptor:listDescriptor forKeyword:kGitXAEKeyArgumentsList]; - - // this is used as a double check in GitX - NSAppleEventDescriptor *url = [NSAppleEventDescriptor descriptorWithString:[repositoryURL absoluteString]]; - [recordDescriptor setParamDescriptor:url forKeyword:typeFileURL]; - } - - // use NSWorkspace to open GitX and send the arguments - // this allows the repository document to modify itself before it shows it's GUI - BOOL didOpenURLs = [[NSWorkspace sharedWorkspace] openURLs:[NSArray arrayWithObject:repositoryURL] - withAppBundleIdentifier:kGitXBundleIdentifier - options:0 - additionalEventParamDescriptor:recordDescriptor - launchIdentifiers:NULL]; - if (!didOpenURLs) { - printf("Unable to open GitX.app\n"); - exit(2); - } + GitXApplication *gitXApp = [SBApplication applicationWithBundleIdentifier:kGitXBundleIdentifier]; + [gitXApp open:repositoryURL]; + return; } void handleInit(NSURL *repositoryURL) From 56f7e18497a7bd6a27e6b5d2773085a36285a440 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 23:39:47 +0100 Subject: [PATCH 12/15] Move `-workingDirectory` and provide an URL-based replacement. --- Classes/git/PBGitRepository.m | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/Classes/git/PBGitRepository.m b/Classes/git/PBGitRepository.m index ec1fd8e23..405e9380c 100644 --- a/Classes/git/PBGitRepository.m +++ b/Classes/git/PBGitRepository.m @@ -216,6 +216,15 @@ - (NSURL *)gitURL { return self.gtRepo.gitDirectoryURL; } +- (NSURL *)workingDirectoryURL { + return self.gtRepo.fileURL; +} + +- (NSString *)workingDirectory +{ + return self.workingDirectoryURL.path; +} + - (void)forceUpdateRevisions { [revisionList forceUpdate]; @@ -567,20 +576,6 @@ - (void) readCurrentBranch self.currentBranch = [self addBranch: [self headRef]]; } -- (NSString *) workingDirectory -{ - const char* workdir = git_repository_workdir(self.gtRepo.git_repository); - if (workdir) - { - NSString* result = [[NSString stringWithUTF8String:workdir] stringByStandardizingPath]; - return result; - } - else - { - return self.fileURL.path; - } -} - #pragma mark Remotes - (NSArray *) remotes From b2d837c7eaa3cae2583573fd21580e1dff7a0e10 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 23:41:09 +0100 Subject: [PATCH 13/15] Add open arguments to our AppleScript dictionary. Note that I'm not really fond of it, I'd prefer having real AppleScript arguments over passing a bunch of strings. But I'm not sure our CLI syntax is "strict" enough. --- Classes/gitx.m | 4 ++-- GitX.h | 1 + GitX.sdef | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Classes/gitx.m b/Classes/gitx.m index 879e2c44a..e27046a1b 100644 --- a/Classes/gitx.m +++ b/Classes/gitx.m @@ -114,10 +114,10 @@ void handleDiffWithArguments(NSURL *repositoryURL, NSArray *arguments) exit(0); } -void handleOpenRepository(NSURL *repositoryURL, NSMutableArray *arguments) +void handleOpenRepository(NSURL *repositoryURL, NSArray *arguments) { GitXApplication *gitXApp = [SBApplication applicationWithBundleIdentifier:kGitXBundleIdentifier]; - [gitXApp open:repositoryURL]; + [gitXApp open:repositoryURL withOptions:arguments]; return; } diff --git a/GitX.h b/GitX.h index ecde8d7a3..276e7e7bc 100644 --- a/GitX.h +++ b/GitX.h @@ -41,6 +41,7 @@ typedef enum GitXPrintingErrorHandling GitXPrintingErrorHandling; - (void) print:(id)x withProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. - (void) quitSaving:(GitXSaveOptions)saving; // Quit the application. - (BOOL) exists:(id)x; // Verify that an object exists. +- (id) open:(id)x withOptions:(NSArray *)withOptions; // Open a document. - (void) showDiff:(NSString *)x; // Show the supplied diff output in a GitX window. - (void) performDiffIn:(NSURL *)x withOptions:(NSArray *)withOptions; // Perform a diff operation in a repository. - (void) initRepository:(NSURL *)x NS_RETURNS_NOT_RETAINED; // Create a git repository at the given filesystem URL. diff --git a/GitX.sdef b/GitX.sdef index 53be7d866..e8ffbdb33 100644 --- a/GitX.sdef +++ b/GitX.sdef @@ -265,6 +265,22 @@ + + + + + + + + + + + + + + + + From feccc27f43426ef48a5d890455a879999568bb58 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 29 Mar 2014 23:45:33 +0100 Subject: [PATCH 14/15] Rewrite the Cocoa Scripting side of things so that `gitx` arguments actually work. Also, cleanup the weird `inWorkingDirectory:` arguments. We're the repository, we know where work from, thanks ;-). --- Classes/git/PBGitRepository.m | 52 +++++++++++++---------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/Classes/git/PBGitRepository.m b/Classes/git/PBGitRepository.m index 405e9380c..61dbacc66 100644 --- a/Classes/git/PBGitRepository.m +++ b/Classes/git/PBGitRepository.m @@ -149,21 +149,17 @@ - (void)makeWindowControllers // if the repository is already open then this is also a good place to catch the event as the window is about to be brought forward - (void)showWindows { - NSAppleEventDescriptor *currentAppleEvent = [[NSAppleEventManager sharedAppleEventManager] currentAppleEvent]; + NSScriptCommand *command = [NSScriptCommand currentCommand]; - if (currentAppleEvent) { - NSAppleEventDescriptor *eventRecord = [currentAppleEvent paramDescriptorForKeyword:keyAEPropData]; + if (command) { + NSURL *repoURL = [command directParameter]; // on app launch there may be many repositories opening, so double check that this is the right repo - NSString *path = [[eventRecord paramDescriptorForKeyword:typeFileURL] stringValue]; - if (path) { - NSURL *workingDirectory = [NSURL URLWithString:path]; - if ([[PBRepositoryFinder gitDirForURL:workingDirectory] isEqual:[self fileURL]]) { - NSAppleEventDescriptor *argumentsList = [eventRecord paramDescriptorForKeyword:kGitXAEKeyArgumentsList]; - [self handleGitXScriptingArguments:argumentsList inWorkingDirectory:workingDirectory]; - - // showWindows may be called more than once during app launch so remove the CLI data after we handle the event - [currentAppleEvent removeDescriptorWithKeyword:keyAEPropData]; + if (repoURL) { + repoURL = [PBRepositoryFinder gitDirForURL:repoURL]; + if ([repoURL isEqual:self.gitURL]) { + NSArray *arguments = command.arguments[@"openOptions"]; + [self handleGitXScriptingArguments:arguments]; } } } @@ -951,7 +947,7 @@ - (BOOL) deleteRef:(PBGitRef *)ref #pragma mark GitX Scripting -- (void)handleRevListArguments:(NSArray *)arguments inWorkingDirectory:(NSURL *)workingDirectory +- (void)handleRevListArguments:(NSArray *)arguments { if (![arguments count]) return; @@ -963,13 +959,13 @@ - (void)handleRevListArguments:(NSArray *)arguments inWorkingDirectory:(NSURL *) PBGitRef *refArgument = [self refForName:[arguments lastObject]]; if (refArgument) { revListSpecifier = [[PBGitRevSpecifier alloc] initWithRef:refArgument]; - revListSpecifier.workingDirectory = workingDirectory; + revListSpecifier.workingDirectory = self.workingDirectoryURL; } } if (!revListSpecifier) { revListSpecifier = [[PBGitRevSpecifier alloc] initWithParameters:arguments]; - revListSpecifier.workingDirectory = workingDirectory; + revListSpecifier.workingDirectory = self.workingDirectoryURL; } self.currentBranch = [self addBranch:revListSpecifier]; @@ -977,7 +973,7 @@ - (void)handleRevListArguments:(NSArray *)arguments inWorkingDirectory:(NSURL *) [self.windowController showHistoryView:self]; } -- (void)handleBranchFilterEventForFilter:(PBGitXBranchFilterType)filter additionalArguments:(NSMutableArray *)arguments inWorkingDirectory:(NSURL *)workingDirectory +- (void)handleBranchFilterEventForFilter:(PBGitXBranchFilterType)filter additionalArguments:(NSArray *)arguments { self.currentBranchFilter = filter; [PBGitDefaults setShowStageView:NO]; @@ -985,23 +981,13 @@ - (void)handleBranchFilterEventForFilter:(PBGitXBranchFilterType)filter addition // treat any additional arguments as a rev-list specifier if ([arguments count] > 1) { - [arguments removeObjectAtIndex:0]; - [self handleRevListArguments:arguments inWorkingDirectory:workingDirectory]; + arguments = [arguments subarrayWithRange:NSMakeRange(1, arguments.count)]; + [self handleRevListArguments:arguments]; } } -- (void)handleGitXScriptingArguments:(NSAppleEventDescriptor *)argumentsList inWorkingDirectory:(NSURL *)workingDirectory +- (void)handleGitXScriptingArguments:(NSArray *)arguments { - NSMutableArray *arguments = [NSMutableArray array]; - uint argumentsIndex = 1; // AppleEvent list descriptor's are one based - while(1) { - NSAppleEventDescriptor *arg = [argumentsList descriptorAtIndex:argumentsIndex++]; - if (arg) - [arguments addObject:[arg stringValue]]; - else - break; - } - if (![arguments count]) return; @@ -1014,22 +1000,22 @@ - (void)handleGitXScriptingArguments:(NSAppleEventDescriptor *)argumentsList inW } if ([firstArgument isEqualToString:@"--all"]) { - [self handleBranchFilterEventForFilter:kGitXAllBranchesFilter additionalArguments:arguments inWorkingDirectory:workingDirectory]; + [self handleBranchFilterEventForFilter:kGitXAllBranchesFilter additionalArguments:arguments]; return; } if ([firstArgument isEqualToString:@"--local"]) { - [self handleBranchFilterEventForFilter:kGitXLocalRemoteBranchesFilter additionalArguments:arguments inWorkingDirectory:workingDirectory]; + [self handleBranchFilterEventForFilter:kGitXLocalRemoteBranchesFilter additionalArguments:arguments]; return; } if ([firstArgument isEqualToString:@"--branch"]) { - [self handleBranchFilterEventForFilter:kGitXSelectedBranchFilter additionalArguments:arguments inWorkingDirectory:workingDirectory]; + [self handleBranchFilterEventForFilter:kGitXSelectedBranchFilter additionalArguments:arguments]; return; } // if the argument is not a known command then treat it as a rev-list specifier - [self handleRevListArguments:arguments inWorkingDirectory:workingDirectory]; + [self handleRevListArguments:arguments]; } // for the scripting bridge From 78f0906d15a6f665f0e83289eec481720ac4d94f Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sun, 30 Mar 2014 00:19:26 +0100 Subject: [PATCH 15/15] Rename `init repository` to `create repository`. This is to prevent `sdp` from inserting `NS_RETURNS_NOT_RETAINED` and triggering a warning. The old name is still there, as an hidden synonym. --- Classes/gitx.m | 2 +- GitX.h | 2 +- GitX.sdef | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Classes/gitx.m b/Classes/gitx.m index e27046a1b..720080173 100644 --- a/Classes/gitx.m +++ b/Classes/gitx.m @@ -124,7 +124,7 @@ void handleOpenRepository(NSURL *repositoryURL, NSArray *arguments) void handleInit(NSURL *repositoryURL) { GitXApplication *gitXApp = [SBApplication applicationWithBundleIdentifier:kGitXBundleIdentifier]; - [gitXApp initRepository:repositoryURL]; + [gitXApp createRepository:repositoryURL]; exit(0); } diff --git a/GitX.h b/GitX.h index 276e7e7bc..a41de291a 100644 --- a/GitX.h +++ b/GitX.h @@ -44,7 +44,7 @@ typedef enum GitXPrintingErrorHandling GitXPrintingErrorHandling; - (id) open:(id)x withOptions:(NSArray *)withOptions; // Open a document. - (void) showDiff:(NSString *)x; // Show the supplied diff output in a GitX window. - (void) performDiffIn:(NSURL *)x withOptions:(NSArray *)withOptions; // Perform a diff operation in a repository. -- (void) initRepository:(NSURL *)x NS_RETURNS_NOT_RETAINED; // Create a git repository at the given filesystem URL. +- (void) createRepository:(NSURL *)x; // Create a git repository at the given filesystem URL. - (void) cloneRepository:(NSString *)x to:(NSURL *)to isBare:(BOOL)isBare; // Clone a repository. @end diff --git a/GitX.sdef b/GitX.sdef index e8ffbdb33..7f4fd4188 100644 --- a/GitX.sdef +++ b/GitX.sdef @@ -294,8 +294,10 @@ - - + + +