Merge pull request #2116 from Dogild/xCodeCappUpdatingCapp

New: updating Cappuccino from xCodeCapp
This commit is contained in:
Antoine Mercadal
2014-06-24 16:43:05 -07:00
11 changed files with 876 additions and 60 deletions
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
68A43034191BF044008A68A7 /* help.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 68A43033191BF044008A68A7 /* help.pdf */; };
E10E4CD717298E5F004AB09E /* project.pbxproj in Resources */ = {isa = PBXBuildFile; fileRef = E164FE2A172188F300263CE3 /* project.pbxproj */; };
E14015421740248C006C2792 /* XcodeProjectCloser.m in Sources */ = {isa = PBXBuildFile; fileRef = E14015411740248C006C2792 /* XcodeProjectCloser.m */; };
E1401543174025B8006C2792 /* XcodeProjectCloser.m in Sources */ = {isa = PBXBuildFile; fileRef = E14015411740248C006C2792 /* XcodeProjectCloser.m */; };
@@ -36,7 +37,6 @@
E171D26C173C1C8300210893 /* xcc in CopyFiles */ = {isa = PBXBuildFile; fileRef = E171D25D173C168C00210893 /* xcc */; };
E17A822D172700B90095CD83 /* XcodeCapp.iconset in Resources */ = {isa = PBXBuildFile; fileRef = E17A822C172700B90095CD83 /* XcodeCapp.iconset */; };
E17B55411732F57700809FFB /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E17B55401732F57700809FFB /* Quartz.framework */; };
E17B55431732F72700809FFB /* help.pdf in Resources */ = {isa = PBXBuildFile; fileRef = E17B55421732F72700809FFB /* help.pdf */; };
E1A5594A172C5EE20088FB61 /* FindSourceFilesOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = E1A55949172C5EE20088FB61 /* FindSourceFilesOperation.m */; };
E1A5594D172CA8D40088FB61 /* ProcessSourceOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = E1A5594C172CA8D40088FB61 /* ProcessSourceOperation.m */; };
E1E90C411735D846005C6D5B /* DDLogLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C391735D846005C6D5B /* DDLogLevel.m */; };
@@ -106,6 +106,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
68A43033191BF044008A68A7 /* help.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = help.pdf; path = Resources/help.pdf; sourceTree = "<group>"; };
E14015401740248C006C2792 /* XcodeProjectCloser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XcodeProjectCloser.h; sourceTree = "<group>"; };
E14015411740248C006C2792 /* XcodeProjectCloser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XcodeProjectCloser.m; sourceTree = "<group>"; };
E164FDCF1720E77100263CE3 /* XcodeCapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XcodeCapp.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -140,7 +141,6 @@
E171D264173C168C00210893 /* xcc-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "xcc-Prefix.pch"; sourceTree = "<group>"; };
E17A822C172700B90095CD83 /* XcodeCapp.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = XcodeCapp.iconset; path = Resources/XcodeCapp.iconset; sourceTree = "<group>"; };
E17B55401732F57700809FFB /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; };
E17B55421732F72700809FFB /* help.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = help.pdf; path = Resources/help.pdf; sourceTree = "<group>"; };
E1A55949172C5EE20088FB61 /* FindSourceFilesOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FindSourceFilesOperation.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
E1A5594C172CA8D40088FB61 /* ProcessSourceOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ProcessSourceOperation.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
E1E90C371735D82B005C6D5B /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = "<group>"; };
@@ -273,6 +273,7 @@
E164FE071720F25400263CE3 /* Resources */ = {
isa = PBXGroup;
children = (
68A43033191BF044008A68A7 /* help.pdf */,
E1ED6B6F173414E100641628 /* icon_128x128.png */,
E1ED6B70173414E100641628 /* icon_128x128@2x.png */,
E164FE2D1721A34900263CE3 /* icon-inactive.png */,
@@ -284,7 +285,6 @@
E170C3FF17298833003DC489 /* icon-error.png */,
E170C40017298833003DC489 /* icon-error@2x.png */,
E17A822C172700B90095CD83 /* XcodeCapp.iconset */,
E17B55421732F72700809FFB /* help.pdf */,
E164FE2A172188F300263CE3 /* project.pbxproj */,
E164FE191720F49A00263CE3 /* Growl Registration Ticket.growlRegDict */,
);
@@ -418,6 +418,7 @@
E10E4CD717298E5F004AB09E /* project.pbxproj in Resources */,
E164FE181720F44B00263CE3 /* parser.j in Resources */,
E164FE1A1720F49A00263CE3 /* Growl Registration Ticket.growlRegDict in Resources */,
68A43034191BF044008A68A7 /* help.pdf in Resources */,
E164FE2F1721A34900263CE3 /* icon-active.png in Resources */,
E164FE301721A34900263CE3 /* icon-inactive.png in Resources */,
E164FE311721A34900263CE3 /* icon-working.png in Resources */,
@@ -427,7 +428,6 @@
E170C40517298833003DC489 /* icon-error@2x.png in Resources */,
E170C40617298833003DC489 /* icon-inactive@2x.png in Resources */,
E170C40717298833003DC489 /* icon-working@2x.png in Resources */,
E17B55431732F72700809FFB /* help.pdf in Resources */,
E1ED6B71173414E100641628 /* icon_128x128.png in Resources */,
E1ED6B72173414E100641628 /* icon_128x128@2x.png in Resources */,
E1E90C62173B42D0005C6D5B /* MainMenu.xib in Resources */,
+8 -1
View File
@@ -147,7 +147,7 @@ AppController *SharedAppControllerInstance = nil;
kDefaultXCCAutoOpenErrorsPanelOnErrors: @YES,
kDefaultXCCAutoOpenErrorsPanelOnCappLint: @YES,
kDefaultXCCAutoShowNotificationOnErrors: @YES,
kDefaultXCCAutoShowNotificationOnCappLint: @NO,
kDefaultXCCAutoShowNotificationOnCappLint: @YES,
kDefaultXCCProjectHistory: [NSArray new],
kDefaultMaxRecentProjects: @20,
kDefaultLogLevel: [NSNumber numberWithInt:LOG_LEVEL_WARN],
@@ -527,4 +527,11 @@ AppController *SharedAppControllerInstance = nil;
self.menuItemHistory.enabled = [projectHistory count] > 0;
}
#pragma mark - Cappuccino methods
- (IBAction)updateCappuccino:(id)sender
{
[self.xcc performSelectorInBackground:@selector(updateCappuccino) withObject:nil];
}
@end
+6 -2
View File
@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>XCCLastCappuccinoReleaseURL</key>
<string>https://github.com/cappuccino/cappuccino/archive/0.9.7.zip</string>
<key>XCCLastCappuccinoMasterBranchURL</key>
<string>https://github.com/cappuccino/cappuccino/archive/master.zip</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
@@ -17,11 +21,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.0.6</string>
<string>3.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>3.0.6</string>
<string>3.1</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSUIElement</key>
Binary file not shown.
+1
View File
@@ -28,5 +28,6 @@ extern NSString * const kDefaultMaxRecentProjects;
extern NSString * const kDefaultLogLevel;
extern NSString * const kDefaultAutoOpenXcodeProject;
extern NSString * const kDefaultUseSymlinkWhenCreatingProject;
extern NSString * const kDefaultUpdateCappuccinoWithLastVersionOfMasterBranch;
#endif
+1
View File
@@ -26,3 +26,4 @@ NSString * const kDefaultMaxRecentProjects = @"maxRecentProjects";
NSString * const kDefaultLogLevel = @"logLevel";
NSString * const kDefaultAutoOpenXcodeProject = @"autoOpenXcodeProject";
NSString * const kDefaultUseSymlinkWhenCreatingProject = @"useSymlinkWhenCreatingProject";
NSString * const kDefaultUpdateCappuccinoWithLastVersionOfMasterBranch = @"updateCappuccinoWithLastVersionOfMasterBranch";
+9
View File
@@ -101,6 +101,9 @@ extern NSString * const XCCCappLintDidEndNotification;
// Whether we are currently processing source files
@property BOOL isProcessing;
// Whether we are currently processing source files
@property BOOL isCappuccinoUpdating;
// Whether $CAPP_BUILD is defined or not
@property BOOL isCappBuildDefined;
@@ -118,6 +121,10 @@ extern NSString * const XCCCappLintDidEndNotification;
@property (unsafe_unretained) IBOutlet NSTableView *errorTable;
@property (strong) IBOutlet NSArrayController *errorListController;
@property (strong) IBOutlet NSProgressIndicator *progressIndicator;
@property (strong) IBOutlet NSTextField *fieldCurrentTask;
@property (strong) IBOutlet NSPanel *updatingCappuccinoPanel;
- (IBAction)openErrorsPanel:(id)sender;
- (IBAction)clearErrors:(id)sender;
- (IBAction)openErrorInEditor:(id)sender;
@@ -153,6 +160,8 @@ extern NSString * const XCCCappLintDidEndNotification;
- (BOOL)checkCappLintForPath:(NSArray*)paths;
- (void)showCappLintErrors;
- (void)updateCappuccino;
@end
@interface XcodeCapp (SnowLeopard)
+251 -4
View File
@@ -230,7 +230,8 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
@"/usr/local/bin",
@"/usr/local/narwhal/bin",
@"~/narwhal/bin",
@"~/bin"
@"~/bin",
@"/usr/bin"
];
NSMutableArray *paths = [self.environmentPaths mutableCopy];
@@ -242,8 +243,11 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
// Make sure we are using jsc as the narwhal engine!
self.environment[@"NARWHAL_ENGINE"] = @"jsc";
// Make sure to not do something in sudo
self.environment[@"CAPP_NOSUDO"] = @"1";
self.executables = @[@"python", @"narwhal-jsc", @"objj", @"nib2cib", @"capp", @"capp_lint"];
self.executables = @[@"python", @"narwhal-jsc", @"objj", @"nib2cib", @"capp", @"capp_lint", @"jake", @"curl", @"unzip", @"rm"];
// This is used to get the env var of $CAPP_BUILD
NSDictionary *processEnvironment = [[NSProcessInfo processInfo] environment];
@@ -1265,15 +1269,29 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
#pragma mark - Shell Helpers
/*!
Run an NSTask with the given arguments
@param launchPath The executable to launch
@param arguments NSArray containing the NSTask arguments
@param returnType Determines whether to return stdout, stderr, either, or nothing in the response
@return NSDictionary containing the return status (NSNumber) and the response (NSString)
*/
- (NSDictionary *)runTaskWithLaunchPath:(NSString *)launchPath arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType
{
return [self runTaskWithLaunchPath:launchPath arguments:arguments returnType:returnType currentDirectoryPath:nil];
}
/*!
Run an NSTask with the given arguments
@param launchPath The executable to launch
@param arguments NSArray containing the NSTask arguments
@param returnType Determines whether to return stdout, stderr, either, or nothing in the response
@param the currentDirectoryPath for the task
@return NSDictionary containing the return status (NSNumber) and the response (NSString)
*/
- (NSDictionary *)runTaskWithLaunchPath:(NSString *)launchPath arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType
- (NSDictionary *)runTaskWithLaunchPath:(NSString *)launchPath arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType currentDirectoryPath:(NSString*)aCurrentDirectoryPath
{
NSTask *task = [NSTask new];
@@ -1282,7 +1300,10 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
task.environment = self.environment;
task.standardOutput = [NSPipe pipe];
task.standardError = [NSPipe pipe];
if (aCurrentDirectoryPath)
task.currentDirectoryPath = aCurrentDirectoryPath;
[task launch];
DDLogVerbose(@"Task launched: %@\n%@", launchPath, arguments);
@@ -1336,6 +1357,7 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
return YES;
}
#pragma mark - Source Files Management
- (BOOL)isObjjFile:(NSString *)path
@@ -1843,6 +1865,231 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
[self.errorListController addObjects:errors];
}
#pragma mark - Cappuccino update
- (void)updateCappuccino
{
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidStartNotification object:self];
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
[self.updatingCappuccinoPanel makeKeyAndOrderFront:self];
self.isCappuccinoUpdating = YES;
[self.progressIndicator startAnimation:self];
[self.progressIndicator setMaxValue:4];
[self.progressIndicator setDoubleValue:0];
NSString *temporaryFolder = NSTemporaryDirectory();
if(![self _hasInitializedUpdateCappuccinoFromFolder:temporaryFolder] ||
![self _hasCleanedInstallOfCappuccinoFromFolder:temporaryFolder] ||
![self _hasInstalledCappuccinoFromFolder:temporaryFolder])
return;
[self notifyUserWithTitle:@"Update Cappuccino" message:@"Updating of Cappuccino completed"];
[self _incrementeProgressBarAndUpdateInformationFieldWithMessage:@"Updating completed"];
[self.progressIndicator stopAnimation:self];
self.isCappuccinoUpdating = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self];
}
- (BOOL)_hasInitializedUpdateCappuccinoFromFolder:(NSString*)aFolder
{
//Be sure to remove an old install
NSMutableArray *rmArguments = [NSMutableArray arrayWithObjects:@"-r", @"cappuccino", nil];
[self runTaskWithLaunchPath:self.executablePaths[@"rm"]
arguments:rmArguments
returnType:kTaskReturnTypeAny
currentDirectoryPath:aFolder];
[self _incrementeProgressBarAndUpdateInformationFieldWithMessage:@"Downloading Cappuccino"];
// Download the file
NSString *cappuccinoURL;
if ([[NSUserDefaults standardUserDefaults] boolForKey:kDefaultUpdateCappuccinoWithLastVersionOfMasterBranch])
cappuccinoURL = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"XCCLastCappuccinoMasterBranchURL"];
else
cappuccinoURL = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"XCCLastCappuccinoReleaseURL"];
NSString *destination = [NSString stringWithFormat:@"%@cappuccino.zip", aFolder];
NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"-Lk", cappuccinoURL, @"-o", destination, nil];
NSDictionary *taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"curl"]
arguments:arguments
returnType:kTaskReturnTypeStdOut];
NSInteger status = [taskResult[@"status"] intValue];
if (status > 1)
{
[self _updatingCappuccinoFailedWithMessage:@"Unable to download Cappuccino"];
return NO;
}
//Unzip the file
NSMutableArray *unzipArguments = [NSMutableArray arrayWithObjects:@"-u", @"-o", @"-q", @"-d", @"cappuccino", @"cappuccino.zip", nil];
NSDictionary *unzipTaskResult = [self runTaskWithLaunchPath:self.executablePaths[@"unzip"]
arguments:unzipArguments
returnType:kTaskReturnTypeAny
currentDirectoryPath:aFolder];
NSInteger unzipStatus = [unzipTaskResult[@"status"] intValue];
if (unzipStatus >= 1)
{
DDLogVerbose(@"Unable to unzip Cappuccino");
[self _updatingCappuccinoFailedWithMessage:@"Unable to unzip Cappuccino"];
return NO;
}
return YES;
}
- (BOOL)_hasCleanedInstallOfCappuccinoFromFolder:(NSString*)aFolder
{
NSString* path = [self _cappuccinoPathForFolder:aFolder];
[self _incrementeProgressBarAndUpdateInformationFieldWithMessage:@"Jake clobber"];
//Jake clobber
NSMutableArray *jakeClobberArguments = [NSMutableArray arrayWithObjects:@"clobber", nil];
NSDictionary *jakeClobberTaskResult = [self runJakeTaskWithArguments:jakeClobberArguments currentDirectoryPath:path];
NSInteger jakeInstallStatus = [jakeClobberTaskResult[@"status"] intValue];
if (jakeInstallStatus == 1)
{
DDLogVerbose(@"Jake clobber failed: %@", jakeClobberTaskResult[@"response"]);
[self _updatingCappuccinoFailedWithMessage:@"Jake clobber failed"];
return NO;
}
return YES;
}
- (BOOL)_hasInstalledCappuccinoFromFolder:(NSString*)aFolder
{
NSString* path = [self _cappuccinoPathForFolder:aFolder];
[self _incrementeProgressBarAndUpdateInformationFieldWithMessage:@"Jake install"];
//Jake install
NSMutableArray *jakeInstallArguments = [NSMutableArray arrayWithObjects:@"install", nil];
NSDictionary *jakeInstallTaskResult = [self runJakeTaskWithArguments:jakeInstallArguments currentDirectoryPath:path];
NSInteger jakeInstallStatus = [jakeInstallTaskResult[@"status"] intValue];
if (jakeInstallStatus == 1)
{
DDLogVerbose(@"Jake install failed: %@", jakeInstallTaskResult[@"response"]);
[self _updatingCappuccinoFailedWithMessage:@"Jake install failed"];
return NO;
}
return YES;
}
- (NSDictionary*)runJakeTaskWithArguments:(NSMutableArray*)arguments currentDirectoryPath:(NSString*)aCurrentDirectoryPath
{
NSString *launchPath = self.executablePaths[@"jake"];
NSTask *task = [NSTask new];
task.launchPath = launchPath;
task.arguments = arguments;
task.environment = self.environment;
task.standardOutput = [NSPipe new];
task.standardError = [NSPipe new];
if (aCurrentDirectoryPath)
task.currentDirectoryPath = aCurrentDirectoryPath;
// This is needed to log the jake
NSFileHandle* fhOut = [task.standardOutput fileHandleForReading];
[fhOut readInBackgroundAndNotify];
NSFileHandle* fhErr = [task.standardError fileHandleForReading];
[fhErr readInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jakeReceivedData:) name:NSFileHandleReadCompletionNotification object:fhOut];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jakeReceivedError:) name:NSFileHandleReadCompletionNotification object:fhErr];
[task launch];
DDLogVerbose(@"Task launched: %@\n%@", launchPath, arguments);
[task waitUntilExit];
DDLogVerbose(@"Task exited: %@:%d", launchPath, task.terminationStatus);
NSNumber *status = [NSNumber numberWithInt:task.terminationStatus];
NSData *data = nil;
if ([status intValue] == 0)
data = [[task.standardOutput fileHandleForReading] availableData];
else
data = [[task.standardError fileHandleForReading] availableData];
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:fhOut];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:fhErr];
return @{@"status" : status, @"response" : response};
}
-(void)jakeReceivedData:(NSNotification*)notification
{
NSData *data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
DDLogVerbose(@"%@", string);
[[notification object] readInBackgroundAndNotify];
}
-(void)jakeReceivedError:(NSNotification*)notification
{
NSData *data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
DDLogVerbose(@"%@", string);
}
/*!
This return the current path where the tmp cappuccino was downloaded
*/
- (NSString*)_cappuccinoPathForFolder:(NSString*)aFolder
{
NSFileManager *fileManger = [NSFileManager defaultManager];
NSString *contentOfCappuccinoFolder = [[fileManger contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@cappuccino", aFolder] error:nil] firstObject];
return [NSString stringWithFormat:@"%@cappuccino/%@", aFolder, contentOfCappuccinoFolder];
}
- (void)_incrementeProgressBarAndUpdateInformationFieldWithMessage:(NSString*)aString
{
double currentValue = [self.progressIndicator doubleValue];
[self.progressIndicator setDoubleValue:++currentValue];
[self.fieldCurrentTask setStringValue:[NSString stringWithFormat:@"Step %.0f/%.0f : %@", [self.progressIndicator doubleValue], [self.progressIndicator maxValue], aString]];
}
- (void)_updatingCappuccinoFailedWithMessage:(NSString*)aMessage
{
[self.progressIndicator stopAnimation:self];
[self.progressIndicator setDoubleValue:0];
[self.fieldCurrentTask setStringValue:[NSString stringWithFormat:@"Issue : %@", aMessage]];
[self notifyUserWithTitle:@"Error updating Cappuccino" message:aMessage];
self.isCappuccinoUpdating = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self];
}
#pragma mark - User notifications
- (NSString *)applicationNameForGrowl
File diff suppressed because it is too large Load Diff