Skip to content

Commit

Permalink
Add a GitX:// protocol handler
Browse files Browse the repository at this point in the history
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
pieter committed Nov 1, 2008
1 parent b7645ec commit e232181
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 4 deletions.
4 changes: 4 additions & 0 deletions ApplicationController.m
Expand Up @@ -12,6 +12,7 @@
#import "PBRepositoryDocumentController.h"
#import "PBCLIProxy.h"
#import "PBServicesController.h"
#import "PBGitXProtocol.h"

@implementation ApplicationController
@synthesize cliProxy;
Expand All @@ -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];
Expand Down
22 changes: 21 additions & 1 deletion Documentation/CallingFromWebKit.txt
Expand Up @@ -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">
6 changes: 6 additions & 0 deletions GitX.xcodeproj/project.pbxproj
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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>"; };
Expand Down Expand Up @@ -410,6 +413,8 @@
F56244080E9684B0002B6C44 /* PBUnsortableTableHeader.m */,
F50A41210EBB875D00208746 /* PBNiceSplitView.h */,
F50A41220EBB875D00208746 /* PBNiceSplitView.m */,
F5FC41F20EBCBD4300191D80 /* PBGitXProtocol.h */,
F5FC41F30EBCBD4300191D80 /* PBGitXProtocol.m */,
);
name = Aux;
sourceTree = "<group>";
Expand Down Expand Up @@ -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;
};
Expand Down
24 changes: 24 additions & 0 deletions 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

79 changes: 79 additions & 0 deletions 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
4 changes: 4 additions & 0 deletions PBWebController.h
Expand Up @@ -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
29 changes: 26 additions & 3 deletions PBWebController.m
Expand Up @@ -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
{
Expand All @@ -25,6 +27,7 @@ - (void) awakeFromNib
finishedLoading = NO;
[view setUIDelegate:self];
[view setFrameLoadDelegate:self];
[view setResourceLoadDelegate:self];
[[view mainFrame] loadRequest:request];
}

Expand All @@ -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;
Expand Down Expand Up @@ -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];
Expand All @@ -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];
Expand Down

0 comments on commit e232181

Please sign in to comment.