Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add a GitX:// protocol handler

This allows to read in arbitrary blobs from the repository.
For more information, see the CallingFromWebKit.txt
document in the Documentation/ directory.
  • Loading branch information...
commit e232181faefd7e8639c28653de10f14d6b7c869e 1 parent b7645ec
@pieter pieter authored
View
4 ApplicationController.m
@@ -12,6 +12,7 @@
#import "PBRepositoryDocumentController.h"
#import "PBCLIProxy.h"
#import "PBServicesController.h"
+#import "PBGitXProtocol.h"
@implementation ApplicationController
@synthesize cliProxy;
@@ -34,6 +35,9 @@ - (ApplicationController*)init
- (void)registerServices
{
+ // Register URL
+ [NSURLProtocol registerClass:[PBGitXProtocol class]];
+
// Register the service class
PBServicesController *services = [[PBServicesController alloc] init];
[NSApp setServicesProvider:services];
View
22 Documentation/CallingFromWebKit.txt
@@ -78,4 +78,24 @@ async, which means that it doesn't matter if it takes a long time to run.
While you can have direct access to most objects, sometimes it is useful to
have an async task, for example if the operation can take a long time. Use
-this function to keep the UI responsive.
+this function to keep the UI responsive.
+
+Loading files from WebKit
+=========================
+
+All views that have a subclass of PBWebController set as ResourceLoadDelegate
+(this happens automatically if you assign a view to your controllers) gain
+access to the GitX:// protocol. This protocol allows you to load in blobs from
+the repository. The format is as follows:
+
+ GitX://REVISION/path/to/file
+
+Which means that revision can't have a path separator in it (so HEAD is valid,
+but pu/pb/fix_it is not). You also can't just pass on a blob oid. These things
+will probably be fixed in future revisions of the protocol.
+
+What this allows you to do, for instance, is to display images that have
+changed. For example, if you want to show the new file from a diff, you can
+use something like
+
+ <img src="GitX://HEAD:Images/new_file.png">
View
6 GitX.xcodeproj/project.pbxproj
@@ -68,6 +68,7 @@
F5E92A1B0E88550E00056E75 /* empty_file.png in Resources */ = {isa = PBXBuildFile; fileRef = F5E92A1A0E88550E00056E75 /* empty_file.png */; };
F5E92A230E88569500056E75 /* new_file.png in Resources */ = {isa = PBXBuildFile; fileRef = F5E92A220E88569500056E75 /* new_file.png */; };
F5EF8C8E0E9D4A5D0050906B /* PBWebController.m in Sources */ = {isa = PBXBuildFile; fileRef = F5EF8C8D0E9D4A5D0050906B /* PBWebController.m */; };
+ F5FC41F40EBCBD4300191D80 /* PBGitXProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FC41F30EBCBD4300191D80 /* PBGitXProtocol.m */; };
F5FE6C030EB13BC900F30D12 /* PBServicesController.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FE6C020EB13BC900F30D12 /* PBServicesController.m */; };
F5FF4E180E0829C20006317A /* PBGitRevList.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FF4E170E0829C20006317A /* PBGitRevList.m */; };
F5FF4E7A0E082E440006317A /* PBGitGrapher.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FF4E790E082E440006317A /* PBGitGrapher.m */; };
@@ -199,6 +200,8 @@
F5E92A220E88569500056E75 /* new_file.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = new_file.png; path = Images/new_file.png; sourceTree = "<group>"; };
F5EF8C8C0E9D4A5D0050906B /* PBWebController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBWebController.h; sourceTree = "<group>"; };
F5EF8C8D0E9D4A5D0050906B /* PBWebController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBWebController.m; sourceTree = "<group>"; };
+ F5FC41F20EBCBD4300191D80 /* PBGitXProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitXProtocol.h; sourceTree = "<group>"; };
+ F5FC41F30EBCBD4300191D80 /* PBGitXProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitXProtocol.m; sourceTree = "<group>"; };
F5FE6C010EB13BC900F30D12 /* PBServicesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBServicesController.h; sourceTree = "<group>"; };
F5FE6C020EB13BC900F30D12 /* PBServicesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBServicesController.m; sourceTree = "<group>"; };
F5FF4E160E0829C20006317A /* PBGitRevList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitRevList.h; sourceTree = "<group>"; };
@@ -410,6 +413,8 @@
F56244080E9684B0002B6C44 /* PBUnsortableTableHeader.m */,
F50A41210EBB875D00208746 /* PBNiceSplitView.h */,
F50A41220EBB875D00208746 /* PBNiceSplitView.m */,
+ F5FC41F20EBCBD4300191D80 /* PBGitXProtocol.h */,
+ F5FC41F30EBCBD4300191D80 /* PBGitXProtocol.m */,
);
name = Aux;
sourceTree = "<group>";
@@ -643,6 +648,7 @@
F5E424180EA3E4EB0046E362 /* PBWebDiffController.m in Sources */,
F5FE6C030EB13BC900F30D12 /* PBServicesController.m in Sources */,
F50A41230EBB875D00208746 /* PBNiceSplitView.m in Sources */,
+ F5FC41F40EBCBD4300191D80 /* PBGitXProtocol.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
24 PBGitXProtocol.h
@@ -0,0 +1,24 @@
+//
+// PBGitXProtocol.h
+// GitX
+//
+// Created by Pieter de Bie on 01-11-08.
+// Copyright 2008 Pieter de Bie. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import "PBGitRepository.h"
+
+@interface PBGitXProtocol : NSURLProtocol {
+ NSFileHandle *handle;
+}
+@end
+
+@interface NSURLRequest (PBGitXProtocol)
+@property (readonly) PBGitRepository *repository;
+@end
+
+@interface NSMutableURLRequest (PBGitXProtocol)
+@property (retain) PBGitRepository *repository;
+@end
+
View
79 PBGitXProtocol.m
@@ -0,0 +1,79 @@
+//
+// PBGitXProtocol.m
+// GitX
+//
+// Created by Pieter de Bie on 01-11-08.
+// Copyright 2008 Pieter de Bie. All rights reserved.
+//
+
+#import "PBGitXProtocol.h"
+
+
+@implementation PBGitXProtocol
+
++ (BOOL) canInitWithRequest:(NSURLRequest *)request
+{
+ return [[[request URL] scheme] isEqualToString:@"GitX"];
+}
+
++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
+{
+ return request;
+}
+
+-(void)startLoading
+{
+ NSURL *url = [[self request] URL];
+ PBGitRepository *repo = [[self request] repository];
+
+ if(!repo) {
+ [[self client] URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:nil]];
+ return;
+ }
+
+ NSString *specifier = [NSString stringWithFormat:@"%@:%@", [url host], [[url path] substringFromIndex:1]];
+ handle = [repo handleInWorkDirForArguments:[NSArray arrayWithObjects:@"cat-file", @"blob", specifier, nil]];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFinishFileLoad:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
+ [handle readToEndOfFileInBackgroundAndNotify];
+
+ NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[[self request] URL]
+ MIMEType:nil
+ expectedContentLength:-1
+ textEncodingName:nil];
+
+ [[self client] URLProtocol:self
+ didReceiveResponse:response
+ cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+}
+
+- (void) didFinishFileLoad:(NSNotification *)notification
+{
+ NSData *data = [[notification userInfo] valueForKey:NSFileHandleNotificationDataItem];
+ [[self client] URLProtocol:self didLoadData:data];
+ [[self client] URLProtocolDidFinishLoading:self];
+}
+
+- (void) stopLoading
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+@end
+
+@implementation NSURLRequest (PBGitXProtocol)
+
+- (PBGitRepository *) repository
+{
+ return [NSURLProtocol propertyForKey:@"PBGitRepository" inRequest:self];
+}
+@end
+
+@implementation NSMutableURLRequest (PBGitXProtocol)
+@dynamic repository;
+
+- (void) setRepository:(PBGitRepository *)repository
+{
+ [NSURLProtocol setProperty:repository forKey:@"PBGitRepository" inRequest:self];
+}
+
+@end
View
4 PBWebController.h
@@ -16,9 +16,13 @@
// For async git reading
NSMapTable *callbacks;
+
+ // For the repository access
+ IBOutlet id repository;
}
@property (retain) NSString *startFile;
+@property (retain) id repository;
- (WebScriptObject *) script;
@end
View
29 PBWebController.m
@@ -8,11 +8,13 @@
#import "PBWebController.h"
#import "PBGitRepository.h"
+#import "PBGitXProtocol.h"
+
#include <SystemConfiguration/SCNetworkReachability.h>
@implementation PBWebController
-@synthesize startFile;
+@synthesize startFile, repository;
- (void) awakeFromNib
{
@@ -25,6 +27,7 @@ - (void) awakeFromNib
finishedLoading = NO;
[view setUIDelegate:self];
[view setFrameLoadDelegate:self];
+ [view setResourceLoadDelegate:self];
[[view mainFrame] loadRequest:request];
}
@@ -50,6 +53,26 @@ - (void)webView:(WebView *)webView addMessageToConsole:(NSDictionary *)dictionar
NSLog(@"Error from webkit: %@", dictionary);
}
+- (NSURLRequest *)webView:(WebView *)sender
+ resource:(id)identifier
+ willSendRequest:(NSURLRequest *)request
+ redirectResponse:(NSURLResponse *)redirectResponse
+ fromDataSource:(WebDataSource *)dataSource
+{
+ if (!self.repository)
+ return request;
+
+ // TODO: Change this to canInitWithRequest
+ if ([[[request URL] scheme] isEqualToString:@"GitX"]) {
+ NSMutableURLRequest *newRequest = [request mutableCopy];
+ [newRequest setRepository:self.repository];
+ return newRequest;
+ }
+
+ return request;
+}
+
+
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
{
return NO;
@@ -81,7 +104,7 @@ - (BOOL) isReachable:(NSString *)hostname
#pragma mark Using async function from JS
-- (void) runCommand:(WebScriptObject *)arguments inRepository:(PBGitRepository *)repository callBack:(WebScriptObject *)callBack
+- (void) runCommand:(WebScriptObject *)arguments inRepository:(PBGitRepository *)repo callBack:(WebScriptObject *)callBack
{
// The JS bridge does not handle JS Arrays, even though the docs say it does. So, we convert it ourselves.
int length = [[arguments valueForKey:@"length"] intValue];
@@ -90,7 +113,7 @@ - (void) runCommand:(WebScriptObject *)arguments inRepository:(PBGitRepository *
for (i = 0; i < length; i++)
[realArguments addObject:[arguments webScriptValueAtIndex:i]];
- NSFileHandle *handle = [repository handleInWorkDirForArguments:realArguments];
+ NSFileHandle *handle = [repo handleInWorkDirForArguments:realArguments];
[callbacks setObject:callBack forKey:handle];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(JSRunCommandDone:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
[handle readToEndOfFileInBackgroundAndNotify];
Please sign in to comment.
Something went wrong with that request. Please try again.