diff --git a/app/CocoaPods.xcodeproj/project.pbxproj b/app/CocoaPods.xcodeproj/project.pbxproj index c4a97d76..51e76b9a 100644 --- a/app/CocoaPods.xcodeproj/project.pbxproj +++ b/app/CocoaPods.xcodeproj/project.pbxproj @@ -83,6 +83,7 @@ 60E693BD1C4AC6390058DF5F /* CPHomeSidebarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60E693BC1C4AC6390058DF5F /* CPHomeSidebarButton.swift */; }; 60FE01671B9B7AA70027EEE3 /* SMLTextView+CocoaPods.m in Sources */ = {isa = PBXBuildFile; fileRef = 60FE01661B9B7AA70027EEE3 /* SMLTextView+CocoaPods.m */; }; 60FE01701B9B7F1E0027EEE3 /* SUUpdater+DebugMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 60FE016F1B9B7F1E0027EEE3 /* SUUpdater+DebugMode.m */; }; + 657841C91C6BE0EC00B6671E /* CPPodfileInitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657841C81C6BE0EC00B6671E /* CPPodfileInitController.swift */; }; 66F2E29C1C492C5500A1AF1F /* NSColor+CPColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 66F2E29B1C492C5500A1AF1F /* NSColor+CPColors.m */; }; 770382F41A2035B400435285 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 770382F31A2035B400435285 /* Localizable.strings */; }; 77356D751A2253F1002822CF /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 77356D741A2253F1002822CF /* Media.xcassets */; }; @@ -265,6 +266,7 @@ 60FE01661B9B7AA70027EEE3 /* SMLTextView+CocoaPods.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SMLTextView+CocoaPods.m"; sourceTree = ""; }; 60FE016F1B9B7F1E0027EEE3 /* SUUpdater+DebugMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SUUpdater+DebugMode.m"; sourceTree = ""; }; 62FB6E124C8280A7EBFD41C6 /* Pods_CocoaPodsTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CocoaPodsTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 657841C81C6BE0EC00B6671E /* CPPodfileInitController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CPPodfileInitController.swift; sourceTree = ""; }; 66F2E29A1C492C5500A1AF1F /* NSColor+CPColors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSColor+CPColors.h"; sourceTree = ""; }; 66F2E29B1C492C5500A1AF1F /* NSColor+CPColors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSColor+CPColors.m"; sourceTree = ""; }; 750B3A66521735BD745849E5 /* Pods-CocoaPodsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CocoaPodsTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CocoaPodsTests/Pods-CocoaPodsTests.debug.xcconfig"; sourceTree = ""; }; @@ -580,6 +582,7 @@ 93FB07E01C503572007B2CDA /* CPDocumentSource.swift */, 60E693B41C4A71E50058DF5F /* CPSidebarDocumentsController.swift */, 934FF1881C4F1E2A000B4302 /* CPDocumentController.swift */, + 657841C81C6BE0EC00B6671E /* CPPodfileInitController.swift */, ); name = "Home Window"; sourceTree = ""; @@ -996,6 +999,7 @@ 60814A881C2BCFEA00D6663E /* CPWhiteCheckedButton.m in Sources */, 331188571BEBCB0F00272793 /* CPCLIToolInstallationController.m in Sources */, 60E693B51C4A71E50058DF5F /* CPSidebarDocumentsController.swift in Sources */, + 657841C91C6BE0EC00B6671E /* CPPodfileInitController.swift in Sources */, 5BD58BBD1C6D2A7C003787F5 /* CPXcodeProjectCell.swift in Sources */, 606C84721C14C4CA00C6D15F /* CPPodfileMetadataViewController.swift in Sources */, 60E693AC1C49BFDF0058DF5F /* CPHomeWindowDocumentEntry.m in Sources */, diff --git a/app/CocoaPods/Base.lproj/MainMenu.xib b/app/CocoaPods/Base.lproj/MainMenu.xib index 5aa6a9ed..b662a5b8 100644 --- a/app/CocoaPods/Base.lproj/MainMenu.xib +++ b/app/CocoaPods/Base.lproj/MainMenu.xib @@ -1,7 +1,7 @@ - + - + @@ -86,6 +86,11 @@ + + + + + diff --git a/app/CocoaPods/CLI Integrations/CPCLITask.h b/app/CocoaPods/CLI Integrations/CPCLITask.h index 118ecc45..113c12e2 100644 --- a/app/CocoaPods/CLI Integrations/CPCLITask.h +++ b/app/CocoaPods/CLI Integrations/CPCLITask.h @@ -37,6 +37,15 @@ delegate:(id)delegate qualityOfService:(NSQualityOfService)qualityOfService; +/** + * @param workingDirectory The directory for which the command should be performed. + * @param command The `pod` command to execute, such as `install` or `update.` + */ +- (instancetype)initWithWorkingDirectory:(NSString *)workingDirectory + command:(NSString *)command + delegate:(id)delegate + qualityOfService:(NSQualityOfService)qualityOfService; + /** * Perform the task. */ diff --git a/app/CocoaPods/CLI Integrations/CPCLITask.m b/app/CocoaPods/CLI Integrations/CPCLITask.m index c1a2d939..73f2b53a 100644 --- a/app/CocoaPods/CLI Integrations/CPCLITask.m +++ b/app/CocoaPods/CLI Integrations/CPCLITask.m @@ -6,7 +6,7 @@ @interface CPCLITask () @property (nonatomic, weak) id delegate; -@property (nonatomic, weak) CPUserProject *userProject; +@property (nonatomic, weak) NSString *workingDirectory; @property (nonatomic, copy) NSString *command; @property (nonatomic) NSTask *task; @@ -27,14 +27,26 @@ - (instancetype)initWithUserProject:(CPUserProject *)userProject delegate:(id)delegate qualityOfService:(NSQualityOfService)qualityOfService { - if (self = [super init]) { - self.userProject = userProject; + return [self initWithWorkingDirectory:[[userProject.fileURL URLByDeletingLastPathComponent] path] + command:command + delegate:delegate + qualityOfService:qualityOfService]; +} + +- (instancetype)initWithWorkingDirectory:(NSString *)workingDirectory + command:(NSString *)command + delegate:(id)delegate + qualityOfService:(NSQualityOfService)qualityOfService +{ + self = [super init]; + if (self) { + self.workingDirectory = workingDirectory; self.command = command; self.delegate = delegate; self.qualityOfService = qualityOfService; self.terminationStatus = 1; } - + return self; } @@ -57,7 +69,7 @@ - (void)run @"TERM": @"xterm-256color" }; - NSString *workingDirectory = [[self.userProject.fileURL URLByDeletingLastPathComponent] path]; + NSString *workingDirectory = self.workingDirectory; NSString *launchPath = @"/bin/sh"; NSString *envBundleScript = [[NSBundle mainBundle] pathForResource:@"bundle-env" ofType:nil diff --git a/app/CocoaPods/CPDocumentController.swift b/app/CocoaPods/CPDocumentController.swift index 336f6cfc..ecbfe963 100644 --- a/app/CocoaPods/CPDocumentController.swift +++ b/app/CocoaPods/CPDocumentController.swift @@ -9,6 +9,8 @@ class CPDocumentController: NSDocumentController { static let RecentDocumentUpdateNotification = "CPDocumentControllerRecentDocumentUpdateNotification" static let ClearRecentDocumentsNotification = "CPDocumentControllerClearRecentDocumentsNotification" + var podInitController: CPPodfileInitController? + // All of the `openDocument...` calls end up calling this one method, so adding our notification here is simple override func openDocumentWithContentsOfURL(url: NSURL, display displayDocument: Bool, completionHandler: (NSDocument?, Bool, NSError?) -> Void) { @@ -21,6 +23,28 @@ class CPDocumentController: NSDocumentController { } } + override func newDocument(sender: AnyObject?) { + let openPanel = NSOpenPanel() + openPanel.allowsMultipleSelection = false + openPanel.allowedFileTypes = ["xcodeproj"] + + openPanel.beginWithCompletionHandler { buttonIndex in + guard buttonIndex == NSFileHandlingPanelOKButton else { return } + guard let fileURL = openPanel.URL else { return } + + self.podInitController = CPPodfileInitController(xcodeprojURL: fileURL, completionHandler: { podfileURL, error -> () in + guard let podfileURL = podfileURL else { + let alert = NSAlert(error: error! as NSError) + alert.informativeText = error!.message + alert.runModal() + + return + } + self.openDocumentWithContentsOfURL(podfileURL, display: true) { _ in } + }) + } + } + // `noteNewRecentDocument` ends up calling to this method so we can just override this one method override func noteNewRecentDocumentURL(url: NSURL) { diff --git a/app/CocoaPods/CPPodfileInitController.swift b/app/CocoaPods/CPPodfileInitController.swift new file mode 100644 index 00000000..61ff7239 --- /dev/null +++ b/app/CocoaPods/CPPodfileInitController.swift @@ -0,0 +1,65 @@ +import Foundation + +public enum CPPodfileInitErrors: ErrorType { + case CommandError(String) + case NSURLError + + var message: String { + switch self { + case .CommandError(let s): return s + case .NSURLError: return "NSURL unexpectedly nil" + } + } +} + +public class CPPodfileInitController: NSObject, CPCLITaskDelegate { + private var task: CPCLITask! + private let completionHandler: (NSURL?, CPPodfileInitErrors?) -> () + private let output = NSMutableAttributedString() + private let projectURL: NSURL + + init(xcodeprojURL: NSURL, completionHandler: (podfileURL: NSURL?, error: CPPodfileInitErrors?) -> ()) { + self.completionHandler = completionHandler + self.projectURL = xcodeprojURL + + super.init() + let task = CPCLITask(workingDirectory: xcodeprojURL.URLByDeletingLastPathComponent!.path, + command: "init", + delegate: self, + qualityOfService: .UserInitiated) + self.task = task + + self.task.run() + } + + public func task(task: CPCLITask!, didUpdateOutputContents updatedOutput: NSAttributedString!) { + output.appendAttributedString(updatedOutput) + } + + public func taskCompleted(task: CPCLITask!) { + guard task.finishedSuccessfully() else { + self.callbackWithError(CPPodfileInitErrors.CommandError(self.output.string)) + return + } + + guard let podfileURL = projectURL.URLByDeletingLastPathComponent?.URLByAppendingPathComponent("Podfile") where NSFileManager().fileExistsAtPath(podfileURL.path ?? "") + else { + self.callbackWithError(CPPodfileInitErrors.NSURLError) + return + } + + callbackWithSuccess(podfileURL) + } + + private func callbackWithError(error: CPPodfileInitErrors) { + dispatch_async(dispatch_get_main_queue()) { + self.completionHandler(nil, error) + } + } + + private func callbackWithSuccess(url: NSURL) { + dispatch_async(dispatch_get_main_queue()) { + self.completionHandler(url, nil) + } + } +} \ No newline at end of file