├── .gitignore ├── bg.png ├── .DS_Store ├── icon.png ├── server.png ├── test.png ├── Default.png ├── octocat.png ├── rssicon.png ├── servericon.png ├── Git ├── runTests.m ├── ObjGitTest.h ├── ObjGitTest.m ├── NSDataCompression.h ├── ObjGitTree.h ├── ObjGitObject.h ├── ObjGit.h ├── ObjGitObject.m ├── ObjGitCommit.h ├── ObjGitTree.m ├── NSDataCompression.m ├── ObjGitServerHandler.h ├── ObjGitCommit.m ├── ObjGit.m └── ObjGitServerHandler.m ├── GitTest.h ├── GitTest.m ├── main.m ├── ProjectDetailViewController.h ├── ProjectController.h ├── ProjectViewController.h ├── ServerViewController.h ├── CommitDetailViewController.h ├── Picker.h ├── CommitsViewController.h ├── Info.plist ├── TODO ├── LICENSE ├── ProjectController.m ├── Networking ├── TCPServer.h ├── BrowserViewController.h ├── TCPServer.m └── BrowserViewController.m ├── ServerViewController.m ├── Prefix.pch ├── ProjectViewController.m ├── AppController.h ├── ProjectDetailViewController.m ├── Picker.m ├── AppController.m ├── CommitsViewController.m ├── CommitDetailViewController.m └── iGitHub.xcodeproj └── project.pbxproj /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | iGitHub.xcodeproj/schacon.* 3 | 4 | -------------------------------------------------------------------------------- /bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/bg.png -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/.DS_Store -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/icon.png -------------------------------------------------------------------------------- /server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/server.png -------------------------------------------------------------------------------- /test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/test.png -------------------------------------------------------------------------------- /Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/Default.png -------------------------------------------------------------------------------- /octocat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/octocat.png -------------------------------------------------------------------------------- /rssicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/rssicon.png -------------------------------------------------------------------------------- /servericon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/igithub/master/servericon.png -------------------------------------------------------------------------------- /Git/runTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // runTests.m 3 | // iGitHub 4 | // 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | NSLog(@"sup"); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /GitTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // GitTest.h 3 | // iGitHub 4 | // 5 | 6 | #import 7 | 8 | 9 | @interface GitTest : SenTestCase { 10 | 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Git/ObjGitTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitTest.h 3 | // ObjGit 4 | // 5 | 6 | #import 7 | 8 | @interface ObjGitTest : SenTestCase { 9 | 10 | } 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /GitTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // GitTest.m 3 | // iGitHub 4 | // 5 | // Created by Scott Chacon on 9/25/08. 6 | // Copyright 2008 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "GitTest.h" 10 | 11 | 12 | @implementation GitTest 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | 5 | #import 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | NSAutoreleasePool* pool = [NSAutoreleasePool new]; 10 | 11 | UIApplicationMain(argc, argv, nil, @"AppController"); 12 | 13 | [pool release]; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /Git/ObjGitTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitTest.m 3 | // ObjGit 4 | // 5 | 6 | #import 7 | 8 | @interface ObjGitTest : SenTestCase { } 9 | @end 10 | 11 | @implementation ObjGitTest 12 | 13 | - (void) testSomething { 14 | STAssertNotNil(@"hi", @"something cool"); 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Git/NSDataCompression.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDataCompression.h 3 | // ObjGit 4 | // 5 | // thankfully borrowed from the Etoile framework 6 | // 7 | 8 | #include 9 | 10 | @interface NSData (Compression) 11 | 12 | - (NSData *) compressedData; 13 | - (NSData *) decompressedData; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ProjectDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProjectDetailViewController.h 3 | // iGitHub 4 | // 5 | 6 | #import 7 | #import "ObjGit.h" 8 | 9 | @interface ProjectDetailViewController : UITableViewController { 10 | ObjGit *detailItem; 11 | } 12 | 13 | @property (nonatomic, retain) ObjGit *detailItem; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ProjectController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProjectController.h 3 | // iGitHub 4 | // 5 | 6 | #import 7 | 8 | @interface ProjectController : NSObject { 9 | NSMutableArray *list; 10 | } 11 | 12 | - (void)readProjects:(NSString *)projectPath; 13 | - (unsigned)countOfList; 14 | - (id)objectInListAtIndex:(unsigned)theIndex; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ProjectViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProjectViewController.h 3 | // iGitHub 4 | // 5 | 6 | #import 7 | #import "ProjectController.h" 8 | 9 | @interface ProjectViewController : UITableViewController { 10 | ProjectController *projectController; 11 | } 12 | 13 | @property (nonatomic, retain) ProjectController *projectController; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ServerViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ServerViewController.h 3 | // iGitHub 4 | // 5 | // Created by Scott Chacon on 9/30/08. 6 | // Copyright 2008 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface ServerViewController : UIViewController { 13 | UILabel* serverNameLabel; 14 | } 15 | 16 | @property (nonatomic, retain) UILabel* serverNameLabel; 17 | 18 | - (void)setServerName:(NSString *)string; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Git/ObjGitTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitTree.h 3 | // ObjGit 4 | // 5 | 6 | #import 7 | #import "ObjGitObject.h" 8 | 9 | @interface ObjGitTree : NSObject { 10 | NSArray *treeEntries; 11 | ObjGitObject *gitObject; 12 | } 13 | 14 | @property(copy, readwrite) NSArray *treeEntries; 15 | @property(assign, readwrite) ObjGitObject *gitObject; 16 | 17 | - (id) initFromGitObject:(ObjGitObject *)object; 18 | - (void) parseContent; 19 | - (void) logObject; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /CommitDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CommitDetailViewController.h 3 | // iGitHub 4 | // 5 | // Created by Scott Chacon on 9/29/08. 6 | // Copyright 2008 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ObjGit.h" 11 | #import "ObjGitCommit.h" 12 | 13 | @interface CommitDetailViewController : UITableViewController { 14 | ObjGit *gitRepo; 15 | ObjGitCommit *gitCommit; 16 | } 17 | 18 | @property (nonatomic, retain) ObjGit *gitRepo; 19 | @property (nonatomic, retain) ObjGitCommit *gitCommit; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Picker.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: Picker.h 4 | Abstract: 5 | A view that displays both the currently advertised game name and a list of 6 | other games 7 | available on the local network (discovered & displayed by 8 | BrowserViewController). 9 | 10 | */ 11 | 12 | #import 13 | #import "BrowserViewController.h" 14 | 15 | @interface Picker : UIView { 16 | 17 | @private 18 | UILabel* _gameNameLabel; 19 | BrowserViewController* _bvc; 20 | } 21 | 22 | @property (nonatomic, assign) id delegate; 23 | @property (nonatomic, copy) NSString* gameName; 24 | 25 | - (id)initWithFrame:(CGRect)frame type:(NSString *)type; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /CommitsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CommitsViewController.h 3 | // iGitHub 4 | // 5 | 6 | #import 7 | #import "ObjGit.h" 8 | 9 | @interface CommitsViewController : UITableViewController { 10 | ObjGit *gitRepo; 11 | NSString *gitRef; 12 | NSString *gitSha; 13 | NSMutableArray *commitList; 14 | } 15 | 16 | @property (nonatomic, retain) ObjGit *gitRepo; 17 | @property (nonatomic, retain) NSString *gitRef; 18 | @property (nonatomic, retain) NSString *gitSha; 19 | @property (nonatomic, retain) NSMutableArray *commitList; 20 | 21 | - (UITableViewCell *)tableviewCellWithReuseIdentifier:(NSString *)identifier; 22 | - (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Git/ObjGitObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitObject.h 3 | // ObjGit 4 | // 5 | 6 | #import 7 | 8 | @interface ObjGitObject : NSObject { 9 | NSString* sha; 10 | NSInteger size; 11 | NSString* type; 12 | NSString* contents; 13 | char* rawContents; 14 | int rawContentLen; 15 | NSData* raw; 16 | } 17 | 18 | @property(copy, readwrite) NSString *sha; 19 | @property(assign, readwrite) NSInteger size; 20 | @property(copy, readwrite) NSString *type; 21 | @property(copy, readwrite) NSString *contents; 22 | @property(assign, readwrite) char *rawContents; 23 | @property(assign, readwrite) int rawContentLen; 24 | @property(copy, readwrite) NSData *raw; 25 | 26 | - (id) initFromRaw:(NSData *)rawData withSha:(NSString *)shaValue; 27 | - (void) parseRaw; 28 | - (NSData *) inflateRaw:(NSData *)rawData; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | icon.png 13 | CFBundleIdentifier 14 | com.yourcompany.${PRODUCT_NAME:identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundlePackageType 18 | APPL 19 | CFBundleVersion 20 | 1.0 21 | UIRequiresPersistentWiFi 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | ToDo List 3 | ==================================== 4 | 5 | * flick up/down to browse commits 6 | 7 | * status bar (when clones/fetches are happening) 8 | 9 | * about page - who did this 10 | 11 | * how to page 12 | 13 | * sharing screen - so people can see how to clone 14 | 15 | * delete a repo 16 | 17 | * public / private repos 18 | 19 | * commit key for private repos 20 | 21 | 22 | 23 | GitHub Features 24 | ==================================== 25 | 26 | * github user/pass login 27 | 28 | * a "search github" feature 29 | 30 | * fork/clone a github project 31 | 32 | * send a pull request 33 | 34 | * add a list of remotes of people that forked you 35 | 36 | 37 | 38 | Implementation Get-Back-Tos 39 | ==================================== 40 | 41 | * second fetches break 42 | 43 | * read/write blob data from disk rather than memory to handle objects > 100M 44 | 45 | * doesn't save/check saved delta objects 46 | 47 | * won't handle multi-depth refs 'chacon/master', etc 48 | 49 | * doesn't handle ofs-deltas, but the client shouldn't be sending them 50 | 51 | * doesn't keep objects in packs -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2008 Scott Chacon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Git/ObjGit.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGit.h 3 | // ObjGit 4 | // 5 | 6 | //#import 7 | //#import 8 | //#include 9 | 10 | #import 11 | #import "ObjGitObject.h" 12 | 13 | @interface ObjGit : NSObject { 14 | NSString* gitDirectory; 15 | NSString* gitName; 16 | } 17 | 18 | @property(copy, readwrite) NSString *gitDirectory; 19 | @property(copy, readwrite) NSString *gitName; 20 | 21 | - (BOOL) openRepo:(NSString *)dirPath; 22 | - (BOOL) ensureGitPath; 23 | - (void) initGitRepo; 24 | - (NSArray *) getAllRefs; 25 | 26 | - (NSString *) writeObject:(NSData *)objectData withType:(NSString *)type withSize:(int)size; 27 | - (void) updateRef:(NSString *)refName toSha:(NSString *)toSha; 28 | 29 | - (NSMutableArray *) getCommitsFromSha:(NSString *)shaValue withLimit:(int)commitSize; 30 | - (NSString *) getLooseObjectPathBySha:(NSString *)shaValue; 31 | - (BOOL) hasObject: (NSString *)sha1; 32 | - (ObjGitObject *) getObjectFromSha:(NSString *)sha1; 33 | 34 | + (int) isAlpha:(unsigned char)n ; 35 | + (int) gitUnpackHex:(const unsigned char *)rawsha fillSha:(char *)sha1; 36 | + (int) gitPackHex:(const char *)sha1 fillRawSha:(unsigned char *)rawsha; 37 | 38 | @end -------------------------------------------------------------------------------- /Git/ObjGitObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitObject.m 3 | // ObjGit 4 | // 5 | 6 | #import "ObjGitObject.h" 7 | #import "NSDataCompression.h" 8 | 9 | @implementation ObjGitObject 10 | 11 | @synthesize sha; 12 | @synthesize size; 13 | @synthesize type; 14 | @synthesize contents; 15 | @synthesize raw; 16 | @synthesize rawContents; 17 | @synthesize rawContentLen; 18 | 19 | - (id) initFromRaw:(NSData *)rawData withSha:(NSString *)shaValue 20 | { 21 | self = [super init]; 22 | sha = shaValue; 23 | raw = [self inflateRaw:rawData]; 24 | // NSLog(@"init sha: %@", sha); 25 | // NSLog(@"raw: %@", raw); 26 | [self parseRaw]; 27 | return self; 28 | } 29 | 30 | - (void) parseRaw 31 | { 32 | char *ptr, *bytes = (char *)[raw bytes]; 33 | int len, rest; 34 | len = (ptr = memchr(bytes, nil, len = [raw length])) ? ptr - bytes : len; 35 | rest = [raw length] - len - 1; 36 | 37 | ptr++; 38 | NSString *header = [NSString stringWithCString:bytes length:len]; 39 | contents = [NSString stringWithCString:ptr length:rest]; 40 | 41 | rawContents = malloc(rest); 42 | memcpy(rawContents, ptr, rest); 43 | rawContentLen = rest; 44 | 45 | NSArray *headerData = [header componentsSeparatedByString:@" "]; 46 | 47 | type = [headerData objectAtIndex:0]; 48 | size = [[headerData objectAtIndex:1] intValue]; 49 | } 50 | 51 | - (NSData *) inflateRaw:(NSData *)rawData 52 | { 53 | return [rawData decompressedData]; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /ProjectController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProjectController.m 3 | // iGitHub 4 | // 5 | 6 | #import "ProjectController.h" 7 | #import "ObjGit.h" 8 | 9 | @interface ProjectController () 10 | @property (nonatomic, copy, readwrite) NSMutableArray *list; 11 | @end 12 | 13 | @implementation ProjectController 14 | 15 | @synthesize list; 16 | 17 | // Custom set accessor to ensure the new list is mutable 18 | - (void)readProjects:(NSString *)projectPath 19 | { 20 | //NSLog(@"READ PROJECTS:%@", projectPath); 21 | BOOL isDir=NO; 22 | [list release]; 23 | list = [[NSMutableArray alloc] init]; 24 | NSFileManager *fileManager = [NSFileManager defaultManager]; 25 | if ([fileManager fileExistsAtPath:projectPath isDirectory:&isDir] && isDir) { 26 | NSEnumerator *e = [[fileManager directoryContentsAtPath:projectPath] objectEnumerator]; 27 | NSString *thisDir; 28 | while ( (thisDir = [e nextObject]) ) { 29 | NSString *dir = [projectPath stringByAppendingPathComponent:thisDir]; 30 | ObjGit* git = [[ObjGit alloc] init]; 31 | [git openRepo:dir]; 32 | [git setGitName:thisDir]; 33 | [list addObject:git]; 34 | } 35 | } 36 | } 37 | 38 | // Accessor methods for list 39 | - (unsigned)countOfList { 40 | return [list count]; 41 | } 42 | 43 | - (id)objectInListAtIndex:(unsigned)theIndex { 44 | return [list objectAtIndex:theIndex]; 45 | } 46 | 47 | - (void)dealloc { 48 | [list release]; 49 | [super dealloc]; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Git/ObjGitCommit.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitCommit.h 3 | // ObjGit 4 | // 5 | 6 | #import 7 | #import "ObjGitObject.h" 8 | 9 | @interface ObjGitCommit : NSObject { 10 | NSString *sha; 11 | NSArray *parentShas; 12 | NSString *treeSha; 13 | NSString *author; 14 | NSString *author_email; 15 | NSDate *authored_date; 16 | NSString *committer; 17 | NSString *committer_email; 18 | NSDate *committed_date; 19 | NSString *message; 20 | ObjGitObject *git_object; 21 | } 22 | 23 | @property(copy, readwrite) NSString *sha; 24 | @property(copy, readwrite) NSArray *parentShas; 25 | @property(copy, readwrite) NSString *treeSha; 26 | @property(copy, readwrite) NSString *author; 27 | @property(copy, readwrite) NSString *author_email; 28 | @property(copy, readwrite) NSDate *authored_date; 29 | @property(copy, readwrite) NSString *committer; 30 | @property(copy, readwrite) NSString *committer_email; 31 | @property(retain, readwrite) NSDate *committed_date; 32 | @property(assign, readwrite) NSString *message; 33 | @property(assign, readwrite) ObjGitObject *git_object; 34 | 35 | - (id) initFromGitObject:(ObjGitObject *)gitObject; 36 | - (id) initFromRaw:(NSData *)rawData withSha:(NSString *)shaValue; 37 | - (void) parseContent; 38 | - (void) logObject; 39 | - (NSArray *) authorArray; 40 | - (NSArray *) parseAuthorString:(NSString *)authorString withType:(NSString *)typeString; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Networking/TCPServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: TCPServer.h 4 | Abstract: A TCP server that listens on an arbitrary port. 5 | 6 | Version: 1.5 7 | 8 | */ 9 | 10 | #import 11 | 12 | //CLASSES: 13 | 14 | @class TCPServer; 15 | 16 | //ERRORS: 17 | 18 | NSString * const TCPServerErrorDomain; 19 | 20 | typedef enum { 21 | kTCPServerCouldNotBindToIPv4Address = 1, 22 | kTCPServerCouldNotBindToIPv6Address = 2, 23 | kTCPServerNoSocketsAvailable = 3, 24 | } TCPServerErrorCode; 25 | 26 | //PROTOCOLS: 27 | 28 | @protocol TCPServerDelegate 29 | @optional 30 | - (void) serverDidEnableBonjour:(TCPServer*)server withName:(NSString*)name; 31 | - (void) server:(TCPServer*)server didNotEnableBonjour:(NSDictionary *)errorDict; 32 | - (void) didAcceptConnectionForServer:(TCPServer*)server inputStream:(NSInputStream *)istr outputStream:(NSOutputStream *)ostr; 33 | @end 34 | 35 | //CLASS INTERFACES: 36 | 37 | @interface TCPServer : NSObject { 38 | @private 39 | id _delegate; 40 | uint16_t _port; 41 | CFSocketRef _ipv4socket; 42 | NSNetService* _netService; 43 | } 44 | 45 | - (BOOL)start:(NSError **)error; 46 | - (BOOL)stop; 47 | - (BOOL) enableBonjourWithDomain:(NSString*)domain applicationProtocol:(NSString*)protocol name:(NSString*)name; //Pass "nil" for the default local domain - Pass only the application protocol for "protocol" e.g. "myApp" 48 | - (void) disableBonjour; 49 | 50 | @property(assign) id delegate; 51 | 52 | + (NSString*) bonjourTypeFromIdentifier:(NSString*)identifier; 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Git/ObjGitTree.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitTree.m 3 | // ObjGit 4 | // 5 | 6 | #import "ObjGit.h" 7 | #import "ObjGitObject.h" 8 | #import "ObjGitTree.h" 9 | 10 | @implementation ObjGitTree 11 | 12 | @synthesize treeEntries; 13 | @synthesize gitObject; 14 | 15 | - (id) initFromGitObject:(ObjGitObject *)object { 16 | self = [super init]; 17 | self.gitObject = object; 18 | [self parseContent]; 19 | return self; 20 | } 21 | 22 | - (void) logObject 23 | { 24 | NSLog(@"entries : %@", treeEntries); 25 | } 26 | 27 | // 100644 testfile\0[20 char sha] 28 | - (void) parseContent 29 | { 30 | char *contents = [self.gitObject rawContents]; 31 | 32 | char mode[9]; 33 | int modePtr = 0; 34 | char name[255]; 35 | int namePtr = 0; 36 | char sha[41]; 37 | unsigned char rawsha[20]; 38 | 39 | NSString *shaStr, *modeStr, *nameStr; 40 | NSArray *entry; 41 | NSMutableArray *entries; 42 | entries = [[NSMutableArray alloc] init]; 43 | 44 | int i, j, state; 45 | state = 1; 46 | 47 | for(i = 0; i < [self.gitObject rawContentLen] - 1; i++) { 48 | if(contents[i] == 0) { 49 | state = 1; 50 | for(j = 0; j < 20; j++) 51 | rawsha[j] = contents[i + j + 1]; 52 | i += 20; 53 | [ObjGit gitUnpackHex:rawsha fillSha:sha]; 54 | 55 | mode[modePtr] = 0; 56 | name[namePtr] = 0; 57 | 58 | shaStr = [[NSString alloc] initWithBytes:sha length:40 encoding:NSASCIIStringEncoding]; 59 | modeStr = [[NSString alloc] initWithBytes:mode length:modePtr encoding:NSASCIIStringEncoding]; 60 | nameStr = [[NSString alloc] initWithBytes:name length:namePtr encoding:NSUTF8StringEncoding]; 61 | 62 | entry = [NSArray arrayWithObjects:modeStr, nameStr, shaStr, nil]; 63 | [entries addObject:entry]; 64 | 65 | modePtr = 0; 66 | namePtr = 0; 67 | } else { // contents 68 | if(contents[i] == 32) { 69 | state = 2; 70 | } else if(state == 1) { // mode 71 | mode[modePtr] = contents[i]; 72 | modePtr++; 73 | } else { // name 74 | name[namePtr] = contents[i]; 75 | namePtr++; 76 | } 77 | } 78 | } 79 | treeEntries = entries; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Git/NSDataCompression.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDataCompression.m 3 | // ObjGit 4 | // 5 | // thankfully borrowed from the Etoile framework 6 | // 7 | 8 | #import "NSDataCompression.h" 9 | #include 10 | 11 | @implementation NSData (Compression) 12 | - (NSData *) compressedData 13 | { 14 | unsigned int srcLength = [self length]; 15 | if (srcLength > 0) 16 | { 17 | uLong buffLength = srcLength * 1.001 + 12; 18 | NSMutableData *compData = [[NSMutableData alloc] initWithCapacity:buffLength]; 19 | [compData increaseLengthBy:buffLength]; 20 | int error = compress( [compData mutableBytes], &buffLength, 21 | [self bytes], srcLength ); 22 | switch( error ) { 23 | case Z_OK: 24 | [compData setLength: buffLength]; 25 | return [NSData dataWithBytes:[compData bytes] length:buffLength]; 26 | break; 27 | default: 28 | NSAssert( YES, @"Error compressing: Memory Error!" ); 29 | break; 30 | } 31 | //[compData release]; 32 | } 33 | return nil; 34 | } 35 | 36 | - (NSData *) decompressedData 37 | { 38 | if ([self length] == 0) return self; 39 | 40 | unsigned full_length = [self length]; 41 | unsigned half_length = [self length] / 2; 42 | 43 | NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length]; 44 | BOOL done = NO; 45 | int status; 46 | 47 | z_stream strm; 48 | strm.next_in = (Bytef *)[self bytes]; 49 | strm.avail_in = [self length]; 50 | strm.total_out = 0; 51 | strm.zalloc = Z_NULL; 52 | strm.zfree = Z_NULL; 53 | 54 | if (inflateInit (&strm) != Z_OK) return nil; 55 | while (!done) 56 | { 57 | // Make sure we have enough room and reset the lengths. 58 | if (strm.total_out >= [decompressed length]) 59 | [decompressed increaseLengthBy: half_length]; 60 | strm.next_out = [decompressed mutableBytes] + strm.total_out; 61 | strm.avail_out = [decompressed length] - strm.total_out; 62 | 63 | // Inflate another chunk. 64 | status = inflate (&strm, Z_SYNC_FLUSH); 65 | if (status == Z_STREAM_END) done = YES; 66 | else if (status != Z_OK) break; 67 | } 68 | if (inflateEnd (&strm) != Z_OK) return nil; 69 | 70 | // Set real length. 71 | if (done) 72 | { 73 | [decompressed setLength: strm.total_out]; 74 | return [NSData dataWithData: decompressed]; 75 | } 76 | else 77 | return nil; 78 | 79 | } 80 | @end 81 | -------------------------------------------------------------------------------- /Git/ObjGitServerHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitServerHandler.h 3 | // ObjGit 4 | // 5 | 6 | #import 7 | #include 8 | #import "ObjGitObject.h" 9 | 10 | @interface ObjGitServerHandler : NSObject { 11 | NSInputStream* inStream; 12 | NSOutputStream* outStream; 13 | ObjGit* gitRepo; 14 | NSString* gitPath; 15 | 16 | NSMutableArray* refsRead; 17 | NSMutableArray* needRefs; 18 | NSMutableDictionary* refDict; 19 | 20 | int capabilitiesSent; 21 | } 22 | 23 | @property(assign, readwrite) NSInputStream *inStream; 24 | @property(assign, readwrite) NSOutputStream *outStream; 25 | @property(assign, readwrite) ObjGit *gitRepo; 26 | @property(assign, readwrite) NSString *gitPath; 27 | 28 | @property(assign, readwrite) NSMutableArray *refsRead; 29 | @property(assign, readwrite) NSMutableArray *needRefs; 30 | @property(assign, readwrite) NSMutableDictionary *refDict; 31 | 32 | @property(assign, readwrite) int capabilitiesSent; 33 | 34 | - (void) initWithGit:(ObjGit *)git gitPath:(NSString *)gitRepoPath input:(NSInputStream *)streamIn output:(NSOutputStream *)streamOut; 35 | - (void) handleRequest; 36 | 37 | - (void) uploadPack:(NSString *)repositoryName; 38 | - (void) receiveNeeds; 39 | - (void) uploadPackFile; 40 | - (void) sendNack; 41 | - (void) sendPackData; 42 | 43 | - (void) receivePack:(NSString *)repositoryName; 44 | - (void) gatherObjectShasFromCommit:(NSString *)shaValue; 45 | - (void) gatherObjectShasFromTree:(NSString *)shaValue; 46 | - (void) respondPack:(uint8_t *)buffer length:(int)size checkSum:(CC_SHA1_CTX *)checksum; 47 | 48 | - (void) sendRefs; 49 | - (void) sendRef:(NSString *)refName sha:(NSString *)shaString; 50 | - (void) readRefs; 51 | - (void) readPack; 52 | - (void) writeRefs; 53 | - (NSData *) readData:(int)size; 54 | - (NSString *) typeString:(int)type; 55 | - (int) typeInt:(NSString *)type; 56 | - (void) unpackDeltified:(int)type size:(int)size; 57 | 58 | - (NSData *) patchDelta:(NSData *)deltaData withObject:(ObjGitObject *)gitObject; 59 | - (NSArray *) patchDeltaHeaderSize:(NSData *)deltaData position:(unsigned long)position; 60 | 61 | - (NSString *)readServerSha; 62 | - (int) readPackHeader; 63 | - (void) unpackObject; 64 | 65 | - (void) longVal:(uint32_t)raw toByteBuffer:(uint8_t *)buffer; 66 | - (void) packetFlush; 67 | - (void) writeServer:(NSString *)dataWrite; 68 | - (void) writeServerLength:(unsigned int)length; 69 | - (void) sendPacket:(NSString *)dataSend; 70 | - (NSString *) packetReadLine; 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /ServerViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ServerViewController.m 3 | // iGitHub 4 | // 5 | 6 | 7 | #import "ServerViewController.h" 8 | 9 | #define kOffset 5.0 10 | 11 | @implementation ServerViewController 12 | 13 | @synthesize serverNameLabel; 14 | 15 | -(id)init { 16 | self = [super init]; 17 | if (self) { 18 | self.title = @"Server"; 19 | self.tabBarItem.image = [UIImage imageNamed:@"rssicon.png"]; 20 | } 21 | return self; 22 | } 23 | 24 | -(void)loadView { 25 | NSLog(@"First View"); 26 | UIView *firstView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"server.png"]]; 27 | [firstView setAutoresizingMask:UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth]; 28 | [firstView setBackgroundColor:[UIColor yellowColor]]; 29 | self.view = firstView; 30 | [firstView release]; 31 | 32 | UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero]; 33 | [label setTextAlignment:UITextAlignmentCenter]; 34 | [label setFont:[UIFont systemFontOfSize:18.0]]; 35 | [label setTextColor:[UIColor blackColor]]; 36 | [label setBackgroundColor:[UIColor clearColor]]; 37 | label.text = @"Git Server Listening On"; 38 | label.numberOfLines = 1; 39 | [label sizeToFit]; 40 | label.frame = CGRectMake(0.0, 200.0, 320.0, label.frame.size.height); 41 | [self.view addSubview:label]; 42 | 43 | NSString *hostName = [[NSProcessInfo processInfo] hostName]; 44 | if ([hostName hasSuffix:@".local"]) { 45 | hostName = [hostName substringToIndex:([hostName length] - 6)]; 46 | } 47 | label = [[UILabel alloc] initWithFrame:CGRectZero]; 48 | [label setTextAlignment:UITextAlignmentCenter]; 49 | [label setFont:[UIFont systemFontOfSize:28.0]]; 50 | [label setTextColor:[UIColor blackColor]]; 51 | [label setBackgroundColor:[UIColor clearColor]]; 52 | label.text = [NSString stringWithFormat:@"git://%@/", hostName]; 53 | label.numberOfLines = 1; 54 | [label sizeToFit]; 55 | label.frame = CGRectMake(0.0, 250.0, 320.0, label.frame.size.height); 56 | self.serverNameLabel = label; 57 | [self.view addSubview:self.serverNameLabel]; 58 | } 59 | 60 | - (void)setServerName:(NSString *)string { 61 | [self.serverNameLabel setText:string]; 62 | } 63 | 64 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 65 | // Return YES for supported orientations 66 | return (interfaceOrientation == UIInterfaceOrientationPortrait); 67 | } 68 | 69 | 70 | - (void)didReceiveMemoryWarning { 71 | [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview 72 | // Release anything that's not essential, such as cached data 73 | } 74 | 75 | 76 | - (void)dealloc { 77 | [super dealloc]; 78 | } 79 | 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /Prefix.pch: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: Prefix.pch 4 | Abstract: This file is included for support purposes and isn't necessary for 5 | understanding this sample. 6 | 7 | Version: 1.0 8 | 9 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 10 | ("Apple") in consideration of your agreement to the following terms, and your 11 | use, installation, modification or redistribution of this Apple software 12 | constitutes acceptance of these terms. If you do not agree with these terms, 13 | please do not use, install, modify or redistribute this Apple software. 14 | 15 | In consideration of your agreement to abide by the following terms, and subject 16 | to these terms, Apple grants you a personal, non-exclusive license, under 17 | Apple's copyrights in this original Apple software (the "Apple Software"), to 18 | use, reproduce, modify and redistribute the Apple Software, with or without 19 | modifications, in source and/or binary forms; provided that if you redistribute 20 | the Apple Software in its entirety and without modifications, you must retain 21 | this notice and the following text and disclaimers in all such redistributions 22 | of the Apple Software. 23 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used 24 | to endorse or promote products derived from the Apple Software without specific 25 | prior written permission from Apple. Except as expressly stated in this notice, 26 | no other rights or licenses, express or implied, are granted by Apple herein, 27 | including but not limited to any patent rights that may be infringed by your 28 | derivative works or by other works in which the Apple Software may be 29 | incorporated. 30 | 31 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 32 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 33 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 35 | COMBINATION WITH YOUR PRODUCTS. 36 | 37 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 38 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 39 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR 41 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF 42 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 43 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | 45 | Copyright (C) 2008 Apple Inc. All Rights Reserved. 46 | 47 | */ 48 | 49 | #ifdef __OBJC__ 50 | #import 51 | #endif 52 | -------------------------------------------------------------------------------- /ProjectViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProjectViewController.m 3 | // iGitHub 4 | // 5 | 6 | #import "ProjectViewController.h" 7 | #import "ProjectDetailViewController.h" 8 | #import "ObjGit.h" 9 | 10 | 11 | @implementation ProjectViewController 12 | 13 | @synthesize projectController; 14 | 15 | - (id)initWithStyle:(UITableViewStyle)style { 16 | if ((self = [super initWithStyle:style])) { 17 | self.title = NSLocalizedString(@"Projects", @"My Local Git Project List"); 18 | self.tabBarItem.image = [UIImage imageNamed:@"servericon.png"]; 19 | } 20 | return self; 21 | } 22 | 23 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 24 | return 1; 25 | } 26 | 27 | 28 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 29 | return [projectController countOfList]; 30 | } 31 | 32 | 33 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 34 | 35 | static NSString *MyIdentifier = @"MyIdentifier"; 36 | 37 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; 38 | if (cell == nil) { 39 | cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease]; 40 | } 41 | 42 | // Get the object to display and set the value in the cell 43 | ObjGit *itemAtIndex = [projectController objectInListAtIndex:indexPath.row]; 44 | cell.text = [itemAtIndex gitName]; 45 | return cell; 46 | } 47 | 48 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 49 | 50 | ProjectDetailViewController *detailViewController = [[ProjectDetailViewController alloc] initWithStyle:UITableViewStyleGrouped]; 51 | detailViewController.detailItem = [projectController objectInListAtIndex:indexPath.row]; 52 | 53 | // Push the detail view controller 54 | [[self navigationController] pushViewController:detailViewController animated:YES]; 55 | [detailViewController release]; 56 | } 57 | 58 | /* 59 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 60 | 61 | if (editingStyle == UITableViewCellEditingStyleDelete) { 62 | } 63 | if (editingStyle == UITableViewCellEditingStyleInsert) { 64 | } 65 | } 66 | */ 67 | /* 68 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 69 | return YES; 70 | } 71 | */ 72 | /* 73 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 74 | } 75 | */ 76 | /* 77 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 78 | return YES; 79 | } 80 | */ 81 | 82 | 83 | - (void)dealloc { 84 | [super dealloc]; 85 | } 86 | 87 | 88 | - (void)viewDidLoad { 89 | [super viewDidLoad]; 90 | } 91 | 92 | 93 | - (void)viewWillAppear:(BOOL)animated { 94 | [super viewWillAppear:animated]; 95 | } 96 | 97 | - (void)viewDidAppear:(BOOL)animated { 98 | [super viewDidAppear:animated]; 99 | } 100 | 101 | - (void)viewWillDisappear:(BOOL)animated { 102 | } 103 | 104 | - (void)viewDidDisappear:(BOOL)animated { 105 | } 106 | 107 | - (void)didReceiveMemoryWarning { 108 | [super didReceiveMemoryWarning]; 109 | } 110 | 111 | 112 | @end 113 | 114 | -------------------------------------------------------------------------------- /AppController.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: AppController.h 4 | Abstract: UIApplication's delegate class, the central controller of the 5 | application. 6 | 7 | Version: 1.5 8 | 9 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 10 | ("Apple") in consideration of your agreement to the following terms, and your 11 | use, installation, modification or redistribution of this Apple software 12 | constitutes acceptance of these terms. If you do not agree with these terms, 13 | please do not use, install, modify or redistribute this Apple software. 14 | 15 | In consideration of your agreement to abide by the following terms, and subject 16 | to these terms, Apple grants you a personal, non-exclusive license, under 17 | Apple's copyrights in this original Apple software (the "Apple Software"), to 18 | use, reproduce, modify and redistribute the Apple Software, with or without 19 | modifications, in source and/or binary forms; provided that if you redistribute 20 | the Apple Software in its entirety and without modifications, you must retain 21 | this notice and the following text and disclaimers in all such redistributions 22 | of the Apple Software. 23 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used 24 | to endorse or promote products derived from the Apple Software without specific 25 | prior written permission from Apple. Except as expressly stated in this notice, 26 | no other rights or licenses, express or implied, are granted by Apple herein, 27 | including but not limited to any patent rights that may be infringed by your 28 | derivative works or by other works in which the Apple Software may be 29 | incorporated. 30 | 31 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 32 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 33 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 35 | COMBINATION WITH YOUR PRODUCTS. 36 | 37 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 38 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 39 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR 41 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF 42 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 43 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | 45 | Copyright (C) 2008 Apple Inc. All Rights Reserved. 46 | 47 | */ 48 | 49 | #import "BrowserViewController.h" 50 | #import "ServerViewController.h" 51 | #import "TCPServer.h" 52 | #import "ObjGitCommit.h" 53 | 54 | //CLASS INTERFACES: 55 | 56 | @interface AppController : NSObject 57 | { 58 | UIWindow* _window; 59 | TCPServer* _server; 60 | NSInputStream* _inStream; 61 | NSOutputStream* _outStream; 62 | BOOL _inReady; 63 | BOOL _outReady; 64 | UINavigationController *navigationController; 65 | UITabBarController *tabBarController; 66 | ServerViewController *serverViewController; 67 | NSString* gitDir; 68 | } 69 | 70 | @property (nonatomic, retain) UINavigationController *navigationController; 71 | @property (nonatomic, retain) UITabBarController *tabBarController; 72 | @property (nonatomic, retain) ServerViewController *serverViewController; 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /ProjectDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProjectDetailViewController.m 3 | // iGitHub 4 | // 5 | 6 | #import "ProjectDetailViewController.h" 7 | #import "CommitsViewController.h" 8 | #import "ObjGit.h" 9 | 10 | @implementation ProjectDetailViewController 11 | 12 | @synthesize detailItem; 13 | 14 | 15 | - (void)viewWillAppear:(BOOL)animated { 16 | // Update the view with current data before it is displayed 17 | [super viewWillAppear:animated]; 18 | 19 | // Scroll the table view to the top before it appears 20 | [self.tableView reloadData]; 21 | [self.tableView setContentOffset:CGPointZero animated:NO]; 22 | self.title = [detailItem gitName]; 23 | } 24 | 25 | // Standard table view data source and delegate methods 26 | 27 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 28 | // There are two sections, for info and stats 29 | return 2; 30 | } 31 | 32 | 33 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 34 | 35 | NSInteger rows = 0; 36 | switch (section) { 37 | case 0: 38 | // For project data, there is name 39 | rows = 1; 40 | break; 41 | case 1: 42 | // For the branches section, there is size 43 | rows = [[detailItem getAllRefs] count]; 44 | break; 45 | default: 46 | break; 47 | } 48 | return rows; 49 | } 50 | 51 | 52 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 53 | 54 | static NSString *CellIdentifier = @"tvc"; 55 | 56 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 57 | if (cell == nil) { 58 | cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease]; 59 | //cell.selectionStyle = UITableViewCellSelectionStyleNone; 60 | } 61 | 62 | NSString *cellText = nil; 63 | 64 | switch (indexPath.section) { 65 | case 0: 66 | cellText = [detailItem gitName]; 67 | break; 68 | case 1: 69 | cellText = [[[detailItem getAllRefs] objectAtIndex:indexPath.row] objectAtIndex:0]; 70 | 71 | break; 72 | default: 73 | break; 74 | } 75 | 76 | cell.text = cellText; 77 | return cell; 78 | } 79 | 80 | 81 | /* 82 | Provide section titles 83 | HIG note: In this case, since the content of each section is obvious, there's probably no need to provide a title, but the code is useful for illustration. 84 | */ 85 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 86 | 87 | NSString *title = nil; 88 | switch (section) { 89 | case 0: 90 | title = NSLocalizedString(@"Project Info", @"Git Project Information"); 91 | break; 92 | case 1: 93 | title = NSLocalizedString(@"Branches", @"Git Project Refs"); 94 | break; 95 | default: 96 | break; 97 | } 98 | return title; 99 | } 100 | 101 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 102 | CommitsViewController *commitsViewController = [[CommitsViewController alloc] initWithStyle:UITableViewStylePlain]; 103 | NSArray *refArray = [[detailItem getAllRefs] objectAtIndex:indexPath.row]; 104 | NSLog(@"refs:%@", refArray); 105 | 106 | commitsViewController.gitRepo = detailItem; 107 | commitsViewController.gitRef = [refArray objectAtIndex:0]; 108 | commitsViewController.gitSha = [refArray objectAtIndex:1]; 109 | 110 | NSLog(@"TEST"); 111 | 112 | // Push the commit view controller 113 | [[self navigationController] pushViewController:commitsViewController animated:YES]; 114 | [commitsViewController release]; 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /Picker.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | 5 | #import "Picker.h" 6 | 7 | #define kOffset 5.0 8 | 9 | @interface Picker () 10 | @property (nonatomic, retain, readwrite) BrowserViewController* bvc; 11 | @property (nonatomic, retain, readwrite) UILabel* gameNameLabel; 12 | @end 13 | 14 | @implementation Picker 15 | 16 | @synthesize bvc = _bvc; 17 | @synthesize gameNameLabel = _gameNameLabel; 18 | 19 | - (id)initWithFrame:(CGRect)frame type:(NSString*)type { 20 | if ((self = [super initWithFrame:frame])) { 21 | self.bvc = [[BrowserViewController alloc] initWithTitle:nil showDisclosureIndicators:NO showCancelButton:NO]; 22 | [self.bvc searchForServicesOfType:type inDomain:@"local"]; 23 | 24 | self.opaque = YES; 25 | self.backgroundColor = [UIColor blackColor]; 26 | 27 | UIImageView* img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bg.png"]]; 28 | [self addSubview:img]; 29 | [img release]; 30 | 31 | CGFloat runningY = kOffset; 32 | CGFloat width = self.bounds.size.width - 2 * kOffset; 33 | 34 | UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero]; 35 | [label setTextAlignment:UITextAlignmentCenter]; 36 | [label setFont:[UIFont boldSystemFontOfSize:15.0]]; 37 | [label setTextColor:[UIColor whiteColor]]; 38 | [label setShadowColor:[UIColor colorWithWhite:0.0 alpha:0.75]]; 39 | [label setShadowOffset:CGSizeMake(1,1)]; 40 | [label setBackgroundColor:[UIColor clearColor]]; 41 | label.text = @"Git Server At"; 42 | label.numberOfLines = 1; 43 | [label sizeToFit]; 44 | label.frame = CGRectMake(kOffset, runningY, width, label.frame.size.height); 45 | [self addSubview:label]; 46 | 47 | runningY += label.bounds.size.height; 48 | [label release]; 49 | 50 | self.gameNameLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 51 | [self.gameNameLabel setTextAlignment:UITextAlignmentCenter]; 52 | [self.gameNameLabel setFont:[UIFont boldSystemFontOfSize:24.0]]; 53 | [self.gameNameLabel setLineBreakMode:UILineBreakModeTailTruncation]; 54 | [self.gameNameLabel setTextColor:[UIColor whiteColor]]; 55 | [self.gameNameLabel setShadowColor:[UIColor colorWithWhite:0.0 alpha:0.75]]; 56 | [self.gameNameLabel setShadowOffset:CGSizeMake(1,1)]; 57 | [self.gameNameLabel setBackgroundColor:[UIColor clearColor]]; 58 | [self.gameNameLabel setText:@"Default Name"]; 59 | [self.gameNameLabel sizeToFit]; 60 | [self.gameNameLabel setFrame:CGRectMake(kOffset, runningY, width, self.gameNameLabel.frame.size.height)]; 61 | [self.gameNameLabel setText:@""]; 62 | [self addSubview:self.gameNameLabel]; 63 | 64 | runningY += self.gameNameLabel.bounds.size.height + kOffset * 2; 65 | 66 | label = [[UILabel alloc] initWithFrame:CGRectZero]; 67 | [label setTextAlignment:UITextAlignmentCenter]; 68 | [label setFont:[UIFont boldSystemFontOfSize:15.0]]; 69 | [label setTextColor:[UIColor whiteColor]]; 70 | [label setShadowColor:[UIColor colorWithWhite:0.0 alpha:0.75]]; 71 | [label setShadowOffset:CGSizeMake(1,1)]; 72 | [label setBackgroundColor:[UIColor clearColor]]; 73 | label.text = @"git clone"; 74 | label.numberOfLines = 1; 75 | [label sizeToFit]; 76 | label.frame = CGRectMake(kOffset, runningY, width, label.frame.size.height); 77 | [self addSubview:label]; 78 | 79 | runningY += label.bounds.size.height + 2; 80 | 81 | [self.bvc.view setFrame:CGRectMake(0, runningY, self.bounds.size.width, self.bounds.size.height - runningY)]; 82 | [self addSubview:self.bvc.view]; 83 | 84 | } 85 | 86 | return self; 87 | } 88 | 89 | 90 | - (void)dealloc { 91 | // Cleanup any running resolve and free memory 92 | [self.bvc release]; 93 | [self.gameNameLabel release]; 94 | 95 | [super dealloc]; 96 | } 97 | 98 | 99 | - (id)delegate { 100 | return self.bvc.delegate; 101 | } 102 | 103 | 104 | - (void)setDelegate:(id)delegate { 105 | [self.bvc setDelegate:delegate]; 106 | } 107 | 108 | - (NSString *)gameName { 109 | return self.gameNameLabel.text; 110 | } 111 | 112 | - (void)setGameName:(NSString *)string { 113 | [self.gameNameLabel setText:string]; 114 | [self.bvc setOwnName:string]; 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /Git/ObjGitCommit.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitCommit.m 3 | // ObjGit 4 | // 5 | 6 | #import "ObjGitObject.h" 7 | #import "ObjGitCommit.h" 8 | 9 | @implementation ObjGitCommit 10 | 11 | @synthesize parentShas; 12 | @synthesize treeSha; 13 | @synthesize author; 14 | @synthesize author_email; 15 | @synthesize authored_date; 16 | @synthesize committer; 17 | @synthesize committer_email; 18 | @synthesize committed_date; 19 | @synthesize message; 20 | @synthesize git_object; 21 | @synthesize sha; 22 | 23 | - (id) initFromGitObject:(ObjGitObject *)gitObject { 24 | self = [super init]; 25 | self.sha = [gitObject sha]; 26 | self.git_object = gitObject; 27 | [self parseContent]; 28 | return self; 29 | } 30 | 31 | - (id) initFromRaw:(NSData *)rawData withSha:(NSString *)shaValue 32 | { 33 | self = [super init]; 34 | self.git_object = [[ObjGitObject alloc] initFromRaw:rawData withSha:shaValue]; 35 | self.sha = shaValue; 36 | [self parseContent]; 37 | //[self logObject]; 38 | return self; 39 | } 40 | 41 | - (void) logObject 42 | { 43 | NSLog(@"tree : %@", treeSha); 44 | NSLog(@"author : %@, %@ : %@", author, author_email, authored_date); 45 | NSLog(@"committer: %@, %@ : %@", committer, committer_email, committed_date); 46 | NSLog(@"parents : %@", parentShas); 47 | NSLog(@"message : %@", message); 48 | } 49 | 50 | - (NSArray *) authorArray 51 | { 52 | return [NSArray arrayWithObjects:self.author, self.author_email, self.authored_date, nil]; 53 | } 54 | 55 | - (void) parseContent 56 | { 57 | // extract parent shas, tree sha, author/committer info, message 58 | NSArray *lines = [self.git_object.contents componentsSeparatedByString:@"\n"]; 59 | NSEnumerator *enumerator; 60 | NSMutableArray *parents; 61 | NSMutableString *buildMessage; 62 | NSString *line, *key, *val; 63 | int inMessage = 0; 64 | 65 | buildMessage = [NSMutableString new]; 66 | parents = [NSMutableArray new]; 67 | 68 | enumerator = [lines objectEnumerator]; 69 | while ((line = [enumerator nextObject]) != nil) { 70 | // NSLog(@"line: %@", line); 71 | if(!inMessage) { 72 | if([line length] == 0) { 73 | inMessage = 1; 74 | } else { 75 | NSArray *values = [line componentsSeparatedByString:@" "]; 76 | key = [values objectAtIndex: 0]; 77 | val = [values objectAtIndex: 1]; 78 | if([key isEqualToString: @"tree"]) { 79 | self.treeSha = val; 80 | } else if ([key isEqualToString: @"parent"]) { 81 | [parents addObject: val]; 82 | } else if ([key isEqualToString: @"author"]) { 83 | NSArray *name_email_date = [self parseAuthorString:line withType:@"author "]; 84 | self.author = [name_email_date objectAtIndex: 0]; 85 | self.author_email = [name_email_date objectAtIndex: 1]; 86 | self.authored_date = [name_email_date objectAtIndex: 2]; 87 | } else if ([key isEqualToString: @"committer"]) { 88 | NSArray *name_email_date = [self parseAuthorString:line withType:@"committer "]; 89 | self.committer = [name_email_date objectAtIndex: 0]; 90 | self.committer_email = [name_email_date objectAtIndex: 1]; 91 | self.committed_date = [name_email_date objectAtIndex: 2]; 92 | } 93 | } 94 | } else { 95 | [buildMessage appendString: line]; 96 | [buildMessage appendString: @"\n"]; 97 | } 98 | } 99 | self.message = buildMessage; 100 | self.parentShas = parents; 101 | } 102 | 103 | - (NSArray *) parseAuthorString:(NSString *)authorString withType:(NSString *)typeString 104 | { 105 | NSArray *name_email_date; 106 | name_email_date = [authorString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]; 107 | 108 | NSString *nameVal = [name_email_date objectAtIndex: 0]; 109 | NSString *emailVal = [name_email_date objectAtIndex: 1]; 110 | NSString *dateVal = [name_email_date objectAtIndex: 2]; 111 | NSDate *dateDateVal; 112 | dateDateVal = [NSDate dateWithTimeIntervalSince1970:[dateVal doubleValue]]; 113 | 114 | NSMutableString *tempValue = [[NSMutableString alloc] init]; 115 | [tempValue setString:nameVal]; 116 | [tempValue replaceOccurrencesOfString: typeString 117 | withString: @"" 118 | options: 0 119 | range: NSMakeRange(0, [tempValue length])]; 120 | 121 | return [NSArray arrayWithObjects:tempValue, emailVal, dateDateVal, nil]; 122 | } 123 | 124 | @end 125 | -------------------------------------------------------------------------------- /Networking/BrowserViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: BrowserViewController.h 4 | Abstract: 5 | View controller for the service instance list. 6 | This object manages a NSNetServiceBrowser configured to look for Bonjour 7 | services. 8 | It has an array of NSNetService objects that are displayed in a table view. 9 | When the service browser reports that it has discovered a service, the 10 | corresponding NSNetService is added to the array. 11 | When a service goes away, the corresponding NSNetService is removed from the 12 | array. 13 | Selecting an item in the table view asynchronously resolves the corresponding 14 | net service. 15 | When that resolution completes, the delegate is called with the corresponding 16 | NSNetService. 17 | 18 | 19 | Version: 1.5 20 | 21 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 22 | ("Apple") in consideration of your agreement to the following terms, and your 23 | use, installation, modification or redistribution of this Apple software 24 | constitutes acceptance of these terms. If you do not agree with these terms, 25 | please do not use, install, modify or redistribute this Apple software. 26 | 27 | In consideration of your agreement to abide by the following terms, and subject 28 | to these terms, Apple grants you a personal, non-exclusive license, under 29 | Apple's copyrights in this original Apple software (the "Apple Software"), to 30 | use, reproduce, modify and redistribute the Apple Software, with or without 31 | modifications, in source and/or binary forms; provided that if you redistribute 32 | the Apple Software in its entirety and without modifications, you must retain 33 | this notice and the following text and disclaimers in all such redistributions 34 | of the Apple Software. 35 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used 36 | to endorse or promote products derived from the Apple Software without specific 37 | prior written permission from Apple. Except as expressly stated in this notice, 38 | no other rights or licenses, express or implied, are granted by Apple herein, 39 | including but not limited to any patent rights that may be infringed by your 40 | derivative works or by other works in which the Apple Software may be 41 | incorporated. 42 | 43 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 44 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 45 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 46 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 47 | COMBINATION WITH YOUR PRODUCTS. 48 | 49 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 50 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 51 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR 53 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF 54 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 55 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | Copyright (C) 2008 Apple Inc. All Rights Reserved. 58 | 59 | */ 60 | 61 | #import 62 | #import 63 | 64 | @class BrowserViewController; 65 | 66 | @protocol BrowserViewControllerDelegate 67 | @required 68 | // This method will be invoked when the user selects one of the service instances from the list. 69 | // The ref parameter will be the selected (already resolved) instance or nil if the user taps the 'Cancel' button (if shown). 70 | - (void) browserViewController:(BrowserViewController*)bvc didResolveInstance:(NSNetService*)ref; 71 | @end 72 | 73 | @interface BrowserViewController : UITableViewController { 74 | 75 | @private 76 | id _delegate; 77 | NSString* _searchingForServicesString; 78 | NSString* _ownName; 79 | NSNetService* _ownEntry; 80 | BOOL _showDisclosureIndicators; 81 | NSMutableArray* _services; 82 | NSNetServiceBrowser* _netServiceBrowser; 83 | NSNetService* _currentResolve; 84 | NSTimer* _timer; 85 | BOOL _needsActivityIndicator; 86 | BOOL _initialWaitOver; 87 | } 88 | 89 | @property (nonatomic, assign) id delegate; 90 | @property (nonatomic, copy) NSString* searchingForServicesString; 91 | @property (nonatomic, copy) NSString* ownName; 92 | 93 | - (id)initWithTitle:(NSString *)title showDisclosureIndicators:(BOOL)showDisclosureIndicators showCancelButton:(BOOL)showCancelButton; 94 | - (BOOL)searchForServicesOfType:(NSString *)type inDomain:(NSString *)domain; 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /AppController.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: AppController.m 4 | Abstract: UIApplication's delegate class, the central controller of the 5 | application. 6 | 7 | Version: 1.5 8 | 9 | */ 10 | 11 | #import "ObjGit.h" 12 | #import "ObjGitServerHandler.h" 13 | #import "AppController.h" 14 | #import "ProjectViewController.h" 15 | #import "ProjectController.h" 16 | #import "ServerViewController.h" 17 | 18 | #define bonIdentifier @"git" 19 | 20 | //INTERFACES: 21 | 22 | @interface AppController () 23 | 24 | @property (assign, readwrite) NSString *gitDir; 25 | 26 | - (void) setup; 27 | 28 | @end 29 | 30 | //CLASS IMPLEMENTATIONS: 31 | 32 | @implementation AppController 33 | 34 | @synthesize gitDir; 35 | @synthesize navigationController; 36 | @synthesize tabBarController; 37 | @synthesize serverViewController; 38 | 39 | - (NSString *)getGitPath 40 | { 41 | NSArray *paths; 42 | NSString *gitPath = @""; 43 | paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 44 | if ([paths count] > 0) { 45 | gitPath = [NSString stringWithString:[[paths objectAtIndex:0] stringByAppendingPathComponent:@"git"]]; 46 | 47 | BOOL isDir; 48 | NSFileManager *fm = [NSFileManager defaultManager]; 49 | if (![fm fileExistsAtPath:gitPath isDirectory:&isDir] && isDir) { 50 | [fm createDirectoryAtPath:gitPath attributes:nil]; 51 | } 52 | } 53 | return gitPath; 54 | } 55 | 56 | - (void) applicationDidFinishLaunching:(UIApplication*)application 57 | { 58 | NSString * thisHostName = [[NSProcessInfo processInfo] hostName]; 59 | NSLog(@"hostname: %@", thisHostName); 60 | // Create a full-screen window 61 | _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 62 | 63 | // getting the git path 64 | gitDir = [self getGitPath]; 65 | 66 | // Create and configure the navigation and view controllers 67 | ProjectController *pController = [[ProjectController alloc] init]; 68 | [pController readProjects:gitDir]; 69 | 70 | ProjectViewController *projectViewController = [[ProjectViewController alloc] initWithStyle:UITableViewStylePlain]; 71 | [projectViewController setProjectController:pController]; 72 | 73 | ServerViewController *serverController = [[ServerViewController alloc] init]; 74 | self.serverViewController = serverController; 75 | 76 | UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:projectViewController]; 77 | self.navigationController = aNavigationController; 78 | 79 | UITabBarController *atabBarController = [[UITabBarController alloc] init]; 80 | NSArray *vc = [NSArray arrayWithObjects:navigationController, serverViewController, nil]; 81 | [atabBarController setViewControllers:vc animated:NO]; 82 | self.tabBarController = atabBarController; 83 | 84 | // Configure and show the window 85 | [_window addSubview:tabBarController.view]; 86 | [_window makeKeyAndVisible]; 87 | 88 | [projectViewController release]; 89 | [aNavigationController release]; 90 | 91 | [self setup]; 92 | } 93 | 94 | - (void) dealloc 95 | { 96 | NSLog(@"dealloc"); 97 | [_inStream release]; 98 | [_outStream release]; 99 | 100 | [_server release]; 101 | [_window release]; 102 | 103 | [super dealloc]; 104 | } 105 | 106 | - (void) setup { 107 | //[_server release]; 108 | //_server = nil; 109 | 110 | [_inStream release]; 111 | _inStream = nil; 112 | _inReady = NO; 113 | 114 | [_outStream release]; 115 | _outStream = nil; 116 | _outReady = NO; 117 | 118 | _server = [TCPServer new]; 119 | [_server setDelegate:self]; 120 | NSError* error; 121 | if(_server == nil || ![_server start:&error]) { 122 | NSLog(@"Failed creating server: %@", error); 123 | return; 124 | } 125 | 126 | gitDir = [self getGitPath]; 127 | 128 | BOOL isDir=NO; 129 | NSFileManager *fileManager = [NSFileManager defaultManager]; 130 | if ([fileManager fileExistsAtPath:gitDir isDirectory:&isDir] && isDir) { 131 | NSEnumerator *e = [[fileManager directoryContentsAtPath:gitDir] objectEnumerator]; 132 | NSString *thisDir; 133 | while ( (thisDir = [e nextObject]) ) { 134 | NSLog(@"announce:%@", thisDir); 135 | [_server enableBonjourWithDomain:@"local" applicationProtocol:[TCPServer bonjourTypeFromIdentifier:bonIdentifier] name:thisDir]; 136 | } 137 | } 138 | } 139 | 140 | - (void) openStreams 141 | { 142 | NSString *tgitDir = [self getGitPath]; 143 | NSLog(@"gitdir:%@", tgitDir); 144 | 145 | [_outStream open]; 146 | [_inStream open]; 147 | 148 | ObjGit* git = [ObjGit alloc]; 149 | ObjGitServerHandler *obsh = [[ObjGitServerHandler alloc] init]; 150 | NSLog(@"INIT WITH GIT: %@ : %@ : %@ : %@ : %@", obsh, git, tgitDir, _inStream, _outStream); 151 | [obsh initWithGit:git gitPath:tgitDir input:_inStream output:_outStream]; 152 | 153 | [_outStream close]; 154 | [_inStream close]; 155 | 156 | [self setup]; // restart the server 157 | } 158 | 159 | @end 160 | 161 | @implementation AppController (TCPServerDelegate) 162 | 163 | - (void) serverDidEnableBonjour:(TCPServer*)server withName:(NSString*)string 164 | { 165 | //[self.serverViewController setServerName:string]; 166 | //NSLog(@"%@", string); 167 | } 168 | 169 | - (void)didAcceptConnectionForServer:(TCPServer*)server inputStream:(NSInputStream *)istr outputStream:(NSOutputStream *)ostr 170 | { 171 | if (_inStream || _outStream || server != _server) 172 | return; 173 | 174 | NSLog(@"accept connection"); 175 | 176 | [_server stop]; 177 | [_server release]; 178 | _server = nil; 179 | 180 | _inStream = istr; 181 | [_inStream retain]; 182 | _outStream = ostr; 183 | [_outStream retain]; 184 | 185 | [self openStreams]; 186 | } 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /CommitsViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CommitsViewController.m 3 | // iGitHub 4 | // 5 | 6 | #import "CommitsViewController.h" 7 | #import "CommitDetailViewController.h" 8 | #import "ObjGitCommit.h" 9 | 10 | #define ROW_HEIGHT 60 11 | 12 | @implementation CommitsViewController 13 | 14 | @synthesize gitRepo; 15 | @synthesize gitRef; 16 | @synthesize gitSha; 17 | @synthesize commitList; 18 | 19 | - (id)initWithStyle:(UITableViewStyle)style { 20 | if ((self = [super initWithStyle:style])) { 21 | } 22 | return self; 23 | } 24 | 25 | - (void)viewWillAppear:(BOOL)animated { 26 | // Update the view with current data before it is displayed 27 | [super viewWillAppear:animated]; 28 | 29 | // load data 30 | NSLog(@"Data load"); 31 | self.commitList = [gitRepo getCommitsFromSha:gitSha withLimit:30]; 32 | 33 | // Scroll the table view to the top before it appears 34 | [self.tableView reloadData]; 35 | [self.tableView setContentOffset:CGPointZero animated:NO]; 36 | self.title = gitRef; 37 | } 38 | 39 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 40 | return 1; 41 | } 42 | 43 | 44 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 45 | return [self.commitList count]; 46 | } 47 | 48 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 49 | 50 | static NSString *MyIdentifier = @"MyIdentifier"; 51 | 52 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; 53 | if (cell == nil) { 54 | cell = [self tableviewCellWithReuseIdentifier:MyIdentifier]; 55 | } 56 | // Configure the cell 57 | 58 | [self configureCell:cell forIndexPath:indexPath]; 59 | return cell; 60 | } 61 | 62 | #define ONE_TAG 1 63 | #define TWO_TAG 2 64 | #define THR_TAG 3 65 | #define FOUR_TAG 4 66 | 67 | - (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath { 68 | 69 | /* 70 | Cache the formatter. Normally you would use one of the date formatter styles (such as NSDateFormatterShortStyle), but here we want a specific format that excludes seconds. 71 | */ 72 | static NSDateFormatter *dateFormatter = nil; 73 | if (dateFormatter == nil) { 74 | dateFormatter = [[NSDateFormatter alloc] init]; 75 | [dateFormatter setDateFormat:@"MMM dd YY, kk:ss"]; // Sept 5 08:30 76 | } 77 | 78 | ObjGitCommit *commit = [self.commitList objectAtIndex:indexPath.row]; 79 | 80 | UILabel *label; 81 | 82 | // Get the time zone wrapper for the row 83 | label = (UILabel *)[cell viewWithTag:ONE_TAG]; 84 | label.text = [[commit sha] substringToIndex:6]; 85 | 86 | label = (UILabel *)[cell viewWithTag:TWO_TAG]; 87 | label.text = [commit author]; 88 | 89 | label = (UILabel *)[cell viewWithTag:THR_TAG]; 90 | label.text = [dateFormatter stringFromDate:[commit authored_date]]; 91 | 92 | label = (UILabel *)[cell viewWithTag:FOUR_TAG]; 93 | label.text = [commit message]; 94 | } 95 | 96 | 97 | - (UITableViewCell *)tableviewCellWithReuseIdentifier:(NSString *)identifier { 98 | 99 | /* 100 | Create an instance of UITableViewCell and add tagged subviews for the name, local time, and quarter image of the time zone. 101 | */ 102 | CGRect rect; 103 | 104 | rect = CGRectMake(0.0, 0.0, 320.0, ROW_HEIGHT); 105 | 106 | UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:rect reuseIdentifier:identifier] autorelease]; 107 | 108 | #define LEFT_COLUMN_OFFSET 10.0 109 | #define LEFT_COLUMN_WIDTH 70.0 110 | 111 | #define MIDDLE_COLUMN_OFFSET 80.0 112 | #define MIDDLE_COLUMN_WIDTH 130.0 113 | 114 | #define RIGHT_COLUMN_OFFSET 210.0 115 | #define RIGHT_COLUMN_WIDTH 90.0 116 | 117 | #define MAIN_FONT_SIZE 18.0 118 | #define LABEL_HEIGHT 26.0 119 | 120 | /* 121 | Create labels for the text fields; set the highlight color so that when the cell is selected it changes appropriately. 122 | */ 123 | UILabel *label; 124 | 125 | rect = CGRectMake(LEFT_COLUMN_OFFSET, 10, LEFT_COLUMN_WIDTH, LABEL_HEIGHT); 126 | label = [[UILabel alloc] initWithFrame:rect]; 127 | label.tag = ONE_TAG; 128 | label.font = [UIFont fontWithName:@"Courier New" size:15]; 129 | label.adjustsFontSizeToFitWidth = YES; 130 | [cell.contentView addSubview:label]; 131 | label.highlightedTextColor = [UIColor whiteColor]; 132 | [label release]; 133 | 134 | rect = CGRectMake(MIDDLE_COLUMN_OFFSET, 0, MIDDLE_COLUMN_WIDTH, LABEL_HEIGHT); 135 | label = [[UILabel alloc] initWithFrame:rect]; 136 | label.tag = TWO_TAG; 137 | label.font = [UIFont systemFontOfSize:15]; 138 | label.textAlignment = UITextAlignmentLeft; 139 | [cell.contentView addSubview:label]; 140 | label.highlightedTextColor = [UIColor whiteColor]; 141 | [label release]; 142 | 143 | rect = CGRectMake(RIGHT_COLUMN_OFFSET, 0, RIGHT_COLUMN_WIDTH, LABEL_HEIGHT); 144 | label = [[UILabel alloc] initWithFrame:rect]; 145 | label.tag = THR_TAG; 146 | label.textAlignment = UITextAlignmentRight; 147 | label.font = [UIFont systemFontOfSize:10]; 148 | [cell.contentView addSubview:label]; 149 | label.highlightedTextColor = [UIColor whiteColor]; 150 | [label release]; 151 | 152 | rect = CGRectMake(MIDDLE_COLUMN_OFFSET, LABEL_HEIGHT, 200.0, 15); 153 | label = [[UILabel alloc] initWithFrame:rect]; 154 | label.tag = FOUR_TAG; 155 | label.textAlignment = UITextAlignmentLeft; 156 | label.font = [UIFont systemFontOfSize:10]; 157 | [cell.contentView addSubview:label]; 158 | label.highlightedTextColor = [UIColor whiteColor]; 159 | [label release]; 160 | 161 | return cell; 162 | } 163 | 164 | // SWITCH TO SINGLE COMMIT VIEW // 165 | 166 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 167 | CommitDetailViewController *commitViewController = [[CommitDetailViewController alloc] initWithStyle:UITableViewStyleGrouped]; 168 | commitViewController.gitRepo = self.gitRepo; 169 | commitViewController.gitCommit = [self.commitList objectAtIndex:indexPath.row]; 170 | 171 | // Push the commit view controller 172 | [[self navigationController] pushViewController:commitViewController animated:YES]; 173 | [commitViewController release]; 174 | } 175 | 176 | /* 177 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 178 | } 179 | */ 180 | /* 181 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 182 | 183 | if (editingStyle == UITableViewCellEditingStyleDelete) { 184 | } 185 | if (editingStyle == UITableViewCellEditingStyleInsert) { 186 | } 187 | } 188 | */ 189 | /* 190 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 191 | return YES; 192 | } 193 | */ 194 | /* 195 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 196 | } 197 | */ 198 | /* 199 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 200 | return YES; 201 | } 202 | */ 203 | 204 | 205 | - (void)dealloc { 206 | [super dealloc]; 207 | } 208 | 209 | 210 | - (void)viewDidLoad { 211 | [super viewDidLoad]; 212 | } 213 | 214 | - (void)viewDidAppear:(BOOL)animated { 215 | [super viewDidAppear:animated]; 216 | } 217 | 218 | - (void)viewWillDisappear:(BOOL)animated { 219 | } 220 | 221 | - (void)viewDidDisappear:(BOOL)animated { 222 | } 223 | 224 | - (void)didReceiveMemoryWarning { 225 | [super didReceiveMemoryWarning]; 226 | } 227 | 228 | 229 | @end 230 | 231 | -------------------------------------------------------------------------------- /CommitDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CommitDetailViewController.m 3 | // iGitHub 4 | // 5 | 6 | #import "CommitDetailViewController.h" 7 | #import "ObjGit.h" 8 | #import "ObjGitCommit.h" 9 | 10 | @implementation CommitDetailViewController 11 | 12 | @synthesize gitRepo; 13 | @synthesize gitCommit; 14 | 15 | - (id)initWithStyle:(UITableViewStyle)style { 16 | if ((self = [super initWithStyle:style])) { 17 | } 18 | return self; 19 | } 20 | 21 | - (void)viewWillAppear:(BOOL)animated { 22 | // Update the view with current data before it is displayed 23 | [super viewWillAppear:animated]; 24 | 25 | // Scroll the table view to the top before it appears 26 | [self.tableView reloadData]; 27 | [self.tableView setContentOffset:CGPointZero animated:NO]; 28 | self.title = [[gitCommit sha] substringToIndex:6]; 29 | } 30 | 31 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 32 | return 5; 33 | } 34 | 35 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 36 | 37 | NSInteger rows = 0; 38 | switch (section) { 39 | case 0: 40 | // SHA 41 | rows = 1; 42 | break; 43 | case 1: 44 | // Author 45 | rows = 3; 46 | break; 47 | case 2: 48 | // Message 49 | rows = 1; 50 | break; 51 | case 3: 52 | // Tree 53 | rows = 1; 54 | break; 55 | case 4: 56 | // Parents 57 | rows = [[gitCommit parentShas] count]; 58 | break; 59 | default: 60 | break; 61 | } 62 | return rows; 63 | } 64 | 65 | 66 | 67 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 68 | 69 | static NSString *CellIdentifier = @"commitView"; 70 | 71 | static NSDateFormatter *dateFormatter = nil; 72 | if (dateFormatter == nil) { 73 | dateFormatter = [[NSDateFormatter alloc] init]; 74 | [dateFormatter setDateFormat:@"MMM dd YY, kk:ss"]; // Sept 5 08:30 75 | } 76 | 77 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 78 | if (cell == nil) { 79 | cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease]; 80 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 81 | } 82 | 83 | CGRect contentRect; 84 | UILabel *textView; 85 | struct CGSize size; 86 | 87 | switch (indexPath.section) { 88 | case 0: 89 | cell.font = [UIFont fontWithName:@"Courier New" size:12]; 90 | cell.textAlignment = UITextAlignmentCenter; 91 | cell.text = [self.gitCommit sha]; 92 | break; 93 | case 1: 94 | if(indexPath.row == 2) { 95 | cell.text = [dateFormatter stringFromDate:[[self.gitCommit authorArray] objectAtIndex:indexPath.row]]; 96 | } else { 97 | cell.text = [[self.gitCommit authorArray] objectAtIndex:indexPath.row]; 98 | } 99 | break; 100 | case 2: 101 | NSLog(@"Message:%@", [self.gitCommit message]); 102 | 103 | size = [[self.gitCommit message] sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(300.0, 4000) lineBreakMode:UILineBreakModeCharacterWrap]; 104 | 105 | contentRect = CGRectMake(5.0, 5.0, 290.0, size.height); 106 | textView = [[UILabel alloc] initWithFrame:contentRect]; 107 | textView.text = [self.gitCommit message]; 108 | textView.numberOfLines = 0; 109 | textView.lineBreakMode = UILineBreakModeCharacterWrap; 110 | textView.font = [UIFont systemFontOfSize:14]; 111 | [cell.contentView addSubview:textView]; 112 | [textView release]; 113 | break; 114 | case 3: 115 | cell.font = [UIFont fontWithName:@"Courier New" size:12]; 116 | cell.textAlignment = UITextAlignmentCenter; 117 | cell.text = [self.gitCommit treeSha]; 118 | cell.selectionStyle = UITableViewCellSelectionStyleBlue; 119 | break; 120 | case 4: 121 | cell.font = [UIFont fontWithName:@"Courier New" size:12]; 122 | cell.textAlignment = UITextAlignmentCenter; 123 | cell.text = [[gitCommit parentShas] objectAtIndex:indexPath.row]; 124 | cell.selectionStyle = UITableViewCellSelectionStyleBlue; 125 | default: 126 | break; 127 | } 128 | 129 | return cell; 130 | } 131 | 132 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 133 | 134 | NSString *title = nil; 135 | switch (section) { 136 | case 0: 137 | //title = NSLocalizedString(@"Commit SHA1", @"Commit SHA1 Value"); 138 | break; 139 | case 1: 140 | title = NSLocalizedString(@"Author", @"Git Commit Author"); 141 | break; 142 | case 2: 143 | title = NSLocalizedString(@"Commit Message", @"Git Commit Message"); 144 | break; 145 | case 3: 146 | title = NSLocalizedString(@"Tree", @"Git Commit Tree"); 147 | break; 148 | case 4: 149 | title = NSLocalizedString(@"Parents", @"Git Commit Parents"); 150 | break; 151 | default: 152 | break; 153 | } 154 | return title; 155 | } 156 | 157 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 158 | { 159 | CGFloat height = 40.0; 160 | struct CGSize size; 161 | switch (indexPath.section) { 162 | case 0: 163 | height = 30.0; 164 | break; 165 | case 1: 166 | height = 30.0; 167 | break; 168 | case 2: 169 | size = [[self.gitCommit message] sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(300.0, 4000) lineBreakMode:UILineBreakModeCharacterWrap]; 170 | height = size.height + 10; 171 | break; 172 | default: 173 | break; 174 | } 175 | return height; 176 | } 177 | 178 | 179 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 180 | NSString *sha; 181 | switch (indexPath.section) { 182 | case 4: // clicked a parent 183 | sha = [[gitCommit parentShas] objectAtIndex:indexPath.row]; 184 | 185 | CommitDetailViewController *commitViewController = [[CommitDetailViewController alloc] initWithStyle:UITableViewStyleGrouped]; 186 | commitViewController.gitRepo = self.gitRepo; 187 | commitViewController.gitCommit = [[ObjGitCommit alloc] initFromGitObject:[gitRepo getObjectFromSha:sha]]; 188 | 189 | // Push the commit view controller 190 | [[self navigationController] pushViewController:commitViewController animated:YES]; 191 | [commitViewController release]; 192 | break; 193 | default: 194 | break; 195 | } 196 | } 197 | 198 | 199 | /* 200 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 201 | } 202 | */ 203 | /* 204 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 205 | 206 | if (editingStyle == UITableViewCellEditingStyleDelete) { 207 | } 208 | if (editingStyle == UITableViewCellEditingStyleInsert) { 209 | } 210 | } 211 | */ 212 | /* 213 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 214 | return YES; 215 | } 216 | */ 217 | /* 218 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 219 | } 220 | */ 221 | /* 222 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 223 | return YES; 224 | } 225 | */ 226 | 227 | 228 | - (void)dealloc { 229 | [super dealloc]; 230 | } 231 | 232 | 233 | - (void)viewDidLoad { 234 | [super viewDidLoad]; 235 | } 236 | 237 | 238 | - (void)viewDidAppear:(BOOL)animated { 239 | [super viewDidAppear:animated]; 240 | } 241 | 242 | - (void)viewWillDisappear:(BOOL)animated { 243 | } 244 | 245 | - (void)viewDidDisappear:(BOOL)animated { 246 | } 247 | 248 | - (void)didReceiveMemoryWarning { 249 | [super didReceiveMemoryWarning]; 250 | } 251 | 252 | 253 | @end 254 | 255 | -------------------------------------------------------------------------------- /Git/ObjGit.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGit.m 3 | // ObjGit 4 | // 5 | 6 | #import "ObjGit.h" 7 | #import "ObjGitObject.h" 8 | #import "ObjGitCommit.h" 9 | #import "ObjGitServerHandler.h" 10 | #import "NSDataCompression.h" 11 | 12 | #include 13 | 14 | @implementation ObjGit 15 | 16 | @synthesize gitDirectory; 17 | @synthesize gitName; 18 | 19 | - (id) init 20 | { 21 | return self; 22 | } 23 | 24 | - (void) dealloc 25 | { 26 | [super dealloc]; 27 | } 28 | 29 | - (BOOL) ensureGitPath { 30 | BOOL isDir; 31 | NSFileManager *fm = [NSFileManager defaultManager]; 32 | if ([fm fileExistsAtPath:self.gitDirectory isDirectory:&isDir] && isDir) { 33 | return YES; 34 | } else { 35 | [self initGitRepo]; 36 | } 37 | return YES; 38 | } 39 | 40 | - (NSArray *) getAllRefs 41 | { 42 | BOOL isDir=NO; 43 | NSMutableArray *refsFinal = [[NSMutableArray alloc] init]; 44 | NSString *tempRef, *thisSha; 45 | NSString *refsPath = [self.gitDirectory stringByAppendingPathComponent:@"refs"]; 46 | NSFileManager *fileManager = [NSFileManager defaultManager]; 47 | if ([fileManager fileExistsAtPath:refsPath isDirectory:&isDir] && isDir) { 48 | NSEnumerator *e = [[fileManager subpathsAtPath:refsPath] objectEnumerator]; 49 | NSString *thisRef; 50 | while ( (thisRef = [e nextObject]) ) { 51 | tempRef = [refsPath stringByAppendingPathComponent:thisRef]; 52 | thisRef = [@"refs" stringByAppendingPathComponent:thisRef]; 53 | 54 | if ([fileManager fileExistsAtPath:tempRef isDirectory:&isDir] && !isDir) { 55 | thisSha = [NSString stringWithContentsOfFile:tempRef encoding:NSASCIIStringEncoding error:nil]; 56 | [refsFinal addObject:[NSArray arrayWithObjects:thisRef,thisSha,nil]]; 57 | if([thisRef isEqualToString:@"refs/heads/master"]) 58 | [refsFinal addObject:[NSArray arrayWithObjects:@"HEAD",thisSha,nil]]; 59 | } 60 | } 61 | } 62 | return refsFinal; 63 | } 64 | 65 | - (void) updateRef:(NSString *)refName toSha:(NSString *)toSha 66 | { 67 | NSFileManager *fm = [NSFileManager defaultManager]; 68 | NSString *refPath = [self.gitDirectory stringByAppendingPathComponent:refName]; 69 | [fm createFileAtPath:refPath contents:[NSData dataWithBytes:[toSha UTF8String] length:[toSha length]] attributes:nil]; 70 | } 71 | 72 | - (void) initGitRepo { 73 | NSFileManager *fm = [NSFileManager defaultManager]; 74 | [fm createDirectoryAtPath:self.gitDirectory attributes:nil]; 75 | 76 | //NSLog(@"Dir Created: %@ %d", gitDirectory, [gitDirectory length]); 77 | NSString *config = @"[core]\n\trepositoryformatversion = 0\n\tfilemode = true\n\tbare = true\n\tlogallrefupdates = true\n"; 78 | NSString *configFile = [self.gitDirectory stringByAppendingPathComponent:@"config"]; 79 | [fm createFileAtPath:configFile contents:[NSData dataWithBytes:[config UTF8String] length:[config length]] attributes:nil]; 80 | 81 | NSString *head = @"ref: refs/heads/master\n"; 82 | NSString *headFile = [self.gitDirectory stringByAppendingPathComponent:@"HEAD"]; 83 | [fm createFileAtPath:headFile contents:[NSData dataWithBytes:[head UTF8String] length:[head length]] attributes:nil]; 84 | 85 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"refs"] attributes:nil]; 86 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"refs/heads"] attributes:nil]; 87 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"refs/tags"] attributes:nil]; 88 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"objects"] attributes:nil]; 89 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"objects/info"] attributes:nil]; 90 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"objects/pack"] attributes:nil]; 91 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"branches"] attributes:nil]; 92 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"hooks"] attributes:nil]; 93 | [fm createDirectoryAtPath:[self.gitDirectory stringByAppendingPathComponent:@"info"] attributes:nil]; 94 | } 95 | 96 | - (NSString *) writeObject:(NSData *)objectData withType:(NSString *)type withSize:(int)size 97 | { 98 | NSMutableData *object; 99 | NSString *header, *path, *shaStr; 100 | unsigned char rawsha[20]; 101 | char sha1[41]; 102 | 103 | header = [NSString stringWithFormat:@"%@ %d", type, size]; 104 | const char *headerBytes = [header cStringUsingEncoding:NSASCIIStringEncoding]; 105 | 106 | object = [NSMutableData dataWithBytes:headerBytes length:([header length] + 1)]; 107 | [object appendData:objectData]; 108 | 109 | CC_SHA1([object bytes], [object length], rawsha); 110 | [ObjGit gitUnpackHex:rawsha fillSha:sha1]; 111 | NSLog(@"WRITING SHA: %s", sha1); 112 | 113 | // write object to file 114 | shaStr = [NSString stringWithCString:sha1 encoding:NSASCIIStringEncoding]; 115 | path = [self getLooseObjectPathBySha:shaStr]; 116 | NSData *compress = [[NSData dataWithBytes:[object bytes] length:[object length]] compressedData]; 117 | [compress writeToFile:path atomically:YES]; 118 | return shaStr; 119 | } 120 | 121 | - (BOOL) openRepo:(NSString *)dirPath 122 | { 123 | self.gitDirectory = dirPath; 124 | return YES; 125 | } 126 | 127 | - (NSMutableArray *) getCommitsFromSha:(NSString *)shaValue withLimit:(int)commitSize 128 | { 129 | NSString *currentSha; 130 | NSMutableArray *toDoArray = [NSMutableArray arrayWithCapacity:10]; 131 | NSMutableArray *commitArray = [NSMutableArray arrayWithCapacity:commitSize]; 132 | ObjGitCommit *gCommit; 133 | 134 | [toDoArray addObject: shaValue]; 135 | 136 | // loop for commits 137 | while( ([toDoArray count] > 0) && ([commitArray count] < commitSize) ) { 138 | currentSha = [[toDoArray objectAtIndex: 0] retain]; 139 | [toDoArray removeObjectAtIndex:0]; 140 | 141 | NSString *objectPath = [self getLooseObjectPathBySha:currentSha]; 142 | NSFileHandle *fm = [NSFileHandle fileHandleForReadingAtPath:objectPath]; 143 | 144 | gCommit = [[ObjGitCommit alloc] initFromRaw:[fm availableData] withSha:currentSha]; 145 | 146 | [toDoArray addObjectsFromArray:gCommit.parentShas]; 147 | [commitArray addObject:gCommit]; 148 | } 149 | 150 | // NSLog(@"s: %@", commitArray); 151 | //[toDoArray release]; 152 | return commitArray; 153 | } 154 | 155 | - (ObjGitObject *) getObjectFromSha:(NSString *)sha1 156 | { 157 | NSString *objectPath = [self getLooseObjectPathBySha:sha1]; 158 | //NSLog(@"READ FROM FILE: %@", objectPath); 159 | NSFileHandle *fm = [NSFileHandle fileHandleForReadingAtPath:objectPath]; 160 | ObjGitObject *obj = [[ObjGitObject alloc] initFromRaw:[fm availableData] withSha:sha1]; 161 | [fm closeFile]; 162 | return obj; 163 | } 164 | 165 | - (BOOL) hasObject: (NSString *)sha1 166 | { 167 | NSString *path; 168 | path = [self getLooseObjectPathBySha:sha1]; 169 | NSFileManager *fm = [NSFileManager defaultManager]; 170 | if ([fm fileExistsAtPath:path]) { 171 | return YES; 172 | } else { 173 | // TODO : check packs 174 | } 175 | return NO; 176 | } 177 | 178 | - (NSString *) getLooseObjectPathBySha: (NSString *)shaValue 179 | { 180 | NSString *looseSubDir = [shaValue substringWithRange:NSMakeRange(0, 2)]; 181 | NSString *looseFileName = [shaValue substringWithRange:NSMakeRange(2, 38)]; 182 | 183 | NSString *dir = [NSString stringWithFormat: @"%@/objects/%@", self.gitDirectory, looseSubDir]; 184 | 185 | BOOL isDir; 186 | NSFileManager *fm = [NSFileManager defaultManager]; 187 | if (!([fm fileExistsAtPath:dir isDirectory:&isDir] && isDir)) { 188 | [fm createDirectoryAtPath:dir attributes:nil]; 189 | } 190 | 191 | return [NSString stringWithFormat: @"%@/objects/%@/%@", \ 192 | self.gitDirectory, looseSubDir, looseFileName]; 193 | } 194 | 195 | 196 | /* 197 | * returns 1 if the char is alphanumeric, 0 if not 198 | */ 199 | + (int) isAlpha:(unsigned char)n 200 | { 201 | if(n <= 102 && n >= 97) { 202 | return 1; 203 | } 204 | return 0; 205 | } 206 | 207 | /* 208 | * fills a 40-char string with a readable hex version of 20-char sha binary 209 | */ 210 | + (int) gitUnpackHex:(const unsigned char *)rawsha fillSha:(char *)sha1 211 | { 212 | static const char hex[] = "0123456789abcdef"; 213 | int i; 214 | 215 | for (i = 0; i < 20; i++) { 216 | unsigned char n = rawsha[i]; 217 | sha1[i * 2] = hex[((n >> 4) & 15)]; 218 | n <<= 4; 219 | sha1[(i * 2) + 1] = hex[((n >> 4) & 15)]; 220 | } 221 | sha1[40] = 0; 222 | 223 | return 1; 224 | } 225 | 226 | /* 227 | * fills 20-char sha from 40-char hex version 228 | */ 229 | + (int) gitPackHex:(const char *)sha1 fillRawSha:(unsigned char *)rawsha 230 | { 231 | unsigned char byte = 0; 232 | int i, j = 0; 233 | 234 | for (i = 1; i <= 40; i++) { 235 | unsigned char n = sha1[i - 1]; 236 | 237 | if([ObjGit isAlpha:n]) { 238 | byte |= ((n & 15) + 9) & 15; 239 | } else { 240 | byte |= (n & 15); 241 | } 242 | if(i & 1) { 243 | byte <<= 4; 244 | } else { 245 | rawsha[j] = (byte & 0xff); 246 | j++; 247 | byte = 0; 248 | } 249 | } 250 | return 1; 251 | } 252 | 253 | @end 254 | 255 | -------------------------------------------------------------------------------- /Networking/TCPServer.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: TCPServer.m 4 | Abstract: A TCP server that listens on an arbitrary port. 5 | 6 | Version: 1.5 7 | 8 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 9 | ("Apple") in consideration of your agreement to the following terms, and your 10 | use, installation, modification or redistribution of this Apple software 11 | constitutes acceptance of these terms. If you do not agree with these terms, 12 | please do not use, install, modify or redistribute this Apple software. 13 | 14 | In consideration of your agreement to abide by the following terms, and subject 15 | to these terms, Apple grants you a personal, non-exclusive license, under 16 | Apple's copyrights in this original Apple software (the "Apple Software"), to 17 | use, reproduce, modify and redistribute the Apple Software, with or without 18 | modifications, in source and/or binary forms; provided that if you redistribute 19 | the Apple Software in its entirety and without modifications, you must retain 20 | this notice and the following text and disclaimers in all such redistributions 21 | of the Apple Software. 22 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used 23 | to endorse or promote products derived from the Apple Software without specific 24 | prior written permission from Apple. Except as expressly stated in this notice, 25 | no other rights or licenses, express or implied, are granted by Apple herein, 26 | including but not limited to any patent rights that may be infringed by your 27 | derivative works or by other works in which the Apple Software may be 28 | incorporated. 29 | 30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 31 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 32 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 34 | COMBINATION WITH YOUR PRODUCTS. 35 | 36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 37 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 38 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR 40 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF 41 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 42 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 | 44 | Copyright (C) 2008 Apple Inc. All Rights Reserved. 45 | 46 | */ 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #import "TCPServer.h" 54 | 55 | NSString * const TCPServerErrorDomain = @"TCPServerErrorDomain"; 56 | 57 | @interface TCPServer () 58 | @property(nonatomic,retain) NSNetService* netService; 59 | @property(assign) uint16_t port; 60 | @end 61 | 62 | @implementation TCPServer 63 | 64 | @synthesize delegate=_delegate, netService=_netService, port=_port; 65 | 66 | - (id)init { 67 | return self; 68 | } 69 | 70 | - (void)dealloc { 71 | [self stop]; 72 | [super dealloc]; 73 | } 74 | 75 | - (void)handleNewConnectionFromAddress:(NSData *)addr inputStream:(NSInputStream *)istr outputStream:(NSOutputStream *)ostr { 76 | // if the delegate implements the delegate method, call it 77 | if (self.delegate && [self.delegate respondsToSelector:@selector(didAcceptConnectionForServer:inputStream:outputStream:)]) { 78 | [self.delegate didAcceptConnectionForServer:self inputStream:istr outputStream:ostr]; 79 | } 80 | } 81 | 82 | // This function is called by CFSocket when a new connection comes in. 83 | // We gather some data here, and convert the function call to a method 84 | // invocation on TCPServer. 85 | static void TCPServerAcceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { 86 | TCPServer *server = (TCPServer *)info; 87 | if (kCFSocketAcceptCallBack == type) { 88 | // for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle 89 | CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data; 90 | uint8_t name[SOCK_MAXADDRLEN]; 91 | socklen_t namelen = sizeof(name); 92 | NSData *peer = nil; 93 | if (0 == getpeername(nativeSocketHandle, (struct sockaddr *)name, &namelen)) { 94 | peer = [NSData dataWithBytes:name length:namelen]; 95 | } 96 | CFReadStreamRef readStream = NULL; 97 | CFWriteStreamRef writeStream = NULL; 98 | CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &readStream, &writeStream); 99 | if (readStream && writeStream) { 100 | CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); 101 | CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); 102 | [server handleNewConnectionFromAddress:peer inputStream:(NSInputStream *)readStream outputStream:(NSOutputStream *)writeStream]; 103 | } else { 104 | // on any failure, need to destroy the CFSocketNativeHandle 105 | // since we are not going to use it any more 106 | close(nativeSocketHandle); 107 | } 108 | if (readStream) CFRelease(readStream); 109 | if (writeStream) CFRelease(writeStream); 110 | } 111 | } 112 | 113 | - (BOOL)start:(NSError **)error { 114 | CFSocketContext socketCtxt = {0, self, NULL, NULL, NULL}; 115 | _ipv4socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)&TCPServerAcceptCallBack, &socketCtxt); 116 | 117 | if (NULL == _ipv4socket) { 118 | if (error) *error = [[NSError alloc] initWithDomain:TCPServerErrorDomain code:kTCPServerNoSocketsAvailable userInfo:nil]; 119 | if (_ipv4socket) CFRelease(_ipv4socket); 120 | _ipv4socket = NULL; 121 | return NO; 122 | } 123 | 124 | 125 | int yes = 1; 126 | setsockopt(CFSocketGetNative(_ipv4socket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes)); 127 | 128 | // set up the IPv4 endpoint; use port 0, so the kernel will choose an arbitrary port for us, which will be advertised using Bonjour 129 | struct sockaddr_in addr4; 130 | memset(&addr4, 0, sizeof(addr4)); 131 | addr4.sin_len = sizeof(addr4); 132 | addr4.sin_family = AF_INET; 133 | addr4.sin_port = htons(9418); 134 | addr4.sin_addr.s_addr = htonl(INADDR_ANY); 135 | NSData *address4 = [NSData dataWithBytes:&addr4 length:sizeof(addr4)]; 136 | 137 | if (kCFSocketSuccess != CFSocketSetAddress(_ipv4socket, (CFDataRef)address4)) { 138 | if (error) *error = [[NSError alloc] initWithDomain:TCPServerErrorDomain code:kTCPServerCouldNotBindToIPv4Address userInfo:nil]; 139 | if (_ipv4socket) CFRelease(_ipv4socket); 140 | _ipv4socket = NULL; 141 | return NO; 142 | } 143 | 144 | // now that the binding was successful, we get the port number 145 | // -- we will need it for the NSNetService 146 | NSData *addr = [(NSData *)CFSocketCopyAddress(_ipv4socket) autorelease]; 147 | memcpy(&addr4, [addr bytes], [addr length]); 148 | self.port = ntohs(addr4.sin_port); 149 | NSLog(@"created server: %d", self.port); 150 | 151 | // set up the run loop sources for the sockets 152 | CFRunLoopRef cfrl = CFRunLoopGetCurrent(); 153 | CFRunLoopSourceRef source4 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _ipv4socket, 0); 154 | CFRunLoopAddSource(cfrl, source4, kCFRunLoopCommonModes); 155 | CFRelease(source4); 156 | 157 | return YES; 158 | } 159 | 160 | - (BOOL)stop { 161 | [self disableBonjour]; 162 | 163 | if (_ipv4socket) { 164 | CFSocketInvalidate(_ipv4socket); 165 | CFRelease(_ipv4socket); 166 | _ipv4socket = NULL; 167 | } 168 | 169 | return YES; 170 | } 171 | 172 | - (BOOL) enableBonjourWithDomain:(NSString*)domain applicationProtocol:(NSString*)protocol name:(NSString*)name 173 | { 174 | if(![domain length]) 175 | domain = @""; //Will use default Bonjour registration doamins, typically just ".local" 176 | if(![name length]) 177 | name = @""; //Will use default Bonjour name, e.g. the name assigned to the device in iTunes 178 | 179 | if(!protocol || ![protocol length] || _ipv4socket == NULL) 180 | return NO; 181 | 182 | NSLog(@"on domain: %@", domain); 183 | 184 | NSArray *keys = [NSArray arrayWithObjects:@"description", nil]; 185 | NSArray *objects = [NSArray arrayWithObjects:@"iphone git server", nil]; 186 | NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; 187 | 188 | self.netService = [[NSNetService alloc] initWithDomain:domain type:protocol name:name port:self.port]; 189 | [self.netService setTXTRecordData:[NSNetService dataFromTXTRecordDictionary:dictionary]]; 190 | 191 | if(self.netService == nil) 192 | return NO; 193 | 194 | [self.netService scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 195 | [self.netService publish]; 196 | [self.netService setDelegate:self]; 197 | 198 | return YES; 199 | } 200 | 201 | /* 202 | Bonjour will not allow conflicting service instance names (in the same domain), and may have automatically renamed 203 | the service if there was a conflict. We pass the name back to the delegate so that the name can be displayed to 204 | the user. 205 | See http://developer.apple.com/networking/bonjour/faq.html for more information. 206 | */ 207 | 208 | - (void)netServiceDidPublish:(NSNetService *)sender 209 | { 210 | if (self.delegate && [self.delegate respondsToSelector:@selector(serverDidEnableBonjour:withName:)]) 211 | [self.delegate serverDidEnableBonjour:self withName:sender.name]; 212 | } 213 | 214 | - (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary *)errorDict 215 | { 216 | [super netServiceDidPublish:sender]; 217 | if(self.delegate && [self.delegate respondsToSelector:@selector(server:didNotEnableBonjour:)]) 218 | [self.delegate server:self didNotEnableBonjour:errorDict]; 219 | } 220 | 221 | - (void) disableBonjour 222 | { 223 | if(self.netService) { 224 | [self.netService stop]; 225 | [self.netService removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 226 | self.netService = nil; 227 | } 228 | } 229 | 230 | - (NSString*) description 231 | { 232 | return [NSString stringWithFormat:@"<%@ = 0x%08X | p %d | ns %@>", [self class], (long)self, self.port, self.netService]; 233 | } 234 | 235 | + (NSString*) bonjourTypeFromIdentifier:(NSString*)identifier { 236 | if (![identifier length]) 237 | return nil; 238 | 239 | return [NSString stringWithFormat:@"_%@._tcp.", identifier]; 240 | } 241 | 242 | @end 243 | -------------------------------------------------------------------------------- /Networking/BrowserViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: BrowserViewController.m 4 | Abstract: 5 | View controller for the service instance list. 6 | This object manages a NSNetServiceBrowser configured to look for Bonjour 7 | services. 8 | It has an array of NSNetService objects that are displayed in a table view. 9 | When the service browser reports that it has discovered a service, the 10 | corresponding NSNetService is added to the array. 11 | When a service goes away, the corresponding NSNetService is removed from the 12 | array. 13 | Selecting an item in the table view asynchronously resolves the corresponding 14 | net service. 15 | When that resolution completes, the delegate is called with the corresponding 16 | NSNetService. 17 | 18 | 19 | Version: 1.5 20 | 21 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 22 | ("Apple") in consideration of your agreement to the following terms, and your 23 | use, installation, modification or redistribution of this Apple software 24 | constitutes acceptance of these terms. If you do not agree with these terms, 25 | please do not use, install, modify or redistribute this Apple software. 26 | 27 | In consideration of your agreement to abide by the following terms, and subject 28 | to these terms, Apple grants you a personal, non-exclusive license, under 29 | Apple's copyrights in this original Apple software (the "Apple Software"), to 30 | use, reproduce, modify and redistribute the Apple Software, with or without 31 | modifications, in source and/or binary forms; provided that if you redistribute 32 | the Apple Software in its entirety and without modifications, you must retain 33 | this notice and the following text and disclaimers in all such redistributions 34 | of the Apple Software. 35 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used 36 | to endorse or promote products derived from the Apple Software without specific 37 | prior written permission from Apple. Except as expressly stated in this notice, 38 | no other rights or licenses, express or implied, are granted by Apple herein, 39 | including but not limited to any patent rights that may be infringed by your 40 | derivative works or by other works in which the Apple Software may be 41 | incorporated. 42 | 43 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 44 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 45 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 46 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 47 | COMBINATION WITH YOUR PRODUCTS. 48 | 49 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 50 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 51 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR 53 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF 54 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 55 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | Copyright (C) 2008 Apple Inc. All Rights Reserved. 58 | 59 | */ 60 | 61 | #import "BrowserViewController.h" 62 | 63 | #define kProgressIndicatorSize 20.0 64 | 65 | // A category on NSNetService that's used to sort NSNetService objects by their name. 66 | @interface NSNetService (BrowserViewControllerAdditions) 67 | - (NSComparisonResult) localizedCaseInsensitiveCompareByName:(NSNetService*)aService; 68 | @end 69 | 70 | @implementation NSNetService (BrowserViewControllerAdditions) 71 | - (NSComparisonResult) localizedCaseInsensitiveCompareByName:(NSNetService*)aService { 72 | return [[self name] localizedCaseInsensitiveCompare:[aService name]]; 73 | } 74 | @end 75 | 76 | 77 | @interface BrowserViewController() 78 | @property (nonatomic, retain, readwrite) NSNetService* ownEntry; 79 | @property (nonatomic, assign, readwrite) BOOL showDisclosureIndicators; 80 | @property (nonatomic, retain, readwrite) NSMutableArray* services; 81 | @property (nonatomic, retain, readwrite) NSNetServiceBrowser* netServiceBrowser; 82 | @property (nonatomic, retain, readwrite) NSNetService* currentResolve; 83 | @property (nonatomic, retain, readwrite) NSTimer* timer; 84 | @property (nonatomic, assign, readwrite) BOOL needsActivityIndicator; 85 | @property (nonatomic, assign, readwrite) BOOL initialWaitOver; 86 | 87 | - (void)stopCurrentResolve; 88 | - (void)initialWaitOver:(NSTimer*)timer; 89 | @end 90 | 91 | @implementation BrowserViewController 92 | 93 | @synthesize delegate = _delegate; 94 | @synthesize ownEntry = _ownEntry; 95 | @synthesize showDisclosureIndicators = _showDisclosureIndicators; 96 | @synthesize currentResolve = _currentResolve; 97 | @synthesize netServiceBrowser = _netServiceBrowser; 98 | @synthesize services = _services; 99 | @synthesize needsActivityIndicator = _needsActivityIndicator; 100 | @dynamic timer; 101 | @synthesize initialWaitOver = _initialWaitOver; 102 | 103 | 104 | - (id)initWithTitle:(NSString*)title showDisclosureIndicators:(BOOL)show showCancelButton:(BOOL)showCancelButton { 105 | 106 | if ((self = [super initWithStyle:UITableViewStylePlain])) { 107 | self.title = title; 108 | _services = [[NSMutableArray alloc] init]; 109 | self.showDisclosureIndicators = show; 110 | 111 | if (showCancelButton) { 112 | // add Cancel button as the nav bar's custom right view 113 | UIBarButtonItem *addButton = [[UIBarButtonItem alloc] 114 | initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAction)]; 115 | self.navigationItem.rightBarButtonItem = addButton; 116 | [addButton release]; 117 | } 118 | 119 | // Make sure we have a chance to discover devices before showing the user that nothing was found (yet) 120 | [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(initialWaitOver:) userInfo:nil repeats:NO]; 121 | } 122 | 123 | return self; 124 | } 125 | 126 | - (NSString *)searchingForServicesString { 127 | return _searchingForServicesString; 128 | } 129 | 130 | // Holds the string that's displayed in the table view during service discovery. 131 | - (void)setSearchingForServicesString:(NSString *)searchingForServicesString { 132 | if (_searchingForServicesString != searchingForServicesString) { 133 | [_searchingForServicesString release]; 134 | _searchingForServicesString = [searchingForServicesString copy]; 135 | 136 | // If there are no services, reload the table to ensure that searchingForServicesString appears. 137 | if ([self.services count] == 0) { 138 | [self.tableView reloadData]; 139 | } 140 | } 141 | } 142 | 143 | - (NSString *)ownName { 144 | return _ownName; 145 | } 146 | 147 | // Holds the string that's displayed in the table view during service discovery. 148 | - (void)setOwnName:(NSString *)name { 149 | if (_ownName != name) { 150 | _ownName = [name copy]; 151 | 152 | if (self.ownEntry) 153 | [self.services addObject:self.ownEntry]; 154 | 155 | NSNetService* service; 156 | 157 | for (service in self.services) { 158 | if ([service.name isEqual:name]) { 159 | self.ownEntry = service; 160 | [_services removeObject:service]; 161 | break; 162 | } 163 | } 164 | 165 | [self.tableView reloadData]; 166 | } 167 | } 168 | 169 | // Creates an NSNetServiceBrowser that searches for services of a particular type in a particular domain. 170 | // If a service is currently being resolved, stop resolving it and stop the service browser from 171 | // discovering other services. 172 | - (BOOL)searchForServicesOfType:(NSString *)type inDomain:(NSString *)domain { 173 | 174 | [self stopCurrentResolve]; 175 | [self.netServiceBrowser stop]; 176 | [self.services removeAllObjects]; 177 | 178 | NSNetServiceBrowser *aNetServiceBrowser = [[NSNetServiceBrowser alloc] init]; 179 | if(!aNetServiceBrowser) { 180 | // The NSNetServiceBrowser couldn't be allocated and initialized. 181 | return NO; 182 | } 183 | 184 | aNetServiceBrowser.delegate = self; 185 | self.netServiceBrowser = aNetServiceBrowser; 186 | [aNetServiceBrowser release]; 187 | [self.netServiceBrowser searchForServicesOfType:type inDomain:domain]; 188 | 189 | [self.tableView reloadData]; 190 | return YES; 191 | } 192 | 193 | 194 | - (NSTimer *)timer { 195 | return _timer; 196 | } 197 | 198 | // When this is called, invalidate the existing timer before releasing it. 199 | - (void)setTimer:(NSTimer *)newTimer { 200 | [_timer invalidate]; 201 | [newTimer retain]; 202 | [_timer release]; 203 | _timer = newTimer; 204 | } 205 | 206 | 207 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 208 | return 1; 209 | } 210 | 211 | 212 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 213 | // If there are no services and searchingForServicesString is set, show one row to tell the user. 214 | NSUInteger count = [self.services count]; 215 | if (count == 0 && self.searchingForServicesString && self.initialWaitOver) 216 | return 1; 217 | 218 | return count; 219 | } 220 | 221 | 222 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 223 | 224 | static NSString *tableCellIdentifier = @"UITableViewCell"; 225 | UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:tableCellIdentifier]; 226 | if (cell == nil) { 227 | cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:tableCellIdentifier] autorelease]; 228 | } 229 | 230 | NSUInteger count = [self.services count]; 231 | if (count == 0 && self.searchingForServicesString) { 232 | // If there are no services and searchingForServicesString is set, show one row explaining that to the user. 233 | cell.text = self.searchingForServicesString; 234 | cell.textColor = [UIColor colorWithWhite:0.5 alpha:0.5]; 235 | cell.accessoryType = UITableViewCellAccessoryNone; 236 | return cell; 237 | } 238 | 239 | // Set up the text for the cell 240 | NSNetService* service = [self.services objectAtIndex:indexPath.row]; 241 | cell.text = [service name]; 242 | cell.textColor = [UIColor blackColor]; 243 | cell.accessoryType = self.showDisclosureIndicators ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone; 244 | 245 | // Note that the underlying array could have changed, and we want to show the activity indicator on the correct cell 246 | if (self.needsActivityIndicator && self.currentResolve == service) { 247 | if (!cell.accessoryView) { 248 | CGRect frame = CGRectMake(0.0, 0.0, kProgressIndicatorSize, kProgressIndicatorSize); 249 | UIActivityIndicatorView* spinner = [[UIActivityIndicatorView alloc] initWithFrame:frame]; 250 | [spinner startAnimating]; 251 | spinner.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; 252 | [spinner sizeToFit]; 253 | spinner.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | 254 | UIViewAutoresizingFlexibleRightMargin | 255 | UIViewAutoresizingFlexibleTopMargin | 256 | UIViewAutoresizingFlexibleBottomMargin); 257 | cell.accessoryView = spinner; 258 | [spinner release]; 259 | } 260 | } else if (cell.accessoryView) { 261 | cell.accessoryView = nil; 262 | } 263 | 264 | return cell; 265 | } 266 | 267 | 268 | - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { 269 | // Ignore the selection if there are no services. 270 | if ([self.services count] == 0) 271 | return nil; 272 | 273 | return indexPath; 274 | } 275 | 276 | 277 | - (void)stopCurrentResolve { 278 | 279 | self.needsActivityIndicator = NO; 280 | self.timer = nil; 281 | 282 | [self.currentResolve stop]; 283 | self.currentResolve = nil; 284 | } 285 | 286 | 287 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 288 | // If another resolve was running, stop it first 289 | 290 | [self stopCurrentResolve]; 291 | self.currentResolve = [self.services objectAtIndex:indexPath.row]; 292 | 293 | [self.currentResolve setDelegate:self]; 294 | // Attempt to resolve the service. A value of 0.0 sets an unlimited time to resolve it. The user can 295 | // choose to cancel the resolve by selecting another service in the table view. 296 | [self.currentResolve resolveWithTimeout:0.0]; 297 | 298 | // Make sure we give the user some feedback that the resolve is happening. 299 | // We will be called back asynchronously, so we don't want the user to think 300 | // we're just stuck. 301 | self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(showWaiting:) userInfo:self.currentResolve repeats:NO]; 302 | [self.tableView reloadData]; 303 | } 304 | 305 | // If necessary, sets up state to show an activity indicator to let the user know that a resolve is occuring. 306 | - (void)showWaiting:(NSTimer*)timer { 307 | 308 | if (timer == self.timer) { 309 | [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES]; 310 | NSNetService* service = (NSNetService*)[self.timer userInfo]; 311 | if (self.currentResolve == service) { 312 | self.needsActivityIndicator = YES; 313 | [self.tableView reloadData]; 314 | } 315 | } 316 | } 317 | 318 | 319 | - (void)initialWaitOver:(NSTimer*)timer { 320 | self.initialWaitOver= YES; 321 | if (![self.services count]) 322 | [self.tableView reloadData]; 323 | } 324 | 325 | 326 | - (void)sortAndUpdateUI { 327 | // Sort the services by name. 328 | [self.services sortUsingSelector:@selector(localizedCaseInsensitiveCompareByName:)]; 329 | [self.tableView reloadData]; 330 | } 331 | 332 | 333 | - (void)netServiceBrowser:(NSNetServiceBrowser*)netServiceBrowser didRemoveService:(NSNetService*)service moreComing:(BOOL)moreComing { 334 | // If a service went away, stop resolving it if it's currently being resolve, 335 | // remove it from the list and update the table view if no more events are queued. 336 | 337 | if (self.currentResolve && [service isEqual:self.currentResolve]) { 338 | [self stopCurrentResolve]; 339 | } 340 | [self.services removeObject:service]; 341 | if (self.ownEntry == service) 342 | self.ownEntry = nil; 343 | 344 | // If moreComing is NO, it means that there are no more messages in the queue from the Bonjour daemon, so we should update the UI. 345 | // When moreComing is set, we don't update the UI so that it doesn't 'flash'. 346 | if (!moreComing) { 347 | [self sortAndUpdateUI]; 348 | } 349 | } 350 | 351 | 352 | - (void)netServiceBrowser:(NSNetServiceBrowser*)netServiceBrowser didFindService:(NSNetService*)service moreComing:(BOOL)moreComing { 353 | // If a service came online, add it to the list and update the table view if no more events are queued. 354 | if ([service.name isEqual:self.ownName]) 355 | self.ownEntry = service; 356 | else 357 | [self.services addObject:service]; 358 | 359 | // If moreComing is NO, it means that there are no more messages in the queue from the Bonjour daemon, so we should update the UI. 360 | // When moreComing is set, we don't update the UI so that it doesn't 'flash'. 361 | if (!moreComing) { 362 | [self sortAndUpdateUI]; 363 | } 364 | } 365 | 366 | 367 | // This should never be called, since we resolve with a timeout of 0.0, which means indefinite 368 | - (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict { 369 | [self stopCurrentResolve]; 370 | [self.tableView reloadData]; 371 | } 372 | 373 | 374 | - (void)netServiceDidResolveAddress:(NSNetService *)service { 375 | assert(service == self.currentResolve); 376 | 377 | [service retain]; 378 | [self stopCurrentResolve]; 379 | 380 | [self.delegate browserViewController:self didResolveInstance:service]; 381 | [service release]; 382 | } 383 | 384 | 385 | - (void)cancelAction { 386 | [self.delegate browserViewController:self didResolveInstance:nil]; 387 | } 388 | 389 | 390 | - (void)dealloc { 391 | // Cleanup any running resolve and free memory 392 | [self stopCurrentResolve]; 393 | self.services = nil; 394 | [self.netServiceBrowser stop]; 395 | self.netServiceBrowser = nil; 396 | [_searchingForServicesString release]; 397 | [_ownName release]; 398 | [_ownEntry release]; 399 | 400 | [super dealloc]; 401 | } 402 | 403 | 404 | @end 405 | -------------------------------------------------------------------------------- /Git/ObjGitServerHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjGitServerHandler.m 3 | // ObjGit 4 | // 5 | 6 | #define NULL_SHA @"0000000000000000000000000000000000000000" 7 | #define CAPABILITIES @" report-status delete-refs " 8 | 9 | #define PACK_SIGNATURE 0x5041434b /* "PACK" */ 10 | #define PACK_VERSION 2 11 | 12 | #define OBJ_NONE 0 13 | #define OBJ_COMMIT 1 14 | #define OBJ_TREE 2 15 | #define OBJ_BLOB 3 16 | #define OBJ_TAG 4 17 | #define OBJ_OFS_DELTA 6 18 | #define OBJ_REF_DELTA 7 19 | 20 | #import "ObjGit.h" 21 | #import "ObjGitObject.h" 22 | #import "ObjGitCommit.h" 23 | #import "ObjGitTree.h" 24 | #import "ObjGitServerHandler.h" 25 | #import "NSDataCompression.h" 26 | #include 27 | #include 28 | 29 | @implementation ObjGitServerHandler 30 | 31 | @synthesize inStream; 32 | @synthesize outStream; 33 | @synthesize gitRepo; 34 | @synthesize gitPath; 35 | 36 | @synthesize refsRead; 37 | @synthesize needRefs; 38 | @synthesize refDict; 39 | 40 | @synthesize capabilitiesSent; 41 | 42 | - (void) initWithGit:(ObjGit *)git gitPath:(NSString *)gitRepoPath input:(NSInputStream *)streamIn output:(NSOutputStream *)streamOut 43 | { 44 | gitRepo = git; 45 | gitPath = gitRepoPath; 46 | inStream = streamIn; 47 | outStream = streamOut; 48 | [self handleRequest]; 49 | } 50 | 51 | /* 52 | * initiates communication with an incoming request 53 | * and passes it to the appropriate receiving function 54 | * either upload-pack for fetches or receive-pack for pushes 55 | */ 56 | - (void) handleRequest { 57 | NSLog(@"HANDLE REQUEST"); 58 | NSString *header, *command, *repository, *repo, *hostpath; 59 | header = [self packetReadLine]; 60 | 61 | NSArray *values = [header componentsSeparatedByString:@" "]; 62 | command = [values objectAtIndex: 0]; 63 | repository = [values objectAtIndex: 1]; 64 | 65 | values = [repository componentsSeparatedByCharactersInSet:[NSCharacterSet controlCharacterSet]]; 66 | repo = [values objectAtIndex: 0]; 67 | hostpath = [values objectAtIndex: 1]; 68 | 69 | NSLog(@"header: %@ : %@ : %@", command, repo, hostpath); 70 | 71 | NSString *dir = [gitPath stringByAppendingPathComponent:repo]; 72 | [gitRepo openRepo:dir]; 73 | 74 | if([command isEqualToString: @"git-receive-pack"]) { // git push // 75 | [self receivePack:repository]; 76 | } else if ([command isEqualToString: @"git-upload-pack"]) { // git fetch // 77 | [self uploadPack:repository]; 78 | } 79 | 80 | } 81 | 82 | /*** UPLOAD-PACK FUNCTIONS ***/ 83 | 84 | - (void) uploadPack:(NSString *)repositoryName { 85 | [self sendRefs]; 86 | [self receiveNeeds]; 87 | [self uploadPackFile]; 88 | //NSLog(@"out:%@", outStream); 89 | //NSLog(@"out avail:%d", [outStream hasSpaceAvailable]); 90 | //NSLog(@" in avail:%d", [inStream hasBytesAvailable]); 91 | } 92 | 93 | - (void) receiveNeeds 94 | { 95 | NSLog(@"receive needs"); 96 | NSString *data, *cmd, *sha; 97 | NSArray *values; 98 | needRefs = [[NSMutableArray alloc] init]; 99 | 100 | while(![(data = [self packetReadLine]) isEqualToString:@"done\n"]) { 101 | if([data length] > 40) { 102 | NSLog(@"data line: %@", data); 103 | 104 | values = [data componentsSeparatedByString:@" "]; 105 | cmd = [values objectAtIndex: 0]; 106 | sha = [values objectAtIndex: 1]; 107 | 108 | [needRefs addObject:values]; 109 | } 110 | } 111 | 112 | //puts @session.recv(9) 113 | NSLog(@"need refs:%@", needRefs); 114 | NSLog(@"sending nack"); 115 | [self sendNack]; 116 | } 117 | 118 | - (void) uploadPackFile 119 | { 120 | NSLog(@"upload pack file"); 121 | NSString *command, *shaValue; 122 | NSArray *thisRef; 123 | 124 | refDict = [[NSMutableDictionary alloc] init]; 125 | 126 | NSEnumerator *e = [needRefs objectEnumerator]; 127 | while ( (thisRef = [e nextObject]) ) { 128 | command = [thisRef objectAtIndex:0]; 129 | shaValue = [thisRef objectAtIndex:1]; 130 | if([command isEqualToString:@"have"]) { 131 | [refDict setObject:@"have" forKey:shaValue]; 132 | } 133 | } 134 | 135 | NSLog(@"gathering shas"); 136 | e = [needRefs objectEnumerator]; 137 | while ( (thisRef = [e nextObject]) ) { 138 | command = [thisRef objectAtIndex:0]; 139 | shaValue = [thisRef objectAtIndex:1]; 140 | if([command isEqualToString:@"want"]) { 141 | [self gatherObjectShasFromCommit:shaValue]; 142 | } 143 | } 144 | 145 | [self sendPackData]; 146 | } 147 | 148 | - (void) sendPackData 149 | { 150 | NSLog(@"send pack data"); 151 | NSString *current; 152 | NSEnumerator *e; 153 | 154 | CC_SHA1_CTX *checksum; 155 | CC_SHA1_Init(checksum); 156 | 157 | //NSArray *shas; 158 | //shas = [refDict keysSortedByValueUsingSelector:@selector(compare:)]; 159 | 160 | uint8_t buffer[5]; 161 | 162 | // write pack header 163 | 164 | [self longVal:htonl(PACK_SIGNATURE) toByteBuffer:buffer]; 165 | [self respondPack:buffer length:4 checkSum:checksum]; 166 | 167 | [self longVal:htonl(PACK_VERSION) toByteBuffer:buffer]; 168 | [self respondPack:buffer length:4 checkSum:checksum]; 169 | 170 | [self longVal:htonl([refDict count]) toByteBuffer:buffer]; 171 | NSLog(@"write len [%d %d %d %d]", buffer[0], buffer[1], buffer[2], buffer[3]); 172 | [self respondPack:buffer length:4 checkSum:checksum]; 173 | 174 | //NSLog(@"refs: %@", shas); 175 | e = [refDict keyEnumerator]; 176 | ObjGitObject *obj; 177 | NSData *objData, *data; 178 | int size, btype, c; 179 | while ( (current = [e nextObject]) ) { 180 | obj = [gitRepo getObjectFromSha:current]; 181 | size = [obj size]; 182 | btype = [self typeInt:[obj type]]; 183 | 184 | c = (btype << 4) | (size & 15); 185 | size = (size >> 4); 186 | if(size > 0) 187 | c |= 0x80; 188 | buffer[0] = c; 189 | [self respondPack:buffer length:1 checkSum:checksum]; 190 | 191 | while (size > 0) { 192 | c = size & 0x7f; 193 | size = (size >> 7); 194 | if(size > 0) 195 | c |= 0x80; 196 | buffer[0] = c; 197 | [self respondPack:buffer length:1 checkSum:checksum]; 198 | } 199 | 200 | // pack object data 201 | //NSLog(@"srclen:%d, %d", [obj size], [obj rawContentLen]); 202 | objData = [NSData dataWithBytes:[obj rawContents] length:([obj rawContentLen])]; 203 | data = [objData compressedData]; 204 | 205 | int len = [data length]; 206 | uint8_t dataBuffer[len + 1]; 207 | [data getBytes:dataBuffer]; 208 | 209 | [self respondPack:dataBuffer length:len checkSum:checksum]; 210 | } 211 | 212 | unsigned char finalSha[20]; 213 | CC_SHA1_Final(finalSha, checksum); 214 | 215 | [outStream write:finalSha maxLength:20]; 216 | NSLog(@"end sent"); 217 | } 218 | 219 | - (void) respondPack:(uint8_t *)buffer length:(int)size checkSum:(CC_SHA1_CTX *)checksum 220 | { 221 | CC_SHA1_Update(checksum, buffer, size); 222 | [outStream write:buffer maxLength:size]; 223 | } 224 | 225 | - (void) longVal:(uint32_t)raw toByteBuffer:(uint8_t *)buffer 226 | { 227 | buffer[3] = (raw >> 24); 228 | buffer[2] = (raw >> 16); 229 | buffer[1] = (raw >> 8); 230 | buffer[0] = (raw); 231 | } 232 | 233 | - (void) gatherObjectShasFromCommit:(NSString *)shaValue 234 | { 235 | NSString *parentSha; 236 | ObjGitCommit *commit = [[ObjGitCommit alloc] initFromGitObject:[gitRepo getObjectFromSha:shaValue]]; 237 | [refDict setObject:@"_commit" forKey:shaValue]; 238 | 239 | // add the tree objects 240 | [self gatherObjectShasFromTree:[commit treeSha]]; 241 | 242 | NSArray *parents = [commit parentShas]; 243 | 244 | NSEnumerator *e = [parents objectEnumerator]; 245 | while ( (parentSha = [e nextObject]) ) { 246 | NSLog(@"parent sha:%@", parentSha); 247 | // TODO : check that refDict does not have this 248 | [self gatherObjectShasFromCommit:parentSha]; 249 | } 250 | } 251 | 252 | - (void) gatherObjectShasFromTree:(NSString *)shaValue 253 | { 254 | ObjGitTree *tree = [ObjGitTree alloc]; 255 | [tree initFromGitObject:[gitRepo getObjectFromSha:shaValue]]; 256 | [refDict setObject:@"/" forKey:shaValue]; 257 | NSEnumerator *e = [[tree treeEntries] objectEnumerator]; 258 | //[tree release]; 259 | NSArray *entries; 260 | NSString *name, *sha, *mode; 261 | while ( (entries = [e nextObject]) ) { 262 | mode = [entries objectAtIndex:0]; 263 | name = [entries objectAtIndex:1]; 264 | sha = [entries objectAtIndex:2]; 265 | [refDict setObject:name forKey:sha]; 266 | if ([mode isEqualToString:@"40000"]) { // tree 267 | // TODO : check that refDict does not have this 268 | [self gatherObjectShasFromTree:sha]; 269 | } 270 | } 271 | } 272 | 273 | 274 | - (void) sendNack 275 | { 276 | [self sendPacket:@"0007NAK"]; 277 | } 278 | 279 | 280 | /*** UPLOAD-PACK FUNCTIONS END ***/ 281 | 282 | 283 | 284 | /*** RECEIVE-PACK FUNCTIONS ***/ 285 | 286 | /* 287 | * handles a push request - this involves validating the request, 288 | * initializing the repository if it's not there, sending the 289 | * refs we have, receiving the packfile form the client and unpacking 290 | * the packed objects (eventually we should have an option to keep the 291 | * packfile and build an index instead) 292 | */ 293 | - (void) receivePack:(NSString *)repositoryName { 294 | capabilitiesSent = 0; 295 | 296 | [gitRepo ensureGitPath]; 297 | 298 | [self sendRefs]; 299 | [self readRefs]; 300 | [self readPack]; 301 | [self writeRefs]; 302 | [self packetFlush]; 303 | } 304 | 305 | - (void) sendRefs { 306 | NSLog(@"send refs"); 307 | 308 | NSArray *refs = [gitRepo getAllRefs]; 309 | NSLog(@"refs: %@", refs); 310 | 311 | NSEnumerator *e = [refs objectEnumerator]; 312 | NSString *refName, *shaValue; 313 | NSArray *thisRef; 314 | while ( (thisRef = [e nextObject]) ) { 315 | refName = [thisRef objectAtIndex:0]; 316 | shaValue = [thisRef objectAtIndex:1]; 317 | [self sendRef:refName sha:shaValue]; 318 | } 319 | 320 | // send capabilities and null sha to client if no refs // 321 | if(!capabilitiesSent) 322 | [self sendRef:@"capabilities^{}" sha:NULL_SHA]; 323 | [self packetFlush]; 324 | } 325 | 326 | - (void) sendRef:(NSString *)refName sha:(NSString *)shaString { 327 | NSString *sendData; 328 | if(capabilitiesSent) 329 | sendData = [[NSString alloc] initWithFormat:@"%@ %@\n", shaString, refName]; 330 | else 331 | sendData = [[NSString alloc] initWithFormat:@"%@ %@\0%@\n", shaString, refName, CAPABILITIES]; 332 | [self writeServer:sendData]; 333 | capabilitiesSent = 1; 334 | } 335 | 336 | - (void) readRefs { 337 | NSString *data, *old, *new, *refName, *cap, *refStuff; 338 | NSLog(@"read refs"); 339 | data = [self packetReadLine]; 340 | NSMutableArray *refs = [[NSMutableArray alloc] init]; 341 | while([data length] > 0) { 342 | 343 | NSArray *values = [data componentsSeparatedByString:@" "]; 344 | old = [values objectAtIndex:0]; 345 | new = [values objectAtIndex:1]; 346 | refStuff = [values objectAtIndex:2]; 347 | 348 | NSArray *ref = [refStuff componentsSeparatedByString:@"\0"]; 349 | refName = [ref objectAtIndex:0]; 350 | cap = nil; 351 | if([ref count] > 1) 352 | cap = [ref objectAtIndex:1]; 353 | 354 | NSArray *refData = [NSArray arrayWithObjects:old, new, refName, cap, nil]; 355 | [refs addObject:refData]; // save the refs for writing later 356 | 357 | /* DEBUGGING */ 358 | NSLog(@"ref: [%@ : %@ : %@]", old, new, refName, cap); 359 | 360 | data = [self packetReadLine]; 361 | } 362 | refsRead = [NSArray arrayWithArray:refs]; 363 | } 364 | 365 | /* 366 | * read packfile data from the stream and expand the objects out to disk 367 | */ 368 | - (void) readPack { 369 | NSLog(@"read pack"); 370 | int n; 371 | int entries = [self readPackHeader]; 372 | 373 | for(n = 1; n <= entries; n++) { 374 | NSLog(@"entry: %d", n); 375 | [self unpackObject]; 376 | } 377 | 378 | // receive and process checksum 379 | uint8_t checksum[20]; 380 | [inStream read:checksum maxLength:20]; 381 | } 382 | 383 | - (void) unpackObject { 384 | // read in the header 385 | int size, type, shift; 386 | uint8_t byte[1]; 387 | [inStream read:byte maxLength:1]; 388 | 389 | size = byte[0] & 0xf; 390 | type = (byte[0] >> 4) & 7; 391 | shift = 4; 392 | while((byte[0] & 0x80) != 0) { 393 | [inStream read:byte maxLength:1]; 394 | size |= ((byte[0] & 0x7f) << shift); 395 | shift += 7; 396 | } 397 | 398 | NSLog(@"TYPE: %d", type); 399 | NSLog(@"size: %d", size); 400 | 401 | if((type == OBJ_COMMIT) || (type == OBJ_TREE) || (type == OBJ_BLOB) || (type == OBJ_TAG)) { 402 | NSData *objectData; 403 | objectData = [self readData:size]; 404 | [gitRepo writeObject:objectData withType:[self typeString:type] withSize:size]; 405 | // TODO : check saved delta objects 406 | } else if ((type == OBJ_REF_DELTA) || (type == OBJ_OFS_DELTA)) { 407 | [self unpackDeltified:type size:size]; 408 | } else { 409 | NSLog(@"bad object type %d", type); 410 | } 411 | } 412 | 413 | - (void) unpackDeltified:(int)type size:(int)size { 414 | if(type == OBJ_REF_DELTA) { 415 | NSString *sha1; 416 | NSData *objectData, *contents; 417 | 418 | sha1 = [self readServerSha]; 419 | //NSLog(@"DELTA SHA: %@", sha1); 420 | objectData = [self readData:size]; 421 | 422 | if([gitRepo hasObject:sha1]) { 423 | ObjGitObject *object; 424 | object = [gitRepo getObjectFromSha:sha1]; 425 | contents = [self patchDelta:objectData withObject:object]; 426 | //NSLog(@"unpacked delta: %@ : %@", contents, [object type]); 427 | [gitRepo writeObject:contents withType:[object type] withSize:[contents length]]; 428 | //[object release]; 429 | } else { 430 | // TODO : OBJECT ISN'T HERE YET, SAVE THIS DELTA FOR LATER // 431 | /* 432 | @delta_list[sha1] ||= [] 433 | @delta_list[sha1] << delta 434 | */ 435 | } 436 | } else { 437 | // offset deltas not supported yet 438 | // this isn't returned in the capabilities, so it shouldn't be a problem 439 | } 440 | } 441 | 442 | - (NSData *) patchDelta:(NSData *)deltaData withObject:(ObjGitObject *)gitObject 443 | { 444 | unsigned long sourceSize, destSize, position; 445 | unsigned long cp_off, cp_size; 446 | unsigned char c[2], d[2]; 447 | 448 | int buffLength = 1000; 449 | NSMutableData *buffer = [[NSMutableData alloc] initWithCapacity:buffLength]; 450 | 451 | NSArray *sizePos = [self patchDeltaHeaderSize:deltaData position:0]; 452 | sourceSize = [[sizePos objectAtIndex:0] longValue]; 453 | position = [[sizePos objectAtIndex:1] longValue]; 454 | 455 | //NSLog(@"SS: %d Pos:%d", sourceSize, position); 456 | 457 | sizePos = [self patchDeltaHeaderSize:deltaData position:position]; 458 | destSize = [[sizePos objectAtIndex:0] longValue]; 459 | position = [[sizePos objectAtIndex:1] longValue]; 460 | 461 | NSData *source = [NSData dataWithBytes:[gitObject rawContents] length:[gitObject rawContentLen]]; 462 | 463 | //NSLog(@"SOURCE:%@", source); 464 | NSMutableData *destination = [NSMutableData dataWithCapacity:destSize]; 465 | 466 | while (position < ([deltaData length])) { 467 | [deltaData getBytes:c range:NSMakeRange(position, 1)]; 468 | //NSLog(@"DS: %d Pos:%d", destSize, position); 469 | //NSLog(@"CHR: %d", c[0]); 470 | 471 | position += 1; 472 | if((c[0] & 0x80) != 0) { 473 | position -= 1; 474 | cp_off = cp_size = 0; 475 | 476 | if((c[0] & 0x01) != 0) { 477 | [deltaData getBytes:d range:NSMakeRange(position += 1, 1)]; 478 | cp_off = d[0]; 479 | } 480 | if((c[0] & 0x02) != 0) { 481 | [deltaData getBytes:d range:NSMakeRange(position += 1, 1)]; 482 | cp_off |= d[0] << 8; 483 | } 484 | if((c[0] & 0x04) != 0) { 485 | [deltaData getBytes:d range:NSMakeRange(position += 1, 1)]; 486 | cp_off |= d[0] << 16; 487 | } 488 | if((c[0] & 0x08) != 0) { 489 | [deltaData getBytes:d range:NSMakeRange(position += 1, 1)]; 490 | cp_off |= d[0] << 24; 491 | } 492 | if((c[0] & 0x10) != 0) { 493 | [deltaData getBytes:d range:NSMakeRange(position += 1, 1)]; 494 | cp_size = d[0]; 495 | } 496 | if((c[0] & 0x20) != 0) { 497 | [deltaData getBytes:d range:NSMakeRange(position += 1, 1)]; 498 | cp_size |= d[0] << 8; 499 | } 500 | if((c[0] & 0x40) != 0) { 501 | [deltaData getBytes:d range:NSMakeRange(position += 1, 1)]; 502 | cp_size |= d[0] << 16; 503 | } 504 | if(cp_size == 0) 505 | cp_size = 0x10000; 506 | 507 | position += 1; 508 | //NSLog(@"pos: %d", position); 509 | //NSLog(@"offset: %d, %d", cp_off, cp_size); 510 | 511 | if(cp_size > buffLength) { 512 | buffLength = cp_size + 1; 513 | [buffer setLength:buffLength]; 514 | } 515 | 516 | [source getBytes:[buffer mutableBytes] range:NSMakeRange(cp_off, cp_size)]; 517 | [destination appendBytes:[buffer bytes] length:cp_size]; 518 | //NSLog(@"dest: %@", destination); 519 | } else if(c[0] != 0) { 520 | if(c[0] > destSize) 521 | break; 522 | //NSLog(@"thingy: %d, %d", position, c[0]); 523 | [deltaData getBytes:[buffer mutableBytes] range:NSMakeRange(position, c[0])]; 524 | [destination appendBytes:[buffer bytes] length:c[0]]; 525 | position += c[0]; 526 | destSize -= c[0]; 527 | } else { 528 | NSLog(@"invalid delta data"); 529 | } 530 | } 531 | return destination; 532 | } 533 | 534 | - (NSArray *) patchDeltaHeaderSize:(NSData *)deltaData position:(unsigned long)position 535 | { 536 | unsigned long size = 0; 537 | int shift = 0; 538 | unsigned char c[2]; 539 | 540 | do { 541 | [deltaData getBytes:c range:NSMakeRange(position, 1)]; 542 | //NSLog(@"read bytes:%d %d", c[0], position); 543 | position += 1; 544 | size |= (c[0] & 0x7f) << shift; 545 | shift += 7; 546 | } while ( (c[0] & 0x80) != 0 ); 547 | 548 | return [NSArray arrayWithObjects:[NSNumber numberWithLong:size], [NSNumber numberWithLong:position], nil]; 549 | } 550 | 551 | - (NSString *) readServerSha 552 | { 553 | char sha[41]; 554 | uint8_t rawsha[20]; 555 | [inStream read:rawsha maxLength:20]; 556 | [ObjGit gitUnpackHex:rawsha fillSha:sha]; 557 | return [[NSString alloc] initWithBytes:sha length:40 encoding:NSASCIIStringEncoding]; 558 | } 559 | 560 | - (NSString *) typeString:(int)type { 561 | if (type == OBJ_COMMIT) 562 | return @"commit"; 563 | if (type == OBJ_TREE) 564 | return @"tree"; 565 | if (type == OBJ_BLOB) 566 | return @"blob"; 567 | if (type == OBJ_TAG) 568 | return @"tag"; 569 | return @""; 570 | } 571 | 572 | - (int) typeInt:(NSString *)type { 573 | if([type isEqualToString:@"commit"]) 574 | return OBJ_COMMIT; 575 | if([type isEqualToString:@"tree"]) 576 | return OBJ_TREE; 577 | if([type isEqualToString:@"blob"]) 578 | return OBJ_BLOB; 579 | if([type isEqualToString:@"tag"]) 580 | return OBJ_TAG; 581 | return 0; 582 | } 583 | 584 | - (NSData *) readData:(int)size { 585 | // read in the data 586 | NSMutableData *decompressed = [NSMutableData dataWithLength: size]; 587 | BOOL done = NO; 588 | int status; 589 | 590 | uint8_t buffer[2]; 591 | [inStream read:buffer maxLength:1]; 592 | 593 | z_stream strm; 594 | strm.next_in = buffer; 595 | strm.avail_in = 1; 596 | strm.total_out = 0; 597 | strm.zalloc = Z_NULL; 598 | strm.zfree = Z_NULL; 599 | 600 | if (inflateInit (&strm) != Z_OK) 601 | NSLog(@"Inflate Issue"); 602 | 603 | while (!done) 604 | { 605 | // Make sure we have enough room and reset the lengths. 606 | if (strm.total_out >= [decompressed length]) 607 | [decompressed increaseLengthBy: 100]; 608 | strm.next_out = [decompressed mutableBytes] + strm.total_out; 609 | strm.avail_out = [decompressed length] - strm.total_out; 610 | 611 | // Inflate another chunk. 612 | status = inflate (&strm, Z_SYNC_FLUSH); 613 | if (status == Z_STREAM_END) done = YES; 614 | else if (status != Z_OK) { 615 | NSLog(@"status for break: %d", status); 616 | break; 617 | } 618 | 619 | if(!done) { 620 | [inStream read:buffer maxLength:1]; 621 | strm.next_in = buffer; 622 | strm.avail_in = 1; 623 | } 624 | } 625 | if (inflateEnd (&strm) != Z_OK) 626 | NSLog(@"Inflate Issue"); 627 | 628 | // Set real length. 629 | if (done) 630 | [decompressed setLength: strm.total_out]; 631 | 632 | return decompressed; 633 | } 634 | 635 | - (int) readPackHeader { 636 | NSLog(@"read pack header"); 637 | 638 | uint8_t inSig[4], inVer[4], inEntries[4]; 639 | uint32_t version, entries; 640 | [inStream read:inSig maxLength:4]; 641 | [inStream read:inVer maxLength:4]; 642 | [inStream read:inEntries maxLength:4]; 643 | 644 | entries = (inEntries[0] << 24) | (inEntries[1] << 16) | (inEntries[2] << 8) | inEntries[3]; 645 | version = (inVer[0] << 24) | (inVer[1] << 16) | (inVer[2] << 8) | inVer[3]; 646 | if(version == 2) 647 | return entries; 648 | else 649 | return 0; 650 | } 651 | 652 | /* 653 | * write refs to disk after successful read 654 | */ 655 | - (void) writeRefs { 656 | NSLog(@"write refs"); 657 | NSEnumerator *e = [refsRead objectEnumerator]; 658 | NSArray *thisRef; 659 | NSString *toSha, *refName, *sendOk; 660 | 661 | [self writeServer:@"unpack ok\n"]; 662 | 663 | while ( (thisRef = [e nextObject]) ) { 664 | NSLog(@"ref: %@", thisRef); 665 | toSha = [thisRef objectAtIndex:1]; 666 | refName = [thisRef objectAtIndex:2]; 667 | [gitRepo updateRef:refName toSha:toSha]; 668 | sendOk = [NSString stringWithFormat:@"ok %@\n", refName]; 669 | [self writeServer:sendOk]; 670 | } 671 | } 672 | 673 | 674 | /*** NETWORK FUNCTIONS ***/ 675 | 676 | - (void) packetFlush { 677 | [self sendPacket:@"0000"]; 678 | } 679 | 680 | - (void) sendPacket:(NSString *)dataWrite { 681 | NSLog(@"send:[%@]", dataWrite); 682 | int len = [dataWrite length]; 683 | uint8_t buffer[len]; 684 | [[dataWrite dataUsingEncoding:NSUTF8StringEncoding] getBytes:buffer]; 685 | [outStream write:buffer maxLength:len]; 686 | } 687 | 688 | // FROM GIT : pkt-line.c : Linus // 689 | 690 | #define hex(a) (hexchar[(a) & 15]) 691 | - (void) writeServer:(NSString *)dataWrite { 692 | //NSLog(@"write:[%@]", dataWrite); 693 | unsigned int len = [dataWrite length]; 694 | len += 4; 695 | [self writeServerLength:len]; 696 | //NSLog(@"write data"); 697 | [self sendPacket:dataWrite]; 698 | } 699 | 700 | - (void) writeServerLength:(unsigned int)length 701 | { 702 | static char hexchar[] = "0123456789abcdef"; 703 | uint8_t buffer[5]; 704 | 705 | buffer[0] = hex(length >> 12); 706 | buffer[1] = hex(length >> 8); 707 | buffer[2] = hex(length >> 4); 708 | buffer[3] = hex(length); 709 | 710 | //NSLog(@"write len [%c %c %c %c]", buffer[0], buffer[1], buffer[2], buffer[3]); 711 | [outStream write:buffer maxLength:4]; 712 | } 713 | 714 | - (NSString *) packetReadLine { 715 | uint8_t linelen[4]; 716 | unsigned int len = 0; 717 | len = [inStream read:linelen maxLength:4]; 718 | 719 | if(!len) { 720 | if ([inStream streamStatus] != NSStreamStatusAtEnd) 721 | NSLog(@"protocol error: read error"); 722 | return nil; 723 | } 724 | 725 | int n; 726 | len = 0; 727 | for (n = 0; n < 4; n++) { 728 | unsigned char c = linelen[n]; 729 | len <<= 4; 730 | if (c >= '0' && c <= '9') { 731 | len += c - '0'; 732 | continue; 733 | } 734 | if (c >= 'a' && c <= 'f') { 735 | len += c - 'a' + 10; 736 | continue; 737 | } 738 | if (c >= 'A' && c <= 'F') { 739 | len += c - 'A' + 10; 740 | continue; 741 | } 742 | NSLog(@"protocol error: bad line length character"); 743 | } 744 | 745 | if (!len) 746 | return @""; 747 | 748 | len -= 4; 749 | uint8_t data[len + 1]; 750 | 751 | [inStream read:data maxLength:len]; 752 | data[len] = 0; 753 | 754 | return [[NSString alloc] initWithBytes:data length:len encoding:NSASCIIStringEncoding]; 755 | } 756 | 757 | @end 758 | -------------------------------------------------------------------------------- /iGitHub.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */; }; 11 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 12 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 13 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 14 | 2D500B1C0D5A766900DBA0E3 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D500B1B0D5A766900DBA0E3 /* AppController.m */; }; 15 | 2D500FA20D5A86A600DBA0E3 /* TCPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D500F920D5A86A600DBA0E3 /* TCPServer.m */; }; 16 | 2D500FB40D5A86C000DBA0E3 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D500FB20D5A86C000DBA0E3 /* SystemConfiguration.framework */; }; 17 | 310855400E92A7F300208197 /* ServerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3108553F0E92A7F300208197 /* ServerViewController.m */; }; 18 | 3108557A0E92B4B200208197 /* server.png in Resources */ = {isa = PBXBuildFile; fileRef = 310855790E92B4B200208197 /* server.png */; }; 19 | 310855870E92B81200208197 /* servericon.png in Resources */ = {isa = PBXBuildFile; fileRef = 310855860E92B81200208197 /* servericon.png */; }; 20 | 3108559C0E92B95B00208197 /* rssicon.png in Resources */ = {isa = PBXBuildFile; fileRef = 3108559B0E92B95B00208197 /* rssicon.png */; }; 21 | 310F88EE0E89A95700FA95A4 /* TODO in Resources */ = {isa = PBXBuildFile; fileRef = 310F88ED0E89A95700FA95A4 /* TODO */; }; 22 | 311D2AF80E904D7000A08291 /* CommitsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 311D2AF70E904D7000A08291 /* CommitsViewController.m */; }; 23 | 311D2CD10E9155E500A08291 /* CommitDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 311D2CD00E9155E500A08291 /* CommitDetailViewController.m */; }; 24 | 312C951E0E7A38F200182164 /* ObjGit.m in Sources */ = {isa = PBXBuildFile; fileRef = 312C951D0E7A38F200182164 /* ObjGit.m */; }; 25 | 316381DB0E8FEECB00044E4A /* ProjectViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 316381CC0E8FED3100044E4A /* ProjectViewController.m */; }; 26 | 316382540E900E7100044E4A /* ProjectController.m in Sources */ = {isa = PBXBuildFile; fileRef = 316382530E900E7100044E4A /* ProjectController.m */; }; 27 | 316382CB0E901A9300044E4A /* ProjectDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 316382CA0E901A9300044E4A /* ProjectDetailViewController.m */; }; 28 | 3191AB5F0E830E8600957F79 /* ObjGitCommit.m in Sources */ = {isa = PBXBuildFile; fileRef = 3191AB5A0E830E8600957F79 /* ObjGitCommit.m */; }; 29 | 3191AB600E830E8600957F79 /* ObjGitObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 3191AB5C0E830E8600957F79 /* ObjGitObject.m */; }; 30 | 3191AB610E830E8600957F79 /* ObjGitServerHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 3191AB5E0E830E8600957F79 /* ObjGitServerHandler.m */; }; 31 | 3191AB730E830F7800957F79 /* NSDataCompression.m in Sources */ = {isa = PBXBuildFile; fileRef = 3191AB720E830F7800957F79 /* NSDataCompression.m */; }; 32 | 3191AB810E830FA600957F79 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3191AB800E830FA600957F79 /* libz.dylib */; }; 33 | 31C5B2870E8BF40500B07BE9 /* ObjGitTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 31C5B2860E8BF40500B07BE9 /* ObjGitTree.m */; }; 34 | 31C5B2D00E8C31B000B07BE9 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31C5B2CF0E8C31B000B07BE9 /* SenTestingKit.framework */; }; 35 | 31C5B2F10E8C326100B07BE9 /* ObjGitTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 31C5B2860E8BF40500B07BE9 /* ObjGitTree.m */; }; 36 | 31C5B2F20E8C326100B07BE9 /* ObjGitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 31C5B2A20E8C2CEE00B07BE9 /* ObjGitTest.m */; }; 37 | 31C5B2F30E8C327E00B07BE9 /* ObjGit.m in Sources */ = {isa = PBXBuildFile; fileRef = 312C951D0E7A38F200182164 /* ObjGit.m */; }; 38 | 31C5B2F40E8C327E00B07BE9 /* ObjGitCommit.m in Sources */ = {isa = PBXBuildFile; fileRef = 3191AB5A0E830E8600957F79 /* ObjGitCommit.m */; }; 39 | 31C5B2F50E8C327E00B07BE9 /* ObjGitObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 3191AB5C0E830E8600957F79 /* ObjGitObject.m */; }; 40 | 31C5B2F60E8C327E00B07BE9 /* ObjGitServerHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 3191AB5E0E830E8600957F79 /* ObjGitServerHandler.m */; }; 41 | 31C5B3020E8C330200B07BE9 /* NSDataCompression.m in Sources */ = {isa = PBXBuildFile; fileRef = 3191AB720E830F7800957F79 /* NSDataCompression.m */; }; 42 | 31C5B3070E8C333B00B07BE9 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3191AB800E830FA600957F79 /* libz.dylib */; }; 43 | 31C5B3100E8C333E00B07BE9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 44 | 31C5B3660E8C33F200B07BE9 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D500FB20D5A86C000DBA0E3 /* SystemConfiguration.framework */; }; 45 | 31CB1FCD0E929EDD008B3093 /* test.png in Resources */ = {isa = PBXBuildFile; fileRef = 31CB1FCC0E929EDD008B3093 /* test.png */; }; 46 | 4A50295F0DF7068E00D72A3B /* BrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A50295E0DF7068E00D72A3B /* BrowserViewController.m */; }; 47 | 4A6968FE0E1AD83800DCB40C /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 4A6968FD0E1AD83800DCB40C /* Default.png */; }; 48 | 4ACBF2160E1AC84C002CC43E /* bg.png in Resources */ = {isa = PBXBuildFile; fileRef = 4ACBF2150E1AC84C002CC43E /* bg.png */; }; 49 | 8406D2F00DF4B487005DDED6 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 8406D2EF0DF4B487005DDED6 /* icon.png */; }; 50 | /* End PBXBuildFile section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 54 | 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 55 | 1D6058910D05DD3D006BFB54 /* iGitHub.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iGitHub.app; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 57 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 58 | 2D500B1A0D5A766900DBA0E3 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; 59 | 2D500B1B0D5A766900DBA0E3 /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppController.m; sourceTree = ""; }; 60 | 2D500F910D5A86A600DBA0E3 /* TCPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TCPServer.h; path = Networking/TCPServer.h; sourceTree = ""; }; 61 | 2D500F920D5A86A600DBA0E3 /* TCPServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TCPServer.m; path = Networking/TCPServer.m; sourceTree = ""; }; 62 | 2D500FB20D5A86C000DBA0E3 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 63 | 3108553E0E92A7F300208197 /* ServerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerViewController.h; sourceTree = ""; }; 64 | 3108553F0E92A7F300208197 /* ServerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerViewController.m; sourceTree = ""; }; 65 | 310855790E92B4B200208197 /* server.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = server.png; sourceTree = ""; }; 66 | 310855860E92B81200208197 /* servericon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = servericon.png; sourceTree = ""; }; 67 | 3108559B0E92B95B00208197 /* rssicon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = rssicon.png; sourceTree = ""; }; 68 | 310F88ED0E89A95700FA95A4 /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = ""; }; 69 | 311D2AF60E904D7000A08291 /* CommitsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommitsViewController.h; sourceTree = ""; }; 70 | 311D2AF70E904D7000A08291 /* CommitsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommitsViewController.m; sourceTree = ""; }; 71 | 311D2CCF0E9155E500A08291 /* CommitDetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommitDetailViewController.h; sourceTree = ""; }; 72 | 311D2CD00E9155E500A08291 /* CommitDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommitDetailViewController.m; sourceTree = ""; }; 73 | 312C951C0E7A38F200182164 /* ObjGit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjGit.h; sourceTree = ""; }; 74 | 312C951D0E7A38F200182164 /* ObjGit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjGit.m; sourceTree = ""; }; 75 | 316381CB0E8FED3100044E4A /* ProjectViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectViewController.h; sourceTree = ""; }; 76 | 316381CC0E8FED3100044E4A /* ProjectViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProjectViewController.m; sourceTree = ""; }; 77 | 316382520E900E7100044E4A /* ProjectController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectController.h; sourceTree = ""; }; 78 | 316382530E900E7100044E4A /* ProjectController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProjectController.m; sourceTree = ""; }; 79 | 316382C90E901A9300044E4A /* ProjectDetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectDetailViewController.h; sourceTree = ""; }; 80 | 316382CA0E901A9300044E4A /* ProjectDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProjectDetailViewController.m; sourceTree = ""; }; 81 | 3191AB590E830E8600957F79 /* ObjGitCommit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjGitCommit.h; sourceTree = ""; }; 82 | 3191AB5A0E830E8600957F79 /* ObjGitCommit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjGitCommit.m; sourceTree = ""; }; 83 | 3191AB5B0E830E8600957F79 /* ObjGitObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjGitObject.h; sourceTree = ""; }; 84 | 3191AB5C0E830E8600957F79 /* ObjGitObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjGitObject.m; sourceTree = ""; }; 85 | 3191AB5D0E830E8600957F79 /* ObjGitServerHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjGitServerHandler.h; sourceTree = ""; }; 86 | 3191AB5E0E830E8600957F79 /* ObjGitServerHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjGitServerHandler.m; sourceTree = ""; }; 87 | 3191AB710E830F7800957F79 /* NSDataCompression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSDataCompression.h; sourceTree = ""; }; 88 | 3191AB720E830F7800957F79 /* NSDataCompression.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDataCompression.m; sourceTree = ""; }; 89 | 3191AB800E830FA600957F79 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 90 | 31C5B2850E8BF40500B07BE9 /* ObjGitTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjGitTree.h; sourceTree = ""; }; 91 | 31C5B2860E8BF40500B07BE9 /* ObjGitTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjGitTree.m; sourceTree = ""; }; 92 | 31C5B2A20E8C2CEE00B07BE9 /* ObjGitTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjGitTest.m; sourceTree = ""; }; 93 | 31C5B2C90E8C313C00B07BE9 /* UnitTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 94 | 31C5B2CA0E8C313C00B07BE9 /* UnitTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnitTests-Info.plist"; sourceTree = ""; }; 95 | 31C5B2CF0E8C31B000B07BE9 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 96 | 31CB1FCC0E929EDD008B3093 /* test.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = test.png; sourceTree = ""; }; 97 | 32CA4F630368D1EE00C91783 /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = ""; }; 98 | 4A50295D0DF7068E00D72A3B /* BrowserViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BrowserViewController.h; path = Networking/BrowserViewController.h; sourceTree = ""; }; 99 | 4A50295E0DF7068E00D72A3B /* BrowserViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BrowserViewController.m; path = Networking/BrowserViewController.m; sourceTree = ""; }; 100 | 4A6968FD0E1AD83800DCB40C /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 101 | 4ACBF2150E1AC84C002CC43E /* bg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bg.png; sourceTree = ""; }; 102 | 8406D2EF0DF4B487005DDED6 /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = ""; }; 103 | 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 104 | /* End PBXFileReference section */ 105 | 106 | /* Begin PBXFrameworksBuildPhase section */ 107 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 108 | isa = PBXFrameworksBuildPhase; 109 | buildActionMask = 2147483647; 110 | files = ( 111 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 112 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 113 | 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */, 114 | 2D500FB40D5A86C000DBA0E3 /* SystemConfiguration.framework in Frameworks */, 115 | 3191AB810E830FA600957F79 /* libz.dylib in Frameworks */, 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | 31C5B2C60E8C313C00B07BE9 /* Frameworks */ = { 120 | isa = PBXFrameworksBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | 31C5B3660E8C33F200B07BE9 /* SystemConfiguration.framework in Frameworks */, 124 | 31C5B3100E8C333E00B07BE9 /* Foundation.framework in Frameworks */, 125 | 31C5B3070E8C333B00B07BE9 /* libz.dylib in Frameworks */, 126 | 31C5B2D00E8C31B000B07BE9 /* SenTestingKit.framework in Frameworks */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | /* End PBXFrameworksBuildPhase section */ 131 | 132 | /* Begin PBXGroup section */ 133 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 1D6058910D05DD3D006BFB54 /* iGitHub.app */, 137 | 31C5B2C90E8C313C00B07BE9 /* UnitTests.octest */, 138 | ); 139 | name = Products; 140 | sourceTree = ""; 141 | }; 142 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 312C951B0E7A38F200182164 /* Git */, 146 | 2D500B1D0D5A766B00DBA0E3 /* Classes */, 147 | 2D500B6F0D5A793600DBA0E3 /* Support */, 148 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 149 | 29B97317FDCFA39411CA2CEA /* Resources */, 150 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 151 | 19C28FACFE9D520D11CA2CBB /* Products */, 152 | 3191AB800E830FA600957F79 /* libz.dylib */, 153 | 310F88ED0E89A95700FA95A4 /* TODO */, 154 | 31C5B2CA0E8C313C00B07BE9 /* UnitTests-Info.plist */, 155 | ); 156 | name = CustomTemplate; 157 | sourceTree = ""; 158 | }; 159 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 32CA4F630368D1EE00C91783 /* Prefix.pch */, 163 | 29B97316FDCFA39411CA2CEA /* main.m */, 164 | ); 165 | name = "Other Sources"; 166 | sourceTree = ""; 167 | }; 168 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 3108559B0E92B95B00208197 /* rssicon.png */, 172 | 310855860E92B81200208197 /* servericon.png */, 173 | 310855790E92B4B200208197 /* server.png */, 174 | 31CB1FCC0E929EDD008B3093 /* test.png */, 175 | 4ACBF2150E1AC84C002CC43E /* bg.png */, 176 | 8406D2EF0DF4B487005DDED6 /* icon.png */, 177 | 8D1107310486CEB800E47090 /* Info.plist */, 178 | 4A6968FD0E1AD83800DCB40C /* Default.png */, 179 | ); 180 | name = Resources; 181 | sourceTree = ""; 182 | }; 183 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 31C5B2CF0E8C31B000B07BE9 /* SenTestingKit.framework */, 187 | 2D500FB20D5A86C000DBA0E3 /* SystemConfiguration.framework */, 188 | 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */, 189 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 190 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 191 | ); 192 | name = Frameworks; 193 | sourceTree = ""; 194 | }; 195 | 2D500B1D0D5A766B00DBA0E3 /* Classes */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 2D500B1A0D5A766900DBA0E3 /* AppController.h */, 199 | 2D500B1B0D5A766900DBA0E3 /* AppController.m */, 200 | 4A50295D0DF7068E00D72A3B /* BrowserViewController.h */, 201 | 4A50295E0DF7068E00D72A3B /* BrowserViewController.m */, 202 | 316381CB0E8FED3100044E4A /* ProjectViewController.h */, 203 | 316381CC0E8FED3100044E4A /* ProjectViewController.m */, 204 | 316382520E900E7100044E4A /* ProjectController.h */, 205 | 316382530E900E7100044E4A /* ProjectController.m */, 206 | 316382C90E901A9300044E4A /* ProjectDetailViewController.h */, 207 | 316382CA0E901A9300044E4A /* ProjectDetailViewController.m */, 208 | 311D2AF60E904D7000A08291 /* CommitsViewController.h */, 209 | 311D2AF70E904D7000A08291 /* CommitsViewController.m */, 210 | 311D2CCF0E9155E500A08291 /* CommitDetailViewController.h */, 211 | 311D2CD00E9155E500A08291 /* CommitDetailViewController.m */, 212 | 3108553E0E92A7F300208197 /* ServerViewController.h */, 213 | 3108553F0E92A7F300208197 /* ServerViewController.m */, 214 | ); 215 | name = Classes; 216 | sourceTree = ""; 217 | }; 218 | 2D500B6F0D5A793600DBA0E3 /* Support */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | 2D500F910D5A86A600DBA0E3 /* TCPServer.h */, 222 | 2D500F920D5A86A600DBA0E3 /* TCPServer.m */, 223 | ); 224 | name = Support; 225 | sourceTree = ""; 226 | }; 227 | 312C951B0E7A38F200182164 /* Git */ = { 228 | isa = PBXGroup; 229 | children = ( 230 | 3191AB710E830F7800957F79 /* NSDataCompression.h */, 231 | 3191AB720E830F7800957F79 /* NSDataCompression.m */, 232 | 3191AB590E830E8600957F79 /* ObjGitCommit.h */, 233 | 3191AB5A0E830E8600957F79 /* ObjGitCommit.m */, 234 | 3191AB5B0E830E8600957F79 /* ObjGitObject.h */, 235 | 3191AB5C0E830E8600957F79 /* ObjGitObject.m */, 236 | 3191AB5D0E830E8600957F79 /* ObjGitServerHandler.h */, 237 | 3191AB5E0E830E8600957F79 /* ObjGitServerHandler.m */, 238 | 312C951C0E7A38F200182164 /* ObjGit.h */, 239 | 312C951D0E7A38F200182164 /* ObjGit.m */, 240 | 31C5B2850E8BF40500B07BE9 /* ObjGitTree.h */, 241 | 31C5B2860E8BF40500B07BE9 /* ObjGitTree.m */, 242 | 31C5B2A20E8C2CEE00B07BE9 /* ObjGitTest.m */, 243 | ); 244 | path = Git; 245 | sourceTree = ""; 246 | }; 247 | /* End PBXGroup section */ 248 | 249 | /* Begin PBXNativeTarget section */ 250 | 1D6058900D05DD3D006BFB54 /* iGitHub */ = { 251 | isa = PBXNativeTarget; 252 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "iGitHub" */; 253 | buildPhases = ( 254 | 1D60588D0D05DD3D006BFB54 /* Resources */, 255 | 1D60588E0D05DD3D006BFB54 /* Sources */, 256 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 257 | ); 258 | buildRules = ( 259 | ); 260 | dependencies = ( 261 | ); 262 | name = iGitHub; 263 | productName = foo; 264 | productReference = 1D6058910D05DD3D006BFB54 /* iGitHub.app */; 265 | productType = "com.apple.product-type.application"; 266 | }; 267 | 31C5B2C80E8C313C00B07BE9 /* UnitTests */ = { 268 | isa = PBXNativeTarget; 269 | buildConfigurationList = 31C5B2CE0E8C313D00B07BE9 /* Build configuration list for PBXNativeTarget "UnitTests" */; 270 | buildPhases = ( 271 | 31C5B2C40E8C313C00B07BE9 /* Resources */, 272 | 31C5B2C50E8C313C00B07BE9 /* Sources */, 273 | 31C5B2C60E8C313C00B07BE9 /* Frameworks */, 274 | 31C5B2C70E8C313C00B07BE9 /* ShellScript */, 275 | ); 276 | buildRules = ( 277 | ); 278 | dependencies = ( 279 | ); 280 | name = UnitTests; 281 | productName = UnitTests; 282 | productReference = 31C5B2C90E8C313C00B07BE9 /* UnitTests.octest */; 283 | productType = "com.apple.product-type.bundle"; 284 | }; 285 | /* End PBXNativeTarget section */ 286 | 287 | /* Begin PBXProject section */ 288 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 289 | isa = PBXProject; 290 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "iGitHub" */; 291 | compatibilityVersion = "Xcode 3.1"; 292 | hasScannedForEncodings = 1; 293 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 294 | projectDirPath = ""; 295 | projectRoot = ""; 296 | targets = ( 297 | 1D6058900D05DD3D006BFB54 /* iGitHub */, 298 | 31C5B2C80E8C313C00B07BE9 /* UnitTests */, 299 | ); 300 | }; 301 | /* End PBXProject section */ 302 | 303 | /* Begin PBXResourcesBuildPhase section */ 304 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 305 | isa = PBXResourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | 8406D2F00DF4B487005DDED6 /* icon.png in Resources */, 309 | 4ACBF2160E1AC84C002CC43E /* bg.png in Resources */, 310 | 4A6968FE0E1AD83800DCB40C /* Default.png in Resources */, 311 | 310F88EE0E89A95700FA95A4 /* TODO in Resources */, 312 | 31CB1FCD0E929EDD008B3093 /* test.png in Resources */, 313 | 3108557A0E92B4B200208197 /* server.png in Resources */, 314 | 310855870E92B81200208197 /* servericon.png in Resources */, 315 | 3108559C0E92B95B00208197 /* rssicon.png in Resources */, 316 | ); 317 | runOnlyForDeploymentPostprocessing = 0; 318 | }; 319 | 31C5B2C40E8C313C00B07BE9 /* Resources */ = { 320 | isa = PBXResourcesBuildPhase; 321 | buildActionMask = 2147483647; 322 | files = ( 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | /* End PBXResourcesBuildPhase section */ 327 | 328 | /* Begin PBXShellScriptBuildPhase section */ 329 | 31C5B2C70E8C313C00B07BE9 /* ShellScript */ = { 330 | isa = PBXShellScriptBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | ); 334 | inputPaths = ( 335 | ); 336 | outputPaths = ( 337 | ); 338 | runOnlyForDeploymentPostprocessing = 0; 339 | shellPath = /bin/sh; 340 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 341 | }; 342 | /* End PBXShellScriptBuildPhase section */ 343 | 344 | /* Begin PBXSourcesBuildPhase section */ 345 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 346 | isa = PBXSourcesBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | 316381DB0E8FEECB00044E4A /* ProjectViewController.m in Sources */, 350 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 351 | 2D500B1C0D5A766900DBA0E3 /* AppController.m in Sources */, 352 | 2D500FA20D5A86A600DBA0E3 /* TCPServer.m in Sources */, 353 | 4A50295F0DF7068E00D72A3B /* BrowserViewController.m in Sources */, 354 | 312C951E0E7A38F200182164 /* ObjGit.m in Sources */, 355 | 3191AB5F0E830E8600957F79 /* ObjGitCommit.m in Sources */, 356 | 3191AB600E830E8600957F79 /* ObjGitObject.m in Sources */, 357 | 3191AB610E830E8600957F79 /* ObjGitServerHandler.m in Sources */, 358 | 3191AB730E830F7800957F79 /* NSDataCompression.m in Sources */, 359 | 31C5B2870E8BF40500B07BE9 /* ObjGitTree.m in Sources */, 360 | 316382540E900E7100044E4A /* ProjectController.m in Sources */, 361 | 316382CB0E901A9300044E4A /* ProjectDetailViewController.m in Sources */, 362 | 311D2AF80E904D7000A08291 /* CommitsViewController.m in Sources */, 363 | 311D2CD10E9155E500A08291 /* CommitDetailViewController.m in Sources */, 364 | 310855400E92A7F300208197 /* ServerViewController.m in Sources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | 31C5B2C50E8C313C00B07BE9 /* Sources */ = { 369 | isa = PBXSourcesBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | 31C5B3020E8C330200B07BE9 /* NSDataCompression.m in Sources */, 373 | 31C5B2F30E8C327E00B07BE9 /* ObjGit.m in Sources */, 374 | 31C5B2F40E8C327E00B07BE9 /* ObjGitCommit.m in Sources */, 375 | 31C5B2F50E8C327E00B07BE9 /* ObjGitObject.m in Sources */, 376 | 31C5B2F60E8C327E00B07BE9 /* ObjGitServerHandler.m in Sources */, 377 | 31C5B2F10E8C326100B07BE9 /* ObjGitTree.m in Sources */, 378 | 31C5B2F20E8C326100B07BE9 /* ObjGitTest.m in Sources */, 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | /* End PBXSourcesBuildPhase section */ 383 | 384 | /* Begin XCBuildConfiguration section */ 385 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 386 | isa = XCBuildConfiguration; 387 | buildSettings = { 388 | ALWAYS_SEARCH_USER_PATHS = NO; 389 | COPY_PHASE_STRIP = NO; 390 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 391 | GCC_DYNAMIC_NO_PIC = NO; 392 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 393 | GCC_OPTIMIZATION_LEVEL = 0; 394 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 395 | GCC_PREFIX_HEADER = Prefix.pch; 396 | INFOPLIST_FILE = Info.plist; 397 | "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( 398 | "-framework", 399 | CFNetwork, 400 | ); 401 | "OTHER_LDFLAGS[sdk=iphonesimulator2.0][arch=*]" = ( 402 | "-framework", 403 | CoreServices, 404 | ); 405 | PREBINDING = NO; 406 | PRODUCT_NAME = iGitHub; 407 | WARNING_CFLAGS = "-Wall"; 408 | }; 409 | name = Debug; 410 | }; 411 | 1D6058950D05DD3E006BFB54 /* Release */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | ALWAYS_SEARCH_USER_PATHS = NO; 415 | COPY_PHASE_STRIP = YES; 416 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 417 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 418 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 419 | GCC_PREFIX_HEADER = Prefix.pch; 420 | INFOPLIST_FILE = Info.plist; 421 | "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( 422 | "-framework", 423 | CFNetwork, 424 | ); 425 | "OTHER_LDFLAGS[sdk=iphonesimulator2.0][arch=*]" = ( 426 | "-framework", 427 | CoreServices, 428 | ); 429 | PREBINDING = NO; 430 | PRODUCT_NAME = iGitHub; 431 | WARNING_CFLAGS = "-Wall"; 432 | }; 433 | name = Release; 434 | }; 435 | 31C5B2CC0E8C313D00B07BE9 /* Debug */ = { 436 | isa = XCBuildConfiguration; 437 | buildSettings = { 438 | ALWAYS_SEARCH_USER_PATHS = NO; 439 | COPY_PHASE_STRIP = NO; 440 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 441 | GCC_DYNAMIC_NO_PIC = NO; 442 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 443 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 444 | GCC_MODEL_TUNING = G5; 445 | GCC_OPTIMIZATION_LEVEL = 0; 446 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 447 | GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Cocoa.framework/Headers/Cocoa.h"; 448 | INFOPLIST_FILE = "UnitTests-Info.plist"; 449 | INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles"; 450 | OTHER_LDFLAGS = ( 451 | "-framework", 452 | Cocoa, 453 | "-framework", 454 | SenTestingKit, 455 | ); 456 | PREBINDING = NO; 457 | PRODUCT_NAME = UnitTests; 458 | SDKROOT = macosx10.5; 459 | WRAPPER_EXTENSION = octest; 460 | }; 461 | name = Debug; 462 | }; 463 | 31C5B2CD0E8C313D00B07BE9 /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | ALWAYS_SEARCH_USER_PATHS = NO; 467 | COPY_PHASE_STRIP = YES; 468 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 469 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 470 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 471 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 472 | GCC_MODEL_TUNING = G5; 473 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 474 | GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Cocoa.framework/Headers/Cocoa.h"; 475 | INFOPLIST_FILE = "UnitTests-Info.plist"; 476 | INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles"; 477 | OTHER_LDFLAGS = ( 478 | "-framework", 479 | Cocoa, 480 | "-framework", 481 | SenTestingKit, 482 | ); 483 | PREBINDING = NO; 484 | PRODUCT_NAME = UnitTests; 485 | WRAPPER_EXTENSION = octest; 486 | ZERO_LINK = NO; 487 | }; 488 | name = Release; 489 | }; 490 | C01FCF4F08A954540054247B /* Debug */ = { 491 | isa = XCBuildConfiguration; 492 | buildSettings = { 493 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 494 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 495 | ONLY_ACTIVE_ARCH = YES; 496 | SDKROOT = iphoneos2.0; 497 | }; 498 | name = Debug; 499 | }; 500 | C01FCF5008A954540054247B /* Release */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 504 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 505 | SDKROOT = iphoneos2.0; 506 | }; 507 | name = Release; 508 | }; 509 | /* End XCBuildConfiguration section */ 510 | 511 | /* Begin XCConfigurationList section */ 512 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "iGitHub" */ = { 513 | isa = XCConfigurationList; 514 | buildConfigurations = ( 515 | 1D6058940D05DD3E006BFB54 /* Debug */, 516 | 1D6058950D05DD3E006BFB54 /* Release */, 517 | ); 518 | defaultConfigurationIsVisible = 0; 519 | defaultConfigurationName = Release; 520 | }; 521 | 31C5B2CE0E8C313D00B07BE9 /* Build configuration list for PBXNativeTarget "UnitTests" */ = { 522 | isa = XCConfigurationList; 523 | buildConfigurations = ( 524 | 31C5B2CC0E8C313D00B07BE9 /* Debug */, 525 | 31C5B2CD0E8C313D00B07BE9 /* Release */, 526 | ); 527 | defaultConfigurationIsVisible = 0; 528 | defaultConfigurationName = Release; 529 | }; 530 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "iGitHub" */ = { 531 | isa = XCConfigurationList; 532 | buildConfigurations = ( 533 | C01FCF4F08A954540054247B /* Debug */, 534 | C01FCF5008A954540054247B /* Release */, 535 | ); 536 | defaultConfigurationIsVisible = 0; 537 | defaultConfigurationName = Release; 538 | }; 539 | /* End XCConfigurationList section */ 540 | }; 541 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 542 | } 543 | --------------------------------------------------------------------------------