From c40cb31a400f8a708a228f2844bd7e88db598d10 Mon Sep 17 00:00:00 2001 From: Eldon Ahrold Date: Wed, 10 Sep 2014 23:28:14 -0500 Subject: [PATCH 01/52] Completed Doc strings to LGAutoPkgTask class --- AutoPkgr/LGAutoPkgTask.h | 134 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 3 deletions(-) diff --git a/AutoPkgr/LGAutoPkgTask.h b/AutoPkgr/LGAutoPkgTask.h index 1bbcdac9..1c43b792 100644 --- a/AutoPkgr/LGAutoPkgTask.h +++ b/AutoPkgr/LGAutoPkgTask.h @@ -20,20 +20,38 @@ #import #import "LGAutoPkgr.h" +/** + * Constant to access recipe key in autopkg search + */ extern NSString *const kLGAutoPkgRecipeKey; +/** + * Constant to access recipe path key in autopkg search + */ extern NSString *const kLGAutoPkgRecipePathKey; +/** + * Constant to access repo name in autopkg search and autopkg repo-list + */ extern NSString *const kLGAutoPkgRepoKey; +/** + * Constant to access local path of the installed repo from autopkg repo-list + */ extern NSString *const kLGAutoPkgRepoPathKey; @interface LGAutoPkgTask : NSObject +/** + * Arguments passed into autopkg + */ @property (copy, nonatomic) NSArray *arguments; /** - * The block to use for providing run status updates asynchronously. + * stdout from autopkg */ -@property (copy) void (^runStatusUpdate)(NSString *message, double progress); @property (copy, nonatomic, readonly) NSString *standardOutString; + +/** + * stderr from autopkg + */ @property (copy, nonatomic, readonly) NSString *standardErrString; /** @@ -47,42 +65,152 @@ extern NSString *const kLGAutoPkgRepoPathKey; */ @property (nonatomic, readonly) BOOL complete; +/** + * The block to use for providing run status updates asynchronously. + */ +@property (copy) void (^runStatusUpdate)(NSString *message, double progress); + +#pragma mark - Instance Methods +/** + * Launch task in a synchronous way + * + * @param error NSError object populated should error occur + * + * @return YES if the task was completed successfully, no if the task ended with an error; + * + * @discussion a cancel request will also result in a return of YES; + */ - (BOOL)launch:(NSError **)error; + +/** + * Launch task in an asynchronous way + * + * @param reply The block to be executed on upon task completion. This block has no return value and takes one argument: NSError + * + * @discussion this runs on a background queue; + */ - (void)launchInBackground:(void (^)(NSError *error))reply; -- (BOOL)cancel:(NSError **)error; +/** + * Cancel the current task + * + * @return YES if task was successfully canceled, NO is the task is still running. + */ +- (BOOL)cancel; + +#pragma mark +/** + * Equivelant to /usr/bin/local/autopkg run --recipe-list=xxx --report-plist=xxx + * + * @param recipeList Full path to the recipe list + * @param progress block to be executed whenever new progress information is avaliable. This block has no return value and takes two arguments: NSString, double + * @param reply The block to be executed on upon task completion. This block has no return value and takes two arguments: NSDictionary (with ther report plist data), NSError + */ +- (void)runRecipeList:(NSString *)recipeList + progress:(void (^)(NSString *, double))progress + reply:(void (^)(NSDictionary *, NSError *))reply; + +/** + * Equivelant to /usr/bin/local/autopkg run recipe1 recipe2 ... recipe(n) --report-plist=xxx + * + * @param recipes Array of recipes to run + * @param progress Block to be executed whenever new progress information is avaliable. This block has no return value and takes two arguments: NSString, double + * @param reply The block to be executed on upon task completion. This block has no return value and takes one argument: NSError + */ +- (void)runRecipes:(NSArray *)recipes + progress:(void (^)(NSString *message))progress + reply:(void (^)(NSError *error))reply; #pragma mark - Class Methods #pragma mark-- Run methods + +/** + * Convience Accessor to autopkg run: see runRecipeList:progress:reply for details + * + */ + (void)runRecipeList:(NSString *)recipeList progress:(void (^)(NSString *message, double taskProgress))progress reply:(void (^)(NSDictionary *report, NSError *error))reply; +/** + * Convience Accessor for autopkg run: see runRecipes:progress:reply for details + * + */ + (void)runRecipes:(NSArray *)recipes progress:(void (^)(NSString *message))progress reply:(void (^)(NSError *error))reply; +/** + * Equivelant to /usr/bin/local/autopkg search [recipe] + * + * @param recipe recipe to search for + * @param reply The block to be executed on upon task completion. This block has no return value and takes two arguments: NSArray, NSError + * @discussion the NSArray in the reply block is and array of dictionaries, each dictionary entry contains 3 items recipe, repo, and repo path. You can use the kLGAutoPkgRecipeKey, kLGAutoPkgRepoKey, and kLGAutoPkgRepoPathKey strings to access the dictionary entries. + */ + (void)search:(NSString *)recipe reply:(void (^)(NSArray *results, NSError *error))reply; +/** + * Equivelant to /usr/bin/local/autopkg make-override [recipe] + * + * @param recipe Recipe override file to create + * @param reply The block to be executed on upon task completion. This block has no return value and takes one argument: NSError + */ + (void)makeOverride:(NSString *)recipe reply:(void (^)(NSError *error))reply; +/** + * Equivelant to /usr/bin/local/autopkg list-recipes + * + * @param reply The block to be executed on upon task completion. This block has no return value and takes two arguments: NSArray, NSError + */ + (void)listRecipes:(void (^)(NSArray *recipes, NSError *error))reply; +/** + * Equivelant to /usr/bin/local/autopkg list-recipes + * + * @return List of recipes + */ + (NSArray *)listRecipes; #pragma mark-- Repo methods +/** + * Equivelant to /usr/bin/local/autopkg repo-add [recipe_repo_url] + * + * @param repo repo to add + * @param reply The block to be executed on upon task completion. This block has no return value and takes one argument: NSError + */ + (void)repoAdd:(NSString *)repo reply:(void (^)(NSError *error))reply; +/** + * Equivelant to /usr/bin/local/autopkg repo-remove [repo] + * + * @param repo repo to remove + * @param reply The block to be executed on upon task completion. This block has no return value and takes one argument: NSError + */ + (void)repoRemove:(NSString *)repo reply:(void (^)(NSError *error))reply; +/** + * Equivelant to /usr/bin/local/autopkg repo-update + * + * @param reply The block to be executed on upon task completion. This block has no return value and takes one argument: NSError + */ + (void)repoUpdate:(void (^)(NSError *error))reply; +/** + * Equivelant to /usr/bin/local/autopkg repo-list + * + * @param reply The block to be executed on upon task completion. This block has no return value and takes two arguments: NSArray, NSError + */ + (void)repoList:(void (^)(NSArray *repos, NSError *error))reply; #pragma mark-- Other +/** + * Equivelant to /usr/bin/local/autopkg version + * + * @return version string + */ + (NSString *)version; @end From d796d830337fded136f0d66474b9a5050b5407fa Mon Sep 17 00:00:00 2001 From: Eldon Ahrold Date: Wed, 10 Sep 2014 23:28:45 -0500 Subject: [PATCH 02/52] Added ability to cancel autopkg run --- AutoPkgr/LGAutoPkgTask.m | 131 +++++++++++++------ AutoPkgr/LGConfigurationWindowController.h | 2 + AutoPkgr/LGConfigurationWindowController.m | 24 +++- AutoPkgr/LGConfigurationWindowController.xib | 25 +++- AutoPkgr/LGError.m | 5 + 5 files changed, 134 insertions(+), 53 deletions(-) diff --git a/AutoPkgr/LGAutoPkgTask.m b/AutoPkgr/LGAutoPkgTask.m index a771aa58..f7e2db1f 100644 --- a/AutoPkgr/LGAutoPkgTask.m +++ b/AutoPkgr/LGAutoPkgTask.m @@ -20,7 +20,6 @@ #import "LGAutoPkgTask.h" #import "LGApplications.h" #import "LGVersionComparator.h" - #import NSString *const kLGAutoPkgRecipeKey = @"recipe"; @@ -36,10 +35,14 @@ } @interface LGAutoPkgTask () +@property (copy, nonatomic, readwrite) NSString *standardOutString; +@property (copy, nonatomic, readwrite) NSString *standardErrString; @property (copy, nonatomic) NSString *reportPlistFile; @property (copy, nonatomic) NSDictionary *reportPlist; @property (copy, nonatomic) NSString *version; @property (nonatomic) BOOL AUTOPKG_VERSION_0_4_0; +@property (nonatomic, readwrite) BOOL complete; + @end @@ -52,9 +55,6 @@ @implementation LGAutoPkgTask { - (void)dealloc { _task.terminationHandler = nil; - if ([_task.standardOutput isKindOfClass:[NSPipe class]]) { - [_task.standardOutput fileHandleForReading].readabilityHandler = nil; - } } - (id)init @@ -72,8 +72,8 @@ - (BOOL)launch:(NSError *__autoreleasing *)error { [_task setArguments:_internalArgs]; - // If an instance of autopkg is running, and we're trying to - // do a run, exit + // If an instance of autopkg is running, + // and we're trying to do a run, exit if (_verb == kLGAutoPkgRun && [[self class] instanceIsRunning]) { return [LGError errorWithCode:kLGErrorMultipleRunsOfAutopkg error:error]; @@ -82,6 +82,19 @@ - (BOOL)launch:(NSError *__autoreleasing *)error [self setFileHandles]; [_task launch]; [_task waitUntilExit]; + + // set the complete property to YES in case of an observer + _complete = YES; + + // make sure the out and error readability handlers get set to nil + // so the filehandle will get closed + if ([_task.standardOutput isKindOfClass:[NSPipe class]]) { + [_task.standardOutput fileHandleForReading].readabilityHandler = nil; + } + + if ([_task.standardError isKindOfClass:[NSPipe class]]) { + [_task.standardError fileHandleForReading].readabilityHandler = nil; + } return [LGError errorWithTaskError:_task verb:_verb @@ -98,10 +111,10 @@ - (void)launchInBackground:(void (^)(NSError *))reply }]; } -- (BOOL)cancel:(NSError *__autoreleasing *)error +- (BOOL)cancel { [_task terminate]; - return [LGError errorWithTaskError:_task verb:_verb error:error]; + return ![_task isRunning]; } - (void)setFileHandles @@ -117,7 +130,13 @@ - (void)setFileHandles // To get status from autopkg set NSUnbufferedIO environment keyto YES // Thanks to help from -- http://stackoverflow.com/questions/8251010 - _task.environment = @{ @"NSUnbufferedIO" : @"YES" }; + NSMutableDictionary *environment = [[NSMutableDictionary alloc] init]; + + NSDictionary *processEnvironment = [[NSProcessInfo processInfo] environment]; + [environment addEntriesFromDictionary:processEnvironment]; + [environment addEntriesFromDictionary:@{ @"NSUnbufferedIO" : @"YES"}]; + + _task.environment = environment; NSPredicate *processingPredicate = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH[cd] 'Processing'"]; [[_task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *handle) { @@ -175,28 +194,30 @@ - (void)setArguments:(NSArray *)arguments - (NSString *)standardErrString { - NSString *standardError; - NSData *data; - if ([_task.standardError isKindOfClass:[NSPipe class]]) { - data = [[_task.standardError fileHandleForReading] readDataToEndOfFile]; - } - if (data) { - standardError = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + if ( !_standardErrString) { + NSData *data; + if ([_task.standardError isKindOfClass:[NSPipe class]]) { + data = [[_task.standardError fileHandleForReading] readDataToEndOfFile]; + } + if (data) { + _standardErrString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + } } - return standardError; + return _standardErrString; } - (NSString *)standardOutString { - NSString *standardOutput; - NSData *data; - if ([_task.standardOutput isKindOfClass:[NSPipe class]]) { - data = [[_task.standardOutput fileHandleForReading] readDataToEndOfFile]; - } - if (data) { - standardOutput = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + if (!_standardOutString) { + NSData *data; + if ([_task.standardOutput isKindOfClass:[NSPipe class]]) { + data = [[_task.standardOutput fileHandleForReading] readDataToEndOfFile]; + } + if (data) { + _standardOutString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + } } - return standardOutput; + return _standardOutString; } - (NSDictionary *)reportPlist @@ -284,7 +305,8 @@ - (NSString *)version if (_version) { return _version; } - return [[self class] version]; + _version = [[self class] version]; + return _version; } - (BOOL)AUTOPKG_VERSION_0_4_0 @@ -307,44 +329,67 @@ - (NSInteger)recipeListCount return count; } -#pragma mark - Class Methods -#pragma mark-- Recipe Methods -+ (void)runRecipes:(NSArray *)recipes +#pragma mark - Convience Instance Methods +- (void)runRecipes:(NSArray *)recipes progress:(void (^)(NSString *))progress reply:(void (^)(NSError *))reply { - LGAutoPkgTask *task = [[LGAutoPkgTask alloc] init]; NSMutableArray *fullRecipes = [[NSMutableArray alloc] init]; [fullRecipes addObject:@"run"]; for (NSString *recipe in recipes) { [fullRecipes addObject:recipe]; } - + [fullRecipes addObjectsFromArray:@[ @"-v", @"--report-plist" ]]; - task.arguments = [NSArray arrayWithArray:fullRecipes]; - - [task setRunStatusUpdate:^(NSString *message, double progressUpdate) { + self.arguments = [NSArray arrayWithArray:fullRecipes]; + + [self setRunStatusUpdate:^(NSString *message, double progressUpdate) { progress(message); }]; - - [task launchInBackground:^(NSError *error) { + + [self launchInBackground:^(NSError *error) { reply(error); }]; } -+ (void)runRecipeList:(NSString *)recipeList +- (void)runRecipeList:(NSString *)recipeList progress:(void (^)(NSString *, double))progress reply:(void (^)(NSDictionary *, NSError *))reply { - LGAutoPkgTask *task = [[LGAutoPkgTask alloc] init]; - task.arguments = @[ @"run", @"--recipe-list", recipeList, @"--report-plist" ]; - - [task setRunStatusUpdate:^(NSString *message, double progressUpdate) { + self.arguments = @[ @"run", @"--recipe-list", recipeList, @"--report-plist" ]; + + [self setRunStatusUpdate:^(NSString *message, double progressUpdate) { progress(message,progressUpdate); }]; + + [self launchInBackground:^(NSError *error) { + reply(self.reportPlist,error); + }]; +} - [task launchInBackground:^(NSError *error) { - reply(task.reportPlist,error); +#pragma mark - Class Methods +#pragma mark-- Recipe Methods ++ (void)runRecipes:(NSArray *)recipes + progress:(void (^)(NSString *))progress + reply:(void (^)(NSError *))reply +{ + LGAutoPkgTask *task = [[LGAutoPkgTask alloc] init]; + [task runRecipes:recipes progress:^(NSString *message) { + progress(message); + } reply:^(NSError *error) { + reply(error); + }]; +} + ++ (void)runRecipeList:(NSString *)recipeList + progress:(void (^)(NSString *, double))progress + reply:(void (^)(NSDictionary *, NSError *))reply +{ + LGAutoPkgTask *task = [[LGAutoPkgTask alloc] init]; + [task runRecipeList:recipeList progress:^(NSString *message, double prog) { + progress(message,prog); + } reply:^(NSDictionary *report, NSError *error) { + reply(report,error); }]; } diff --git a/AutoPkgr/LGConfigurationWindowController.h b/AutoPkgr/LGConfigurationWindowController.h index 0b7df064..03502e28 100644 --- a/AutoPkgr/LGConfigurationWindowController.h +++ b/AutoPkgr/LGConfigurationWindowController.h @@ -58,6 +58,7 @@ @property (weak) IBOutlet NSButton *installGitButton; @property (weak) IBOutlet NSButton *installAutoPkgButton; @property (weak) IBOutlet NSButton *checkAppsNowButton; +@property (weak) IBOutlet NSButton *cancelAutoPkgRunButton; @property (weak) IBOutlet NSButton *updateRepoNowButton; // Labels @@ -104,6 +105,7 @@ - (IBAction)addAutoPkgRepoURL:(id)sender; - (IBAction)updateReposNow:(id)sender; - (IBAction)checkAppsNow:(id)sender; +- (IBAction)cancelAutoPkgRun:(id)sender; - (void)runCommandAsRoot:(NSString *)command; - (void)downloadAndInstallAutoPkg; diff --git a/AutoPkgr/LGConfigurationWindowController.m b/AutoPkgr/LGConfigurationWindowController.m index 13b22e42..d7bcbcef 100644 --- a/AutoPkgr/LGConfigurationWindowController.m +++ b/AutoPkgr/LGConfigurationWindowController.m @@ -33,6 +33,7 @@ @interface LGConfigurationWindowController () { LGDefaults *defaults; + LGAutoPkgTask *_task; } @end @@ -865,17 +866,30 @@ - (void)updateReposNowCompleteNotificationRecieved:(NSNotification *)notificatio - (IBAction)checkAppsNow:(id)sender { NSString *recipeList = [LGApplications recipeList]; - + [_cancelAutoPkgRunButton setHidden:NO]; [self startProgressWithMessage:@"Running selected AutoPkg recipes."]; - [LGAutoPkgTask runRecipeList:recipeList + _task = [[LGAutoPkgTask alloc] init]; + [_task runRecipeList:recipeList progress:^(NSString *message, double taskProgress) { [self updateProgress:message progress:taskProgress]; } reply:^(NSDictionary *report,NSError *error) { [self stopProgress:error]; - LGEmailer *emailer = [LGEmailer new]; - [emailer sendEmailForReport:report error:error]; - }];} + if (report.count || error) { + LGEmailer *emailer = [LGEmailer new]; + [emailer sendEmailForReport:report error:error]; + } + _task = nil; + [_cancelAutoPkgRunButton setHidden:YES]; + }]; +} + +- (IBAction)cancelAutoPkgRun:(id)sender{ + if(_task){ + [_task cancel]; + } +} + - (void)autoPkgRunCompleteNotificationRecieved:(NSNotification *)notification { diff --git a/AutoPkgr/LGConfigurationWindowController.xib b/AutoPkgr/LGConfigurationWindowController.xib index d9e2c085..21f022c0 100644 --- a/AutoPkgr/LGConfigurationWindowController.xib +++ b/AutoPkgr/LGConfigurationWindowController.xib @@ -14,6 +14,7 @@ + @@ -55,7 +56,7 @@ - + @@ -1096,7 +1097,7 @@ - + @@ -1114,15 +1115,29 @@ - - + + - + + diff --git a/AutoPkgr/LGError.m b/AutoPkgr/LGError.m index 0ca7df42..0453969f 100644 --- a/AutoPkgr/LGError.m +++ b/AutoPkgr/LGError.m @@ -182,6 +182,11 @@ + (NSError *)errorWithTaskError:(NSTask *)task verb:(LGAutoPkgVerb)verb return nil; } + if (task.terminationReason == NSTaskTerminationReasonUncaughtSignal) { + DLog(@"AutoPkg run canceled by user"); + return nil; + } + NSError *error; NSString *errorMsg = errorMessageFromAutoPkgVerb(verb); NSString *errorDetails; From 2d6e74c6793ba4af10238239204ec2b2aeacab99 Mon Sep 17 00:00:00 2001 From: Eldon Ahrold Date: Thu, 11 Sep 2014 01:05:51 -0500 Subject: [PATCH 03/52] Improved git installed detection. -- added LGDefaults @property gitPath. -- now it sets GIT_PATH key in com.github.autopkg --- AutoPkgr/LGConfigurationWindowController.m | 26 +------- AutoPkgr/LGDefaults.h | 1 + AutoPkgr/LGDefaults.m | 77 +++++++++++++++------- AutoPkgr/LGHostInfo.h | 3 +- AutoPkgr/LGHostInfo.m | 68 ++++++++++++++++--- 5 files changed, 115 insertions(+), 60 deletions(-) diff --git a/AutoPkgr/LGConfigurationWindowController.m b/AutoPkgr/LGConfigurationWindowController.m index 13b22e42..8abeccbb 100644 --- a/AutoPkgr/LGConfigurationWindowController.m +++ b/AutoPkgr/LGConfigurationWindowController.m @@ -278,7 +278,7 @@ - (void)windowDidLoad } if ([hostInfo autoPkgInstalled]) { - BOOL updateAvailable = [self autoPkgUpdateAvailable]; + BOOL updateAvailable = [hostInfo autoPkgUpdateAvailable]; if (updateAvailable) { [installAutoPkgButton setEnabled:YES]; [installAutoPkgButton setTitle:@"Update AutoPkg"]; @@ -466,30 +466,6 @@ - (void)save } -- (BOOL)autoPkgUpdateAvailable -{ - // TODO: This check shouldn't block the main thread - - // Get the currently installed version of AutoPkg - LGHostInfo *hostInfo = [[LGHostInfo alloc] init]; - NSString *installedAutoPkgVersionString = [hostInfo getAutoPkgVersion]; - NSLog(@"Installed version of AutoPkg: %@", installedAutoPkgVersionString); - - // Get the latest version of AutoPkg available on GitHub - LGGitHubJSONLoader *jsonLoader = [[LGGitHubJSONLoader alloc] init]; - NSString *latestAutoPkgVersionString = [jsonLoader getLatestAutoPkgReleaseVersionNumber]; - - // Determine if AutoPkg is up-to-date by comparing the version strings - LGVersionComparator *vc = [[LGVersionComparator alloc] init]; - BOOL newVersionAvailable = [vc isVersion:latestAutoPkgVersionString greaterThanVersion:installedAutoPkgVersionString]; - if (newVersionAvailable) { - NSLog(@"A new version of AutoPkg is available. Version %@ is installed and version %@ is available.", installedAutoPkgVersionString, latestAutoPkgVersionString); - return YES; - } - - return NO; -} - - (void)runCommandAsRoot:(NSString *)command { // Super dirty hack, but way easier than diff --git a/AutoPkgr/LGDefaults.h b/AutoPkgr/LGDefaults.h index d6aacbd6..bee208e2 100644 --- a/AutoPkgr/LGDefaults.h +++ b/AutoPkgr/LGDefaults.h @@ -48,6 +48,7 @@ @property (copy, nonatomic) NSString *autoPkgCacheDir; @property (copy, nonatomic) NSString *autoPkgRecipeOverridesDir; @property (copy, nonatomic) NSString *munkiRepo; +@property (copy, nonatomic) NSString *gitPath; @property (copy, nonatomic) NSString *autoPkgRecipeRepoDir; @property (copy, nonatomic, readonly) NSArray *autoPkgRecipeSearchDirs; @property (copy, nonatomic, readonly) NSDictionary *autoPkgRecipeRepos; diff --git a/AutoPkgr/LGDefaults.m b/AutoPkgr/LGDefaults.m index f0b7d893..010480f6 100644 --- a/AutoPkgr/LGDefaults.m +++ b/AutoPkgr/LGDefaults.m @@ -47,49 +47,53 @@ - (BOOL)synchronize return RC; } -#pragma mark - EMail -// +#pragma mark +#pragma mark EMail - (NSString *)SMTPServer { return [self objectForKey:kLGSMTPServer]; } + - (void)setSMTPServer:(NSString *)SMTPServer { [self setObject:SMTPServer forKey:kLGSMTPServer]; } -// +#pragma mark - (NSInteger)SMTPPort { return [self integerForKey:kLGSMTPPort]; } + - (void)setSMTPPort:(NSInteger)SMTPPort { [self setInteger:SMTPPort forKey:kLGSMTPPort]; } -// +#pragma mark - (NSString *)SMTPUsername { return [self objectForKey:kLGSMTPUsername]; } + - (void)setSMTPUsername:(NSString *)SMTPUsername { [self setObject:SMTPUsername forKey:kLGSMTPUsername]; } -// +#pragma mark - (NSString *)SMTPFrom { return [self objectForKey:kLGSMTPFrom]; } + - (void)setSMTPFrom:(NSString *)SMTPFrom { [self setObject:SMTPFrom forKey:kLGSMTPFrom]; } -// +#pragma mark - (NSArray *)SMTPTo { return [self objectForKey:kLGSMTPTo]; } -// + - (void)setSMTPTo:(NSArray *)SMTPTo { [self setObject:SMTPTo forKey:kLGSMTPTo]; @@ -100,61 +104,68 @@ - (BOOL)SMTPTLSEnabled { return [self boolForKey:kLGSMTPTLSEnabled]; } + - (void)setSMTPTLSEnabled:(BOOL)SMTPTLSEnabled { [self setBool:SMTPTLSEnabled forKey:kLGSMTPTLSEnabled]; } -// +#pragma mark - (BOOL)SMTPAuthenticationEnabled { return [self boolForKey:kLGSMTPAuthenticationEnabled]; } + - (void)setSMTPAuthenticationEnabled:(BOOL)SMTPAuthenticationEnabled { [self setBool:SMTPAuthenticationEnabled forKey:kLGSMTPAuthenticationEnabled]; } -// +#pragma mark - (BOOL)warnBeforeQuittingEnabled { return [self boolForKey:kLGWarnBeforeQuittingEnabled]; } + - (void)setWarnBeforeQuittingEnabled:(BOOL)WarnBeforeQuittingEnabled { [self setBool:WarnBeforeQuittingEnabled forKey:kLGWarnBeforeQuittingEnabled]; } -// +#pragma mark - (BOOL)hasCompletedInitialSetup { return [self boolForKey:kLGHasCompletedInitialSetup]; } + - (void)setHasCompletedInitialSetup:(BOOL)HasCompletedInitialSetup { [self setBool:HasCompletedInitialSetup forKey:kLGHasCompletedInitialSetup]; } -// +#pragma mark - (BOOL)sendEmailNotificationsWhenNewVersionsAreFoundEnabled { return [self boolForKey:kLGSendEmailNotificationsWhenNewVersionsAreFoundEnabled]; } + - (void)setSendEmailNotificationsWhenNewVersionsAreFoundEnabled:(BOOL)SendEmailNotificationsWhenNewVersionsAreFoundEnabled { [self setBool:SendEmailNotificationsWhenNewVersionsAreFoundEnabled forKey:kLGSendEmailNotificationsWhenNewVersionsAreFoundEnabled]; } -// +#pragma mark - (BOOL)checkForNewVersionsOfAppsAutomaticallyEnabled { return [self boolForKey:kLGCheckForNewVersionsOfAppsAutomaticallyEnabled]; } + - (void)setCheckForNewVersionsOfAppsAutomaticallyEnabled:(BOOL)CheckForNewVersionsOfAppsAutomaticallyEnabled { [self setBool:CheckForNewVersionsOfAppsAutomaticallyEnabled forKey:kLGCheckForNewVersionsOfAppsAutomaticallyEnabled]; } -// --(BOOL)checkForRepoUpdatesAutomaticallyEnabled +#pragma mark +- (BOOL)checkForRepoUpdatesAutomaticallyEnabled { return [self boolForKey:kLGCheckForRepoUpdatesAutomaticallyEnabled]; } --(void)setCheckForRepoUpdatesAutomaticallyEnabled:(BOOL)checkForRepoUpdatesAutomaticallyEnabled + +- (void)setCheckForRepoUpdatesAutomaticallyEnabled:(BOOL)checkForRepoUpdatesAutomaticallyEnabled { [self setBool:checkForRepoUpdatesAutomaticallyEnabled forKey:kLGCheckForRepoUpdatesAutomaticallyEnabled]; } @@ -164,11 +175,13 @@ - (NSInteger)autoPkgRunInterval { return [self integerForKey:kLGAutoPkgRunInterval]; } + - (void)setAutoPkgRunInterval:(NSInteger)autoPkgRunInterval { [self setInteger:autoPkgRunInterval forKey:kLGAutoPkgRunInterval]; } -// + +#pragma mark - (NSString *)autoPkgCacheDir { return [self autoPkgDomainObject:@"CACHE_DIR"]; @@ -179,6 +192,7 @@ - (void)setAutoPkgCacheDir:(NSString *)autoPkgCacheDir [self setAutoPkgDomainObject:autoPkgCacheDir forKey:@"CACHE_DIR"]; } +#pragma mark - (NSString *)autoPkgRecipeOverridesDir { return [self autoPkgDomainObject:@"RECIPE_OVERRIDE_DIRS"]; @@ -188,16 +202,19 @@ - (void)setAutoPkgRecipeOverridesDir:(NSString *)autoPkgRecipeOverridesDir { [self setAutoPkgDomainObject:autoPkgRecipeOverridesDir forKey:@"RECIPE_OVERRIDE_DIRS"]; } -// + +#pragma mark - (NSString *)autoPkgRecipeRepoDir { return [self autoPkgDomainObject:@"RECIPE_REPO_DIR"]; } + - (void)setAutoPkgRecipeRepoDir:(NSString *)autoPkgRecipeRepoDir { [self setAutoPkgDomainObject:autoPkgRecipeRepoDir forKey:@"RECIPE_REPO_DIR"]; } -// + +#pragma mark - (NSArray *)autoPkgRecipeSearchDirs { return [self autoPkgDomainObject:@"RECIPE_SEARCH_DIRS"]; @@ -207,43 +224,53 @@ - (void)setAutoPkgRecipeSearchDirs:(NSArray *)autoPkgRecipeSearchDirs { [self setAutoPkgDomainObject:autoPkgRecipeSearchDirs forKey:@"RECIPE_SEARCH_DIRS"]; } -// +#pragma mark - (NSDictionary *)autoPkgRecipeRepos { return [self autoPkgDomainObject:@"RECIPE_REPOS"]; } + - (void)setAutoPkgRecipeRepos:(NSDictionary *)autoPkgRecipeRepos { [self setAutoPkgDomainObject:autoPkgRecipeRepos forKey:@"RECIPE_REPOS"]; } -// +#pragma mark - (NSString *)munkiRepo { return [self autoPkgDomainObject:@"MUNKI_REPO"]; } + - (void)setMunkiRepo:(NSString *)munkiRepo { [self setAutoPkgDomainObject:munkiRepo forKey:@"MUNKI_REPO"]; } -// +#pragma mark +- (NSString *)gitPath +{ + return [self autoPkgDomainObject:@"GIT_PATH"]; +} +- (void)setGitPath:(NSString *)gitPath +{ + [self setAutoPkgDomainObject:gitPath forKey:@"GIT_PATH"]; +} #pragma mark - Util Methods #pragma mark - CFPrefs --(id)autoPkgDomainObject:(NSString*)key{ +- (id)autoPkgDomainObject:(NSString *)key +{ id value = CFBridgingRelease(CFPreferencesCopyAppValue((__bridge CFStringRef)(key), - (__bridge CFStringRef)(kLGAutoPkgPreferenceDomain))); + (__bridge CFStringRef)(kLGAutoPkgPreferenceDomain))); return value; } --(void)setAutoPkgDomainObject:(id)object forKey:(NSString *)key +- (void)setAutoPkgDomainObject:(id)object forKey:(NSString *)key { CFPreferencesSetAppValue((__bridge CFStringRef)(key), (__bridge CFTypeRef)(object), (__bridge CFStringRef)(kLGAutoPkgPreferenceDomain)); } - #pragma mark - Class Methods + (BOOL)fixRelativePathsInAutoPkgDefaults:(NSError *__autoreleasing *)error neededFixing:(NSInteger *)neededFixing { diff --git a/AutoPkgr/LGHostInfo.h b/AutoPkgr/LGHostInfo.h index 21e1500d..aa7bcb29 100644 --- a/AutoPkgr/LGHostInfo.h +++ b/AutoPkgr/LGHostInfo.h @@ -29,6 +29,7 @@ - (NSString *)getAutoPkgVersion; - (BOOL)gitInstalled; - (BOOL)autoPkgInstalled; +- (BOOL)autoPkgUpdateAvailable; -+ (NSArray *)knownGitPaths; +- (NSArray *)knownGitPaths; @end diff --git a/AutoPkgr/LGHostInfo.m b/AutoPkgr/LGHostInfo.m index 4309177b..833259d6 100644 --- a/AutoPkgr/LGHostInfo.m +++ b/AutoPkgr/LGHostInfo.m @@ -22,6 +22,11 @@ #import "LGHostInfo.h" #import "LGConstants.h" #import "LGAutoPkgr.h" +#import "LGGitHubJSONLoader.h" +#import "LGVersionComparator.h" + +NSString *const kLGCLIToolsGit = @"/Library/Developer/CommandLineTools/usr/bin" ; +NSString *const kLGXcodeGit = @"/Applications/Xcode.app/Contents/Developer/usr/bin/git"; @implementation LGHostInfo @@ -45,15 +50,33 @@ - (NSString *)getUserAtHostName - (BOOL)gitInstalled { NSFileManager *fm = [[NSFileManager alloc] init]; - NSArray *knownGitPaths = [[self class] knownGitPaths]; - - for (NSString *path in knownGitPaths) { - if ([fm isExecutableFileAtPath:[path stringByAppendingPathComponent:@"git"]]) { - if ([path isEqualToString:knownGitPaths[0]]) { - DLog(@"Git was installed via Xcode command line tools."); + LGDefaults *defaults = [[LGDefaults alloc] init]; + + // First see if AutoPkg already has a GIT_PATH key set + // and if the executable still exists + BOOL isDir; + NSString *setGit = [defaults gitPath]; + if ([fm fileExistsAtPath:setGit isDirectory:&isDir] && !isDir) { + if ([fm isExecutableFileAtPath:setGit]) { + return YES; + } + } + + // If nothing is set, then iterate through the list + // of known git paths trying to locate one. + for (NSString *path in [self knownGitPaths]) { + NSString *gitExec = [path stringByAppendingPathComponent:@"git"]; + if ([fm isExecutableFileAtPath:gitExec]) { + if ([path isEqualToString:kLGCLIToolsGit]) { + DLog(@"Using Git was installed via Xcode command line tools."); + } else if ([path isEqualToString:kLGXcodeGit]){ + DLog(@"Using Git from XCode Applicaiton."); } else { - DLog(@"Found Git binary at %@", path); + DLog(@"Using Git binary at %@", gitExec); } + + // if we found a viable git binary write it into AutoPkg's preferences + defaults.gitPath = gitExec; return YES; } } @@ -104,8 +127,35 @@ - (BOOL)autoPkgInstalled return NO; } -+ (NSArray *)knownGitPaths +- (BOOL)autoPkgUpdateAvailable +{ + // TODO: This check shouldn't block the main thread + + // Get the currently installed version of AutoPkg + NSString *installedAutoPkgVersionString = [self getAutoPkgVersion]; + NSLog(@"Installed version of AutoPkg: %@", installedAutoPkgVersionString); + + // Get the latest version of AutoPkg available on GitHub + LGGitHubJSONLoader *jsonLoader = [[LGGitHubJSONLoader alloc] init]; + NSString *latestAutoPkgVersionString = [jsonLoader getLatestAutoPkgReleaseVersionNumber]; + + // Determine if AutoPkg is up-to-date by comparing the version strings + LGVersionComparator *vc = [[LGVersionComparator alloc] init]; + BOOL newVersionAvailable = [vc isVersion:latestAutoPkgVersionString greaterThanVersion:installedAutoPkgVersionString]; + if (newVersionAvailable) { + NSLog(@"A new version of AutoPkg is available. Version %@ is installed and version %@ is available.", installedAutoPkgVersionString, latestAutoPkgVersionString); + return YES; + } + return NO; +} + +- (NSArray *)knownGitPaths { - return @[ @"/Library/Developer/CommandLineTools/usr/bin/", @"/usr/local/bin/", @"/opt/boxen/homebrew/bin/" ]; + return @[ @"/usr/local/git/bin", + @"/opt/boxen/homebrew/bin", + @"/usr/local/bin", + kLGCLIToolsGit, + kLGXcodeGit]; } + @end From 1048b0b9fe7f10273b82dc01599336650cbc4c9c Mon Sep 17 00:00:00 2001 From: Eldon Ahrold Date: Thu, 11 Sep 2014 01:13:41 -0500 Subject: [PATCH 04/52] LGInstaller class and relevant modifications to other classes -- added flexibility to LGGitHubJSONLoader getLatestRelease by allowing for specifying a URL -- added install test to AutoPkgrTests for both git and autopkg --- AutoPkgr.xcodeproj/project.pbxproj | 6 + AutoPkgr/LGConstants.h | 1 + AutoPkgr/LGConstants.m | 1 + AutoPkgr/LGGitHubJSONLoader.h | 3 +- AutoPkgr/LGGitHubJSONLoader.m | 45 ++++++-- AutoPkgr/LGInstaller.h | 43 +++++++ AutoPkgr/LGInstaller.m | 175 +++++++++++++++++++++++++++++ AutoPkgrTests/AutoPkgrTests.m | 14 ++- 8 files changed, 277 insertions(+), 11 deletions(-) create mode 100644 AutoPkgr/LGInstaller.h create mode 100644 AutoPkgr/LGInstaller.m diff --git a/AutoPkgr.xcodeproj/project.pbxproj b/AutoPkgr.xcodeproj/project.pbxproj index 366943c5..bb61d39a 100644 --- a/AutoPkgr.xcodeproj/project.pbxproj +++ b/AutoPkgr.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ BE025CFF19BAEF8800D36345 /* LGAutoPkgSchedule.m in Sources */ = {isa = PBXBuildFile; fileRef = BE025CFD19BAEF8800D36345 /* LGAutoPkgSchedule.m */; }; BE57AC2A19BA3BBC00BB17B1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BE57AC2C19BA3BBC00BB17B1 /* Localizable.strings */; }; BE87994B1995BA410082472B /* LGDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = BE87994A1995BA410082472B /* LGDefaults.m */; }; + BEAA76CC19BFD635002D73EE /* LGInstaller.m in Sources */ = {isa = PBXBuildFile; fileRef = BEAA76CB19BFD635002D73EE /* LGInstaller.m */; }; BEFC931D1995F0710074C938 /* LGError.m in Sources */ = {isa = PBXBuildFile; fileRef = BEFC931C1995F0710074C938 /* LGError.m */; }; /* End PBXBuildFile section */ @@ -169,6 +170,8 @@ BE8799491995BA410082472B /* LGDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LGDefaults.h; sourceTree = ""; }; BE87994A1995BA410082472B /* LGDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LGDefaults.m; sourceTree = ""; }; BE94AA7B19BB8A78001A00D0 /* LGProgressDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LGProgressDelegate.h; sourceTree = ""; }; + BEAA76CA19BFD635002D73EE /* LGInstaller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LGInstaller.h; sourceTree = ""; }; + BEAA76CB19BFD635002D73EE /* LGInstaller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LGInstaller.m; sourceTree = ""; }; BEFC931B1995F0710074C938 /* LGError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LGError.h; sourceTree = ""; }; BEFC931C1995F0710074C938 /* LGError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LGError.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -329,6 +332,8 @@ BEFC931C1995F0710074C938 /* LGError.m */, BE8799491995BA410082472B /* LGDefaults.h */, BE87994A1995BA410082472B /* LGDefaults.m */, + BEAA76CA19BFD635002D73EE /* LGInstaller.h */, + BEAA76CB19BFD635002D73EE /* LGInstaller.m */, ); name = Models; sourceTree = ""; @@ -519,6 +524,7 @@ BEFC931D1995F0710074C938 /* LGError.m in Sources */, 1AC98416195CE99E0071CAB3 /* SSKeychain.m in Sources */, 1A979FE01960BCCC00EE9881 /* LGUnzipper.m in Sources */, + BEAA76CC19BFD635002D73EE /* LGInstaller.m in Sources */, BE025CF619BAE93400D36345 /* LGAutoPkgTask.m in Sources */, 6A0BABE9196E560000A136BB /* LGPopularRepositories.m in Sources */, ); diff --git a/AutoPkgr/LGConstants.h b/AutoPkgr/LGConstants.h index 4148c123..9ec83081 100644 --- a/AutoPkgr/LGConstants.h +++ b/AutoPkgr/LGConstants.h @@ -32,6 +32,7 @@ extern NSString *const kLGAutoPkgUpdateAvailableLabel; #pragma mark - Static URLs extern NSString *const kLGAutoPkgReleasesJSONURL; +extern NSString *const kLGGitReleasesJSONURL; extern NSString *const kLGAutoPkgDownloadURL; extern NSString *const kLGAutoPkgRepositoriesJSONURL; diff --git a/AutoPkgr/LGConstants.m b/AutoPkgr/LGConstants.m index 14f0ddf7..99879751 100644 --- a/AutoPkgr/LGConstants.m +++ b/AutoPkgr/LGConstants.m @@ -35,6 +35,7 @@ #pragma mark - Static URLs NSString *const kLGAutoPkgReleasesJSONURL = @"https://api.github.com/repos/autopkg/autopkg/releases"; +NSString *const kLGGitReleasesJSONURL = @"https://api.github.com/repos/timcharper/git_osx_installer/releases"; NSString *const kLGAutoPkgDownloadURL = @"https://github.com/autopkg/autopkg/zipball/master"; NSString *const kLGAutoPkgRepositoriesJSONURL = @"https://api.github.com/orgs/autopkg/repos"; diff --git a/AutoPkgr/LGGitHubJSONLoader.h b/AutoPkgr/LGGitHubJSONLoader.h index 4e1199c0..b9e7d55b 100644 --- a/AutoPkgr/LGGitHubJSONLoader.h +++ b/AutoPkgr/LGGitHubJSONLoader.h @@ -25,9 +25,10 @@ - (NSData *)getJSONFromURL:(NSURL *)url; - (NSArray *)getArrayFromJSONData:(NSData *)reqData; -- (NSDictionary *)getLatestAutoPkgReleaseDictionary; +- (NSDictionary *)getLatestReleaseDictionary:(NSString *)githubURL; - (NSArray *)getAutoPkgRecipeRepos; - (NSString *)getLatestAutoPkgReleaseVersionNumber; - (NSString *)getLatestAutoPkgDownloadURL; +- (NSString *)getGitDownloadURL; @end diff --git a/AutoPkgr/LGGitHubJSONLoader.m b/AutoPkgr/LGGitHubJSONLoader.m index 6f3f3e06..cbfa79b8 100644 --- a/AutoPkgr/LGGitHubJSONLoader.m +++ b/AutoPkgr/LGGitHubJSONLoader.m @@ -67,15 +67,18 @@ - (NSArray *)getArrayFromJSONData:(NSData *)reqData return nil; } -- (NSDictionary *)getLatestAutoPkgReleaseDictionary +- (NSArray *)getReleaseArray:(NSString *)githubURL { // Get the JSON data - NSArray *releasesArray = [self getArrayFromJSONData:[self getJSONFromURL:[NSURL URLWithString:kLGAutoPkgReleasesJSONURL]]]; + NSData *data = [self getJSONFromURL:[NSURL URLWithString:githubURL]]; + return [self getArrayFromJSONData:data]; +} +- (NSDictionary *)getLatestReleaseDictionary:(NSString *)githubURL +{ // GitHub returns the latest release from the API at index 0 - NSDictionary *latestVersionDict = [releasesArray objectAtIndex:0]; - - return latestVersionDict; + NSArray *releases = [self getReleaseArray:githubURL]; + return releases.count ? releases[0] : nil; } - (NSArray *)getAutoPkgRecipeRepos @@ -124,7 +127,7 @@ - (NSArray *)getAutoPkgRecipeRepos - (NSString *)getLatestAutoPkgReleaseVersionNumber { // Get an NSDictionary of the latest release JSON - NSDictionary *latestVersionDict = [self getLatestAutoPkgReleaseDictionary]; + NSDictionary *latestVersionDict = [self getLatestReleaseDictionary:kLGAutoPkgReleasesJSONURL]; // AutoPkg version numbers are prepended with "v" // Let's remove that from our version string @@ -137,12 +140,38 @@ - (NSString *)getLatestAutoPkgReleaseVersionNumber - (NSString *)getLatestAutoPkgDownloadURL { // Get an NSDictionary of the latest release JSON - NSDictionary *latestVersionDict = [self getLatestAutoPkgReleaseDictionary]; + NSDictionary *latestVersionDict = [self getLatestReleaseDictionary:kLGAutoPkgReleasesJSONURL]; // Get the AutoPkg PKG download URL - NSString *browserDownloadURL = [[[latestVersionDict objectForKey:@"assets"] objectAtIndex:0] objectForKey:@"browser_download_url"]; + NSString *browserDownloadURL = [[[latestVersionDict objectForKey:@"assets"] firstObject] objectForKey:@"browser_download_url"]; return browserDownloadURL; } +- (NSString *)getGitDownloadURL +{ + NSString *version; + NSString *browserDownloadURL; + + NSArray *releases = [self getReleaseArray:kLGGitReleasesJSONURL]; + // Get an NSDictionary of the latest release JSON + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8) { + // Mavericks and beyond + version = [releases firstObject][@"tag_name"]; + } else { + // Mountian Lion compatible + version = @"v1.8.5.2"; + } + + for (NSDictionary *dict in releases) { + if ([dict[@"tag_name"] isEqualToString:version]) { + browserDownloadURL = [dict[@"assets"] firstObject][@"browser_download_url"]; + break; + } + } + // Get the Git DMG download URL for the approperiate version + NSLog(@"%@", browserDownloadURL); + + return browserDownloadURL; +} @end diff --git a/AutoPkgr/LGInstaller.h b/AutoPkgr/LGInstaller.h new file mode 100644 index 00000000..8c930c75 --- /dev/null +++ b/AutoPkgr/LGInstaller.h @@ -0,0 +1,43 @@ +// +// LGInstaller.h +// AutoPkgr +// +// Created by Eldon on 9/9/14. +// Copyright (c) 2014 The Linde Group, Inc. All rights reserved. +// + +#import +#import "LGProgressDelegate.h" + +@interface LGInstaller : NSObject + +@property (weak) NSWindow *modalWindow; +@property (weak) id progressDelegate; + +#pragma mark - Async Methods +/** + * Install supported Git from github release page + * + * @param reply block that is executed upon completion that takes one argument NSError + */ +- (void)installGit:(void (^)(NSError *error))reply; + +/** + * Install AutoPkg from github release page + * + * @param reply block that is executed upon completion that takes one argument NSError + */ +- (void)installAutoPkg:(void (^)(NSError *error))reply; + +/** + * Update AutoPkgr + * + * @param reply block that is executed upon completion that takes one argument NSError + */ +// - (void)updateAutoPkgr:(void (^)(NSError* error))reply; + +#pragma mark - Blocking Methdos +- (BOOL)runGitInstaller:(NSError **)error; +- (BOOL)runAutoPkgInstaller:(NSError **)error; + +@end diff --git a/AutoPkgr/LGInstaller.m b/AutoPkgr/LGInstaller.m new file mode 100644 index 00000000..44a839dd --- /dev/null +++ b/AutoPkgr/LGInstaller.m @@ -0,0 +1,175 @@ +// +// LGInstaller.m +// AutoPkgr +// +// Created by Eldon on 9/9/14. +// Copyright (c) 2014 The Linde Group, Inc. All rights reserved. +// + +#import "LGInstaller.h" +#import "LGAutoPkgr.h" +#import "LGHostInfo.h" +#import "LGGitHubJSONLoader.h" + +@implementation LGInstaller { + NSString *_mountPoint; +} + +- (void)installGit:(void (^)(NSError *error))reply +{ + NSOperationQueue *bgQueue = [[NSOperationQueue alloc] init]; + [bgQueue addOperationWithBlock:^{ + NSError *error; + [_progressDelegate startProgressWithMessage:@"Installing Git"]; + [self runGitInstaller:&error]; + [_progressDelegate stopProgress:error]; + reply(error); + }]; +} + +- (BOOL)runGitInstaller:(NSError *__autoreleasing *)error +{ + // download pkg from google code (source forge is almost impossible to reach) + [_progressDelegate updateProgress:@"Downloading git" progress:5.0]; + LGGitHubJSONLoader *jsonLoader = [[LGGitHubJSONLoader alloc] init]; + + // Get the latest AutoPkg PKG download URL + NSString *downloadURL = [jsonLoader getGitDownloadURL]; + + NSString *tmpFile = [NSTemporaryDirectory() stringByAppendingPathComponent:[downloadURL lastPathComponent]]; + + [_progressDelegate updateProgress:@"Building Package" progress:25.0]; + // Download AutoPkg to the temporary directory + if (![[NSFileManager defaultManager] fileExistsAtPath:tmpFile]) { + NSData *gitDMG = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:downloadURL]]; + if (!gitDMG || ![gitDMG writeToFile:tmpFile atomically:YES]) { + DLog(@"Could not write the Git installer DMG to the system path"); + return [LGError errorWithCode:kLGErrorInstallGit error:error]; + } + } + + // Open DMG + BOOL RC = NO; + [_progressDelegate updateProgress:@"Mounting DMG" progress:50.0]; + if ([self mountDMG:tmpFile] && _mountPoint) { + // install Pkg + NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:_mountPoint error:nil]; + + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"pathExtension == 'pkg'"]; + + NSString *pkg = [[contents filteredArrayUsingPredicate:predicate] firstObject]; + NSString *asVolume = [_mountPoint stringByReplacingOccurrencesOfString:@" " withString:@"\\\\ "]; + + NSString *installCommand = [NSString stringWithFormat:@"/usr/sbin/installer -pkg %@ -target /", [asVolume stringByAppendingPathComponent:pkg]]; + DLog(@" %@", installCommand); + [_progressDelegate updateProgress:@"Installing..." progress:75.0]; + RC = [self runCommandAsRoot:installCommand error:error]; + } + + if (RC) { + // If the installer was performed from here + // set the autopkg GIT_PATH key + [[LGDefaults standardUserDefaults] setGitPath:@"/usr/local/git/bin/git"]; + } + + [_progressDelegate updateProgress:@"Unmounting DMG..." progress:100.0]; + [self unmountVolume]; + return RC; +} + +- (BOOL)runAutoPkgInstaller:(NSError *__autoreleasing *)error +{ + LGGitHubJSONLoader *jsonLoader = [[LGGitHubJSONLoader alloc] init]; + + [_progressDelegate updateProgress:@"Downloading git" progress:5.0]; + // Get the latest AutoPkg PKG download URL + NSString *downloadURL = [jsonLoader getLatestAutoPkgDownloadURL]; + + // Get path for autopkg-x.x.x.pkg + NSString *autoPkgPkg = [NSTemporaryDirectory() stringByAppendingPathComponent:[downloadURL lastPathComponent]]; + + [_progressDelegate updateProgress:@"Building Package" progress:25.0]; + // Download AutoPkg to the temporary directory + NSData *autoPkg = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:downloadURL]]; + [autoPkg writeToFile:autoPkgPkg atomically:YES]; + + // Set the `installer` command + NSString *command = [NSString stringWithFormat:@"/usr/sbin/installer -pkg %@ -target /", autoPkgPkg]; + + // Install the AutoPkg PKG as root + [_progressDelegate updateProgress:@"Installing package" progress:75.0]; + return [self runCommandAsRoot:command error:error]; + [_progressDelegate updateProgress:@"Installing package" progress:100.0]; +} + +- (void)installAutoPkg:(void (^)(NSError *error))reply +{ + NSOperationQueue *bgQueue = [[NSOperationQueue alloc] init]; + [bgQueue addOperationWithBlock:^{ + NSError *error; + [_progressDelegate startProgressWithMessage:@"Installing AutoPkg"]; + [self runAutoPkgInstaller:&error]; + [_progressDelegate stopProgress:error]; + reply(error); + }]; +} + +- (void)updateAutoPkgr:(void (^)(NSError *error))reply +{ + // possibly do what we need to with sparkle // +} + +#pragma mark - Util Methods +- (BOOL)runCommandAsRoot:(NSString *)command error:(NSError *__autoreleasing *)error; +{ + // Super dirty hack, but way easier than + // using Authorization Services + NSDictionary *errorDict = [[NSDictionary alloc] init]; + NSString *script = [NSString stringWithFormat:@"do shell script \"sh -c '%@'\" with administrator privileges", command]; + NSLog(@"AppleScript commands: %@", script); + NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:script]; + if ([appleScript executeAndReturnError:&errorDict]) { + return YES; + } else { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : errorDict[NSAppleScriptErrorBriefMessage], + NSLocalizedRecoverySuggestionErrorKey : errorDict[NSAppleScriptErrorMessage] }; + NSNumber *exitCode = errorDict[NSAppleScriptErrorNumber]; + + if (error) + *error = [NSError errorWithDomain:kLGApplicationName code:[exitCode intValue] userInfo:userInfo]; + return NO; + } +} + +- (BOOL)unmountVolume +{ + if (_mountPoint) { + NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/hdiutil" arguments:@[ @"detach", _mountPoint ]]; + [task waitUntilExit]; + return task.terminationStatus == 0; + } + return YES; +} + +- (BOOL)mountDMG:(NSString *)path +{ + NSTask *task = [[NSTask alloc] init]; + task.launchPath = @"/usr/bin/hdiutil"; + task.arguments = @[ @"attach", path, @"-plist" ]; + task.standardOutput = [NSPipe pipe]; + + [task launch]; + [task waitUntilExit]; + + NSData *data = [[task.standardOutput fileHandleForReading] readDataToEndOfFile]; + if (data) { + NSDictionary *dict = CFBridgingRelease(CFPropertyListCreateFromXMLData(kCFAllocatorDefault, + (__bridge CFDataRef)(data), + kCFPropertyListImmutable, + NULL)); + + _mountPoint = dict[@"system-entities"][1][@"mount-point"]; + } + return task.terminationStatus == 0; +} +@end diff --git a/AutoPkgrTests/AutoPkgrTests.m b/AutoPkgrTests/AutoPkgrTests.m index d6334b2f..91f6cfbe 100644 --- a/AutoPkgrTests/AutoPkgrTests.m +++ b/AutoPkgrTests/AutoPkgrTests.m @@ -20,6 +20,7 @@ // #import +#import "LGInstaller.h" @interface AutoPkgrTests : XCTestCase @@ -39,9 +40,18 @@ - (void)tearDown [super tearDown]; } -- (void)testExample +- (void)testInstallGit { - XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); + NSError *error; + LGInstaller *installer = [[LGInstaller alloc] init]; + XCTAssertTrue([installer runGitInstaller:&error], @"%@",error); +} + +- (void)testInstallAutoPkg +{ + NSError *error; + LGInstaller *installer = [[LGInstaller alloc] init]; + XCTAssertTrue([installer runAutoPkgInstaller:&error], @"%@",error); } @end From addf011a9024e0618bb756b7790180658cfe31dd Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Thu, 11 Sep 2014 06:16:09 -0700 Subject: [PATCH 05/52] Adjusted constraints on cancel button. Also made minor changes to log output. --- AutoPkgr/LGApplications.m | 6 +++--- AutoPkgr/LGAutoPkgSchedule.m | 4 ++-- AutoPkgr/LGConfigurationWindowController.m | 18 +++++++++--------- AutoPkgr/LGConfigurationWindowController.xib | 15 ++++++++++----- AutoPkgr/LGError.m | 2 +- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/AutoPkgr/LGApplications.m b/AutoPkgr/LGApplications.m index d5ada268..90c00ad7 100644 --- a/AutoPkgr/LGApplications.m +++ b/AutoPkgr/LGApplications.m @@ -127,7 +127,7 @@ - (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableCol if (index != NSNotFound) { [workingArray removeObjectAtIndex:index]; } else { - NSLog(@"Cannot find item %@ in workingArray", [searchedApps objectAtIndex:row]); + NSLog(@"Cannot find item %@ in workingArray.", [searchedApps objectAtIndex:row]); } } activeApps = [NSArray arrayWithArray:workingArray]; @@ -161,7 +161,7 @@ - (void)writeRecipeList NSString *autoPkgrSupportDirectory = [self getAppSupportDirectory]; if ([autoPkgrSupportDirectory isEqual:@""]) { - NSLog(@"Could not write recipe_list.txt"); + NSLog(@"Could not write recipe_list.txt."); return; } @@ -184,7 +184,7 @@ - (void)writeRecipeList [recipe_list writeToFile:recipeListFile atomically:YES encoding:NSUTF8StringEncoding error:&error]; if (error) { - NSLog(@"Error while writing %@", recipeListFile); + NSLog(@"Error while writing %@.", recipeListFile); } } diff --git a/AutoPkgr/LGAutoPkgSchedule.m b/AutoPkgr/LGAutoPkgSchedule.m index bb4c71ba..0fb827f4 100644 --- a/AutoPkgr/LGAutoPkgSchedule.m +++ b/AutoPkgr/LGAutoPkgSchedule.m @@ -64,7 +64,7 @@ - (void)runAutoPkg LGDefaults *defaults = [[LGDefaults alloc] init]; if (defaults.checkForNewVersionsOfAppsAutomaticallyEnabled) { - NSLog(@"Beginning scheduled run of AutoPkg"); + NSLog(@"Beginning scheduled run of AutoPkg."); [_progressDelegate startProgressWithMessage:@"Starting scheduled run..."]; NSString *recipeList = [LGApplications recipeList]; @@ -73,7 +73,7 @@ - (void)runAutoPkg [_progressDelegate updateProgress:message progress:taskProgress]; } reply:^(NSDictionary *report, NSError *error) { - NSLog(@"Scheduled run of AutoPkg complete"); + NSLog(@"Scheduled run of AutoPkg complete."); [_progressDelegate stopProgress:error]; LGEmailer *emailer = [LGEmailer new]; [emailer sendEmailForReport:report error:error]; diff --git a/AutoPkgr/LGConfigurationWindowController.m b/AutoPkgr/LGConfigurationWindowController.m index d7bcbcef..9fcbf86c 100644 --- a/AutoPkgr/LGConfigurationWindowController.m +++ b/AutoPkgr/LGConfigurationWindowController.m @@ -457,9 +457,9 @@ - (void)save // Store the password used for SMTP authentication in the default keychain [SSKeychain setPassword:[smtpPassword stringValue] forService:kLGApplicationName account:[smtpUsername stringValue] error:&error]; if (error) { - NSLog(@"Error while storing e-mail password: %@", error); + NSLog(@"Error while storing email password in keychain: %@", error); } else { - NSLog(@"Reset password"); + NSLog(@"Stored email password in keychain."); } // Synchronize with the defaults database @@ -500,9 +500,9 @@ - (void)runCommandAsRoot:(NSString *)command NSLog(@"AppleScript commands: %@", script); NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:script]; if ([appleScript executeAndReturnError:&error]) { - NSLog(@"Authorization successful!"); + NSLog(@"Authorization successful."); } else { - NSLog(@"Authorization failed! Error: %@.", error); + NSLog(@"Authorization failed. Error: %@.", error); } } @@ -585,7 +585,7 @@ - (void)downloadAndInstallAutoPkg // Update the autoPkgStatus icon and label if it installed successfully if ([hostInfo autoPkgInstalled]) { - NSLog(@"AutoPkg installed successfully!"); + NSLog(@"AutoPkg installed successfully."); [autoPkgStatusLabel setStringValue:kLGAutoPkgInstalledLabel]; [autoPkgStatusIcon setImage:[NSImage imageNamed:NSImageNameStatusAvailable]]; [installAutoPkgButton setEnabled:NO]; @@ -627,7 +627,7 @@ - (IBAction)openLocalMunkiRepoFolder:(id)sender NSLog(@"%@ does not exist.", defaults.munkiRepo); NSAlert *alert = [[NSAlert alloc] init]; [alert addButtonWithTitle:@"OK"]; - [alert setMessageText:@"Cannot find the Munki Repository."]; + [alert setMessageText:@"Cannot find the Munki repository."]; [alert setInformativeText:[NSString stringWithFormat:@"%@ could not find the Munki repository located in %@. Please verify that this folder exists.", kLGApplicationName, defaults.munkiRepo]]; [alert setAlertStyle:NSWarningAlertStyle]; [alert beginSheetModalForWindow:self.window @@ -970,9 +970,9 @@ - (void)controlTextDidEndEditing:(NSNotification *)notification NSError *error; [SSKeychain setPassword:[smtpPassword stringValue] forService:kLGApplicationName account:[smtpUsername stringValue] error:&error]; if (error) { - NSLog(@"Error while storing e-mail password: %@", error); + NSLog(@"Error while storing e-mail password in keychain: %@", error); } else { - NSLog(@"Reset password"); + NSLog(@"Stored email password in keychain."); } } else { NSLog(@"Uncaught controlTextDidEndEditing"); @@ -1026,7 +1026,7 @@ - (void)changeSmtpAuthenticationButtonState - (void)changeSendEmailNotificationsWhenNewVersionsAreFoundButtonState { defaults.sendEmailNotificationsWhenNewVersionsAreFoundEnabled = [sendEmailNotificationsWhenNewVersionsAreFoundButton state]; - NSLog(@"%@ email notifications.", defaults.sendEmailNotificationsWhenNewVersionsAreFoundEnabled ? @"Enabling" : @"Disabling"); + NSLog(@"%@ email notifications.", defaults.sendEmailNotificationsWhenNewVersionsAreFoundEnabled ? @"Enabling" : @"Disabling"); [defaults synchronize]; } diff --git a/AutoPkgr/LGConfigurationWindowController.xib b/AutoPkgr/LGConfigurationWindowController.xib index 21f022c0..de31a437 100644 --- a/AutoPkgr/LGConfigurationWindowController.xib +++ b/AutoPkgr/LGConfigurationWindowController.xib @@ -56,7 +56,7 @@ - + @@ -1097,7 +1097,7 @@ - + @@ -1115,7 +1115,7 @@ - + @@ -1124,9 +1124,12 @@ - - @@ -104,7 +100,6 @@ - - - - - - - - - - - - - - @@ -145,17 +126,14 @@ - - - - @@ -316,7 +281,6 @@ - @@ -325,13 +289,12 @@ - - + @@ -376,7 +339,6 @@ @@ -418,14 +380,12 @@ - - @@ -451,7 +410,6 @@ - @@ -521,14 +476,12 @@ - - @@ -548,7 +500,6 @@ - @@ -560,7 +511,6 @@ - @@ -569,7 +519,6 @@ - @@ -581,7 +530,6 @@ - @@ -590,7 +538,6 @@ - @@ -602,7 +549,6 @@ - @@ -611,7 +557,6 @@ - @@ -623,16 +568,13 @@ - - @@ -649,7 +590,6 @@ - @@ -661,7 +601,6 @@ - @@ -670,7 +609,6 @@ - @@ -685,7 +623,6 @@ - @@ -926,7 +850,6 @@ - @@ -938,7 +861,6 @@ - @@ -975,7 +895,6 @@ - @@ -987,7 +906,6 @@