From f84ad60568ca169523702b917ab9c91d7cf4323e Mon Sep 17 00:00:00 2001 From: Geronimo Max Falk Date: Sat, 9 May 2015 23:23:35 +0200 Subject: [PATCH 01/20] Add settings for HTTP proxy and forced HTTPS instead of GIT for github --- Alcatraz.xcodeproj/project.pbxproj | 6 + Alcatraz/ATZPluginWindowController.xib | 19 ++- .../Controllers/ATZPluginWindowController.m | 160 +++++++++++------- Alcatraz/Helpers/ATZConfig.h | 42 +++++ Alcatraz/Helpers/ATZConfig.m | 94 ++++++++++ Alcatraz/Helpers/ATZDownloader.h | 10 +- Alcatraz/Helpers/ATZDownloader.m | 99 +++++------ Alcatraz/Helpers/ATZGit.h | 22 +-- Alcatraz/Helpers/ATZGit.m | 107 +++++++----- Alcatraz/en.lproj/Localizable.strings | 1 + 10 files changed, 370 insertions(+), 190 deletions(-) create mode 100644 Alcatraz/Helpers/ATZConfig.h create mode 100644 Alcatraz/Helpers/ATZConfig.m diff --git a/Alcatraz.xcodeproj/project.pbxproj b/Alcatraz.xcodeproj/project.pbxproj index f45dda2..3fb2097 100644 --- a/Alcatraz.xcodeproj/project.pbxproj +++ b/Alcatraz.xcodeproj/project.pbxproj @@ -75,6 +75,7 @@ 8AD5249F174102F9008B451F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8AD524A2174102F9008B451F /* Localizable.strings */; }; 8ADC22341A2AD5B800DB7BCA /* ATZPreviewImageButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 8ADC22331A2AD5B800DB7BCA /* ATZPreviewImageButton.m */; }; 8AF670C919C2DE8A00E1C168 /* ATZSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AF670C819C2DE8A00E1C168 /* ATZSegmentedControl.m */; }; + FF9ED6C11AFE8670000EF0DF /* ATZConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9ED6C01AFE8670000EF0DF /* ATZConfig.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -179,6 +180,8 @@ 8ADC22331A2AD5B800DB7BCA /* ATZPreviewImageButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATZPreviewImageButton.m; path = Views/ATZPreviewImageButton.m; sourceTree = ""; }; 8AF670C719C2DE8A00E1C168 /* ATZSegmentedControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATZSegmentedControl.h; path = Views/ATZSegmentedControl.h; sourceTree = ""; }; 8AF670C819C2DE8A00E1C168 /* ATZSegmentedControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATZSegmentedControl.m; path = Views/ATZSegmentedControl.m; sourceTree = ""; }; + FF9ED6BF1AFE8670000EF0DF /* ATZConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ATZConfig.h; sourceTree = ""; }; + FF9ED6C01AFE8670000EF0DF /* ATZConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ATZConfig.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -349,6 +352,8 @@ 8917DA131726B63B00F0B2D2 /* ATZDownloader.m */, 8917DA141726B63B00F0B2D2 /* ATZGit.h */, 8917DA151726B63B00F0B2D2 /* ATZGit.m */, + FF9ED6BF1AFE8670000EF0DF /* ATZConfig.h */, + FF9ED6C01AFE8670000EF0DF /* ATZConfig.m */, 8917DA161726B63B00F0B2D2 /* ATZShell.h */, 8917DA171726B63B00F0B2D2 /* ATZShell.m */, 89B4F2BC172FF5AC001FD2E3 /* ATZPBXProjParser.h */, @@ -527,6 +532,7 @@ 8AA0F57A19C2210600556AAF /* ATZFillableButton.m in Sources */, 8917DA191726B63B00F0B2D2 /* ATZGit.m in Sources */, 8917DA1A1726B63B00F0B2D2 /* ATZShell.m in Sources */, + FF9ED6C11AFE8670000EF0DF /* ATZConfig.m in Sources */, 89B4F2BE172FF5AC001FD2E3 /* ATZPBXProjParser.m in Sources */, 8A133EE319C235FD0068FCB9 /* ATZPackageListTableCellView.m in Sources */, 8A1732A81A2694BB002033D6 /* NSColor+Alcatraz.m in Sources */, diff --git a/Alcatraz/ATZPluginWindowController.xib b/Alcatraz/ATZPluginWindowController.xib index 9dc0c5e..8d40a8d 100644 --- a/Alcatraz/ATZPluginWindowController.xib +++ b/Alcatraz/ATZPluginWindowController.xib @@ -1,12 +1,13 @@ - + - + + @@ -90,9 +91,10 @@ + - + @@ -209,6 +211,17 @@ + + + + + + + + + + + diff --git a/Alcatraz/Controllers/ATZPluginWindowController.m b/Alcatraz/Controllers/ATZPluginWindowController.m index 6be8a64..7b0633b 100644 --- a/Alcatraz/Controllers/ATZPluginWindowController.m +++ b/Alcatraz/Controllers/ATZPluginWindowController.m @@ -1,5 +1,5 @@ // PluginWindowController.m -// +// // Copyright (c) 2014 Marin Usalj | supermar.in // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -8,10 +8,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -36,21 +36,24 @@ #import "ATZFillableButton.h" #import "ATZPackageTableViewDelegate.h" +#import "ATZGit.h" +#import "ATZConfig.h" static NSString *const ALL_ITEMS_ID = @"AllItemsToolbarItem"; static NSString *const CLASS_PREDICATE_FORMAT = @"(self isKindOfClass: %@)"; static NSString *const SEARCH_PREDICATE_FORMAT = @"(name contains[cd] %@ OR summary contains[cd] %@)"; static NSString *const INSTALLED_PREDICATE_FORMAT = @"(installed == YES)"; -typedef NS_ENUM(NSInteger, ATZFilterSegment) { +typedef NS_ENUM (NSInteger, ATZFilterSegment) { ATZFilterSegmentPlugins = 0, ATZFilterSegmentColorSchemes = 1, ATZFilterSegmentTemplates = 2, }; @interface ATZPluginWindowController () +@property (nonatomic, weak) IBOutlet NSMenuItem *forceHttpsForGitMenuItem; @property (nonatomic, assign) NSView *hoverButtonsContainer; -@property (nonatomic, strong) ATZPackageTableViewDelegate* tableViewDelegate; +@property (nonatomic, strong) ATZPackageTableViewDelegate *tableViewDelegate; @end @implementation ATZPluginWindowController @@ -62,10 +65,13 @@ - (id)init { - (id)initWithBundle:(NSBundle *)bundle { if (self = [super initWithWindowNibName:NSStringFromClass([ATZPluginWindowController class])]) { @try { - if ([NSUserNotificationCenter class]) + _forceHttpsForGitMenuItem.state = [ATZConfig forceHttps]; + if ([NSUserNotificationCenter class]) { [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self]; + } + }@catch (NSException *exception) { + NSLog(@"I've heard you like exceptions... %@", exception); } - @catch(NSException *exception) { NSLog(@"I've heard you like exceptions... %@", exception); } } return self; } @@ -73,8 +79,9 @@ - (id)initWithBundle:(NSBundle *)bundle { - (void)windowDidLoad { [super windowDidLoad]; [self addVersionToWindow]; - if ([self.window respondsToSelector:@selector(setTitleVisibility:)]) + if ([self.window respondsToSelector:@selector(setTitleVisibility:)]) { self.window.titleVisibility = NSWindowTitleHidden; + } } - (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification { @@ -89,24 +96,25 @@ - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentN - (IBAction)installPressed:(ATZFillableButton *)button { ATZPackage *package = [self.tableViewDelegate tableView:self.tableView objectValueForTableColumn:0 row:[self.tableView rowForView:button]]; - - if (package.isInstalled) + + if (package.isInstalled) { [self removePackage:package andUpdateControl:button]; - else + } else { [self installPackage:package andUpdateControl:button]; + } } - (NSDictionary *)segmentClassMapping { static NSDictionary *segmentClassMapping; if (!segmentClassMapping) { - segmentClassMapping = @{@(ATZFilterSegmentColorSchemes): [ATZColorScheme class], - @(ATZFilterSegmentPlugins): [ATZPlugin class], - @(ATZFilterSegmentTemplates): [ATZTemplate class]}; + segmentClassMapping = @{@(ATZFilterSegmentColorSchemes): [ATZColorScheme class], + @(ATZFilterSegmentPlugins): [ATZPlugin class], + @(ATZFilterSegmentTemplates): [ATZTemplate class]}; } return segmentClassMapping; } -- (IBAction)segmentedControlPressed:(NSSegmentedControl*)sender { +- (IBAction)segmentedControlPressed:(NSSegmentedControl *)sender { [self updatePredicate]; } @@ -126,44 +134,67 @@ - (void)controlTextDidChange:(NSNotification *)note { } - (void)keyDown:(NSEvent *)event { - if (hasPressedCommandF(event)) + if (hasPressedCommandF(event)) { [self.window makeFirstResponder:self.searchField]; - else + } else { [super keyDown:event]; + } } - (IBAction)reloadPackages:(id)sender { ATZDownloader *downloader = [ATZDownloader new]; [downloader downloadPackageListWithCompletion:^(NSDictionary *packageList, NSError *error) { + if (error) { + NSLog(@"Error while downloading packages! %@", error); + } else { + self.packages = [ATZPackageFactory createPackagesFromDicts:packageList]; + [self reloadTableView]; + [self updatePackages]; + } + }]; +} - if (error) { - NSLog(@"Error while downloading packages! %@", error); - } else { - self.packages = [ATZPackageFactory createPackagesFromDicts:packageList]; - [self reloadTableView]; - [self updatePackages]; - } - }]; +- (IBAction)updateForceHttpsForGit:(NSMenuItem *)sender { + sender.state = !sender.state; + NSLog(@"Force https: %@", sender.state ? @"YES" : @"NO"); + [ATZConfig setForceHttps:sender.state]; } -- (IBAction)updatePackageRepoPath:(id)sender { - // present dialog with text field, update repo path, redownload package list +- (NSAlert *)createAlert:(NSString *)messageText { NSAlert *alert = [NSAlert new]; - alert.messageText = [Alcatraz localizedStringForKey:@"change-path.message"]; + alert.messageText = [Alcatraz localizedStringForKey:messageText]; [alert addButtonWithTitle:[Alcatraz localizedStringForKey:@"actions.save"]]; [alert addButtonWithTitle:[Alcatraz localizedStringForKey:@"actions.cancel"]]; + return alert; +} + +- (IBAction)updateSetHttpProxyForGit:(id)sender { + NSAlert *alert = [self createAlert:@"http-proxy.message"]; NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 500, 24)]; - input.stringValue = [ATZDownloader packageRepoPath]; + input.stringValue = [ATZConfig httpProxy]; alert.accessoryView = input; - if ([alert runModal] == NSAlertFirstButtonReturn && ![input.stringValue isEqualToString:[ATZDownloader packageRepoPath]]) { - [ATZDownloader setPackagesRepoPath:input.stringValue]; + if ([alert runModal] == NSAlertFirstButtonReturn) { + NSLog(@"Proxy set to: %@", input.stringValue); + [ATZConfig setHttpProxy:input.stringValue]; + } +} + +- (IBAction)updatePackageRepoPath:(id)sender { + // present dialog with text field, update repo path, redownload package list + NSAlert *alert = [self createAlert:@"change-path.message"]; + NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 500, 24)]; + input.stringValue = [ATZConfig packageRepoPath]; + alert.accessoryView = input; + + if ([alert runModal] == NSAlertFirstButtonReturn && ![input.stringValue isEqualToString:[ATZConfig packageRepoPath]]) { + [ATZConfig setPackagesRepoPath:input.stringValue]; [self reloadPackages:nil]; } } - (IBAction)resetPackageRepoPath:(id)sender { - [ATZDownloader resetPackageRepoPath]; + [ATZConfig resetPackageRepoPath]; [self reloadPackages:nil]; } @@ -180,12 +211,14 @@ - (void)reloadTableView { #pragma mark - Private - (void)enqueuePackageUpdate:(ATZPackage *)package { - if (!package.isInstalled) return; + if (!package.isInstalled) { + return; + } NSOperation *updateOperation = [NSBlockOperation blockOperationWithBlock:^{ - [package updateWithProgress:^(NSString *proggressMessage, CGFloat progress){} - completion:^(NSError *failure){}]; - }]; + [package updateWithProgress:^(NSString *proggressMessage, CGFloat progress){} + completion:^(NSError *failure){}]; + }]; [updateOperation addDependency:[[NSOperationQueue mainQueue] operations].lastObject]; [[NSOperationQueue mainQueue] addOperation:updateOperation]; } @@ -198,18 +231,22 @@ - (void)removePackage:(ATZPackage *)package andUpdateControl:(ATZFillableButton - (void)installPackage:(ATZPackage *)package andUpdateControl:(ATZFillableButton *)control { [package installWithProgress:^(NSString *progressMessage, CGFloat progress) { - control.title = @"INSTALLING"; - [control setFillRatio:progress * 100 animated:YES]; - } completion:^(NSError *failure) { - control.title = package.isInstalled ? @"REMOVE" : @"INSTALL"; - [control setFillRatio:(package.isInstalled ? 100 : 0) animated:YES]; - if (package.requiresRestart) [self postNotificationForInstalledPackage:package]; - }]; + control.title = @"INSTALLING"; + [control setFillRatio:progress * 100 animated:YES]; + } completion:^(NSError *failure) { + control.title = package.isInstalled ? @"REMOVE" : @"INSTALL"; + [control setFillRatio:(package.isInstalled ? 100 : 0) animated:YES]; + if (package.requiresRestart) { + [self postNotificationForInstalledPackage:package]; + } + }]; } - (void)postNotificationForInstalledPackage:(ATZPackage *)package { - if (![NSUserNotificationCenter class] || !package.isInstalled) return; - + if (![NSUserNotificationCenter class] || !package.isInstalled) { + return; + } + NSUserNotification *notification = [NSUserNotification new]; notification.title = [NSString stringWithFormat:@"%@ installed", package.type]; NSString *restartText = package.requiresRestart ? @" Please restart Xcode to use it." : @""; @@ -224,16 +261,19 @@ BOOL hasPressedCommandF(NSEvent *event) { - (void)updatePredicate { NSString *searchText = self.searchField.stringValue; - NSMutableArray* predicates = [[NSMutableArray alloc] initWithCapacity:3]; + NSMutableArray *predicates = [[NSMutableArray alloc] initWithCapacity:3]; Class selectedPackageClass = [self segmentClassMapping][@([self.packageTypeSegmentedControl selectedSegment])]; - if (selectedPackageClass) + if (selectedPackageClass) { [predicates addObject:[NSPredicate predicateWithFormat:CLASS_PREDICATE_FORMAT, selectedPackageClass]]; + } - if (searchText.length > 0) + if (searchText.length > 0) { [predicates addObject:[NSPredicate predicateWithFormat:SEARCH_PREDICATE_FORMAT, searchText, searchText]]; + } - if ([self.installationStateSegmentedControl selectedSegment] != 0) + if ([self.installationStateSegmentedControl selectedSegment] != 0) { [predicates addObject:[NSPredicate predicateWithFormat:INSTALLED_PREDICATE_FORMAT]]; + } [self.tableViewDelegate filterUsingPredicate:[NSCompoundPredicate andPredicateWithSubpredicates:predicates]]; [self.tableView reloadData]; @@ -250,21 +290,20 @@ - (void)openWebsite:(NSString *)address { } - (void)displayScreenshotWithPath:(NSString *)screenshotPath withTitle:(NSString *)title { - [self.previewPanel.animator setAlphaValue:0.f]; self.previewPanel.title = title; [self retrieveImageViewForScreenshot:screenshotPath progress:^(CGFloat progress) {} completion:^(NSImage *image) { - [self displayImage:image withTitle:title]; - }]; + [self displayImage:image withTitle:title]; + }]; } -- (void)displayImage:(NSImage *)image withTitle:(NSString*)title { +- (void)displayImage:(NSImage *)image withTitle:(NSString *)title { self.previewImageView.image = image; [NSAnimationContext beginGrouping]; - [self.previewImageView.animator setFrame:(CGRect){ .origin = CGPointMake(0, 0), .size = image.size }]; + [self.previewImageView.animator setFrame:(CGRect){.origin = CGPointMake(0, 0), .size = image.size }]; CGRect previewPanelFrame = (CGRect){.origin = self.previewPanel.frame.origin, .size = image.size}; [self.previewPanel setFrame:previewPanelFrame display:NO animate:NO]; [self.previewPanel.animator center]; @@ -276,18 +315,15 @@ - (void)displayImage:(NSImage *)image withTitle:(NSString*)title { } - (void)retrieveImageViewForScreenshot:(NSString *)screenshotPath progress:(void (^)(CGFloat))downloadProgress completion:(void (^)(NSImage *))completion { - ATZDownloader *downloader = [ATZDownloader new]; [downloader downloadFileFromPath:screenshotPath progress:^(CGFloat progress) { - downloadProgress(progress); - } + downloadProgress(progress); + } completion:^(NSData *responseData, NSError *error) { - - NSImage *image = [[NSImage alloc] initWithData:responseData]; - completion(image); - }]; - + NSImage *image = [[NSImage alloc] initWithData:responseData]; + completion(image); + }]; } - (void)addVersionToWindow { diff --git a/Alcatraz/Helpers/ATZConfig.h b/Alcatraz/Helpers/ATZConfig.h new file mode 100644 index 0000000..a44921b --- /dev/null +++ b/Alcatraz/Helpers/ATZConfig.h @@ -0,0 +1,42 @@ +// +// ATZConfig.h +// Alcatraz +// +// Created by Max on 09/05/15. +// Copyright (c) 2013 Marin Usalj | supermar.in +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@interface ATZConfig : NSObject + ++ (NSString *)packageRepoPath; ++ (void)setPackagesRepoPath:(NSString *)path; ++ (void)resetPackageRepoPath; + ++ (NSString *)httpProxy; ++ (void)setHttpProxy:(NSString *)path; ++ (void)resetHttpProxy; + ++ (BOOL)forceHttps; ++ (void)setForceHttps:(BOOL)httpOnly; ++ (void)resetForceHttps; + +@end diff --git a/Alcatraz/Helpers/ATZConfig.m b/Alcatraz/Helpers/ATZConfig.m new file mode 100644 index 0000000..8060af5 --- /dev/null +++ b/Alcatraz/Helpers/ATZConfig.m @@ -0,0 +1,94 @@ +// +// ATZConfig.m +// Alcatraz +// +// Created by Max on 09/05/15. +// Copyright (c) 2013 Marin Usalj | supermar.in +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "ATZConfig.h" + +static NSString *const ATZ_HTTP_PROXY_KEY = @"ATZGitHttpProxy"; +static NSString *const ATZ_FORCE_HTTPS_KEY = @"ATZForceHttps"; +static NSString *const ATZ_REPO_KEY = @"ATZRepoPath"; +static NSString *const ATZ_DEFAULT_REPO_PATH = @"https://raw.github.com/supermarin/alcatraz-packages/master/packages.json"; + +@implementation ATZConfig + +#pragma mark - Package Repo + ++ (NSString *)packageRepoPath { + NSString *path = [[NSUserDefaults standardUserDefaults] stringForKey:ATZ_REPO_KEY]; + if (!path) { + path = ATZ_DEFAULT_REPO_PATH; + } + + return path; +} + ++ (void)resetPackageRepoPath { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:ATZ_REPO_KEY]; +} + ++ (void)setPackagesRepoPath:(NSString *)path { + [[NSUserDefaults standardUserDefaults] setObject:path forKey:ATZ_REPO_KEY]; +} + +#pragma mark - Http Proxy + ++ (NSString *)httpProxy { + NSString *proxy = [[NSUserDefaults standardUserDefaults] stringForKey:ATZ_HTTP_PROXY_KEY]; + + if (!proxy) { + proxy = @""; + } + + return proxy; +} + ++ (void)resetHttpProxy { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:ATZ_HTTP_PROXY_KEY]; +} + ++ (void)setHttpProxy:(NSString *)proxy { + [[NSUserDefaults standardUserDefaults] setObject:proxy forKey:ATZ_HTTP_PROXY_KEY]; +} + +#pragma mark - Http Only + ++ (BOOL)forceHttps { + BOOL forceHttps = [[NSUserDefaults standardUserDefaults] boolForKey:ATZ_FORCE_HTTPS_KEY]; + + if (!forceHttps) { + forceHttps = YES; + } + + return forceHttps; +} + ++ (void)resetForceHttps { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:ATZ_FORCE_HTTPS_KEY]; +} + ++ (void)setForceHttps:(BOOL)forceHttps { + [[NSUserDefaults standardUserDefaults] setBool:forceHttps forKey:ATZ_FORCE_HTTPS_KEY]; +} + +@end diff --git a/Alcatraz/Helpers/ATZDownloader.h b/Alcatraz/Helpers/ATZDownloader.h index 1da0d1f..343c124 100644 --- a/Alcatraz/Helpers/ATZDownloader.h +++ b/Alcatraz/Helpers/ATZDownloader.h @@ -23,16 +23,12 @@ #import -typedef void(^ATZJSONDownloadCompletion)(NSDictionary *json, NSError *error); -typedef void(^ATZDataDownloadCompletion)(NSData *data, NSError *error); -typedef void(^ATZDownloadProgress)(CGFloat progress); +typedef void (^ATZJSONDownloadCompletion)(NSDictionary *json, NSError *error); +typedef void (^ATZDataDownloadCompletion)(NSData *data, NSError *error); +typedef void (^ATZDownloadProgress)(CGFloat progress); @interface ATZDownloader : NSObject -+ (NSString*)packageRepoPath; -+ (void)setPackagesRepoPath:(NSString*)path; -+ (void)resetPackageRepoPath; - - (void)downloadPackageListWithCompletion:(ATZJSONDownloadCompletion)completion; - (void)downloadFileFromPath:(NSString *)remotePath progress:(ATZDownloadProgress)progress diff --git a/Alcatraz/Helpers/ATZDownloader.m b/Alcatraz/Helpers/ATZDownloader.m index 677a5cc..35ea4c3 100644 --- a/Alcatraz/Helpers/ATZDownloader.m +++ b/Alcatraz/Helpers/ATZDownloader.m @@ -22,8 +22,9 @@ #import "ATZDownloader.h" +#import "ATZConfig.h" -@interface ATZDownloader() +@interface ATZDownloader () @property (strong, nonatomic) NSMutableDictionary *callbacks; @property (strong, nonatomic) NSURLSession *urlSession; @end @@ -31,120 +32,100 @@ @interface ATZDownloader() @implementation ATZDownloader -static NSString *const ATZ_DEFAULT_REPO_PATH = @"https://raw.github.com/supermarin/alcatraz-packages/master/packages.json"; -static NSString *const ATZ_REPO_KEY = @"ATZRepoPath"; static NSString *const PROGRESS = @"progress"; static NSString *const COMPLETION = @"completion"; - (id)init { self = [super init]; - if (!self) return nil; - + if (!self) { + return nil; + } + _callbacks = [NSMutableDictionary new]; - + return self; } - (void)downloadPackageListWithCompletion:(ATZJSONDownloadCompletion)completion { - [self downloadFileFromPath:[ATZDownloader packageRepoPath] + [self downloadFileFromPath:[ATZConfig packageRepoPath] progress:^(CGFloat progress) {} completion:^(NSData *data, NSError *error) { - - if (error) { completion(nil, error); return; } + if (error) { + completion(nil, error); return; + } - NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; - completion(JSON[@"packages"], error); - }]; + NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + completion(JSON[@"packages"], error); + }]; } - (void)downloadFileFromPath:(NSString *)remotePath progress:(ATZDownloadProgress)progress - completion:(ATZDataDownloadCompletion)completion { - + completion:(ATZDataDownloadCompletion)completion { NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:remotePath]]; NSURLSessionTask *task = [[self urlSession] downloadTaskWithRequest:request]; - NSMutableDictionary* callbacks = [[NSMutableDictionary alloc] initWithCapacity:2]; - if (completion) + NSMutableDictionary *callbacks = [[NSMutableDictionary alloc] initWithCapacity:2]; + if (completion) { callbacks[COMPLETION] = completion; - if (progress) + } + if (progress) { callbacks[PROGRESS] = progress; + } self.callbacks[task] = callbacks; - - [task resume]; -} - -#pragma mark - Package Repo - -+ (NSString*)packageRepoPath { - NSString* path = [[NSUserDefaults standardUserDefaults] valueForKey:ATZ_REPO_KEY]; - if (!path) - path = ATZ_DEFAULT_REPO_PATH; - - return path; -} - -+ (void)resetPackageRepoPath { - [[NSUserDefaults standardUserDefaults] removeObjectForKey:ATZ_REPO_KEY]; -} -+ (void)setPackagesRepoPath:(NSString*)path { - [[NSUserDefaults standardUserDefaults] setObject:path forKey:ATZ_REPO_KEY]; + [task resume]; } #pragma mark - NSURLSessionDelegate -- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask - didFinishDownloadingToURL:(NSURL *)location { - +- (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask + didFinishDownloadingToURL:(NSURL *)location { ATZDataDownloadCompletion completionBlock = self.callbacks[downloadTask][COMPLETION]; - if (completionBlock) + if (completionBlock) { completionBlock([NSData dataWithContentsOfURL:location], nil); + } } -- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask - didWriteData:(int64_t)bytesWritten - totalBytesWritten:(int64_t)totalBytesWritten - totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { - +- (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten + totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { CGFloat progress = (CGFloat)totalBytesWritten / (CGFloat)totalBytesExpectedToWrite; - ATZDownloadProgress progressBlock = self.callbacks[downloadTask][PROGRESS]; - if (progressBlock) + ATZDownloadProgress progressBlock = self.callbacks[downloadTask][PROGRESS]; + if (progressBlock) { progressBlock(progress); + } } -- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {} +- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { +} - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler { completionHandler(request); } - #pragma mark - NSURLSessionTask delegate /* Sent as the last message related to a specific task. Error may be * nil, which implies that no error occurred and this task is complete. */ -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task -didCompleteWithError:(NSError *)error { - +- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { } - #pragma mark - Private - (NSURLSession *)urlSession { - if (_urlSession) return _urlSession; - + if (_urlSession) { + return _urlSession; + } + _urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; return _urlSession; } - - - - @end diff --git a/Alcatraz/Helpers/ATZGit.h b/Alcatraz/Helpers/ATZGit.h index 48c281f..5b23e1c 100644 --- a/Alcatraz/Helpers/ATZGit.h +++ b/Alcatraz/Helpers/ATZGit.h @@ -1,5 +1,5 @@ // Git.h -// +// // Copyright (c) 2013 Marin Usalj | supermar.in // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -8,10 +8,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -22,25 +22,13 @@ #import -static NSString *const GIT = @"/usr/bin/git"; -static NSString *const IGNORE_PUSH_CONFIG = @"-c push.default=matching"; -static NSString *const CLONE = @"clone"; -static NSString *const FETCH = @"fetch"; -static NSString *const ORIGIN = @"origin"; -static NSString *const BRANCH = @"branch"; -static NSString *const COMMIT = @"commit"; -static NSString *const TAG = @"tag"; -static NSString *const ORIGIN_MASTER = @"origin/master"; -static NSString *const RESET = @"reset"; -static NSString *const HARD = @"--hard"; - @interface ATZGit : NSObject + (void)cloneRepository:(NSString *)remotePath toLocalPath:(NSString *)localPath - completion:(void(^)(NSString *output, NSError *error))completion; + completion:(void (^)(NSString *output, NSError *error))completion; + (void)updateRepository:(NSString *)localPath revision:(NSString *)revision - completion:(void(^)(NSString *output, NSError *error))completion; + completion:(void (^)(NSString *output, NSError *error))completion; + (NSString *)parseRevisionFromDictionary:(NSDictionary *)dict; diff --git a/Alcatraz/Helpers/ATZGit.m b/Alcatraz/Helpers/ATZGit.m index 8633f43..feb23e3 100644 --- a/Alcatraz/Helpers/ATZGit.m +++ b/Alcatraz/Helpers/ATZGit.m @@ -1,5 +1,5 @@ // Git.m -// +// // Copyright (c) 2013 Marin Usalj | supermar.in // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -8,10 +8,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,94 +23,117 @@ #import "ATZGit.h" #import "ATZShell.h" #import "NSFileManager+Alcatraz.h" +#import "ATZConfig.h" + +static NSString *const GIT = @"/usr/bin/git"; +static NSString *const GITHUB_GIT_ADRESS = @"git@github.com:"; +static NSString *const GITHUB_HTTPS_ADRESS = @"https://github.com/"; +static NSString *const IGNORE_PUSH_CONFIG = @"-c push.default=matching"; +static NSString *const CLONE = @"clone"; +static NSString *const FETCH = @"fetch"; +static NSString *const ORIGIN = @"origin"; +static NSString *const BRANCH = @"branch"; +static NSString *const COMMIT = @"commit"; +static NSString *const TAG = @"tag"; +static NSString *const ORIGIN_MASTER = @"origin/master"; +static NSString *const RESET = @"reset"; +static NSString *const HARD = @"--hard"; @implementation ATZGit + (void)updateRepository:(NSString *)localPath revision:(NSString *)revision - completion:(void(^)(NSString *output, NSError *error))completion { - + completion:(void (^)(NSString *output, NSError *error))completion { NSLog(@"Updating Repo: %@", localPath); [self updateLocalProject:localPath revision:revision completion:completion]; } + (void)cloneRepository:(NSString *)remotePath toLocalPath:(NSString *)localPath - completion:(void (^)(NSString *output, NSError *))completion { - + completion:(void (^)(NSString *output, NSError *))completion { NSLog(@"Cloning Repo: %@", localPath); + if ([ATZConfig forceHttps]) { + remotePath = [self convertRemotePathToHttps:remotePath]; + } [self clone:remotePath to:localPath completion:completion]; } + (NSString *)parseRevisionFromDictionary:(NSDictionary *)dict { return dict[BRANCH] ? [ORIGIN stringByAppendingPathComponent:dict[BRANCH]] : - dict[TAG] ?: - dict[COMMIT] ?: nil; + dict[TAG] ? : + dict[COMMIT] ? : nil; } + (BOOL)areCommandLineToolsAvailable { BOOL areAvailable = YES; @try { [NSTask launchedTaskWithLaunchPath:@"/usr/bin/git" arguments:@[@"--version"]]; - } - @catch (NSException *exception) { + }@catch (NSException *exception) { areAvailable = NO; } return areAvailable; } ++ (NSString *)convertRemotePathToHttps:(NSString *)remotePath { + if ([remotePath containsString:GITHUB_GIT_ADRESS]) { + return [remotePath stringByReplacingOccurrencesOfString:GITHUB_GIT_ADRESS + withString:GITHUB_HTTPS_ADRESS]; + } + return remotePath; +} + ++ (NSArray *)addProxyToArguments:(NSArray *)arguments { + NSArray *proxy = @[[NSString stringWithFormat:@"-c http.proxy=%@", [ATZConfig httpProxy]]]; + + return [arguments arrayByAddingObjectsFromArray:proxy]; +} + #pragma mark - Private + (void)clone:(NSString *)remotePath to:(NSString *)localPath completion:(void (^)(NSString *, NSError *))completion { ATZShell *shell = [ATZShell new]; - - [shell executeCommand:GIT withArguments:@[CLONE, remotePath, localPath, IGNORE_PUSH_CONFIG] - completion:^(NSString *output, NSError *error) { - - NSLog(@"Git Clone output: %@", output); - completion(output, error); - }]; + NSArray *cloneArguments = [self addProxyToArguments:@[CLONE, remotePath, localPath, IGNORE_PUSH_CONFIG]]; + + [shell executeCommand:GIT withArguments:cloneArguments completion:^(NSString *output, NSError *error) { + NSLog(@"Git Clone output: %@", output); + completion(output, error); + }]; } // TODO: refactor, make less shell instances (maybe?) + (void)updateLocalProject:(NSString *)localPath revision:(NSString *)revision completion:(void (^)(NSString *, NSError *))completion { - [self fetch:localPath completion:^(NSString *fetchOutput, NSError *error) { - - if (error) - completion(fetchOutput, error); - else - [self resetHard:localPath revision:revision completion:^(NSString *resetOutput, NSError *error) { - completion(fetchOutput, error); - }]; - }]; + if (error) { + completion(fetchOutput, error); + } else { + [self resetHard:localPath revision:revision completion:^(NSString *resetOutput, NSError *error) { + completion(fetchOutput, error); + }]; + } + }]; } + (void)fetch:(NSString *)localPath completion:(void (^)(NSString *, NSError *))completion { - ATZShell *shell = [ATZShell new]; - [shell executeCommand:GIT withArguments:@[FETCH, ORIGIN] inWorkingDirectory:localPath + NSArray *fetchArguments = @[FETCH, ORIGIN]; + + [shell executeCommand:GIT withArguments:fetchArguments inWorkingDirectory:localPath completion:^(NSString *output, NSError *error) { - - NSLog(@"Git fetch output: %@", output); - completion(output, error); - }]; + NSLog(@"Git fetch output: %@", output); + completion(output, error); + }]; } + (void)resetHard:(NSString *)localPath revision:(NSString *)revision completion:(void (^)(NSString *, NSError *))completion { - ATZShell *shell = [ATZShell new]; - NSArray *resetArguments = @[RESET, HARD, revision ?: ORIGIN_MASTER]; - + NSArray *resetArguments = @[RESET, HARD, revision ? : ORIGIN_MASTER]; + [shell executeCommand:GIT withArguments:resetArguments inWorkingDirectory:localPath completion:^(NSString *output, NSError *error) { - - NSLog(@"Git reset output: %@", output); - completion(output, error); - }]; + NSLog(@"Git reset output: %@", output); + completion(output, error); + }]; } - - @end diff --git a/Alcatraz/en.lproj/Localizable.strings b/Alcatraz/en.lproj/Localizable.strings index 43ed101..19d6292 100644 --- a/Alcatraz/en.lproj/Localizable.strings +++ b/Alcatraz/en.lproj/Localizable.strings @@ -12,6 +12,7 @@ Command Line Tools are available for installation in the Downloads section of Pr "MavericksOnlyWarning" = "Alcatraz for Xcode 5 only supports OS X 10.9+."; "change-path.message" = "Enter a new package repo URL path:"; +"http-proxy.message" = "Enter a HTTP proxy to use:"; "change-path.title" = "Change Package Repo Path"; "actions.cancel" = "Cancel"; "actions.save" = "Save"; \ No newline at end of file From 183eca3086a6419b3f8ab233cb267e2ae9566a2c Mon Sep 17 00:00:00 2001 From: Max Demian Date: Sun, 10 May 2015 18:16:18 +0200 Subject: [PATCH 02/20] Use Environment variables instead of git config to set proxy --- Alcatraz/Helpers/ATZGit.m | 12 ++---- Alcatraz/Helpers/ATZShell.m | 75 ++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/Alcatraz/Helpers/ATZGit.m b/Alcatraz/Helpers/ATZGit.m index feb23e3..f414ac7 100644 --- a/Alcatraz/Helpers/ATZGit.m +++ b/Alcatraz/Helpers/ATZGit.m @@ -51,7 +51,7 @@ + (void)cloneRepository:(NSString *)remotePath toLocalPath:(NSString *)localPath completion:(void (^)(NSString *output, NSError *))completion { NSLog(@"Cloning Repo: %@", localPath); if ([ATZConfig forceHttps]) { - remotePath = [self convertRemotePathToHttps:remotePath]; + remotePath = [self forceHttpsForGithub:remotePath]; } [self clone:remotePath to:localPath completion:completion]; } @@ -73,7 +73,7 @@ + (BOOL)areCommandLineToolsAvailable { return areAvailable; } -+ (NSString *)convertRemotePathToHttps:(NSString *)remotePath { ++ (NSString *)forceHttpsForGithub:(NSString *)remotePath { if ([remotePath containsString:GITHUB_GIT_ADRESS]) { return [remotePath stringByReplacingOccurrencesOfString:GITHUB_GIT_ADRESS withString:GITHUB_HTTPS_ADRESS]; @@ -81,17 +81,11 @@ + (NSString *)convertRemotePathToHttps:(NSString *)remotePath { return remotePath; } -+ (NSArray *)addProxyToArguments:(NSArray *)arguments { - NSArray *proxy = @[[NSString stringWithFormat:@"-c http.proxy=%@", [ATZConfig httpProxy]]]; - - return [arguments arrayByAddingObjectsFromArray:proxy]; -} - #pragma mark - Private + (void)clone:(NSString *)remotePath to:(NSString *)localPath completion:(void (^)(NSString *, NSError *))completion { ATZShell *shell = [ATZShell new]; - NSArray *cloneArguments = [self addProxyToArguments:@[CLONE, remotePath, localPath, IGNORE_PUSH_CONFIG]]; + NSArray *cloneArguments = @[CLONE, remotePath, localPath, IGNORE_PUSH_CONFIG]; [shell executeCommand:GIT withArguments:cloneArguments completion:^(NSString *output, NSError *error) { NSLog(@"Git Clone output: %@", output); diff --git a/Alcatraz/Helpers/ATZShell.m b/Alcatraz/Helpers/ATZShell.m index 8fe3f5a..d1ca9b4 100644 --- a/Alcatraz/Helpers/ATZShell.m +++ b/Alcatraz/Helpers/ATZShell.m @@ -1,5 +1,5 @@ // Shell.m -// +// // Copyright (c) 2013 Marin Usalj | supermar.in // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -8,10 +8,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -21,6 +21,7 @@ // THE SOFTWARE. #import "ATZShell.h" +#import "ATZConfig.h" @interface ATZShell (){} @property (nonatomic, retain) NSMutableData *taskOutput; @@ -29,69 +30,73 @@ @interface ATZShell (){} @implementation ATZShell - (void)executeCommand:(NSString *)command withArguments:(NSArray *)arguments - completion:(void(^)(NSString *taskOutput, NSError *error))completion { - + completion:(void (^)(NSString *taskOutput, NSError *error))completion { [self executeCommand:command withArguments:arguments inWorkingDirectory:nil completion:completion]; } - (void)executeCommand:(NSString *)command withArguments:(NSArray *)arguments inWorkingDirectory:(NSString *)path - completion:(void(^)(NSString *taskOutput, NSError *error))completion { - + completion:(void (^)(NSString *taskOutput, NSError *error))completion { _taskOutput = [NSMutableData new]; NSTask *shellTask = [NSTask new]; - - if (path) [shellTask setCurrentDirectoryPath:path]; + + // Set proxy environment variables for the task. + NSMutableDictionary *environment = [NSMutableDictionary new ]; + [environment addEntriesFromDictionary:[[NSProcessInfo processInfo] environment]]; + [environment setObject:[ATZConfig httpProxy] forKey:@"http_proxy"]; + [environment setObject:[ATZConfig httpProxy] forKey:@"HTTPS_PROXY"]; + [shellTask setEnvironment:environment]; + + if (path) { + [shellTask setCurrentDirectoryPath:path]; + } [shellTask setLaunchPath:command]; [shellTask setArguments:arguments]; - + [self setUpShellOutputForTask:shellTask]; [self setUpStdErrorOutputForTask:shellTask]; - + [self setUpTerminationHandlerForTask:shellTask completion:completion]; [self tryToLaunchTask:shellTask completionIfFailed:completion]; } - #pragma mark - Private - (void)setUpShellOutputForTask:(NSTask *)task { task.standardOutput = [NSPipe pipe]; [[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) { - [self.taskOutput appendData:[file availableData]]; - }]; + [self.taskOutput appendData:[file availableData]]; + }]; } - (void)setUpStdErrorOutputForTask:(NSTask *)task { task.standardError = [NSPipe pipe]; [[task.standardError fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) { - [self.taskOutput appendData:[file availableData]]; - }]; + [self.taskOutput appendData:[file availableData]]; + }]; } -- (void)setUpTerminationHandlerForTask:(NSTask *)task completion:(void(^)(NSString *taskOutput, NSError *error))completion { +- (void)setUpTerminationHandlerForTask:(NSTask *)task completion:(void (^)(NSString *taskOutput, NSError *error))completion { [task setTerminationHandler:^(NSTask *task) { - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - NSString* output = [[NSString alloc] initWithData:self.taskOutput encoding:NSUTF8StringEncoding]; - - if (task.terminationStatus == 0) { - completion(output, nil); - } else { - NSString* reason = [NSString stringWithFormat:@"Task exited with status %d", task.terminationStatus]; - completion(output, [NSError errorWithDomain:reason code:666 userInfo:@{ NSLocalizedDescriptionKey: reason }]); - } - }]; - - [task.standardOutput fileHandleForReading].readabilityHandler = nil; - [task.standardError fileHandleForReading].readabilityHandler = nil; - }]; + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + NSString *output = [[NSString alloc] initWithData:self.taskOutput encoding:NSUTF8StringEncoding]; + + if (task.terminationStatus == 0) { + completion(output, nil); + } else { + NSString *reason = [NSString stringWithFormat:@"Task exited with status %d", task.terminationStatus]; + completion(output, [NSError errorWithDomain:reason code:666 userInfo:@{ NSLocalizedDescriptionKey: reason }]); + } + }]; + + [task.standardOutput fileHandleForReading].readabilityHandler = nil; + [task.standardError fileHandleForReading].readabilityHandler = nil; + }]; } -- (void)tryToLaunchTask:(NSTask *)shellTask completionIfFailed:(void(^)(NSString *taskOutput, NSError *error))completion { +- (void)tryToLaunchTask:(NSTask *)shellTask completionIfFailed:(void (^)(NSString *taskOutput, NSError *error))completion { @try { [shellTask launch]; - } - @catch (NSException *exception) { + }@catch (NSException *exception) { NSLog(@"Shell command execution failed! %@", exception); completion(nil, [NSError errorWithDomain:exception.reason code:667 userInfo:nil]); } From 0bb47a8c8ca013099cca136ad83f2c739be5a763 Mon Sep 17 00:00:00 2001 From: Max Demian Date: Sun, 10 May 2015 18:17:41 +0200 Subject: [PATCH 03/20] GUI Update: Add proxy localization title and enable state for Preference Menu Items --- Alcatraz/ATZPluginWindowController.xib | 5 +++-- Alcatraz/Controllers/ATZPluginWindowController.m | 2 +- Alcatraz/en.lproj/Localizable.strings | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Alcatraz/ATZPluginWindowController.xib b/Alcatraz/ATZPluginWindowController.xib index 8d40a8d..9e6ffc7 100644 --- a/Alcatraz/ATZPluginWindowController.xib +++ b/Alcatraz/ATZPluginWindowController.xib @@ -188,10 +188,10 @@ - + - +