diff --git a/Tools/XcodeCapp/Jakefile b/Tools/XcodeCapp/Jakefile index dc08dd52c..3377dfc5e 100644 --- a/Tools/XcodeCapp/Jakefile +++ b/Tools/XcodeCapp/Jakefile @@ -53,17 +53,6 @@ task ("build", function() if (OS.system("xcodebuild " + args)) OS.exit(1); - - if (!executableExists("xcc")) - { - print("\nWould you like to install the xcc command line tool in /usr/local/bin? yes or no:"); - - if (system.stdin.readLine() == "yes\n") - { - sudo(["mkdir", "-p", "/usr/local/bin"]); - sudo(["ln", "-s", "/Applications/XcodeCapp.app/Contents/MacOS/xcc", "/usr/local/bin/"]); - } - } } else { diff --git a/Tools/XcodeCapp/XcodeCapp.xcodeproj/project.pbxproj b/Tools/XcodeCapp/XcodeCapp.xcodeproj/project.pbxproj index 3449e0637..d896e2a43 100644 --- a/Tools/XcodeCapp/XcodeCapp.xcodeproj/project.pbxproj +++ b/Tools/XcodeCapp/XcodeCapp.xcodeproj/project.pbxproj @@ -7,631 +7,583 @@ objects = { /* Begin PBXBuildFile section */ - 68A43034191BF044008A68A7 /* help.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 68A43033191BF044008A68A7 /* help.pdf */; }; - E10E4CD717298E5F004AB09E /* project.pbxproj in Resources */ = {isa = PBXBuildFile; fileRef = E164FE2A172188F300263CE3 /* project.pbxproj */; }; - E14015421740248C006C2792 /* XcodeProjectCloser.m in Sources */ = {isa = PBXBuildFile; fileRef = E14015411740248C006C2792 /* XcodeProjectCloser.m */; }; - E1401543174025B8006C2792 /* XcodeProjectCloser.m in Sources */ = {isa = PBXBuildFile; fileRef = E14015411740248C006C2792 /* XcodeProjectCloser.m */; }; - E164FDD31720E77100263CE3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E164FDD21720E77100263CE3 /* Cocoa.framework */; }; - E164FDDF1720E77100263CE3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E164FDDE1720E77100263CE3 /* main.m */; }; - E164FDF51720EBC100263CE3 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = E164FDF41720EBC100263CE3 /* AppController.m */; }; - E164FDF71720EBD600263CE3 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E164FDF61720EBD600263CE3 /* Growl.framework */; }; - E164FDFF1720EC5B00263CE3 /* XcodeCapp.m in Sources */ = {isa = PBXBuildFile; fileRef = E164FDFB1720EC5B00263CE3 /* XcodeCapp.m */; }; - E164FE181720F44B00263CE3 /* parser.j in Resources */ = {isa = PBXBuildFile; fileRef = E164FE171720F44B00263CE3 /* parser.j */; }; - E164FE1A1720F49A00263CE3 /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = E164FE191720F49A00263CE3 /* Growl Registration Ticket.growlRegDict */; }; - E164FE1F1720F51E00263CE3 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E164FE1D1720F50100263CE3 /* CoreServices.framework */; }; - E164FE211720F55600263CE3 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E164FDF61720EBD600263CE3 /* Growl.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - E164FE2F1721A34900263CE3 /* icon-active.png in Resources */ = {isa = PBXBuildFile; fileRef = E164FE2C1721A34900263CE3 /* icon-active.png */; }; - E164FE301721A34900263CE3 /* icon-inactive.png in Resources */ = {isa = PBXBuildFile; fileRef = E164FE2D1721A34900263CE3 /* icon-inactive.png */; }; - E164FE311721A34900263CE3 /* icon-working.png in Resources */ = {isa = PBXBuildFile; fileRef = E164FE2E1721A34900263CE3 /* icon-working.png */; }; - E170C3FB17296205003DC489 /* pbxprojModifier.py in CopyFiles */ = {isa = PBXBuildFile; fileRef = E164FE141720F40400263CE3 /* pbxprojModifier.py */; }; - E170C3FC1729620C003DC489 /* mod_pbxproj.py in CopyFiles */ = {isa = PBXBuildFile; fileRef = E164FE131720F40400263CE3 /* mod_pbxproj.py */; }; - E170C3FD1729620F003DC489 /* parser.j in CopyFiles */ = {isa = PBXBuildFile; fileRef = E164FE171720F44B00263CE3 /* parser.j */; }; - E170C40317298833003DC489 /* icon-active@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E170C3FE17298833003DC489 /* icon-active@2x.png */; }; - E170C40417298833003DC489 /* icon-error.png in Resources */ = {isa = PBXBuildFile; fileRef = E170C3FF17298833003DC489 /* icon-error.png */; }; - E170C40517298833003DC489 /* icon-error@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E170C40017298833003DC489 /* icon-error@2x.png */; }; - E170C40617298833003DC489 /* icon-inactive@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E170C40117298833003DC489 /* icon-inactive@2x.png */; }; - E170C40717298833003DC489 /* icon-working@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E170C40217298833003DC489 /* icon-working@2x.png */; }; - E171D25F173C168C00210893 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E171D25E173C168C00210893 /* Foundation.framework */; }; - E171D262173C168C00210893 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E171D261173C168C00210893 /* main.m */; }; - E171D26A173C1ADD00210893 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E164FE1D1720F50100263CE3 /* CoreServices.framework */; }; - E171D26C173C1C8300210893 /* xcc in CopyFiles */ = {isa = PBXBuildFile; fileRef = E171D25D173C168C00210893 /* xcc */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - E17A822D172700B90095CD83 /* XcodeCapp.iconset in Resources */ = {isa = PBXBuildFile; fileRef = E17A822C172700B90095CD83 /* XcodeCapp.iconset */; }; - E17B55411732F57700809FFB /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E17B55401732F57700809FFB /* Quartz.framework */; }; - E1A5594A172C5EE20088FB61 /* FindSourceFilesOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = E1A55949172C5EE20088FB61 /* FindSourceFilesOperation.m */; }; - E1A5594D172CA8D40088FB61 /* ProcessSourceOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = E1A5594C172CA8D40088FB61 /* ProcessSourceOperation.m */; }; - E1E90C411735D846005C6D5B /* DDLogLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C391735D846005C6D5B /* DDLogLevel.m */; }; - E1E90C421735D846005C6D5B /* Notifications.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C3C1735D846005C6D5B /* Notifications.m */; }; - E1E90C431735D846005C6D5B /* UserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C3F1735D846005C6D5B /* UserDefaults.m */; }; - E1E90C4B1735D8A1005C6D5B /* DDASLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C461735D8A1005C6D5B /* DDASLLogger.m */; }; - E1E90C4C1735D8A1005C6D5B /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C481735D8A1005C6D5B /* DDLog.m */; }; - E1E90C4D1735D8A1005C6D5B /* DDTTYLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C4A1735D8A1005C6D5B /* DDTTYLogger.m */; }; - E1E90C62173B42D0005C6D5B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = E1E90C60173B42D0005C6D5B /* MainMenu.xib */; }; - E1E90C67173B44CC005C6D5B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E1E90C65173B44CC005C6D5B /* InfoPlist.strings */; }; - E1ED6B71173414E100641628 /* icon_128x128.png in Resources */ = {isa = PBXBuildFile; fileRef = E1ED6B6F173414E100641628 /* icon_128x128.png */; }; - E1ED6B72173414E100641628 /* icon_128x128@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E1ED6B70173414E100641628 /* icon_128x128@2x.png */; }; + 021B94651B20CECA00F12DDA /* XCCOperationsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 021B94641B20CECA00F12DDA /* XCCOperationsViewController.m */; }; + 021B94671B20D1F800F12DDA /* OperationsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 021B94661B20D1F800F12DDA /* OperationsView.xib */; }; + 021B94691B20D6FC00F12DDA /* ErrorsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 021B94681B20D6FC00F12DDA /* ErrorsView.xib */; }; + 021B946C1B20D71200F12DDA /* XCCErrorsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 021B946B1B20D71200F12DDA /* XCCErrorsViewController.m */; }; + 021B94701B20E31F00F12DDA /* XCCSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 021B946E1B20E31F00F12DDA /* XCCSettingsViewController.m */; }; + 021B94711B20E31F00F12DDA /* SettingsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 021B946F1B20E31F00F12DDA /* SettingsView.xib */; }; + 021B94751B21112500F12DDA /* XCCWelcomeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 021B94741B21112500F12DDA /* XCCWelcomeView.m */; }; + 0255B8401B1F71FB000CA4BC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0255B83F1B1F71FB000CA4BC /* AppDelegate.m */; }; + 0257A65B1B3A2B0000015C1F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6841F2471AF98CE600CFE60E /* MainMenu.xib */; }; + 0258003C1B1E1C470000EB7D /* NSMutableArray+moveIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = 0258003B1B1E1C470000EB7D /* NSMutableArray+moveIndexes.m */; }; + 025800451B1E3F010000EB7D /* XCCAbstractOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 025800441B1E3F010000EB7D /* XCCAbstractOperation.m */; }; + 0258004B1B1E67090000EB7D /* supawhich in Resources */ = {isa = PBXBuildFile; fileRef = 0258004A1B1E67090000EB7D /* supawhich */; }; + 027539111B227D7500F6D824 /* YRKSpinningProgressIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 027539101B227D7500F6D824 /* YRKSpinningProgressIndicator.m */; }; + 680621191B015BF400CB24CD /* XCCCappuccinoProjectControllerDataView.m in Sources */ = {isa = PBXBuildFile; fileRef = 680621181B015BF400CB24CD /* XCCCappuccinoProjectControllerDataView.m */; }; + 6815BBEB1AFC24430030D8BB /* XcodeProjectCloser.m in Sources */ = {isa = PBXBuildFile; fileRef = 6815BBEA1AFC24430030D8BB /* XcodeProjectCloser.m */; }; + 681ADE8F1B0D032C00FC8E08 /* XCCPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 681ADE8E1B0D032C00FC8E08 /* XCCPath.m */; }; + 6824CDDA1B0D5AA700F73447 /* XCCOperationDataView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6824CDD91B0D5AA700F73447 /* XCCOperationDataView.m */; }; + 6824CDDE1B0DA34500F73447 /* XCCMainController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6824CDDD1B0DA34500F73447 /* XCCMainController.m */; }; + 6824CDEA1B0E9CDB00F73447 /* XCCOperationErrorDataView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6824CDE91B0E9CDB00F73447 /* XCCOperationErrorDataView.m */; }; + 6824CDF01B0E9F1400F73447 /* XCCOperationError.m in Sources */ = {isa = PBXBuildFile; fileRef = 6824CDEF1B0E9F1400F73447 /* XCCOperationError.m */; }; + 6841F2441AF98CE600CFE60E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2431AF98CE600CFE60E /* main.m */; }; + 6841F2461AF98CE600CFE60E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6841F2451AF98CE600CFE60E /* Images.xcassets */; }; + 6841F2651AF98DCB00CFE60E /* DDASLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2601AF98DCB00CFE60E /* DDASLLogger.m */; }; + 6841F2661AF98DCB00CFE60E /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2621AF98DCB00CFE60E /* DDLog.m */; }; + 6841F2671AF98DCB00CFE60E /* DDTTYLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2641AF98DCB00CFE60E /* DDTTYLogger.m */; }; + 6841F26C1AF98DDD00CFE60E /* mod_pbxproj.py in Resources */ = {isa = PBXBuildFile; fileRef = 6841F2691AF98DDD00CFE60E /* mod_pbxproj.py */; }; + 6841F26E1AF98DDD00CFE60E /* pbxprojModifier.py in Resources */ = {isa = PBXBuildFile; fileRef = 6841F26B1AF98DDD00CFE60E /* pbxprojModifier.py */; }; + 6841F2781AF98FA300CFE60E /* DDLogLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2771AF98FA300CFE60E /* DDLogLevel.m */; }; + 6841F27C1AF990C300CFE60E /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 6841F27A1AF990C300CFE60E /* Debug.xcconfig */; }; + 6841F27D1AF990C300CFE60E /* Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 6841F27B1AF990C300CFE60E /* Release.xcconfig */; }; + 6841F2A51AF9932300CFE60E /* project.pbxproj in Resources */ = {isa = PBXBuildFile; fileRef = 6841F28A1AF9932300CFE60E /* project.pbxproj */; }; + 6841F2B71AFA83D500CFE60E /* XCCUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2B61AFA83D500CFE60E /* XCCUserDefaults.m */; }; + 6841F2BF1AFA965300CFE60E /* XCCTaskLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2BE1AFA965300CFE60E /* XCCTaskLauncher.m */; }; + 6841F2C41AFABD7200CFE60E /* XCCCappuccinoProject.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2C31AFABD7200CFE60E /* XCCCappuccinoProject.m */; }; + 6841F2CA1AFADEBC00CFE60E /* XCCSourcesFinderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2C71AFADEBC00CFE60E /* XCCSourcesFinderOperation.m */; }; + 6841F2CB1AFADEBC00CFE60E /* XCCSourceProcessingOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 6841F2C91AFADEBC00CFE60E /* XCCSourceProcessingOperation.m */; }; + 6863FBA31AFD55A900040C8E /* XCCFSEventLogUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 6863FBA21AFD55A900040C8E /* XCCFSEventLogUtils.m */; }; + 686ACD311B16397F0089EB03 /* XCCCappuccinoProjectController.m in Sources */ = {isa = PBXBuildFile; fileRef = 686ACD301B16397F0089EB03 /* XCCCappuccinoProjectController.m */; }; + 686C69711B0FAE620095BB3C /* XCCOperationErrorHeaderDataView.m in Sources */ = {isa = PBXBuildFile; fileRef = 686C69701B0FAE620095BB3C /* XCCOperationErrorHeaderDataView.m */; }; + 68B6BF321B1E2546003B265B /* XCCPPXOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B6BF311B1E2546003B265B /* XCCPPXOperation.m */; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - E171D26D173C405C00210893 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E164FDC71720E77100263CE3 /* Project object */; - proxyType = 1; - remoteGlobalIDString = E171D25C173C168C00210893; - remoteInfo = xcc; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - E164FE201720F54800263CE3 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - E164FE211720F55600263CE3 /* Growl.framework in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E170C3F9172961E6003DC489 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 12; - files = ( - E170C3FB17296205003DC489 /* pbxprojModifier.py in CopyFiles */, - E170C3FC1729620C003DC489 /* mod_pbxproj.py in CopyFiles */, - E170C3FD1729620F003DC489 /* parser.j in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E171D25B173C168C00210893 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - E171D26B173C1C6900210893 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 6; - files = ( - E171D26C173C1C8300210893 /* xcc in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ - 68A43033191BF044008A68A7 /* help.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = help.pdf; path = Resources/help.pdf; sourceTree = ""; }; - E14015401740248C006C2792 /* XcodeProjectCloser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XcodeProjectCloser.h; sourceTree = ""; }; - E14015411740248C006C2792 /* XcodeProjectCloser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XcodeProjectCloser.m; sourceTree = ""; }; - E164FDCF1720E77100263CE3 /* XcodeCapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XcodeCapp.app; sourceTree = BUILT_PRODUCTS_DIR; }; - E164FDD21720E77100263CE3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; - E164FDD51720E77100263CE3 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; - E164FDD61720E77100263CE3 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; - E164FDD71720E77100263CE3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - E164FDDE1720E77100263CE3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - E164FDE01720E77100263CE3 /* XcodeCapp-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XcodeCapp-Prefix.pch"; sourceTree = ""; }; - E164FDEF1720E7FA00263CE3 /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - E164FDF01720E7FA00263CE3 /* Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - E164FDF41720EBC100263CE3 /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AppController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - E164FDF61720EBD600263CE3 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = XcodeCapp/Growl.framework; sourceTree = SOURCE_ROOT; }; - E164FDFB1720EC5B00263CE3 /* XcodeCapp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = XcodeCapp.m; sourceTree = ""; usesTabs = 0; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - E164FE131720F40400263CE3 /* mod_pbxproj.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = mod_pbxproj.py; sourceTree = ""; }; - E164FE141720F40400263CE3 /* pbxprojModifier.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = pbxprojModifier.py; sourceTree = ""; }; - E164FE171720F44B00263CE3 /* parser.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = parser.j; sourceTree = ""; }; - E164FE191720F49A00263CE3 /* Growl Registration Ticket.growlRegDict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "Growl Registration Ticket.growlRegDict"; sourceTree = ""; }; - E164FE1D1720F50100263CE3 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; - E164FE2A172188F300263CE3 /* project.pbxproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.pbxproject; lineEnding = 0; name = project.pbxproj; path = Resources/project.pbxproj; sourceTree = ""; }; - E164FE2C1721A34900263CE3 /* icon-active.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-active.png"; path = "Resources/icon-active.png"; sourceTree = ""; }; - E164FE2D1721A34900263CE3 /* icon-inactive.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-inactive.png"; path = "Resources/icon-inactive.png"; sourceTree = ""; }; - E164FE2E1721A34900263CE3 /* icon-working.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-working.png"; path = "Resources/icon-working.png"; sourceTree = ""; }; - E170C3FE17298833003DC489 /* icon-active@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-active@2x.png"; path = "Resources/icon-active@2x.png"; sourceTree = ""; }; - E170C3FF17298833003DC489 /* icon-error.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-error.png"; path = "Resources/icon-error.png"; sourceTree = ""; }; - E170C40017298833003DC489 /* icon-error@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-error@2x.png"; path = "Resources/icon-error@2x.png"; sourceTree = ""; }; - E170C40117298833003DC489 /* icon-inactive@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-inactive@2x.png"; path = "Resources/icon-inactive@2x.png"; sourceTree = ""; }; - E170C40217298833003DC489 /* icon-working@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-working@2x.png"; path = "Resources/icon-working@2x.png"; sourceTree = ""; }; - E171D25D173C168C00210893 /* xcc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xcc; sourceTree = BUILT_PRODUCTS_DIR; }; - E171D25E173C168C00210893 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - E171D261173C168C00210893 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - E171D264173C168C00210893 /* xcc-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "xcc-Prefix.pch"; sourceTree = ""; }; - E17A822C172700B90095CD83 /* XcodeCapp.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = XcodeCapp.iconset; path = Resources/XcodeCapp.iconset; sourceTree = ""; }; - E17B55401732F57700809FFB /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; - E1A55949172C5EE20088FB61 /* FindSourceFilesOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FindSourceFilesOperation.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - E1A5594C172CA8D40088FB61 /* ProcessSourceOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ProcessSourceOperation.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - E1E90C371735D82B005C6D5B /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; - E1E90C381735D846005C6D5B /* DDLogLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLogLevel.h; sourceTree = ""; }; - E1E90C391735D846005C6D5B /* DDLogLevel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDLogLevel.m; sourceTree = ""; }; - E1E90C3A1735D846005C6D5B /* FindSourceFilesOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FindSourceFilesOperation.h; sourceTree = ""; }; - E1E90C3B1735D846005C6D5B /* Notifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Notifications.h; sourceTree = ""; }; - E1E90C3C1735D846005C6D5B /* Notifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Notifications.m; sourceTree = ""; }; - E1E90C3D1735D846005C6D5B /* ProcessSourceOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessSourceOperation.h; sourceTree = ""; }; - E1E90C3E1735D846005C6D5B /* UserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserDefaults.h; sourceTree = ""; }; - E1E90C3F1735D846005C6D5B /* UserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UserDefaults.m; sourceTree = ""; }; - E1E90C401735D846005C6D5B /* XcodeCapp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XcodeCapp.h; sourceTree = ""; }; - E1E90C451735D8A1005C6D5B /* DDASLLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDASLLogger.h; sourceTree = ""; }; - E1E90C461735D8A1005C6D5B /* DDASLLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDASLLogger.m; sourceTree = ""; }; - E1E90C471735D8A1005C6D5B /* DDLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLog.h; sourceTree = ""; }; - E1E90C481735D8A1005C6D5B /* DDLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDLog.m; sourceTree = ""; }; - E1E90C491735D8A1005C6D5B /* DDTTYLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTTYLogger.h; sourceTree = ""; }; - E1E90C4A1735D8A1005C6D5B /* DDTTYLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTTYLogger.m; sourceTree = ""; }; - E1E90C61173B42D0005C6D5B /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; - E1E90C66173B44CC005C6D5B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - E1E90C68173B48DA005C6D5B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E1ED6B6F173414E100641628 /* icon_128x128.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_128x128.png; path = Resources/icon_128x128.png; sourceTree = ""; }; - E1ED6B70173414E100641628 /* icon_128x128@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_128x128@2x.png"; path = "Resources/icon_128x128@2x.png"; sourceTree = ""; }; + 021B94631B20CECA00F12DDA /* XCCOperationsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCOperationsViewController.h; sourceTree = ""; }; + 021B94641B20CECA00F12DDA /* XCCOperationsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCOperationsViewController.m; sourceTree = ""; }; + 021B94661B20D1F800F12DDA /* OperationsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OperationsView.xib; sourceTree = ""; }; + 021B94681B20D6FC00F12DDA /* ErrorsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ErrorsView.xib; sourceTree = ""; }; + 021B946A1B20D71200F12DDA /* XCCErrorsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCErrorsViewController.h; sourceTree = ""; }; + 021B946B1B20D71200F12DDA /* XCCErrorsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCErrorsViewController.m; sourceTree = ""; }; + 021B946D1B20E31F00F12DDA /* XCCSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCSettingsViewController.h; sourceTree = ""; }; + 021B946E1B20E31F00F12DDA /* XCCSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCSettingsViewController.m; sourceTree = ""; }; + 021B946F1B20E31F00F12DDA /* SettingsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsView.xib; sourceTree = ""; }; + 021B94731B21112500F12DDA /* XCCWelcomeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCWelcomeView.h; sourceTree = ""; }; + 021B94741B21112500F12DDA /* XCCWelcomeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCWelcomeView.m; sourceTree = ""; }; + 0255B83F1B1F71FB000CA4BC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 0258003A1B1E1C470000EB7D /* NSMutableArray+moveIndexes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+moveIndexes.h"; sourceTree = ""; }; + 0258003B1B1E1C470000EB7D /* NSMutableArray+moveIndexes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+moveIndexes.m"; sourceTree = ""; }; + 025800431B1E3F010000EB7D /* XCCAbstractOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCAbstractOperation.h; sourceTree = ""; }; + 025800441B1E3F010000EB7D /* XCCAbstractOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCAbstractOperation.m; sourceTree = ""; }; + 0258004A1B1E67090000EB7D /* supawhich */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = supawhich; sourceTree = ""; }; + 0275390F1B227D7500F6D824 /* YRKSpinningProgressIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YRKSpinningProgressIndicator.h; sourceTree = ""; }; + 027539101B227D7500F6D824 /* YRKSpinningProgressIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YRKSpinningProgressIndicator.m; sourceTree = ""; }; + 680621171B015BF400CB24CD /* XCCCappuccinoProjectControllerDataView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCCappuccinoProjectControllerDataView.h; sourceTree = ""; }; + 680621181B015BF400CB24CD /* XCCCappuccinoProjectControllerDataView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCCappuccinoProjectControllerDataView.m; sourceTree = ""; }; + 6815BBE61AFBE6B00030D8BB /* XCCCappuccinoProjectController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCCappuccinoProjectController.h; sourceTree = ""; }; + 6815BBE91AFC24430030D8BB /* XcodeProjectCloser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XcodeProjectCloser.h; sourceTree = ""; }; + 6815BBEA1AFC24430030D8BB /* XcodeProjectCloser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XcodeProjectCloser.m; sourceTree = ""; }; + 681ADE8D1B0D032C00FC8E08 /* XCCPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCPath.h; sourceTree = ""; }; + 681ADE8E1B0D032C00FC8E08 /* XCCPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCPath.m; sourceTree = ""; }; + 6824CDD81B0D5AA700F73447 /* XCCOperationDataView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCOperationDataView.h; sourceTree = ""; }; + 6824CDD91B0D5AA700F73447 /* XCCOperationDataView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCOperationDataView.m; sourceTree = ""; }; + 6824CDDC1B0DA34500F73447 /* XCCMainController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCMainController.h; sourceTree = ""; }; + 6824CDDD1B0DA34500F73447 /* XCCMainController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCMainController.m; sourceTree = ""; }; + 6824CDE81B0E9CDB00F73447 /* XCCOperationErrorDataView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCOperationErrorDataView.h; sourceTree = ""; }; + 6824CDE91B0E9CDB00F73447 /* XCCOperationErrorDataView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCOperationErrorDataView.m; sourceTree = ""; }; + 6824CDEE1B0E9F1400F73447 /* XCCOperationError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XCCOperationError.h; path = XcodeCapp/XCCOperationError.h; sourceTree = ""; }; + 6824CDEF1B0E9F1400F73447 /* XCCOperationError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XCCOperationError.m; path = XcodeCapp/XCCOperationError.m; sourceTree = ""; }; + 6841F23B1AF98CE600CFE60E /* XcodeCapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XcodeCapp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 6841F23F1AF98CE600CFE60E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 6841F2401AF98CE600CFE60E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 6841F2431AF98CE600CFE60E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 6841F2451AF98CE600CFE60E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ../Images.xcassets; sourceTree = ""; }; + 6841F25F1AF98DCB00CFE60E /* DDASLLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDASLLogger.h; sourceTree = ""; }; + 6841F2601AF98DCB00CFE60E /* DDASLLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDASLLogger.m; sourceTree = ""; }; + 6841F2611AF98DCB00CFE60E /* DDLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLog.h; sourceTree = ""; }; + 6841F2621AF98DCB00CFE60E /* DDLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDLog.m; sourceTree = ""; }; + 6841F2631AF98DCB00CFE60E /* DDTTYLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTTYLogger.h; sourceTree = ""; }; + 6841F2641AF98DCB00CFE60E /* DDTTYLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTTYLogger.m; sourceTree = ""; }; + 6841F2691AF98DDD00CFE60E /* mod_pbxproj.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = mod_pbxproj.py; sourceTree = ""; }; + 6841F26B1AF98DDD00CFE60E /* pbxprojModifier.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = pbxprojModifier.py; sourceTree = ""; }; + 6841F2741AF98F6F00CFE60E /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; + 6841F2761AF98FA300CFE60E /* DDLogLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLogLevel.h; sourceTree = ""; }; + 6841F2771AF98FA300CFE60E /* DDLogLevel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDLogLevel.m; sourceTree = ""; }; + 6841F2791AF9902B00CFE60E /* XcodeCapp-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XcodeCapp-Prefix.pch"; sourceTree = ""; }; + 6841F27A1AF990C300CFE60E /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 6841F27B1AF990C300CFE60E /* Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 6841F28A1AF9932300CFE60E /* project.pbxproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.pbxproject; path = project.pbxproj; sourceTree = ""; }; + 6841F2B61AFA83D500CFE60E /* XCCUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCUserDefaults.m; sourceTree = ""; }; + 6841F2B81AFA83E900CFE60E /* XCCUserDefaults.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XCCUserDefaults.h; sourceTree = ""; }; + 6841F2BD1AFA965300CFE60E /* XCCTaskLauncher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCTaskLauncher.h; sourceTree = ""; }; + 6841F2BE1AFA965300CFE60E /* XCCTaskLauncher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCTaskLauncher.m; sourceTree = ""; }; + 6841F2C21AFABD7200CFE60E /* XCCCappuccinoProject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XCCCappuccinoProject.h; path = XcodeCapp/XCCCappuccinoProject.h; sourceTree = ""; }; + 6841F2C31AFABD7200CFE60E /* XCCCappuccinoProject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XCCCappuccinoProject.m; path = XcodeCapp/XCCCappuccinoProject.m; sourceTree = ""; }; + 6841F2C61AFADEBC00CFE60E /* XCCSourcesFinderOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCSourcesFinderOperation.h; sourceTree = ""; }; + 6841F2C71AFADEBC00CFE60E /* XCCSourcesFinderOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCSourcesFinderOperation.m; sourceTree = ""; }; + 6841F2C81AFADEBC00CFE60E /* XCCSourceProcessingOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCSourceProcessingOperation.h; sourceTree = ""; }; + 6841F2C91AFADEBC00CFE60E /* XCCSourceProcessingOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCSourceProcessingOperation.m; sourceTree = ""; }; + 6863FBA11AFD55A900040C8E /* XCCFSEventLogUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCFSEventLogUtils.h; sourceTree = ""; }; + 6863FBA21AFD55A900040C8E /* XCCFSEventLogUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCFSEventLogUtils.m; sourceTree = ""; }; + 686ACD301B16397F0089EB03 /* XCCCappuccinoProjectController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCCappuccinoProjectController.m; sourceTree = ""; }; + 686ACD331B1691AA0089EB03 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 686C696F1B0FAE620095BB3C /* XCCOperationErrorHeaderDataView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCOperationErrorHeaderDataView.h; sourceTree = ""; }; + 686C69701B0FAE620095BB3C /* XCCOperationErrorHeaderDataView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCOperationErrorHeaderDataView.m; sourceTree = ""; }; + 68B6BF301B1E2546003B265B /* XCCPPXOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCCPPXOperation.h; sourceTree = ""; }; + 68B6BF311B1E2546003B265B /* XCCPPXOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCCPPXOperation.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - E164FDCC1720E77100263CE3 /* Frameworks */ = { + 6841F2381AF98CE600CFE60E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E164FDD31720E77100263CE3 /* Cocoa.framework in Frameworks */, - E164FE1F1720F51E00263CE3 /* CoreServices.framework in Frameworks */, - E17B55411732F57700809FFB /* Quartz.framework in Frameworks */, - E164FDF71720EBD600263CE3 /* Growl.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E171D25A173C168C00210893 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E171D26A173C1ADD00210893 /* CoreServices.framework in Frameworks */, - E171D25F173C168C00210893 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - E164FDC61720E77100263CE3 = { + 021B94721B20E41B00F12DDA /* XIBs */ = { isa = PBXGroup; children = ( - E164FDD81720E77100263CE3 /* XcodeCapp */, - E171D260173C168C00210893 /* xcc */, - E164FDD11720E77100263CE3 /* Frameworks */, - E164FDD01720E77100263CE3 /* Products */, + 021B946F1B20E31F00F12DDA /* SettingsView.xib */, + 021B94681B20D6FC00F12DDA /* ErrorsView.xib */, + 021B94661B20D1F800F12DDA /* OperationsView.xib */, + 6841F2471AF98CE600CFE60E /* MainMenu.xib */, + ); + name = XIBs; + sourceTree = ""; + }; + 0275390D1B227D5900F6D824 /* Externals */ = { + isa = PBXGroup; + children = ( + 0275390E1B227D6700F6D824 /* YRKSpinningProgressIndicator */, + 6841F25E1AF98DCB00CFE60E /* Lumberjack */, + ); + name = Externals; + sourceTree = ""; + }; + 0275390E1B227D6700F6D824 /* YRKSpinningProgressIndicator */ = { + isa = PBXGroup; + children = ( + 0275390F1B227D7500F6D824 /* YRKSpinningProgressIndicator.h */, + 027539101B227D7500F6D824 /* YRKSpinningProgressIndicator.m */, + ); + name = YRKSpinningProgressIndicator; + sourceTree = ""; + }; + 680621161B015BDB00CB24CD /* Views */ = { + isa = PBXGroup; + children = ( + 680621171B015BF400CB24CD /* XCCCappuccinoProjectControllerDataView.h */, + 680621181B015BF400CB24CD /* XCCCappuccinoProjectControllerDataView.m */, + 6824CDD81B0D5AA700F73447 /* XCCOperationDataView.h */, + 6824CDD91B0D5AA700F73447 /* XCCOperationDataView.m */, + 6824CDE81B0E9CDB00F73447 /* XCCOperationErrorDataView.h */, + 6824CDE91B0E9CDB00F73447 /* XCCOperationErrorDataView.m */, + 686C696F1B0FAE620095BB3C /* XCCOperationErrorHeaderDataView.h */, + 686C69701B0FAE620095BB3C /* XCCOperationErrorHeaderDataView.m */, + 021B94731B21112500F12DDA /* XCCWelcomeView.h */, + 021B94741B21112500F12DDA /* XCCWelcomeView.m */, + ); + name = Views; + sourceTree = ""; + }; + 6824CDDB1B0D976400F73447 /* Controllers */ = { + isa = PBXGroup; + children = ( + 6824CDDC1B0DA34500F73447 /* XCCMainController.h */, + 6824CDDD1B0DA34500F73447 /* XCCMainController.m */, + 6815BBE61AFBE6B00030D8BB /* XCCCappuccinoProjectController.h */, + 686ACD301B16397F0089EB03 /* XCCCappuccinoProjectController.m */, + 021B94631B20CECA00F12DDA /* XCCOperationsViewController.h */, + 021B94641B20CECA00F12DDA /* XCCOperationsViewController.m */, + 021B946A1B20D71200F12DDA /* XCCErrorsViewController.h */, + 021B946B1B20D71200F12DDA /* XCCErrorsViewController.m */, + 021B946D1B20E31F00F12DDA /* XCCSettingsViewController.h */, + 021B946E1B20E31F00F12DDA /* XCCSettingsViewController.m */, + ); + name = Controllers; + sourceTree = ""; + }; + 6841F2321AF98CE600CFE60E = { + isa = PBXGroup; + children = ( + 6841F2741AF98F6F00CFE60E /* CoreServices.framework */, + 6841F23D1AF98CE600CFE60E /* XcodeCapp */, + 6841F23C1AF98CE600CFE60E /* Products */, ); sourceTree = ""; }; - E164FDD01720E77100263CE3 /* Products */ = { + 6841F23C1AF98CE600CFE60E /* Products */ = { isa = PBXGroup; children = ( - E164FDCF1720E77100263CE3 /* XcodeCapp.app */, - E171D25D173C168C00210893 /* xcc */, + 6841F23B1AF98CE600CFE60E /* XcodeCapp.app */, ); name = Products; sourceTree = ""; }; - E164FDD11720E77100263CE3 /* Frameworks */ = { + 6841F23D1AF98CE600CFE60E /* XcodeCapp */ = { isa = PBXGroup; children = ( - E164FDD21720E77100263CE3 /* Cocoa.framework */, - E164FE1D1720F50100263CE3 /* CoreServices.framework */, - E164FDF61720EBD600263CE3 /* Growl.framework */, - E171D25E173C168C00210893 /* Foundation.framework */, - E164FDD41720E77100263CE3 /* Other Frameworks */, - ); - name = Frameworks; - sourceTree = ""; - }; - E164FDD41720E77100263CE3 /* Other Frameworks */ = { - isa = PBXGroup; - children = ( - E164FDD51720E77100263CE3 /* AppKit.framework */, - E164FDD61720E77100263CE3 /* CoreData.framework */, - E164FDD71720E77100263CE3 /* Foundation.framework */, - E17B55401732F57700809FFB /* Quartz.framework */, - ); - name = "Other Frameworks"; - sourceTree = ""; - }; - E164FDD81720E77100263CE3 /* XcodeCapp */ = { - isa = PBXGroup; - children = ( - E1E90C60173B42D0005C6D5B /* MainMenu.xib */, - E164FDF41720EBC100263CE3 /* AppController.m */, - E1E90C371735D82B005C6D5B /* AppController.h */, - E164FDFB1720EC5B00263CE3 /* XcodeCapp.m */, - E1E90C401735D846005C6D5B /* XcodeCapp.h */, - E14015411740248C006C2792 /* XcodeProjectCloser.m */, - E14015401740248C006C2792 /* XcodeProjectCloser.h */, - E1E90C3C1735D846005C6D5B /* Notifications.m */, - E1E90C3B1735D846005C6D5B /* Notifications.h */, - E1E90C3F1735D846005C6D5B /* UserDefaults.m */, - E1E90C3E1735D846005C6D5B /* UserDefaults.h */, - E1E90C391735D846005C6D5B /* DDLogLevel.m */, - E1E90C381735D846005C6D5B /* DDLogLevel.h */, - E1A55947172C5EA80088FB61 /* Operations */, - E1E90C441735D8A1005C6D5B /* Lumberjack */, - E164FE121720F3E100263CE3 /* Scripts */, - E164FE071720F25400263CE3 /* Resources */, - E164FDD91720E77100263CE3 /* Supporting Files */, + 6841F2401AF98CE600CFE60E /* AppDelegate.h */, + 0255B83F1B1F71FB000CA4BC /* AppDelegate.m */, + 6824CDDB1B0D976400F73447 /* Controllers */, + 68F3B95A1B0CFBCF00A7EF70 /* Models */, + 680621161B015BDB00CB24CD /* Views */, + 6841F2C51AFADE7D00CFE60E /* Operations */, + 6841F2C01AFABD0900CFE60E /* Utils */, + 6841F2681AF98DDD00CFE60E /* Scripts */, + 6841F23E1AF98CE600CFE60E /* Supporting Files */, + 021B94721B20E41B00F12DDA /* XIBs */, + 6841F27E1AF9932300CFE60E /* Resources */, + 0275390D1B227D5900F6D824 /* Externals */, ); path = XcodeCapp; sourceTree = ""; }; - E164FDD91720E77100263CE3 /* Supporting Files */ = { + 6841F23E1AF98CE600CFE60E /* Supporting Files */ = { isa = PBXGroup; children = ( - E1E90C68173B48DA005C6D5B /* Info.plist */, - E1E90C65173B44CC005C6D5B /* InfoPlist.strings */, - E164FDDE1720E77100263CE3 /* main.m */, - E164FDE01720E77100263CE3 /* XcodeCapp-Prefix.pch */, - E164FDEF1720E7FA00263CE3 /* Debug.xcconfig */, - E164FDF01720E7FA00263CE3 /* Release.xcconfig */, + 6841F27A1AF990C300CFE60E /* Debug.xcconfig */, + 6841F27B1AF990C300CFE60E /* Release.xcconfig */, + 6841F23F1AF98CE600CFE60E /* Info.plist */, + 6841F2791AF9902B00CFE60E /* XcodeCapp-Prefix.pch */, + 6841F2431AF98CE600CFE60E /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; - E164FE071720F25400263CE3 /* Resources */ = { + 6841F25E1AF98DCB00CFE60E /* Lumberjack */ = { isa = PBXGroup; children = ( - 68A43033191BF044008A68A7 /* help.pdf */, - E1ED6B6F173414E100641628 /* icon_128x128.png */, - E1ED6B70173414E100641628 /* icon_128x128@2x.png */, - E164FE2D1721A34900263CE3 /* icon-inactive.png */, - E170C40117298833003DC489 /* icon-inactive@2x.png */, - E164FE2E1721A34900263CE3 /* icon-working.png */, - E170C40217298833003DC489 /* icon-working@2x.png */, - E164FE2C1721A34900263CE3 /* icon-active.png */, - E170C3FE17298833003DC489 /* icon-active@2x.png */, - E170C3FF17298833003DC489 /* icon-error.png */, - E170C40017298833003DC489 /* icon-error@2x.png */, - E17A822C172700B90095CD83 /* XcodeCapp.iconset */, - E164FE2A172188F300263CE3 /* project.pbxproj */, - E164FE191720F49A00263CE3 /* Growl Registration Ticket.growlRegDict */, + 6841F25F1AF98DCB00CFE60E /* DDASLLogger.h */, + 6841F2601AF98DCB00CFE60E /* DDASLLogger.m */, + 6841F2611AF98DCB00CFE60E /* DDLog.h */, + 6841F2621AF98DCB00CFE60E /* DDLog.m */, + 6841F2631AF98DCB00CFE60E /* DDTTYLogger.h */, + 6841F2641AF98DCB00CFE60E /* DDTTYLogger.m */, ); - name = Resources; + path = Lumberjack; sourceTree = ""; }; - E164FE121720F3E100263CE3 /* Scripts */ = { + 6841F2681AF98DDD00CFE60E /* Scripts */ = { isa = PBXGroup; children = ( - E164FE171720F44B00263CE3 /* parser.j */, - E164FE141720F40400263CE3 /* pbxprojModifier.py */, - E164FE131720F40400263CE3 /* mod_pbxproj.py */, + 0258004A1B1E67090000EB7D /* supawhich */, + 6841F2691AF98DDD00CFE60E /* mod_pbxproj.py */, + 6841F26B1AF98DDD00CFE60E /* pbxprojModifier.py */, ); path = Scripts; sourceTree = ""; }; - E171D260173C168C00210893 /* xcc */ = { + 6841F27E1AF9932300CFE60E /* Resources */ = { isa = PBXGroup; children = ( - E171D261173C168C00210893 /* main.m */, - E171D263173C168C00210893 /* Supporting Files */, + 6841F2451AF98CE600CFE60E /* Images.xcassets */, + 6841F28A1AF9932300CFE60E /* project.pbxproj */, ); - path = xcc; + path = Resources; sourceTree = ""; }; - E171D263173C168C00210893 /* Supporting Files */ = { + 6841F2C01AFABD0900CFE60E /* Utils */ = { isa = PBXGroup; children = ( - E171D264173C168C00210893 /* xcc-Prefix.pch */, + 681ADE8D1B0D032C00FC8E08 /* XCCPath.h */, + 681ADE8E1B0D032C00FC8E08 /* XCCPath.m */, + 6841F2B61AFA83D500CFE60E /* XCCUserDefaults.m */, + 6841F2B81AFA83E900CFE60E /* XCCUserDefaults.h */, + 6841F2BD1AFA965300CFE60E /* XCCTaskLauncher.h */, + 6841F2BE1AFA965300CFE60E /* XCCTaskLauncher.m */, + 6841F2761AF98FA300CFE60E /* DDLogLevel.h */, + 6841F2771AF98FA300CFE60E /* DDLogLevel.m */, + 6815BBE91AFC24430030D8BB /* XcodeProjectCloser.h */, + 6815BBEA1AFC24430030D8BB /* XcodeProjectCloser.m */, + 6863FBA11AFD55A900040C8E /* XCCFSEventLogUtils.h */, + 6863FBA21AFD55A900040C8E /* XCCFSEventLogUtils.m */, + 0258003A1B1E1C470000EB7D /* NSMutableArray+moveIndexes.h */, + 0258003B1B1E1C470000EB7D /* NSMutableArray+moveIndexes.m */, ); - name = "Supporting Files"; + name = Utils; sourceTree = ""; }; - E1A55947172C5EA80088FB61 /* Operations */ = { + 6841F2C51AFADE7D00CFE60E /* Operations */ = { isa = PBXGroup; children = ( - E1A55949172C5EE20088FB61 /* FindSourceFilesOperation.m */, - E1E90C3A1735D846005C6D5B /* FindSourceFilesOperation.h */, - E1A5594C172CA8D40088FB61 /* ProcessSourceOperation.m */, - E1E90C3D1735D846005C6D5B /* ProcessSourceOperation.h */, + 6841F2C61AFADEBC00CFE60E /* XCCSourcesFinderOperation.h */, + 6841F2C71AFADEBC00CFE60E /* XCCSourcesFinderOperation.m */, + 6841F2C81AFADEBC00CFE60E /* XCCSourceProcessingOperation.h */, + 6841F2C91AFADEBC00CFE60E /* XCCSourceProcessingOperation.m */, + 68B6BF301B1E2546003B265B /* XCCPPXOperation.h */, + 68B6BF311B1E2546003B265B /* XCCPPXOperation.m */, + 025800431B1E3F010000EB7D /* XCCAbstractOperation.h */, + 025800441B1E3F010000EB7D /* XCCAbstractOperation.m */, ); name = Operations; sourceTree = ""; }; - E1E90C441735D8A1005C6D5B /* Lumberjack */ = { + 68F3B95A1B0CFBCF00A7EF70 /* Models */ = { isa = PBXGroup; children = ( - E1E90C451735D8A1005C6D5B /* DDASLLogger.h */, - E1E90C461735D8A1005C6D5B /* DDASLLogger.m */, - E1E90C471735D8A1005C6D5B /* DDLog.h */, - E1E90C481735D8A1005C6D5B /* DDLog.m */, - E1E90C491735D8A1005C6D5B /* DDTTYLogger.h */, - E1E90C4A1735D8A1005C6D5B /* DDTTYLogger.m */, + 6841F2C21AFABD7200CFE60E /* XCCCappuccinoProject.h */, + 6841F2C31AFABD7200CFE60E /* XCCCappuccinoProject.m */, + 6824CDEE1B0E9F1400F73447 /* XCCOperationError.h */, + 6824CDEF1B0E9F1400F73447 /* XCCOperationError.m */, ); - path = Lumberjack; + name = Models; + path = ..; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - E164FDCE1720E77100263CE3 /* XcodeCapp */ = { + 6841F23A1AF98CE600CFE60E /* XcodeCapp */ = { isa = PBXNativeTarget; - buildConfigurationList = E164FDEC1720E77100263CE3 /* Build configuration list for PBXNativeTarget "XcodeCapp" */; + buildConfigurationList = 6841F2581AF98CE600CFE60E /* Build configuration list for PBXNativeTarget "XcodeCapp" */; buildPhases = ( - E164FDCB1720E77100263CE3 /* Sources */, - E164FDCC1720E77100263CE3 /* Frameworks */, - E164FDCD1720E77100263CE3 /* Resources */, - E164FE201720F54800263CE3 /* CopyFiles */, - E170C3F9172961E6003DC489 /* CopyFiles */, - E171D26B173C1C6900210893 /* CopyFiles */, + 6841F2371AF98CE600CFE60E /* Sources */, + 6841F2381AF98CE600CFE60E /* Frameworks */, + 6841F2391AF98CE600CFE60E /* Resources */, ); buildRules = ( ); dependencies = ( - E171D26E173C405C00210893 /* PBXTargetDependency */, ); name = XcodeCapp; productName = XcodeCapp; - productReference = E164FDCF1720E77100263CE3 /* XcodeCapp.app */; + productReference = 6841F23B1AF98CE600CFE60E /* XcodeCapp.app */; productType = "com.apple.product-type.application"; }; - E171D25C173C168C00210893 /* xcc */ = { - isa = PBXNativeTarget; - buildConfigurationList = E171D269173C168C00210893 /* Build configuration list for PBXNativeTarget "xcc" */; - buildPhases = ( - E171D259173C168C00210893 /* Sources */, - E171D25A173C168C00210893 /* Frameworks */, - E171D25B173C168C00210893 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = xcc; - productName = xcc; - productReference = E171D25D173C168C00210893 /* xcc */; - productType = "com.apple.product-type.tool"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - E164FDC71720E77100263CE3 /* Project object */ = { + 6841F2331AF98CE600CFE60E /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; - ORGANIZATIONNAME = "Cappuccino Project"; + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = "cappuccino-project"; + TargetAttributes = { + 6841F23A1AF98CE600CFE60E = { + CreatedOnToolsVersion = 6.3.1; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 0; + }; + }; + }; + }; }; - buildConfigurationList = E164FDCA1720E77100263CE3 /* Build configuration list for PBXProject "XcodeCapp" */; + buildConfigurationList = 6841F2361AF98CE600CFE60E /* Build configuration list for PBXProject "XcodeCapp" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); - mainGroup = E164FDC61720E77100263CE3; - productRefGroup = E164FDD01720E77100263CE3 /* Products */; + mainGroup = 6841F2321AF98CE600CFE60E; + productRefGroup = 6841F23C1AF98CE600CFE60E /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - E164FDCE1720E77100263CE3 /* XcodeCapp */, - E171D25C173C168C00210893 /* xcc */, + 6841F23A1AF98CE600CFE60E /* XcodeCapp */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - E164FDCD1720E77100263CE3 /* Resources */ = { + 6841F2391AF98CE600CFE60E /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - E10E4CD717298E5F004AB09E /* project.pbxproj in Resources */, - E164FE181720F44B00263CE3 /* parser.j in Resources */, - E164FE1A1720F49A00263CE3 /* Growl Registration Ticket.growlRegDict in Resources */, - 68A43034191BF044008A68A7 /* help.pdf in Resources */, - E164FE2F1721A34900263CE3 /* icon-active.png in Resources */, - E164FE301721A34900263CE3 /* icon-inactive.png in Resources */, - E164FE311721A34900263CE3 /* icon-working.png in Resources */, - E17A822D172700B90095CD83 /* XcodeCapp.iconset in Resources */, - E170C40317298833003DC489 /* icon-active@2x.png in Resources */, - E170C40417298833003DC489 /* icon-error.png in Resources */, - E170C40517298833003DC489 /* icon-error@2x.png in Resources */, - E170C40617298833003DC489 /* icon-inactive@2x.png in Resources */, - E170C40717298833003DC489 /* icon-working@2x.png in Resources */, - E1ED6B71173414E100641628 /* icon_128x128.png in Resources */, - E1ED6B72173414E100641628 /* icon_128x128@2x.png in Resources */, - E1E90C62173B42D0005C6D5B /* MainMenu.xib in Resources */, - E1E90C67173B44CC005C6D5B /* InfoPlist.strings in Resources */, + 6841F2461AF98CE600CFE60E /* Images.xcassets in Resources */, + 021B94671B20D1F800F12DDA /* OperationsView.xib in Resources */, + 021B94711B20E31F00F12DDA /* SettingsView.xib in Resources */, + 0258004B1B1E67090000EB7D /* supawhich in Resources */, + 6841F27C1AF990C300CFE60E /* Debug.xcconfig in Resources */, + 6841F26E1AF98DDD00CFE60E /* pbxprojModifier.py in Resources */, + 6841F2A51AF9932300CFE60E /* project.pbxproj in Resources */, + 6841F27D1AF990C300CFE60E /* Release.xcconfig in Resources */, + 0257A65B1B3A2B0000015C1F /* MainMenu.xib in Resources */, + 6841F26C1AF98DDD00CFE60E /* mod_pbxproj.py in Resources */, + 021B94691B20D6FC00F12DDA /* ErrorsView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - E164FDCB1720E77100263CE3 /* Sources */ = { + 6841F2371AF98CE600CFE60E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E164FDDF1720E77100263CE3 /* main.m in Sources */, - E164FDF51720EBC100263CE3 /* AppController.m in Sources */, - E164FDFF1720EC5B00263CE3 /* XcodeCapp.m in Sources */, - E1A5594A172C5EE20088FB61 /* FindSourceFilesOperation.m in Sources */, - E1A5594D172CA8D40088FB61 /* ProcessSourceOperation.m in Sources */, - E1E90C411735D846005C6D5B /* DDLogLevel.m in Sources */, - E1E90C421735D846005C6D5B /* Notifications.m in Sources */, - E1E90C431735D846005C6D5B /* UserDefaults.m in Sources */, - E1E90C4B1735D8A1005C6D5B /* DDASLLogger.m in Sources */, - E1E90C4C1735D8A1005C6D5B /* DDLog.m in Sources */, - E1E90C4D1735D8A1005C6D5B /* DDTTYLogger.m in Sources */, - E14015421740248C006C2792 /* XcodeProjectCloser.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E171D259173C168C00210893 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E171D262173C168C00210893 /* main.m in Sources */, - E1401543174025B8006C2792 /* XcodeProjectCloser.m in Sources */, + 6841F2781AF98FA300CFE60E /* DDLogLevel.m in Sources */, + 68B6BF321B1E2546003B265B /* XCCPPXOperation.m in Sources */, + 021B94701B20E31F00F12DDA /* XCCSettingsViewController.m in Sources */, + 0255B8401B1F71FB000CA4BC /* AppDelegate.m in Sources */, + 0258003C1B1E1C470000EB7D /* NSMutableArray+moveIndexes.m in Sources */, + 6841F2BF1AFA965300CFE60E /* XCCTaskLauncher.m in Sources */, + 027539111B227D7500F6D824 /* YRKSpinningProgressIndicator.m in Sources */, + 6841F2C41AFABD7200CFE60E /* XCCCappuccinoProject.m in Sources */, + 6841F2661AF98DCB00CFE60E /* DDLog.m in Sources */, + 686ACD311B16397F0089EB03 /* XCCCappuccinoProjectController.m in Sources */, + 021B946C1B20D71200F12DDA /* XCCErrorsViewController.m in Sources */, + 021B94651B20CECA00F12DDA /* XCCOperationsViewController.m in Sources */, + 6841F2CB1AFADEBC00CFE60E /* XCCSourceProcessingOperation.m in Sources */, + 6815BBEB1AFC24430030D8BB /* XcodeProjectCloser.m in Sources */, + 6824CDDE1B0DA34500F73447 /* XCCMainController.m in Sources */, + 6863FBA31AFD55A900040C8E /* XCCFSEventLogUtils.m in Sources */, + 680621191B015BF400CB24CD /* XCCCappuccinoProjectControllerDataView.m in Sources */, + 025800451B1E3F010000EB7D /* XCCAbstractOperation.m in Sources */, + 686C69711B0FAE620095BB3C /* XCCOperationErrorHeaderDataView.m in Sources */, + 6824CDF01B0E9F1400F73447 /* XCCOperationError.m in Sources */, + 021B94751B21112500F12DDA /* XCCWelcomeView.m in Sources */, + 6841F2671AF98DCB00CFE60E /* DDTTYLogger.m in Sources */, + 6841F2441AF98CE600CFE60E /* main.m in Sources */, + 6824CDDA1B0D5AA700F73447 /* XCCOperationDataView.m in Sources */, + 6841F2CA1AFADEBC00CFE60E /* XCCSourcesFinderOperation.m in Sources */, + 681ADE8F1B0D032C00FC8E08 /* XCCPath.m in Sources */, + 6841F2651AF98DCB00CFE60E /* DDASLLogger.m in Sources */, + 6841F2B71AFA83D500CFE60E /* XCCUserDefaults.m in Sources */, + 6824CDEA1B0E9CDB00F73447 /* XCCOperationErrorDataView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - E171D26E173C405C00210893 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = E171D25C173C168C00210893 /* xcc */; - targetProxy = E171D26D173C405C00210893 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin PBXVariantGroup section */ - E1E90C60173B42D0005C6D5B /* MainMenu.xib */ = { + 6841F2471AF98CE600CFE60E /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( - E1E90C61173B42D0005C6D5B /* en */, + 686ACD331B1691AA0089EB03 /* Base */, ); name = MainMenu.xib; sourceTree = ""; }; - E1E90C65173B44CC005C6D5B /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - E1E90C66173B44CC005C6D5B /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - E164FDEA1720E77100263CE3 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E164FDEF1720E7FA00263CE3 /* Debug.xcconfig */; - buildSettings = { - DSTROOT = /; - ONLY_ACTIVE_ARCH = YES; - }; - name = Debug; - }; - E164FDEB1720E77100263CE3 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E164FDF01720E7FA00263CE3 /* Release.xcconfig */; - buildSettings = { - COPY_PHASE_STRIP = NO; - DEPLOYMENT_LOCATION = YES; - DSTROOT = /; - }; - name = Release; - }; - E164FDED1720E77100263CE3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/XcodeCapp\"", - ); - MACOSX_DEPLOYMENT_TARGET = 10.6.8; - }; - name = Debug; - }; - E164FDEE1720E77100263CE3 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/XcodeCapp\"", - ); - MACOSX_DEPLOYMENT_TARGET = 10.6.8; - }; - name = Release; - }; - E171D267173C168C00210893 /* Debug */ = { + 6841F2561AF98CE600CFE60E /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6841F27A1AF990C300CFE60E /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "xcc/xcc-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 10.7; + MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; name = Debug; }; - E171D268173C168C00210893 /* Release */ = { + 6841F2571AF98CE600CFE60E /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6841F27B1AF990C300CFE60E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEPLOYMENT_LOCATION = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "xcc/xcc-Prefix.pch"; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.8; - PRODUCT_NAME = "$(TARGET_NAME)"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; }; name = Release; }; + 6841F2591AF98CE600CFE60E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = XcodeCapp/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 6841F25A1AF98CE600CFE60E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = XcodeCapp/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - E164FDCA1720E77100263CE3 /* Build configuration list for PBXProject "XcodeCapp" */ = { + 6841F2361AF98CE600CFE60E /* Build configuration list for PBXProject "XcodeCapp" */ = { isa = XCConfigurationList; buildConfigurations = ( - E164FDEA1720E77100263CE3 /* Debug */, - E164FDEB1720E77100263CE3 /* Release */, + 6841F2561AF98CE600CFE60E /* Debug */, + 6841F2571AF98CE600CFE60E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - E164FDEC1720E77100263CE3 /* Build configuration list for PBXNativeTarget "XcodeCapp" */ = { + 6841F2581AF98CE600CFE60E /* Build configuration list for PBXNativeTarget "XcodeCapp" */ = { isa = XCConfigurationList; buildConfigurations = ( - E164FDED1720E77100263CE3 /* Debug */, - E164FDEE1720E77100263CE3 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E171D269173C168C00210893 /* Build configuration list for PBXNativeTarget "xcc" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E171D267173C168C00210893 /* Debug */, - E171D268173C168C00210893 /* Release */, + 6841F2591AF98CE600CFE60E /* Debug */, + 6841F25A1AF98CE600CFE60E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; - rootObject = E164FDC71720E77100263CE3 /* Project object */; + rootObject = 6841F2331AF98CE600CFE60E /* Project object */; } diff --git a/Tools/XcodeCapp/XcodeCapp/AppController.h b/Tools/XcodeCapp/XcodeCapp/AppController.h deleted file mode 100644 index 7278bd236..000000000 --- a/Tools/XcodeCapp/XcodeCapp/AppController.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is a part of program XcodeCapp - * Copyright (C) 2011 Antoine Mercadal () - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import -#import -#import - -@class XcodeCapp; - -@interface AppController : NSObject - -@property (strong) IBOutlet NSMenu *statusMenu; -@property (unsafe_unretained) IBOutlet NSMenuItem *menuItemHistory; -@property (unsafe_unretained) IBOutlet NSMenuItem *menuItemOpenProject; -@property (unsafe_unretained) IBOutlet NSMenuItem *menuItemShowInFinder; - -@property (strong) IBOutlet NSPanel *aboutWindow; -@property (strong) IBOutlet NSWindow *preferencesWindow; - -@property (strong) IBOutlet NSWindow *helpWindow; -@property (unsafe_unretained) IBOutlet PDFView *helpView; - -@property (strong) IBOutlet NSUserDefaultsController *preferencesController; -@property (strong) IBOutlet XcodeCapp *xcc; - -+ (AppController *)sharedAppController; - -- (IBAction)createProject:(id)sender; -- (IBAction)loadProject:(id)aSender; -- (IBAction)openHelp:(id)aSender; -- (IBAction)openAbout:(id)aSender; - -@end - diff --git a/Tools/XcodeCapp/XcodeCapp/AppController.m b/Tools/XcodeCapp/XcodeCapp/AppController.m deleted file mode 100644 index cd37746ac..000000000 --- a/Tools/XcodeCapp/XcodeCapp/AppController.m +++ /dev/null @@ -1,541 +0,0 @@ -/* - * This file is a part of program XcodeCapp - * Copyright (C) 2011 Antoine Mercadal () - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#import - -#import "AppController.h" -#import "Notifications.h" -#import "XcodeCapp.h" -#import "UserDefaults.h" - - -AppController *SharedAppControllerInstance = nil; - - -@interface AppController () - -@property (nonatomic) NSImage *iconActive; -@property (nonatomic) NSImage *iconInactive; -@property (nonatomic) NSImage *iconWorking; -@property (nonatomic) NSImage *iconError; -@property (nonatomic) NSMenu *recentMenu; -@property NSStatusItem *statusItem; -@property NSString *finderName; -@property BOOL appFinishedLaunching; -@property NSString *pathToOpenAtLaunch; -@property NSFileManager *fm; - -@end - - -@implementation AppController - -+ (AppController *)sharedAppController -{ - return SharedAppControllerInstance; -} - -#pragma mark - Initialization - -- (void)awakeFromNib -{ - SharedAppControllerInstance = self; - self.fm = [NSFileManager defaultManager]; - - [self registerDefaultPreferences]; - [self initLogging]; - - DDLogVerbose(@"\n******************************\n** XcodeCapp started **\n******************************\n"); - - self.aboutWindow.backgroundColor = [NSColor whiteColor]; - [self initStatusItem]; - [self initObservers]; - [self initShowInFinderItem]; - [self pruneProjectHistory]; - [self updateHistoryMenu]; - [self checkFirstLaunch]; -} - -- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename -{ - if (filename) - { - NSString *path = filename.stringByStandardizingPath; - - if (self.appFinishedLaunching) - return [self loadProjectAtPath:path reopening:YES]; - else - self.pathToOpenAtLaunch = path; - } - - return YES; -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notification -{ - self.appFinishedLaunching = YES; - - if (![self.xcc executablesAreAccessible]) - { - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - - NSRunAlertPanel( - @"Executables are missing.", - @"Please make sure that each one of these executables:\n\n" - @"%@\n\n" - @"(or a symlink to it) is within one these directories:\n\n" - @"%@\n\n" - @"They do not all have to be in the same directory.", - @"Quit", - nil, - nil, - [self.xcc.executables componentsJoinedByString:@"\n"], - [self.xcc.environmentPaths componentsJoinedByString:@"\n"]); - - [[NSApplication sharedApplication] terminate:self]; - return; - } - - // If we were opened from the command line, self.pathToOpenAtLaunch will be set. - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - if (!self.pathToOpenAtLaunch) - { - if (![defaults boolForKey:kDefaultXCCReopenLastProject]) - return; - - self.pathToOpenAtLaunch = [defaults objectForKey:kDefaultLastOpenedPath]; - } - - if (self.pathToOpenAtLaunch) - { - if ([[NSFileManager defaultManager] fileExistsAtPath:self.pathToOpenAtLaunch]) - [self loadProjectAtPath:self.pathToOpenAtLaunch reopening:YES]; - else - [defaults removeObjectForKey:kDefaultLastOpenedPath]; - } -} - -/*! - Register default values for preferences -*/ -- (void)registerDefaultPreferences -{ - NSDictionary *appDefaults = @{ - kDefaultLastEventId: [NSNumber numberWithUnsignedLongLong:kFSEventStreamEventIdSinceNow], - kDefaultFirstLaunch: @YES, - kDefaultFirstLaunchVersion: @2.0, - kDefaultXCCAPIMode: [NSNumber numberWithInt:kXCCAPIModeAuto], - kDefaultXCCReactToInodeMod: @YES, - kDefaultXCCReopenLastProject: @YES, - kDefaultXCCAutoOpenErrorsPanelOnErrors: @YES, - kDefaultXCCAutoOpenErrorsPanelOnCappLint: @YES, - kDefaultXCCAutoShowNotificationOnErrors: @YES, - kDefaultXCCAutoShowNotificationOnCappLint: @YES, - kDefaultXCCProjectHistory: [NSArray new], - kDefaultMaxRecentProjects: @20, - kDefaultLogLevel: [NSNumber numberWithInt:LOG_LEVEL_WARN], - kDefaultAutoOpenXcodeProject: @YES, - kDefaultUseSymlinkWhenCreatingProject: @YES, - kDefaultXCCUseDebugFrameworkWithObjj: @YES, - kDefaultXCCShouldProcessObjj: @YES, - kDefaultXCCPanelStyleUtility: @NO, - kDefaultXCCPanelActiveAppWhenOpening: @NO - }; - - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - [defaults registerDefaults:appDefaults]; - [defaults synchronize]; - - [defaults addObserver:self - forKeyPath:kDefaultMaxRecentProjects - options:NSKeyValueObservingOptionNew - context:NULL]; -} - -- (void)initLogging -{ -#if DEBUG - [DDLog addLogger:[DDTTYLogger sharedInstance]]; - [[DDTTYLogger sharedInstance] setColorsEnabled:YES]; - [DDLogLevel setLogLevel:LOG_LEVEL_VERBOSE]; -#else - [DDLog addLogger:[DDASLLogger sharedInstance]]; - - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - int logLevel = (int)[defaults integerForKey:kDefaultLogLevel]; - NSUInteger modifiers = [NSEvent modifierFlags]; - - if (modifiers & NSAlternateKeyMask) - logLevel = LOG_LEVEL_VERBOSE; - - [DDLogLevel setLogLevel:logLevel]; -#endif -} - -- (void)initStatusItem -{ - self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; - self.statusItem.menu = self.statusMenu; - self.statusItem.image = self.iconInactive; - self.statusItem.highlightMode = YES; - self.statusItem.length = self.iconInactive.size.width + 12; // Add some space around the icon - self.statusMenu.delegate = self; -} - -- (void)initObservers -{ - NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; - - [defaultCenter addObserver:self selector:@selector(batchDidStart:) name:XCCBatchDidStartNotification object:nil]; - [defaultCenter addObserver:self selector:@selector(batchDidEnd:) name:XCCBatchDidEndNotification object:nil]; - [defaultCenter addObserver:self selector:@selector(projectDidFinishLoading:) name:XCCProjectDidFinishLoadingNotification object:nil]; -} - -- (void)initShowInFinderItem -{ - // See if PathFinder is available - NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; - NSString *path = [workspace absolutePathForAppBundleWithIdentifier:@"com.cocoatech.PathFinder"]; - - if (path) - self.finderName = path.lastPathComponent.stringByDeletingPathExtension; - else - self.finderName = @"Finder"; - - self.menuItemShowInFinder.title = [NSString stringWithFormat:self.menuItemShowInFinder.title, self.finderName]; -} - -- (void)pruneProjectHistory -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSMutableArray *projectHistory = [[defaults arrayForKey:kDefaultXCCProjectHistory] mutableCopy]; - NSFileManager *fm = [NSFileManager new]; - - for (NSInteger i = projectHistory.count - 1; i >= 0; --i) - { - if (![fm fileExistsAtPath:projectHistory[i]]) - [projectHistory removeObjectAtIndex:i]; - } - - NSInteger maxProjects = [defaults integerForKey:kDefaultMaxRecentProjects]; - - if (projectHistory.count > maxProjects) - [projectHistory removeObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(maxProjects, projectHistory.count - maxProjects)]]; - - [defaults setObject:projectHistory forKey:kDefaultXCCProjectHistory]; -} - -- (void)checkFirstLaunch -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - double firstLaunchVersion = [defaults doubleForKey:kDefaultFirstLaunchVersion]; - - // Note: the scanner will only get the major.minor version numbers, which is what we want. - NSScanner *scanner = [NSScanner scannerWithString:[self bundleVersion]]; - double appVersion = 0.0; - [scanner scanDouble:&appVersion]; - - if ([defaults boolForKey:kDefaultFirstLaunch] || appVersion > firstLaunchVersion) - { - [defaults setBool:NO forKey:kDefaultFirstLaunch]; - [defaults setDouble:appVersion forKey:kDefaultFirstLaunchVersion]; - [self openHelp:self]; - } -} - -#pragma mark - Properties - -- (NSImage *)iconActive -{ - if (!_iconActive) - _iconActive = [NSImage imageNamed:@"icon-active"]; - - return _iconActive; -} - -- (NSImage *)iconInactive -{ - if (!_iconInactive) - _iconInactive = [NSImage imageNamed:@"icon-inactive"]; - - return _iconInactive; -} - -- (NSImage *)iconWorking -{ - if (!_iconWorking) - _iconWorking = [NSImage imageNamed:@"icon-working"]; - - return _iconWorking; -} - -- (NSImage *)iconError -{ - if (!_iconError) - _iconError = [NSImage imageNamed:@"icon-error"]; - - return _iconError; -} - -- (NSMenu *)recentMenu -{ - if (!_recentMenu) - { - _recentMenu = [NSMenu new]; - _recentMenu.delegate = self; - self.menuItemHistory.submenu = _recentMenu; - } - - return _recentMenu; -} - -#pragma mark - Notification handlers - -- (void)batchDidStart:(NSNotification *)note -{ - DDLogVerbose(@"Batch start"); - - self.statusItem.image = self.iconWorking; -} - -- (void)batchDidEnd:(NSNotification *)note -{ - DDLogVerbose(@"Batch end"); - - if (!self.xcc.isLoadingProject) - self.statusItem.image = self.xcc.hasErrors ? self.iconError : self.iconActive; -} - -- (void)projectDidFinishLoading:(NSNotification *)note -{ - self.statusItem.image = self.xcc.hasErrors ? self.iconError : self.iconActive; - self.menuItemOpenProject.title = [NSString stringWithFormat:@"Close “%@”", self.xcc.projectPath.lastPathComponent]; - self.menuItemOpenProject.action = @selector(closeProject:); -} - -// Watch changes to the max recent projects preference -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ - if ([keyPath isEqualToString:kDefaultMaxRecentProjects]) - [self pruneProjectHistory]; -} - -#pragma mark - Actions - -- (IBAction)loadProject:(id)aSender -{ - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - - NSOpenPanel *openPanel = [NSOpenPanel openPanel]; - openPanel.title = @"Choose Cappuccino Project"; - openPanel.canChooseDirectories = YES; - openPanel.canCreateDirectories = YES; - openPanel.canChooseFiles = NO; - - if ([openPanel runModal] != NSFileHandlingPanelOKButton) - return; - - NSString *projectPath = [[openPanel.URLs[0] path] stringByStandardizingPath]; - [self loadProjectAtPath:projectPath reopening:YES]; -} - -- (void)closeProject:(id)aSender -{ - [self.xcc stop]; - - self.statusItem.image = self.iconInactive; - self.menuItemOpenProject.title = @"Open Project…"; - self.menuItemOpenProject.action = @selector(loadProject:); - - [[NSUserDefaults standardUserDefaults] removeObjectForKey:kDefaultLastOpenedPath]; -} - -- (void)switchToProject:(NSMenuItem *)aSender -{ - [self loadProjectAtPath:aSender.representedObject reopening:NO]; -} - -- (void)clearProjectHistory:(id)aSender -{ - [[NSUserDefaults standardUserDefaults] setObject:[NSArray array] forKey:kDefaultXCCProjectHistory]; - [self updateHistoryMenu]; -} - -- (IBAction)showInFinder:(id)aSender -{ - [[NSWorkspace sharedWorkspace] openFile:self.xcc.projectPath withApplication:self.finderName]; -} - -- (IBAction)openHelp:(id)aSender -{ - if (!self.helpView.document) - { - NSURL *helpURL = [[NSBundle mainBundle] URLForResource:@"help" withExtension:@"pdf"]; - PDFDocument *help = [[PDFDocument alloc] initWithURL:helpURL]; - self.helpView.document = help; - } - - [self openWindow:self.helpWindow]; -} - -- (IBAction)openAbout:(id)aSender -{ - [self openWindow:self.aboutWindow]; -} - -- (IBAction)openPreferences:(id)aSender -{ - [self openWindow:self.preferencesWindow]; -} - -- (IBAction)createProject:(id)sender -{ - NSSavePanel *savePanel = [NSSavePanel savePanel]; - savePanel.title = @"Create a new Cappuccino Project"; - savePanel.canCreateDirectories = YES; - - if ([savePanel runModal] != NSFileHandlingPanelOKButton) - return; - - NSString *projectPath = [[savePanel.URL path] stringByStandardizingPath]; - - NSDictionary *taskResult = [self.xcc createProject:projectPath]; - - if ([taskResult[@"status"] intValue]) - return; - - [self loadProjectAtPath:projectPath reopening:YES]; -} - -#pragma mark - Delegates - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app -{ - [self.xcc stop]; - - return NSTerminateNow; -} - -- (BOOL)validateMenuItem:(NSMenuItem *)aMenuItem -{ - NSMenu *menu = aMenuItem.menu; - - if (menu == self.recentMenu) - { - // Disable recent items if they don't exist or are not directories, - // but enable the Clear History item, which is last in the menu. - if ([menu indexOfItem:aMenuItem] == menu.itemArray.count - 1) - return YES; - - BOOL isDirectory; - BOOL exists = [self.fm fileExistsAtPath:aMenuItem.representedObject isDirectory:&isDirectory]; - - return exists && isDirectory; - } - - return YES; -} - -#pragma mark - Bindings - -- (NSString *)bundleVersion -{ - return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; -} - -#pragma mark - Private Helpers - - -- (BOOL)loadProjectAtPath:(NSString *)path reopening:(BOOL)reopen -{ - if (!reopen && [self.xcc.projectPath isEqualToString:path]) - return YES; - - [self closeProject:self]; - - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSMutableArray *projectHistory = [[defaults arrayForKey:kDefaultXCCProjectHistory] mutableCopy]; - - if ([projectHistory containsObject:path]) - [projectHistory removeObject:path]; - - // The path may no longer be there, validate it - NSFileManager *fm = [NSFileManager defaultManager]; - - BOOL exists, isDirectory; - exists = [fm fileExistsAtPath:path isDirectory:&isDirectory]; - - if (exists && isDirectory) - { - [projectHistory insertObject:path atIndex:0]; - } - else - { - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - NSRunAlertPanel(@"Project not found.", @"%@ %@", nil, nil, nil, path, !exists ? @"no longer exists." : @"is not a directory."); - } - - [defaults setObject:projectHistory forKey:kDefaultXCCProjectHistory]; - [self pruneProjectHistory]; - [self updateHistoryMenu]; - - if (exists && isDirectory) - { - [self.xcc loadProjectAtPath:path]; - return YES; - } - else - return NO; -} - -- (void)openWindow:(NSWindow *)aWindow -{ - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [aWindow makeKeyAndOrderFront:nil]; -} - -- (void)updateHistoryMenu -{ - [self.recentMenu removeAllItems]; - NSArray *projectHistory = [[NSUserDefaults standardUserDefaults] arrayForKey:kDefaultXCCProjectHistory]; - - for (NSString *path in projectHistory) - { - NSMenuItem *item = [self.recentMenu addItemWithTitle:path.lastPathComponent action:@selector(switchToProject:) keyEquivalent:@""]; - [item setEnabled:YES]; - item.representedObject = path; - } - - [self.recentMenu addItem:[NSMenuItem separatorItem]]; - [self.recentMenu addItemWithTitle:@"Clear history" action:@selector(clearProjectHistory:) keyEquivalent:@""]; - - self.menuItemHistory.enabled = [projectHistory count] > 0; -} - -#pragma mark - Cappuccino methods - -- (IBAction)updateCappuccino:(id)sender -{ - [self.xcc performSelectorInBackground:@selector(updateCappuccino) withObject:nil]; -} - -@end diff --git a/Tools/XcodeCapp/XcodeCapp/AppDelegate.h b/Tools/XcodeCapp/XcodeCapp/AppDelegate.h new file mode 100644 index 000000000..0681f4678 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/AppDelegate.h @@ -0,0 +1,35 @@ +// +// AppDelegate.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/5/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import +#import + +@class XCCMainController; + + +@interface AppDelegate : NSObject +{ + IBOutlet NSMenu *statusMenu; + IBOutlet NSUserDefaultsController *preferencesController; + IBOutlet NSPanel *aboutWindow; + IBOutlet NSWindow *preferencesWindow; + + NSImage *imageStatusInactive; + NSImage *imageStatusProcessing; + NSImage *imageStatusError; + NSStatusItem *statusItem; +} + +@property IBOutlet XCCMainController *mainWindowController; +@property NSOperationQueue *mainOperationQueue; +@property NSString *version; + +- (IBAction)openAbout:(id)aSender; +- (IBAction)openPreferences:(id)aSender; + +@end \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/AppDelegate.m b/Tools/XcodeCapp/XcodeCapp/AppDelegate.m new file mode 100644 index 000000000..cc53ac681 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/AppDelegate.m @@ -0,0 +1,170 @@ +// +// AppDelegate.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/5/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "AppDelegate.h" +#import "XCCMainController.h" +#import "XCCUserDefaults.h" + +@implementation AppDelegate + + +#pragma mark - Utilities + +- (void)_initUserDefaults +{ + NSDictionary *appDefaults = @{ + XCCUserDefaultsAutoOpenXcodeProject: @YES, + XCCUserDefaultsLogLevel: @LOG_LEVEL_WARN, + XCCUserDefaultsMaxNumberOfConcurrentOperations: @20 + }; + + [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)_initStatusItem +{ + self->imageStatusInactive = [NSImage imageNamed:@"status-icon-inactive"]; + self->imageStatusProcessing = [NSImage imageNamed:@"status-icon-working"]; + self->imageStatusError = [NSImage imageNamed:@"status-icon-error"]; + + self->statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; + self->statusItem.menu = self->statusMenu; + self->statusItem.image = self->imageStatusInactive; + self->statusItem.highlightMode = YES; + self->statusItem.length = self->imageStatusInactive.size.width + 12; +} + +- (void)_initLogging +{ +#if DEBUG + [DDLog addLogger:[DDTTYLogger sharedInstance]]; + [[DDTTYLogger sharedInstance] setColorsEnabled:YES]; + [DDLogLevel setLogLevel:LOG_LEVEL_VERBOSE]; +#else + [DDLog addLogger:[DDASLLogger sharedInstance]]; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + int logLevel = (int)[defaults integerForKey:XCCUserDefaultsLogLevel]; + NSUInteger modifiers = [NSEvent modifierFlags]; + + if (modifiers & NSAlternateKeyMask) + logLevel = LOG_LEVEL_VERBOSE; + + [DDLogLevel setLogLevel:logLevel]; +#endif +} + +- (void)_initOperationQueue +{ + self.mainOperationQueue = [NSOperationQueue new]; + + [self.mainOperationQueue setMaxConcurrentOperationCount:[[[NSUserDefaults standardUserDefaults] objectForKey:XCCUserDefaultsMaxNumberOfConcurrentOperations] intValue]]; +} + +#pragma mark - Actions + +- (IBAction)openPreferences:(id)aSender +{ + [self->preferencesWindow makeKeyAndOrderFront:nil]; +} + +- (IBAction)openAbout:(id)aSender +{ + [self->aboutWindow makeKeyAndOrderFront:nil]; +} + + +#pragma mark - Observers + +- (void)_startObservers +{ + [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:XCCUserDefaultsMaxNumberOfConcurrentOperations options:NSKeyValueObservingOptionNew context:nil]; + + [self.mainOperationQueue addObserver:self forKeyPath:@"operationCount" options:NSKeyValueObservingOptionNew context:nil]; + [self.mainWindowController addObserver:self forKeyPath:@"totalNumberOfErrors" options:NSKeyValueObservingOptionNew context:nil]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if (object == [NSUserDefaults standardUserDefaults] && [keyPath isEqualToString:XCCUserDefaultsMaxNumberOfConcurrentOperations]) + { + [self.mainOperationQueue setMaxConcurrentOperationCount:[change[NSKeyValueChangeNewKey] intValue]]; + } + else + { + NSImage *image; + + if (self.mainOperationQueue.operationCount) + image = self->imageStatusProcessing; + else if ([self.mainWindowController totalNumberOfErrors]) + image = self->imageStatusError; + else + image = self->imageStatusInactive; + + [self->statusItem performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO]; + } +} + + +#pragma mark - Delegates + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + DDLogVerbose(@"\n******************************\n** XcodeCapp started **\n******************************\n"); + + self.version = [NSBundle mainBundle].infoDictionary[@"CFBundleShortVersionString"]; + + [self _initUserDefaults]; + [self _initLogging]; + [self _initOperationQueue]; + [self _initStatusItem]; + + [self _startObservers]; + + [self->_mainWindowController windowDidLoad]; +} + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app +{ + DDLogVerbose(@"Stop listening to all projects"); + [self.mainWindowController notifyCappuccinoControllersApplicationIsClosing]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + return NSTerminateNow; +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification +{ + DDLogVerbose(@"\n******************************\n** XcodeCapp stopped **\n******************************\n"); +} + +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag +{ + [self.mainWindowController showWindow:self]; + return YES; +} + +- (BOOL)application:(NSApplication *)application openFile:(NSString *)filename +{ + BOOL isDir; + + [[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&isDir]; + + if (isDir) + { + [self.mainWindowController manageCappuccinoProjectControllerForPath:filename]; + return YES; + } + else + { + return NO; + } +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/Base.lproj/MainMenu.xib b/Tools/XcodeCapp/XcodeCapp/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..370db68e3 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Base.lproj/MainMenu.xib @@ -0,0 +1,1044 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This represents the number of operations XcodeCapp can do in parallel. Decrease the this value if you encounter slugginesh or over CPU usage. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/XcodeCapp/XcodeCapp/Debug.xcconfig b/Tools/XcodeCapp/XcodeCapp/Debug.xcconfig index 9ec35ffbf..9c74d6764 100644 --- a/Tools/XcodeCapp/XcodeCapp/Debug.xcconfig +++ b/Tools/XcodeCapp/XcodeCapp/Debug.xcconfig @@ -13,7 +13,7 @@ ONLY_ACTIVE_ARCH = YES DEBUG_INFORMATION_FORMAT = dwarf-with-dsym COMBINE_HIDPI_IMAGES = YES INSTALL_PATH = $(LOCAL_APPS_DIR) -MACOSX_DEPLOYMENT_TARGET = 10.6.8 +MACOSX_DEPLOYMENT_TARGET = 10.10 COPY_PHASE_STRIP = NO INFOPLIST_FILE = XcodeCapp/Info.plist PRODUCT_NAME = XcodeCapp diff --git a/Tools/XcodeCapp/XcodeCapp/ErrorsView.xib b/Tools/XcodeCapp/XcodeCapp/ErrorsView.xib new file mode 100644 index 000000000..df069a1ce --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/ErrorsView.xib @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/XcodeCapp/XcodeCapp/FindSourceFilesOperation.h b/Tools/XcodeCapp/XcodeCapp/FindSourceFilesOperation.h deleted file mode 100644 index ce4d5eb04..000000000 --- a/Tools/XcodeCapp/XcodeCapp/FindSourceFilesOperation.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// FindSourceFilesOperation.h -// XcodeCapp -// -// Created by Aparajita on 4/27/13. -// Copyright (c) 2013 Cappuccino Project. All rights reserved. -// - -#import - -@class XcodeCapp; - - -extern NSString * const XCCNeedSourceToProjectPathMappingNotification; - - -@interface FindSourceFilesOperation : NSOperation - -- (id)initWithXCC:(XcodeCapp *)xcc projectId:(NSNumber *)projectId path:(NSString *)path; - -@end diff --git a/Tools/XcodeCapp/XcodeCapp/FindSourceFilesOperation.m b/Tools/XcodeCapp/XcodeCapp/FindSourceFilesOperation.m deleted file mode 100644 index aa44e4c58..000000000 --- a/Tools/XcodeCapp/XcodeCapp/FindSourceFilesOperation.m +++ /dev/null @@ -1,172 +0,0 @@ -// -// FindSourceFilesOperation.m -// XcodeCapp -// -// Created by Aparajita on 4/27/13. -// Copyright (c) 2013 Cappuccino Project. All rights reserved. -// - -#import "FindSourceFilesOperation.h" -#import "ProcessSourceOperation.h" -#import "XcodeCapp.h" - -NSString * const XCCNeedSourceToProjectPathMappingNotification = @"XCCNeedSourceToProjectPathMappingNotification"; - - -@interface FindSourceFilesOperation () - -@property XcodeCapp *xcc; -@property NSNumber *projectId; -@property NSString *projectPathToSearch; -@property NSString *projectPath; - -@end - - -@implementation FindSourceFilesOperation - -- (id)initWithXCC:(XcodeCapp *)xcc projectId:(NSNumber *)projectId path:(NSString *)path -{ - self = [super init]; - - if (self) - { - self.xcc = xcc; - self.projectId = projectId; - self.projectPathToSearch = path; - self.projectPath = xcc.projectPath; - } - - return self; -} - -- (void)main -{ - [self findSourceFilesAtProjectPath:self.projectPathToSearch]; -} - -- (void)findSourceFilesAtProjectPath:(NSString *)aProjectPath -{ - if (self.isCancelled) - return; - - DDLogVerbose(@"-->findSourceFiles: %@", aProjectPath); - - NSError *error = NULL; - NSString *projectPath = [self.projectPath stringByAppendingPathComponent:aProjectPath]; - NSFileManager *fm = [NSFileManager defaultManager]; - - NSArray *urls = [fm contentsOfDirectoryAtURL:[NSURL fileURLWithPath:projectPath.stringByResolvingSymlinksInPath] - includingPropertiesForKeys:@[NSURLIsDirectoryKey, NSURLIsSymbolicLinkKey] - options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants | NSDirectoryEnumerationSkipsSubdirectoryDescendants - error:&error]; - - if (!urls) - return; - - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - - for (NSURL *url in urls) - { - if (self.isCancelled) - return; - - NSString *filename = url.lastPathComponent; - - NSString *projectRelativePath = [aProjectPath stringByAppendingPathComponent:filename]; - NSString *realPath = url.path; - NSURL *resolvedURL = url; - - NSNumber *isDirectory, *isSymlink; - [url getResourceValue:&isSymlink forKey:NSURLIsSymbolicLinkKey error:nil]; - - if (isSymlink.boolValue == YES) - { - resolvedURL = [url URLByResolvingSymlinksInPath]; - - if ([resolvedURL checkResourceIsReachableAndReturnError:nil]) - { - filename = resolvedURL.lastPathComponent; - realPath = resolvedURL.path; - } - else - continue; - } - - [resolvedURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil]; - - if (isDirectory.boolValue == YES) - { - if ([self.xcc shouldIgnoreDirectoryNamed:filename]) - { - DDLogVerbose(@"ignored symlinked directory: %@", projectRelativePath); - continue; - } - - // If the resolved path is not within the project directory and is not ignored, add a mapping to it - // so we can map the resolved path back to the project directory later. - if (isSymlink.boolValue == YES) - { - NSString *fullProjectPath = [self.projectPath stringByAppendingPathComponent:projectRelativePath]; - - if (![realPath hasPrefix:fullProjectPath] && ![self.xcc pathMatchesIgnoredPaths:fullProjectPath]) - { - DDLogVerbose(@"symlinked directory: %@ -> %@", projectRelativePath, realPath); - - NSDictionary *info = - @{ - @"projectId":self.projectId, - @"sourcePath":realPath, - @"projectPath":fullProjectPath - }; - - if (self.isCancelled) - return; - - [center postNotificationName:XCCNeedSourceToProjectPathMappingNotification object:self userInfo:info]; - } - else - DDLogVerbose(@"ignored symlinked directory: %@", projectRelativePath); - } - - [self findSourceFilesAtProjectPath:projectRelativePath]; - continue; - } - - if (self.isCancelled) - return; - - if ([self.xcc pathMatchesIgnoredPaths:realPath]) - continue; - - NSString *projectSourcePath = [self.projectPath stringByAppendingPathComponent:projectRelativePath]; - - if ([self.xcc isObjjFile:filename] || [self.xcc isXibFile:filename]) - { - NSString *processedPath; - - if ([self.xcc isObjjFile:filename]) - processedPath = [[self.xcc shadowBasePathForProjectSourcePath:projectSourcePath] stringByAppendingPathExtension:@"h"]; - else - processedPath = [projectSourcePath.stringByDeletingPathExtension stringByAppendingPathExtension:@"cib"]; - - if (![fm fileExistsAtPath:processedPath]) - [self createProcessingOperationForProjectSourcePath:projectSourcePath]; - } - } - - DDLogVerbose(@"<--findSourceFiles: %@", aProjectPath); -} - -- (void)createProcessingOperationForProjectSourcePath:(NSString *)projectSourcePath -{ - if (self.isCancelled) - return; - - ProcessSourceOperation *op = [[ProcessSourceOperation alloc] initWithXCC:self.xcc - projectId:self.projectId - sourcePath:projectSourcePath]; - [[NSOperationQueue currentQueue] addOperation:op]; -} - -@end diff --git a/Tools/XcodeCapp/XcodeCapp/Growl Registration Ticket.growlRegDict b/Tools/XcodeCapp/XcodeCapp/Growl Registration Ticket.growlRegDict deleted file mode 100644 index 01a301463..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl Registration Ticket.growlRegDict +++ /dev/null @@ -1,12 +0,0 @@ - - - - - TicketVersion - 1 - AllNotifications - - DefaultNotifications - - - diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Growl b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Growl deleted file mode 120000 index 85956e2d2..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Growl +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Growl \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Headers b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Headers deleted file mode 120000 index a177d2a6b..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Headers +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Headers \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Resources b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Resources deleted file mode 120000 index 953ee36f3..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Resources +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Resources \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Growl b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Growl deleted file mode 100755 index e35673015..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Growl and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/Growl.h b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/Growl.h deleted file mode 100644 index 7b1a3247d..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/Growl.h +++ /dev/null @@ -1,5 +0,0 @@ -#include - -#ifdef __OBJC__ -# include -#endif diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h deleted file mode 100644 index 363975762..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h +++ /dev/null @@ -1,567 +0,0 @@ -// -// GrowlApplicationBridge.h -// Growl -// -// Created by Evan Schoenberg on Wed Jun 16 2004. -// Copyright 2004-2006 The Growl Project. All rights reserved. -// - -/*! - * @header GrowlApplicationBridge.h - * @abstract Defines the GrowlApplicationBridge class. - * @discussion This header defines the GrowlApplicationBridge class as well as - * the GROWL_PREFPANE_BUNDLE_IDENTIFIER constant. - */ - -#ifndef __GrowlApplicationBridge_h__ -#define __GrowlApplicationBridge_h__ - -#import -#import -#import - -//Forward declarations -@protocol GrowlApplicationBridgeDelegate; - -//------------------------------------------------------------------------------ -#pragma mark - - -/*! - * @class GrowlApplicationBridge - * @abstract A class used to interface with Growl. - * @discussion This class provides a means to interface with Growl. - * - * Currently it provides a way to detect if Growl is installed and launch the - * GrowlHelperApp if it's not already running. - */ -@interface GrowlApplicationBridge : NSObject { - -} - -/*! - * @method isGrowlInstalled - * @abstract Detects whether Growl is installed. - * @discussion Determines if the Growl prefpane and its helper app are installed. - * @result this method will forever return YES. - */ -+ (BOOL) isGrowlInstalled __attribute__((deprecated)); - -/*! - * @method isGrowlRunning - * @abstract Detects whether GrowlHelperApp is currently running. - * @discussion Cycles through the process list to find whether GrowlHelperApp is running and returns its findings. - * @result Returns YES if GrowlHelperApp is running, NO otherwise. - */ -+ (BOOL) isGrowlRunning; - - -/*! - * @method isMistEnabled - * @abstract Gives the caller a fairly good indication of whether or not built-in notifications(Mist) will be used. - * @discussion since this call makes use of isGrowlRunning it is entirely possible for this value to change between call and - * executing a notification dispatch - * @result Returns YES if Growl isn't reachable and the developer has not opted-out of - * Mist and the user hasn't set the global mist enable key to false. - */ -+ (BOOL)isMistEnabled; - -/*! - * @method setShouldUseBuiltInNotifications - * @abstract opt-out mechanism for the mist notification style in the event growl can't be reached. - * @discussion if growl is unavailable due to not being installed or as a result of being turned off then - * this option can enable/disable a built-in fire and forget display style - * @param should Specifies whether or not the developer wants to opt-in (default) or opt out - * of the built-in Mist style in the event Growl is unreachable. - */ -+ (void)setShouldUseBuiltInNotifications:(BOOL)should; - -/*! - * @method shouldUseBuiltInNotifications - * @abstract returns the current opt-in state of the framework's use of the Mist display style. - * @result Returns NO if the developer opt-ed out of Mist, the default value is YES. - */ -+ (BOOL)shouldUseBuiltInNotifications; - -#pragma mark - - -/*! - * @method setGrowlDelegate: - * @abstract Set the object which will be responsible for providing and receiving Growl information. - * @discussion This must be called before using GrowlApplicationBridge. - * - * The methods in the GrowlApplicationBridgeDelegate protocol are required - * and return the basic information needed to register with Growl. - * - * The methods in the GrowlApplicationBridgeDelegate_InformalProtocol - * informal protocol are individually optional. They provide a greater - * degree of interaction between the application and growl such as informing - * the application when one of its Growl notifications is clicked by the user. - * - * The methods in the GrowlApplicationBridgeDelegate_Installation_InformalProtocol - * informal protocol are individually optional and are only applicable when - * using the Growl-WithInstaller.framework which allows for automated Growl - * installation. - * - * When this method is called, data will be collected from inDelegate, Growl - * will be launched if it is not already running, and the application will be - * registered with Growl. - * - * If using the Growl-WithInstaller framework, if Growl is already installed - * but this copy of the framework has an updated version of Growl, the user - * will be prompted to update automatically. - * - * @param inDelegate The delegate for the GrowlApplicationBridge. It must conform to the GrowlApplicationBridgeDelegate protocol. - */ -+ (void) setGrowlDelegate:(id)inDelegate; - -/*! - * @method growlDelegate - * @abstract Return the object responsible for providing and receiving Growl information. - * @discussion See setGrowlDelegate: for details. - * @result The Growl delegate. - */ -+ (id) growlDelegate; - -#pragma mark - - -/*! - * @method notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext: - * @abstract Send a Growl notification. - * @discussion This is the preferred means for sending a Growl notification. - * The notification name and at least one of the title and description are - * required (all three are preferred). All other parameters may be - * nil (or 0 or NO as appropriate) to accept default values. - * - * If using the Growl-WithInstaller framework, if Growl is not installed the - * user will be prompted to install Growl. If the user cancels, this method - * will have no effect until the next application session, at which time when - * it is called the user will be prompted again. The user is also given the - * option to not be prompted again. If the user does choose to install Growl, - * the requested notification will be displayed once Growl is installed and - * running. - * - * @param title The title of the notification displayed to the user. - * @param description The full description of the notification displayed to the user. - * @param notifName The internal name of the notification. Should be human-readable, as it will be displayed in the Growl preference pane. - * @param iconData NSData object to show with the notification as its icon. If nil, the application's icon will be used instead. - * @param priority The priority of the notification. The default value is 0; positive values are higher priority and negative values are lower priority. Not all Growl displays support priority. - * @param isSticky If YES, the notification will remain on screen until clicked. Not all Growl displays support sticky notifications. - * @param clickContext A context passed back to the Growl delegate if it implements -(void)growlNotificationWasClicked: and the notification is clicked. Not all display plugins support clicking. The clickContext must be plist-encodable (completely of NSString, NSArray, NSNumber, NSDictionary, and NSData types). - */ -+ (void) notifyWithTitle:(NSString *)title - description:(NSString *)description - notificationName:(NSString *)notifName - iconData:(NSData *)iconData - priority:(signed int)priority - isSticky:(BOOL)isSticky - clickContext:(id)clickContext; - -/*! - * @method notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:identifier: - * @abstract Send a Growl notification. - * @discussion This is the preferred means for sending a Growl notification. - * The notification name and at least one of the title and description are - * required (all three are preferred). All other parameters may be - * nil (or 0 or NO as appropriate) to accept default values. - * - * If using the Growl-WithInstaller framework, if Growl is not installed the - * user will be prompted to install Growl. If the user cancels, this method - * will have no effect until the next application session, at which time when - * it is called the user will be prompted again. The user is also given the - * option to not be prompted again. If the user does choose to install Growl, - * the requested notification will be displayed once Growl is installed and - * running. - * - * @param title The title of the notification displayed to the user. - * @param description The full description of the notification displayed to the user. - * @param notifName The internal name of the notification. Should be human-readable, as it will be displayed in the Growl preference pane. - * @param iconData NSData object to show with the notification as its icon. If nil, the application's icon will be used instead. - * @param priority The priority of the notification. The default value is 0; positive values are higher priority and negative values are lower priority. Not all Growl displays support priority. - * @param isSticky If YES, the notification will remain on screen until clicked. Not all Growl displays support sticky notifications. - * @param clickContext A context passed back to the Growl delegate if it implements -(void)growlNotificationWasClicked: and the notification is clicked. Not all display plugins support clicking. The clickContext must be plist-encodable (completely of NSString, NSArray, NSNumber, NSDictionary, and NSData types). - * @param identifier An identifier for this notification. Notifications with equal identifiers are coalesced. - */ -+ (void) notifyWithTitle:(NSString *)title - description:(NSString *)description - notificationName:(NSString *)notifName - iconData:(NSData *)iconData - priority:(signed int)priority - isSticky:(BOOL)isSticky - clickContext:(id)clickContext - identifier:(NSString *)identifier; - -/*! @method notifyWithDictionary: - * @abstract Notifies using a userInfo dictionary suitable for passing to - * NSDistributedNotificationCenter. - * @param userInfo The dictionary to notify with. - * @discussion Before Growl 0.6, your application would have posted - * notifications using NSDistributedNotificationCenter by - * creating a userInfo dictionary with the notification data. This had the - * advantage of allowing you to add other data to the dictionary for programs - * besides Growl that might be listening. - * - * This method allows you to use such dictionaries without being restricted - * to using NSDistributedNotificationCenter. The keys for this dictionary - * can be found in GrowlDefines.h. - */ -+ (void) notifyWithDictionary:(NSDictionary *)userInfo; - -#pragma mark - - -/*! @method registerWithDictionary: - * @abstract Register your application with Growl without setting a delegate. - * @discussion When you call this method with a dictionary, - * GrowlApplicationBridge registers your application using that dictionary. - * If you pass nil, GrowlApplicationBridge will ask the delegate - * (if there is one) for a dictionary, and if that doesn't work, it will look - * in your application's bundle for an auto-discoverable plist. - * (XXX refer to more information on that) - * - * If you pass a dictionary to this method, it must include the - * GROWL_APP_NAME key, unless a delegate is set. - * - * This method is mainly an alternative to the delegate system introduced - * with Growl 0.6. Without a delegate, you cannot receive callbacks such as - * -growlIsReady (since they are sent to the delegate). You can, - * however, set a delegate after registering without one. - * - * This method was introduced in Growl.framework 0.7. - */ -+ (BOOL) registerWithDictionary:(NSDictionary *)regDict; - -/*! @method reregisterGrowlNotifications - * @abstract Reregister the notifications for this application. - * @discussion This method does not normally need to be called. If your - * application changes what notifications it is registering with Growl, call - * this method to have the Growl delegate's - * -registrationDictionaryForGrowl method called again and the - * Growl registration information updated. - * - * This method is now implemented using -registerWithDictionary:. - */ -+ (void) reregisterGrowlNotifications; - -#pragma mark - - -/*! @method setWillRegisterWhenGrowlIsReady: - * @abstract Tells GrowlApplicationBridge to register with Growl when Growl - * launches (or not). - * @discussion When Growl has started listening for notifications, it posts a - * GROWL_IS_READY notification on the Distributed Notification - * Center. GrowlApplicationBridge listens for this notification, using it to - * perform various tasks (such as calling your delegate's - * -growlIsReady method, if it has one). If this method is - * called with YES, one of those tasks will be to reregister - * with Growl (in the manner of -reregisterGrowlNotifications). - * - * This attribute is automatically set back to NO (the default) - * after every GROWL_IS_READY notification. - * @param flag YES if you want GrowlApplicationBridge to register with - * Growl when next it is ready; NO if not. - */ -+ (void) setWillRegisterWhenGrowlIsReady:(BOOL)flag; - -/*! @method willRegisterWhenGrowlIsReady - * @abstract Reports whether GrowlApplicationBridge will register with Growl - * when Growl next launches. - * @result YES if GrowlApplicationBridge will register with Growl - * when next it posts GROWL_IS_READY; NO if not. - */ -+ (BOOL) willRegisterWhenGrowlIsReady; - -#pragma mark - - -/*! @method registrationDictionaryFromDelegate - * @abstract Asks the delegate for a registration dictionary. - * @discussion If no delegate is set, or if the delegate's - * -registrationDictionaryForGrowl method returns - * nil, this method returns nil. - * - * This method does not attempt to clean up the dictionary in any way - for - * example, if it is missing the GROWL_APP_NAME key, the result - * will be missing it too. Use +[GrowlApplicationBridge - * registrationDictionaryByFillingInDictionary:] or - * +[GrowlApplicationBridge - * registrationDictionaryByFillingInDictionary:restrictToKeys:] to try - * to fill in missing keys. - * - * This method was introduced in Growl.framework 0.7. - * @result A registration dictionary. - */ -+ (NSDictionary *) registrationDictionaryFromDelegate; - -/*! @method registrationDictionaryFromBundle: - * @abstract Looks in a bundle for a registration dictionary. - * @discussion This method looks in a bundle for an auto-discoverable - * registration dictionary file using -[NSBundle - * pathForResource:ofType:]. If it finds one, it loads the file using - * +[NSDictionary dictionaryWithContentsOfFile:] and returns the - * result. - * - * If you pass nil as the bundle, the main bundle is examined. - * - * This method does not attempt to clean up the dictionary in any way - for - * example, if it is missing the GROWL_APP_NAME key, the result - * will be missing it too. Use +[GrowlApplicationBridge - * registrationDictionaryByFillingInDictionary:] or - * +[GrowlApplicationBridge - * registrationDictionaryByFillingInDictionary:restrictToKeys:] to try - * to fill in missing keys. - * - * This method was introduced in Growl.framework 0.7. - * @result A registration dictionary. - */ -+ (NSDictionary *) registrationDictionaryFromBundle:(NSBundle *)bundle; - -/*! @method bestRegistrationDictionary - * @abstract Obtains a registration dictionary, filled out to the best of - * GrowlApplicationBridge's knowledge. - * @discussion This method creates a registration dictionary as best - * GrowlApplicationBridge knows how. - * - * First, GrowlApplicationBridge contacts the Growl delegate (if there is - * one) and gets the registration dictionary from that. If no such dictionary - * was obtained, GrowlApplicationBridge looks in your application's main - * bundle for an auto-discoverable registration dictionary file. If that - * doesn't exist either, this method returns nil. - * - * Second, GrowlApplicationBridge calls - * +registrationDictionaryByFillingInDictionary: with whatever - * dictionary was obtained. The result of that method is the result of this - * method. - * - * GrowlApplicationBridge uses this method when you call - * +setGrowlDelegate:, or when you call - * +registerWithDictionary: with nil. - * - * This method was introduced in Growl.framework 0.7. - * @result A registration dictionary. - */ -+ (NSDictionary *) bestRegistrationDictionary; - -#pragma mark - - -/*! @method registrationDictionaryByFillingInDictionary: - * @abstract Tries to fill in missing keys in a registration dictionary. - * @discussion This method examines the passed-in dictionary for missing keys, - * and tries to work out correct values for them. As of 0.7, it uses: - * - * Key Value - * --- ----- - * GROWL_APP_NAME CFBundleExecutableName - * GROWL_APP_ICON_DATA The data of the icon of the application. - * GROWL_APP_LOCATION The location of the application. - * GROWL_NOTIFICATIONS_DEFAULT GROWL_NOTIFICATIONS_ALL - * - * Keys are only filled in if missing; if a key is present in the dictionary, - * its value will not be changed. - * - * This method was introduced in Growl.framework 0.7. - * @param regDict The dictionary to fill in. - * @result The dictionary with the keys filled in. This is an autoreleased - * copy of regDict. - */ -+ (NSDictionary *) registrationDictionaryByFillingInDictionary:(NSDictionary *)regDict; - -/*! @method registrationDictionaryByFillingInDictionary:restrictToKeys: - * @abstract Tries to fill in missing keys in a registration dictionary. - * @discussion This method examines the passed-in dictionary for missing keys, - * and tries to work out correct values for them. As of 0.7, it uses: - * - * Key Value - * --- ----- - * GROWL_APP_NAME CFBundleExecutableName - * GROWL_APP_ICON_DATA The data of the icon of the application. - * GROWL_APP_LOCATION The location of the application. - * GROWL_NOTIFICATIONS_DEFAULT GROWL_NOTIFICATIONS_ALL - * - * Only those keys that are listed in keys will be filled in. - * Other missing keys are ignored. Also, keys are only filled in if missing; - * if a key is present in the dictionary, its value will not be changed. - * - * This method was introduced in Growl.framework 0.7. - * @param regDict The dictionary to fill in. - * @param keys The keys to fill in. If nil, any missing keys are filled in. - * @result The dictionary with the keys filled in. This is an autoreleased - * copy of regDict. - */ -+ (NSDictionary *) registrationDictionaryByFillingInDictionary:(NSDictionary *)regDict restrictToKeys:(NSSet *)keys; - -/*! @brief Tries to fill in missing keys in a notification dictionary. - * @param notifDict The dictionary to fill in. - * @return The dictionary with the keys filled in. This will be a separate instance from \a notifDict. - * @discussion This function examines the \a notifDict for missing keys, and - * tries to get them from the last known registration dictionary. As of 1.1, - * the keys that it will look for are: - * - * \li GROWL_APP_NAME - * \li GROWL_APP_ICON_DATA - * - * @since Growl.framework 1.1 - */ -+ (NSDictionary *) notificationDictionaryByFillingInDictionary:(NSDictionary *)regDict; - -+ (NSDictionary *) frameworkInfoDictionary; - -#pragma mark - - -/*! - *@method growlURLSchemeAvailable - *@abstract Lets the app know whether growl:// is registered on the system, used for certain methods below this - *@return Returns whether growl:// is registered on the system - *@discussion Methods such as openGrowlPreferences rely on the growl:// URL scheme to function - * Further, this method can provide a check on whether Growl is installed, - * however, the framework will not be relying on this method for choosing when/how to notify, - * and it is not recommended that the app rely on it for other than whether to use growl:// methods - *@since Growl.framework 1.4 - */ -+ (BOOL) isGrowlURLSchemeAvailable; - -/*! - * @method openGrowlPreferences: - * @abstract Open Growl preferences, optionally to this app's settings, growl:// method - * @param showApp Whether to show the application's settings, otherwise just opens to the last position - * @return Return's whether opening the URL was succesfull or not. - * @discussion Will launch if Growl is installed, but not running, and open the preferences window - * Uses growl:// URL scheme - * @since Growl.framework 1.4 - */ -+ (BOOL) openGrowlPreferences:(BOOL)showApp; - -@end - -//------------------------------------------------------------------------------ -#pragma mark - - -/*! - * @protocol GrowlApplicationBridgeDelegate - * @abstract Required protocol for the Growl delegate. - * @discussion The methods in this protocol are optional and are called - * automatically as needed by GrowlApplicationBridge. See - * +[GrowlApplicationBridge setGrowlDelegate:]. - * See also GrowlApplicationBridgeDelegate_InformalProtocol. - */ - -@protocol GrowlApplicationBridgeDelegate - -@optional - -/*! - * @method registrationDictionaryForGrowl - * @abstract Return the dictionary used to register this application with Growl. - * @discussion The returned dictionary gives Growl the complete list of - * notifications this application will ever send, and it also specifies which - * notifications should be enabled by default. Each is specified by an array - * of NSString objects. - * - * For most applications, these two arrays can be the same (if all sent - * notifications should be displayed by default). - * - * The NSString objects of these arrays will correspond to the - * notificationName: parameter passed in - * +[GrowlApplicationBridge - * notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:] calls. - * - * The dictionary should have the required key object pairs: - * key: GROWL_NOTIFICATIONS_ALL object: NSArray of NSString objects - * key: GROWL_NOTIFICATIONS_DEFAULT object: NSArray of NSString objects - * - * The dictionary may have the following key object pairs: - * key: GROWL_NOTIFICATIONS_HUMAN_READABLE_NAMES object: NSDictionary of key: notification name object: human-readable notification name - * - * You do not need to implement this method if you have an auto-discoverable - * plist file in your app bundle. (XXX refer to more information on that) - * - * @result The NSDictionary to use for registration. - */ -- (NSDictionary *) registrationDictionaryForGrowl; - -/*! - * @method applicationNameForGrowl - * @abstract Return the name of this application which will be used for Growl bookkeeping. - * @discussion This name is used both internally and in the Growl preferences. - * - * This should remain stable between different versions and incarnations of - * your application. - * For example, "SurfWriter" is a good app name, whereas "SurfWriter 2.0" and - * "SurfWriter Lite" are not. - * - * You do not need to implement this method if you are providing the - * application name elsewhere, meaning in an auto-discoverable plist file in - * your app bundle (XXX refer to more information on that) or in the result - * of -registrationDictionaryForGrowl. - * - * @result The name of the application using Growl. - */ -- (NSString *) applicationNameForGrowl; - -/*! - * @method applicationIconForGrowl - * @abstract Return the NSImage to treat as the application icon. - * @discussion The delegate may optionally return an NSImage - * object to use as the application icon. If this method is not implemented, - * {{{-applicationIconDataForGrowl}}} is tried. If that method is not - * implemented, the application's own icon is used. Neither method is - * generally needed. - * @result The NSImage to treat as the application icon. - */ -- (NSImage *) applicationIconForGrowl; - -/*! - * @method applicationIconDataForGrowl - * @abstract Return the NSData to treat as the application icon. - * @discussion The delegate may optionally return an NSData - * object to use as the application icon; if this is not implemented, the - * application's own icon is used. This is not generally needed. - * @result The NSData to treat as the application icon. - * @deprecated In version 1.1, in favor of {{{-applicationIconForGrowl}}}. - */ -- (NSData *) applicationIconDataForGrowl; - -/*! - * @method growlIsReady - * @abstract Informs the delegate that Growl has launched. - * @discussion Informs the delegate that Growl (specifically, the - * GrowlHelperApp) was launched successfully. The application can take actions - * with the knowledge that Growl is installed and functional. - */ -- (void) growlIsReady; - -/*! - * @method growlNotificationWasClicked: - * @abstract Informs the delegate that a Growl notification was clicked. - * @discussion Informs the delegate that a Growl notification was clicked. It - * is only sent for notifications sent with a non-nil - * clickContext, so if you want to receive a message when a notification is - * clicked, clickContext must not be nil when calling - * +[GrowlApplicationBridge notifyWithTitle: description:notificationName:iconData:priority:isSticky:clickContext:]. - * @param clickContext The clickContext passed when displaying the notification originally via +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:]. - */ -- (void) growlNotificationWasClicked:(id)clickContext; - -/*! - * @method growlNotificationTimedOut: - * @abstract Informs the delegate that a Growl notification timed out. - * @discussion Informs the delegate that a Growl notification timed out. It - * is only sent for notifications sent with a non-nil - * clickContext, so if you want to receive a message when a notification is - * clicked, clickContext must not be nil when calling - * +[GrowlApplicationBridge notifyWithTitle: description:notificationName:iconData:priority:isSticky:clickContext:]. - * @param clickContext The clickContext passed when displaying the notification originally via +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:]. - */ -- (void) growlNotificationTimedOut:(id)clickContext; - - -/*! - * @method hasNetworkClientEntitlement - * @abstract Used only in sandboxed situations since we don't know whether the app has com.apple.security.network.client entitlement - * @discussion GrowlDelegate calls to find out if we have the com.apple.security.network.client entitlement, - * since we can't find this out without hitting the sandbox. We only call it if we detect that the application is sandboxed. - */ -- (BOOL) hasNetworkClientEntitlement; - -@end - -#pragma mark - - -#endif /* __GrowlApplicationBridge_h__ */ diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/GrowlDefines.h b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/GrowlDefines.h deleted file mode 100644 index 0a196f1e3..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Headers/GrowlDefines.h +++ /dev/null @@ -1,386 +0,0 @@ -// -// GrowlDefines.h -// - -#ifndef _GROWLDEFINES_H -#define _GROWLDEFINES_H - -#ifdef __OBJC__ -#define XSTR(x) (@x) -#else -#define XSTR CFSTR -#endif - -/*! @header GrowlDefines.h - * @abstract Defines all the notification keys. - * @discussion Defines all the keys used for registration with Growl and for - * Growl notifications. - * - * Most applications should use the functions or methods of Growl.framework - * instead of posting notifications such as those described here. - * @updated 2004-01-25 - */ - -// UserInfo Keys for Registration -#pragma mark UserInfo Keys for Registration - -/*! @group Registration userInfo keys */ -/* @abstract Keys for the userInfo dictionary of a GROWL_APP_REGISTRATION distributed notification. - * @discussion The values of these keys describe the application and the - * notifications it may post. - * - * Your application must register with Growl before it can post Growl - * notifications (and have them not be ignored). However, as of Growl 0.6, - * posting GROWL_APP_REGISTRATION notifications directly is no longer the - * preferred way to register your application. Your application should instead - * use Growl.framework's delegate system. - * See +[GrowlApplicationBridge setGrowlDelegate:] or Growl_SetDelegate for - * more information. - */ - -/*! @defined GROWL_APP_NAME - * @abstract The name of your application. - * @discussion The name of your application. This should remain stable between - * different versions and incarnations of your application. - * For example, "SurfWriter" is a good app name, whereas "SurfWriter 2.0" and - * "SurfWriter Lite" are not. - */ -#define GROWL_APP_NAME XSTR("ApplicationName") -/*! @defined GROWL_APP_ID - * @abstract The bundle identifier of your application. - * @discussion The bundle identifier of your application. This key should - * be unique for your application while there may be several applications - * with the same GROWL_APP_NAME. - * This key is optional. - */ -#define GROWL_APP_ID XSTR("ApplicationId") -/*! @defined GROWL_APP_ICON_DATA - * @abstract The image data for your application's icon. - * @discussion Image data representing your application's icon. This may be - * superimposed on a notification icon as a badge, used as the notification - * icon when a notification-specific icon is not supplied, or ignored - * altogether, depending on the display. Must be in a format supported by - * NSImage, such as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. - * - * Optional. Not supported by all display plugins. - */ -#define GROWL_APP_ICON_DATA XSTR("ApplicationIcon") -/*! @defined GROWL_NOTIFICATIONS_DEFAULT - * @abstract The array of notifications to turn on by default. - * @discussion These are the names of the notifications that should be enabled - * by default when your application registers for the first time. If your - * application reregisters, Growl will look here for any new notification - * names found in GROWL_NOTIFICATIONS_ALL, but ignore any others. - */ -#define GROWL_NOTIFICATIONS_DEFAULT XSTR("DefaultNotifications") -/*! @defined GROWL_NOTIFICATIONS_ALL - * @abstract The array of all notifications your application can send. - * @discussion These are the names of all of the notifications that your - * application may post. See GROWL_NOTIFICATION_NAME for a discussion of good - * notification names. - */ -#define GROWL_NOTIFICATIONS_ALL XSTR("AllNotifications") -/*! @defined GROWL_NOTIFICATIONS_HUMAN_READABLE_DESCRIPTIONS - * @abstract A dictionary of human-readable names for your notifications. - * @discussion By default, the Growl UI will display notifications by the names given in GROWL_NOTIFICATIONS_ALL - * which correspond to the GROWL_NOTIFICATION_NAME. This dictionary specifies the human-readable name to display. - * The keys of the dictionary are GROWL_NOTIFICATION_NAME strings; the objects are the human-readable versions. - * For any GROWL_NOTIFICATION_NAME not specific in this dictionary, the GROWL_NOTIFICATION_NAME will be displayed. - * - * This key is optional. - */ -#define GROWL_NOTIFICATIONS_HUMAN_READABLE_NAMES XSTR("HumanReadableNames") -/*! @defined GROWL_NOTIFICATIONS_DESCRIPTIONS -* @abstract A dictionary of descriptions of _when_ each notification occurs -* @discussion This is an NSDictionary whose keys are GROWL_NOTIFICATION_NAME strings and whose objects are -* descriptions of _when_ each notification occurs, such as "You received a new mail message" or -* "A file finished downloading". -* -* This key is optional. -*/ -#define GROWL_NOTIFICATIONS_DESCRIPTIONS XSTR("NotificationDescriptions") -/*! @defined GROWL_NOTIFICATIONS_ICONS - * @abstract A dictionary of icons for each notification - * @discussion This is an NSDictionary whose keys are GROWL_NOTIFICATION_NAME strings and whose objects are - * icons for each notification, for GNTP spec - * - * This key is optional. - */ -#define GROWL_NOTIFICATIONS_ICONS XSTR("NotificationIcons") - -/*! @defined GROWL_TICKET_VERSION - * @abstract The version of your registration ticket. - * @discussion Include this key in a ticket plist file that you put in your - * application bundle for auto-discovery. The current ticket version is 1. - */ -#define GROWL_TICKET_VERSION XSTR("TicketVersion") -// UserInfo Keys for Notifications -#pragma mark UserInfo Keys for Notifications - -/*! @group Notification userInfo keys */ -/* @abstract Keys for the userInfo dictionary of a GROWL_NOTIFICATION distributed notification. - * @discussion The values of these keys describe the content of a Growl - * notification. - * - * Not all of these keys are supported by all displays. Only the name, title, - * and description of a notification are universal. Most of the built-in - * displays do support all of these keys, and most other visual displays - * probably will also. But, as of 0.6, the Log, MailMe, and Speech displays - * support only textual data. - */ - -/*! @defined GROWL_NOTIFICATION_NAME - * @abstract The name of the notification. - * @discussion The name of the notification. Note that if you do not define - * GROWL_NOTIFICATIONS_HUMAN_READABLE_NAMES when registering your ticket originally this name - * will the one displayed within the Growl preference pane and should be human-readable. - */ -#define GROWL_NOTIFICATION_NAME XSTR("NotificationName") -/*! @defined GROWL_NOTIFICATION_TITLE - * @abstract The title to display in the notification. - * @discussion The title of the notification. Should be very brief. - * The title usually says what happened, e.g. "Download complete". - */ -#define GROWL_NOTIFICATION_TITLE XSTR("NotificationTitle") -/*! @defined GROWL_NOTIFICATION_DESCRIPTION - * @abstract The description to display in the notification. - * @discussion The description should be longer and more verbose than the title. - * The description usually tells the subject of the action, - * e.g. "Growl-0.6.dmg downloaded in 5.02 minutes". - */ -#define GROWL_NOTIFICATION_DESCRIPTION XSTR("NotificationDescription") -/*! @defined GROWL_NOTIFICATION_ICON - * @discussion Image data for the notification icon. Image data must be in a format - * supported by NSImage, such as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. - * - * Optional. Not supported by all display plugins. - */ -#define GROWL_NOTIFICATION_ICON_DATA XSTR("NotificationIcon") -/*! @defined GROWL_NOTIFICATION_APP_ICON - * @discussion Image data for the application icon, in case GROWL_APP_ICON does - * not apply for some reason. Image data be in a format supported by NSImage, such - * as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. - * - * Optional. Not supported by all display plugins. - */ -#define GROWL_NOTIFICATION_APP_ICON_DATA XSTR("NotificationAppIcon") -/*! @defined GROWL_NOTIFICATION_PRIORITY - * @discussion The priority of the notification as an integer number from - * -2 to +2 (+2 being highest). - * - * Optional. Not supported by all display plugins. - */ -#define GROWL_NOTIFICATION_PRIORITY XSTR("NotificationPriority") -/*! @defined GROWL_NOTIFICATION_STICKY - * @discussion A Boolean number controlling whether the notification is sticky. - * - * Optional. Not supported by all display plugins. - */ -#define GROWL_NOTIFICATION_STICKY XSTR("NotificationSticky") -/*! @defined GROWL_NOTIFICATION_CLICK_CONTEXT - * @abstract Identifies which notification was clicked. - * @discussion An identifier for the notification for clicking purposes. - * - * This will be passed back to the application when the notification is - * clicked. It must be plist-encodable (a data, dictionary, array, number, or - * string object), and it should be unique for each notification you post. - * A good click context would be a UUID string returned by NSProcessInfo or - * CFUUID. - * - * Optional. Not supported by all display plugins. - */ -#define GROWL_NOTIFICATION_CLICK_CONTEXT XSTR("NotificationClickContext") - -/*! @defined GROWL_NOTIFICATION_IDENTIFIER - * @abstract An identifier for the notification for coalescing purposes. - * Notifications with the same identifier fall into the same class; only - * the last notification of a class is displayed on the screen. If a - * notification of the same class is currently being displayed, it is - * replaced by this notification. - * - * Optional. Not supported by all display plugins. - */ -#define GROWL_NOTIFICATION_IDENTIFIER XSTR("GrowlNotificationIdentifier") - -/*! @defined GROWL_APP_PID - * @abstract The process identifier of the process which sends this - * notification. If this field is set, the application will only receive - * clicked and timed out notifications which originate from this process. - * - * Optional. - */ -#define GROWL_APP_PID XSTR("ApplicationPID") - -/*! @defined GROWL_NOTIFICATION_PROGRESS -* @abstract If this key is set, it should contain a double value wrapped -* in a NSNumber which describes some sort of progress (from 0.0 to 100.0). -* If this is key is not set, no progress bar is shown. -* -* Optional. Not supported by all display plugins. -*/ -#define GROWL_NOTIFICATION_PROGRESS XSTR("NotificationProgress") - -/*! @defined GROWL_NOTIFICATION_ALREADY_SHOWN - * @abstract If this key is set, it should contain a bool value wrapped - * in a NSNumber which describes whether the notification has - * already been displayed, for instance by built in Notification - * Center support. This value can be used to allow display - * plugins to skip a notification, while still allowing Growl - * actions to run on them. - * - * Optional. Not supported by all display plugins. - */ -#define GROWL_NOTIFICATION_ALREADY_SHOWN XSTR("AlreadyShown") - - -// Notifications -#pragma mark Notifications - -/*! @group Notification names */ -/* @abstract Names of distributed notifications used by Growl. - * @discussion These are notifications used by applications (directly or - * indirectly) to interact with Growl, and by Growl for interaction between - * its components. - * - * Most of these should no longer be used in Growl 0.6 and later, in favor of - * Growl.framework's GrowlApplicationBridge APIs. - */ - -/*! @defined GROWL_APP_REGISTRATION - * @abstract The distributed notification for registering your application. - * @discussion This is the name of the distributed notification that can be - * used to register applications with Growl. - * - * The userInfo dictionary for this notification can contain these keys: - *
    - *
  • GROWL_APP_NAME
  • - *
  • GROWL_APP_ICON_DATA
  • - *
  • GROWL_NOTIFICATIONS_ALL
  • - *
  • GROWL_NOTIFICATIONS_DEFAULT
  • - *
- * - * No longer recommended as of Growl 0.6. An alternate method of registering - * is to use Growl.framework's delegate system. - * See +[GrowlApplicationBridge setGrowlDelegate:] or Growl_SetDelegate for - * more information. - */ -#define GROWL_APP_REGISTRATION XSTR("GrowlApplicationRegistrationNotification") -/*! @defined GROWL_APP_REGISTRATION_CONF - * @abstract The distributed notification for confirming registration. - * @discussion The name of the distributed notification sent to confirm the - * registration. Used by the Growl preference pane. Your application probably - * does not need to use this notification. - */ -#define GROWL_APP_REGISTRATION_CONF XSTR("GrowlApplicationRegistrationConfirmationNotification") -/*! @defined GROWL_NOTIFICATION - * @abstract The distributed notification for Growl notifications. - * @discussion This is what it all comes down to. This is the name of the - * distributed notification that your application posts to actually send a - * Growl notification. - * - * The userInfo dictionary for this notification can contain these keys: - *
    - *
  • GROWL_NOTIFICATION_NAME (required)
  • - *
  • GROWL_NOTIFICATION_TITLE (required)
  • - *
  • GROWL_NOTIFICATION_DESCRIPTION (required)
  • - *
  • GROWL_NOTIFICATION_ICON
  • - *
  • GROWL_NOTIFICATION_APP_ICON
  • - *
  • GROWL_NOTIFICATION_PRIORITY
  • - *
  • GROWL_NOTIFICATION_STICKY
  • - *
  • GROWL_NOTIFICATION_CLICK_CONTEXT
  • - *
  • GROWL_APP_NAME (required)
  • - *
- * - * No longer recommended as of Growl 0.6. Three alternate methods of posting - * notifications are +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:], - * Growl_NotifyWithTitleDescriptionNameIconPriorityStickyClickContext, and - * Growl_PostNotification. - */ -#define GROWL_NOTIFICATION XSTR("GrowlNotification") -/*! @defined GROWL_PING - * @abstract A distributed notification to check whether Growl is running. - * @discussion This is used by the Growl preference pane. If it receives a - * GROWL_PONG, the preference pane takes this to mean that Growl is running. - */ -#define GROWL_PING XSTR("Honey, Mind Taking Out The Trash") -/*! @defined GROWL_PONG - * @abstract The distributed notification sent in reply to GROWL_PING. - * @discussion GrowlHelperApp posts this in reply to GROWL_PING. - */ -#define GROWL_PONG XSTR("What Do You Want From Me, Woman") -/*! @defined GROWL_IS_READY - * @abstract The distributed notification sent when Growl starts up. - * @discussion GrowlHelperApp posts this when it has begin listening on all of - * its sources for new notifications. GrowlApplicationBridge (in - * Growl.framework), upon receiving this notification, reregisters using the - * registration dictionary supplied by its delegate. - */ -#define GROWL_IS_READY XSTR("Lend Me Some Sugar; I Am Your Neighbor!") - - -/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_CLICKED_SUFFIX - * @abstract Part of the name of the distributed notification sent when a supported notification is clicked. - * @discussion When a Growl notification with a click context is clicked on by - * the user, Growl posts a distributed notification whose name is in the format: - * [NSString stringWithFormat:@"%@-%d-%@", appName, pid, GROWL_DISTRIBUTED_NOTIFICATION_CLICKED_SUFFIX] - * The GrowlApplicationBridge responds to this notification by calling a callback in its delegate. - */ -#define GROWL_DISTRIBUTED_NOTIFICATION_CLICKED_SUFFIX XSTR("GrowlClicked!") - -/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_TIMED_OUT_SUFFIX - * @abstract Part of the name of the distributed notification sent when a supported notification times out without being clicked. - * @discussion When a Growl notification with a click context times out, Growl posts a distributed notification - * whose name is in the format: - * [NSString stringWithFormat:@"%@-%d-%@", appName, pid, GROWL_DISTRIBUTED_NOTIFICATION_TIMED_OUT_SUFFIX] - * The GrowlApplicationBridge responds to this notification by calling a callback in its delegate. - * NOTE: The user may have actually clicked the 'close' button; this triggers an *immediate* time-out of the notification. - */ -#define GROWL_DISTRIBUTED_NOTIFICATION_TIMED_OUT_SUFFIX XSTR("GrowlTimedOut!") - -/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_ON - * @abstract The distributed notification sent when the Notification Center support is toggled on in Growl 2.0 - * @discussion When the user enables Notification Center support in Growl 2.0, this notification is sent - * to inform all running apps that they should now speak to Notification Center directly. - */ -#define GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_ON XSTR("GrowlNotificationCenterOn!") - -/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_OFF - * @abstract The distributed notification sent when the Notification Center support is toggled off in Growl 2.0 - * @discussion When the user enables Notification Center support in Growl 2.0, this notification is sent - * to inform all running apps that they should no longer speak to Notification Center directly. - */ -#define GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_OFF XSTR("GrowlNotificationCenterOff!") - -/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_QUERY - * @abstract The distributed notification sent by an application to query Growl 2.0's notification center support. - * @discussion When an app starts up, it will send this query to get Growl 2.0 to spit out whether notification - * center support is on or off. - */ -#define GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_QUERY XSTR("GrowlNotificationCenterYN?") - - -/*! @group Other symbols */ -/* Symbols which don't fit into any of the other categories. */ - -/*! @defined GROWL_KEY_CLICKED_CONTEXT - * @abstract Used internally as the key for the clickedContext passed over DNC. - * @discussion This key is used in GROWL_NOTIFICATION_CLICKED, and contains the - * click context that was supplied in the original notification. - */ -#define GROWL_KEY_CLICKED_CONTEXT XSTR("ClickedContext") -/*! @defined GROWL_REG_DICT_EXTENSION - * @abstract The filename extension for registration dictionaries. - * @discussion The GrowlApplicationBridge in Growl.framework registers with - * Growl by creating a file with the extension of .(GROWL_REG_DICT_EXTENSION) - * and opening it in the GrowlHelperApp. This happens whether or not Growl is - * running; if it was stopped, it quits immediately without listening for - * notifications. - */ -#define GROWL_REG_DICT_EXTENSION XSTR("growlRegDict") - - -#define GROWL_POSITION_PREFERENCE_KEY @"GrowlSelectedPosition" - -#define GROWL_PLUGIN_CONFIG_ID XSTR("GrowlPluginConfigurationID") - -#endif //ndef _GROWLDEFINES_H diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Resources/Info.plist b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Resources/Info.plist deleted file mode 100644 index 6a90f41b9..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/Resources/Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - BuildMachineOSBuild - 12C60 - CFBundleDevelopmentRegion - English - CFBundleExecutable - Growl - CFBundleIdentifier - com.growl.growlframework - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - FMWK - CFBundleShortVersionString - 2.0.1 - CFBundleSignature - GRRR - CFBundleVersion - 2.0.1 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 4G2008a - DTPlatformVersion - GM - DTSDKBuild - 12C37 - DTSDKName - macosx10.8 - DTXcode - 0452 - DTXcodeBuild - 4G2008a - NSPrincipalClass - GrowlApplicationBridge - - diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/_CodeSignature/CodeResources b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/_CodeSignature/CodeResources deleted file mode 100644 index 420b594ac..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/A/_CodeSignature/CodeResources +++ /dev/null @@ -1,34 +0,0 @@ - - - - - files - - Resources/Info.plist - - VZb3f8My4te/5JwcjfvotgCXTAs= - - - rules - - ^Resources/ - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^version.plist$ - - - - diff --git a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/Current b/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/Current deleted file mode 120000 index 8c7e5a667..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Growl.framework/Versions/Current +++ /dev/null @@ -1 +0,0 @@ -A \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..bfabdabe8 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "icon-16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "icon-16@2x.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "icon-32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "icon-32@2x.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "icon-128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "icon-128@2x.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "icon-256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "icon-256@2x.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "icon-512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "icon-512@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-128.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-128.png new file mode 100644 index 000000000..1006b8206 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-128.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-128@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-128@2x.png new file mode 100644 index 000000000..ea7433539 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-128@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-16.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-16.png new file mode 100644 index 000000000..fc1987cb3 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-16.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-16@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-16@2x.png new file mode 100644 index 000000000..09ae68008 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-16@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-256.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-256.png new file mode 100644 index 000000000..ea7433539 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-256.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-256@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-256@2x.png new file mode 100644 index 000000000..704187e93 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-256@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-32.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-32.png new file mode 100644 index 000000000..09ae68008 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-32.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-32@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-32@2x.png new file mode 100644 index 000000000..fe18ecddb Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-32@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-512.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-512.png new file mode 100644 index 000000000..704187e93 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-512.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-512@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-512@2x.png new file mode 100644 index 000000000..9971fa352 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/AppIcon.appiconset/icon-512@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/Contents.json new file mode 100644 index 000000000..228097351 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "logo-1.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "logo.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/logo-1.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/logo-1.png new file mode 100644 index 000000000..4dd29ab9b Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/logo-1.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/logo.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/logo.png new file mode 100644 index 000000000..082c1748b Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/logo.imageset/logo.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/Contents.json new file mode 100644 index 000000000..61476fab9 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "open-in-editor-white.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "open-in-editor-white@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/open-in-editor-white.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/open-in-editor-white.png new file mode 100644 index 000000000..7561ed193 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/open-in-editor-white.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/open-in-editor-white@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/open-in-editor-white@2x.png new file mode 100644 index 000000000..7c0e08e57 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor-white.imageset/open-in-editor-white@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/Contents.json new file mode 100644 index 000000000..1022c31ea --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "open-in-editor.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "open-in-editor@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/open-in-editor.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/open-in-editor.png new file mode 100644 index 000000000..06f3e010c Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/open-in-editor.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/open-in-editor@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/open-in-editor@2x.png new file mode 100644 index 000000000..ea70b9528 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-editor.imageset/open-in-editor@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/Contents.json new file mode 100644 index 000000000..c3357f076 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "open-in-finder-white.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "open-in-finder-white@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/open-in-finder-white.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/open-in-finder-white.png new file mode 100644 index 000000000..23d975c92 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/open-in-finder-white.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/open-in-finder-white@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/open-in-finder-white@2x.png new file mode 100644 index 000000000..acf0fde6e Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder-white.imageset/open-in-finder-white@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/Contents.json new file mode 100644 index 000000000..96f8df963 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "open-in-finder.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "open-in-finder@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/open-in-finder.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/open-in-finder.png new file mode 100644 index 000000000..4b712fa71 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/open-in-finder.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/open-in-finder@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/open-in-finder@2x.png new file mode 100644 index 000000000..234f7d4b4 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-finder.imageset/open-in-finder@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/Contents.json new file mode 100644 index 000000000..6b7504451 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "open-in-terminal-white.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "open-in-terminal-white@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/open-in-terminal-white.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/open-in-terminal-white.png new file mode 100644 index 000000000..38d2d81d6 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/open-in-terminal-white.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/open-in-terminal-white@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/open-in-terminal-white@2x.png new file mode 100644 index 000000000..8b9190c88 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal-white.imageset/open-in-terminal-white@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/Contents.json new file mode 100644 index 000000000..b145a3411 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "open-in-terminal.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "open-in-terminal@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/open-in-terminal.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/open-in-terminal.png new file mode 100644 index 000000000..eee421bef Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/open-in-terminal.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/open-in-terminal@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/open-in-terminal@2x.png new file mode 100644 index 000000000..7eef41672 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-terminal.imageset/open-in-terminal@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/Contents.json new file mode 100644 index 000000000..d84dcb3cd --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "open-in-xcode-white.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "open-in-xcode-white@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/open-in-xcode-white.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/open-in-xcode-white.png new file mode 100644 index 000000000..ac8a11dea Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/open-in-xcode-white.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/open-in-xcode-white@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/open-in-xcode-white@2x.png new file mode 100644 index 000000000..a5b74ce37 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode-white.imageset/open-in-xcode-white@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/Contents.json new file mode 100644 index 000000000..c79552eef --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "open-in-xcode.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "open-in-xcode@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/open-in-xcode.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/open-in-xcode.png new file mode 100644 index 000000000..889091bbc Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/open-in-xcode.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/open-in-xcode@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/open-in-xcode@2x.png new file mode 100644 index 000000000..2d51078cb Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/open-in-xcode.imageset/open-in-xcode@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/Contents.json new file mode 100644 index 000000000..438fd1e6a --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "resync-white.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "resync-white@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/resync-white.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/resync-white.png new file mode 100644 index 000000000..a6e8bc53f Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/resync-white.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/resync-white@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/resync-white@2x.png new file mode 100644 index 000000000..7c525f305 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync-white.imageset/resync-white@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/Contents.json new file mode 100644 index 000000000..5d1abc1a6 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "resync.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "resync@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/resync.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/resync.png new file mode 100644 index 000000000..5f68a7cbe Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/resync.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/resync@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/resync@2x.png new file mode 100644 index 000000000..eb4a7fe7e Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/resync.imageset/resync@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/Contents.json new file mode 100644 index 000000000..076b3c5a7 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "run-white.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "run-white@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/run-white.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/run-white.png new file mode 100644 index 000000000..f478f54da Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/run-white.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/run-white@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/run-white@2x.png new file mode 100644 index 000000000..6eb4aa61f Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run-white.imageset/run-white@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/Contents.json new file mode 100644 index 000000000..1a623ba9a --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "run.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "run@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/run.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/run.png new file mode 100644 index 000000000..196ae06fe Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/run.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/run@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/run@2x.png new file mode 100644 index 000000000..46ebcfeb3 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/run.imageset/run@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/Contents.json new file mode 100644 index 000000000..4949c3028 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "status-icon-error.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "status-icon-error@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/status-icon-error.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/status-icon-error.png new file mode 100644 index 000000000..40708df3a Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/status-icon-error.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/status-icon-error@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/status-icon-error@2x.png new file mode 100644 index 000000000..d83bbf67e Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-error.imageset/status-icon-error@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/Contents.json new file mode 100644 index 000000000..72969ef8e --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "status-icon-inactive.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "status-icon-inactive@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/status-icon-inactive.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/status-icon-inactive.png new file mode 100644 index 000000000..bf3419bdd Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/status-icon-inactive.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/status-icon-inactive@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/status-icon-inactive@2x.png new file mode 100644 index 000000000..f211be1e9 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-inactive.imageset/status-icon-inactive@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/Contents.json new file mode 100644 index 000000000..7ffae5e38 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "status-icon-working.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "status-icon-working@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/status-icon-working.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/status-icon-working.png new file mode 100644 index 000000000..b30331206 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/status-icon-working.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/status-icon-working@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/status-icon-working@2x.png new file mode 100644 index 000000000..a4fc5eb13 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/status-icon-working.imageset/status-icon-working@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/Contents.json new file mode 100644 index 000000000..3564a183b --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "stop-white.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "stop-white@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/stop-white.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/stop-white.png new file mode 100644 index 000000000..c560752a2 Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/stop-white.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/stop-white@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/stop-white@2x.png new file mode 100644 index 000000000..cc9cd167a Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop-white.imageset/stop-white@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/Contents.json b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/Contents.json new file mode 100644 index 000000000..200b65658 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "stop.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "stop@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/stop.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/stop.png new file mode 100644 index 000000000..0267f32fa Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/stop.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/stop@2x.png b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/stop@2x.png new file mode 100644 index 000000000..9a91a6a4d Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Images.xcassets/stop.imageset/stop@2x.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Info.plist b/Tools/XcodeCapp/XcodeCapp/Info.plist index bb698451f..e3365df23 100644 --- a/Tools/XcodeCapp/XcodeCapp/Info.plist +++ b/Tools/XcodeCapp/XcodeCapp/Info.plist @@ -2,39 +2,60 @@ - XCCLastCappuccinoReleaseURL - https://github.com/cappuccino/cappuccino/archive/0.9.8.zip - XCCLastCappuccinoMasterBranchURL - https://github.com/cappuccino/cappuccino/archive/master.zip + NSUserNotificationAlertStyle + alert CFBundleDevelopmentRegion - English + en + CFBundleDocumentTypes + + + CFBundleTypeIconFile + + CFBundleTypeName + LSItemContentTypes + CFBundleTypeRole + Editor + LSHandlerRank + Default + LSItemContentTypes + + public.folder + + + CFBundleExecutable - ${EXECUTABLE_NAME} + $(EXECUTABLE_NAME) CFBundleIconFile - XcodeCapp.icns + Icon.icns CFBundleIdentifier org.cappuccino.xcodecapp CFBundleInfoDictionaryVersion 6.0 CFBundleName - ${PRODUCT_NAME} + $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString - 3.2 + Version 4.0 CFBundleSignature ???? CFBundleVersion - 3.2 + 1 LSApplicationCategoryType public.app-category.developer-tools - LSUIElement - + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2015 cappuccino-project. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass NSApplication XCCCompatibilityVersion - 3 + 4 + XCCLastCappuccinoMasterBranchURL + https://github.com/cappuccino/cappuccino/archive/master.zip + XCCLastCappuccinoReleaseURL + https://github.com/cappuccino/cappuccino/archive/0.9.8.zip diff --git a/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDASLLogger.m b/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDASLLogger.m index 4ec1e7cbf..540efada1 100755 --- a/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDASLLogger.m +++ b/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDASLLogger.m @@ -45,7 +45,7 @@ static DDASLLogger *sharedInstance; return sharedInstance; } -- (id)init +- (instancetype)init { if (sharedInstance != nil) { diff --git a/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDLog.h b/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDLog.h index 57c2f096c..c24a5e4e2 100755 --- a/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDLog.h +++ b/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDLog.h @@ -487,11 +487,11 @@ NSString *DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy); * If you write custom loggers or formatters, you will be dealing with objects of this class. **/ -enum { +typedef NS_OPTIONS(NSUInteger, DDLogMessageOptions) +{ DDLogMessageCopyFile = 1 << 0, DDLogMessageCopyFunction = 1 << 1, }; -typedef int DDLogMessageOptions; @interface DDLogMessage : NSObject { @@ -534,7 +534,7 @@ typedef int DDLogMessageOptions; * However, if you need them to be copied you may use the options parameter to specify this. * Options is a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction. **/ -- (id)initWithLogMsg:(NSString *)logMsg +- (instancetype)initWithLogMsg:(NSString *)logMsg level:(int)logLevel flag:(int)logFlag context:(int)logContext @@ -548,18 +548,18 @@ typedef int DDLogMessageOptions; * Returns the threadID as it appears in NSLog. * That is, it is a hexadecimal value which is calculated from the machThreadID. **/ -- (NSString *)threadID; +@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSString *threadID; /** * Convenience property to get just the file name, as the file variable is generally the full file path. * This method does not include the file extension, which is generally unwanted for logging purposes. **/ -- (NSString *)fileName; +@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSString *fileName; /** * Returns the function variable in NSString form. **/ -- (NSString *)methodName; +@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSString *methodName; @end @@ -591,7 +591,6 @@ typedef int DDLogMessageOptions; dispatch_queue_t loggerQueue; } -- (id )logFormatter; -- (void)setLogFormatter:(id )formatter; +@property (NS_NONATOMIC_IOSONLY, strong) id logFormatter; @end diff --git a/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDLog.m b/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDLog.m index 7d75d8121..ed21455fd 100755 --- a/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDLog.m +++ b/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDLog.m @@ -786,7 +786,7 @@ NSString *DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy) @implementation DDLoggerNode -- (id)initWithLogger:(id )aLogger loggerQueue:(dispatch_queue_t)aLoggerQueue +- (instancetype)initWithLogger:(id )aLogger loggerQueue:(dispatch_queue_t)aLoggerQueue { if ((self = [super init])) { @@ -834,7 +834,7 @@ static char *dd_str_copy(const char *str) return result; } -- (id)initWithLogMsg:(NSString *)msg +- (instancetype)initWithLogMsg:(NSString *)msg level:(int)level flag:(int)flag context:(int)context @@ -890,7 +890,7 @@ static char *dd_str_copy(const char *str) if (function == NULL) return nil; else - return [[NSString alloc] initWithUTF8String:function]; + return @(function); } - (void)dealloc @@ -913,7 +913,7 @@ static char *dd_str_copy(const char *str) @implementation DDAbstractLogger -- (id)init +- (instancetype)init { if ((self = [super init])) { diff --git a/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDTTYLogger.m b/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDTTYLogger.m index 3157d84e9..599240e43 100755 --- a/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDTTYLogger.m +++ b/Tools/XcodeCapp/XcodeCapp/Lumberjack/DDTTYLogger.m @@ -115,7 +115,7 @@ size_t resetCodeLen; } -- (id)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)mask context:(int)ctxt; +- (instancetype)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)mask context:(int)ctxt NS_DESIGNATED_INITIALIZER; @end @@ -813,7 +813,7 @@ static DDTTYLogger *sharedInstance; return sharedInstance; } -- (id)init +- (instancetype)init { if (sharedInstance != nil) { @@ -827,12 +827,12 @@ static DDTTYLogger *sharedInstance; calendar = [NSCalendar autoupdatingCurrentCalendar]; calendarUnitFlags = 0; - calendarUnitFlags |= NSYearCalendarUnit; - calendarUnitFlags |= NSMonthCalendarUnit; - calendarUnitFlags |= NSDayCalendarUnit; - calendarUnitFlags |= NSHourCalendarUnit; - calendarUnitFlags |= NSMinuteCalendarUnit; - calendarUnitFlags |= NSSecondCalendarUnit; + calendarUnitFlags |= NSCalendarUnitYear; + calendarUnitFlags |= NSCalendarUnitMonth; + calendarUnitFlags |= NSCalendarUnitDay; + calendarUnitFlags |= NSCalendarUnitHour; + calendarUnitFlags |= NSCalendarUnitMinute; + calendarUnitFlags |= NSCalendarUnitSecond; // Initialze 'app' variable (char *) @@ -954,7 +954,7 @@ static DDTTYLogger *sharedInstance; } if (i < [colorProfilesArray count]) - [colorProfilesArray replaceObjectAtIndex:i withObject:newColorProfile]; + colorProfilesArray[i] = newColorProfile; else [colorProfilesArray addObject:newColorProfile]; }}; @@ -992,7 +992,7 @@ static DDTTYLogger *sharedInstance; NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile); - [colorProfilesDict setObject:newColorProfile forKey:tag]; + colorProfilesDict[tag] = newColorProfile; }}; // The design of the setter logic below is taken from the DDAbstractLogger implementation. @@ -1189,7 +1189,7 @@ static DDTTYLogger *sharedInstance; { if (logMessage->tag) { - colorProfile = [colorProfilesDict objectForKey:logMessage->tag]; + colorProfile = colorProfilesDict[logMessage->tag]; } if (colorProfile == nil) { @@ -1359,7 +1359,7 @@ static DDTTYLogger *sharedInstance; @implementation DDTTYLoggerColorProfile -- (id)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)aMask context:(int)ctxt +- (instancetype)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)aMask context:(int)ctxt { if ((self = [super init])) { @@ -1390,7 +1390,7 @@ static DDTTYLogger *sharedInstance; // Map foreground color to closest available shell color fgCodeIndex = [DDTTYLogger codeIndexForColor:fgColor]; - fgCodeRaw = [codes_fg objectAtIndex:fgCodeIndex]; + fgCodeRaw = codes_fg[fgCodeIndex]; NSString *escapeSeq = @"\033["; @@ -1424,7 +1424,7 @@ static DDTTYLogger *sharedInstance; // Map background color to closest available shell color bgCodeIndex = [DDTTYLogger codeIndexForColor:bgColor]; - bgCodeRaw = [codes_bg objectAtIndex:bgCodeIndex]; + bgCodeRaw = codes_bg[bgCodeIndex]; NSString *escapeSeq = @"\033["; diff --git a/Tools/XcodeCapp/XcodeCapp/NSMutableArray+moveIndexes.h b/Tools/XcodeCapp/XcodeCapp/NSMutableArray+moveIndexes.h new file mode 100644 index 000000000..fdfedd6a1 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/NSMutableArray+moveIndexes.h @@ -0,0 +1,15 @@ +// +// NSMutableArray+moveIndexes.h +// XcodeCapp +// +// Created by Antoine Mercadal on 6/2/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@interface NSMutableArray (MoveIndexes) + +- (void)moveIndexes:(NSIndexSet *)indexes toIndex:(NSUInteger)insertIndex; + +@end \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/NSMutableArray+moveIndexes.m b/Tools/XcodeCapp/XcodeCapp/NSMutableArray+moveIndexes.m new file mode 100644 index 000000000..6dadc75d3 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/NSMutableArray+moveIndexes.m @@ -0,0 +1,43 @@ +// +// NSMutableArray+moveIndexes.m +// XcodeCapp +// +// Created by Antoine Mercadal on 6/2/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "NSMutableArray+moveIndexes.h" + +@implementation NSMutableArray (MoveIndexes) + +- (void)moveIndexes:(NSIndexSet *)indexes toIndex:(NSUInteger)insertIndex +{ + NSUInteger aboveCount = 0; + id object; + NSUInteger removeIndex; + + NSUInteger index = [indexes lastIndex]; + + while (index != NSNotFound) + { + if (index >= insertIndex) + { + removeIndex = index + aboveCount; + aboveCount ++; + } + else + { + removeIndex = index; + insertIndex --; + } + + object = self[removeIndex]; + + [self removeObjectAtIndex:removeIndex]; + [self insertObject:object atIndex:insertIndex]; + + index = [indexes indexLessThanIndex:index]; + } +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/Notifications.h b/Tools/XcodeCapp/XcodeCapp/Notifications.h deleted file mode 100644 index b5478399a..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Notifications.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Notifications.h -// XcodeCapp -// -// Created by Aparajita on 4/27/13. -// Copyright (c) 2013 Cappuccino Project. All rights reserved. -// - -#ifndef XcodeCapp_Notifications_h -#define XcodeCapp_Notifications_h - -extern NSString * const XCCProjectDidFinishLoadingNotification; -extern NSString * const XCCBatchDidStartNotification; -extern NSString * const XCCBatchDidEndNotification; -extern NSString * const XCCConversionDidStartNotification; -extern NSString * const XCCConversionDidEndNotification; -extern NSString * const XCCConversionDidGenerateErrorNotification; - -#endif diff --git a/Tools/XcodeCapp/XcodeCapp/Notifications.m b/Tools/XcodeCapp/XcodeCapp/Notifications.m deleted file mode 100644 index b8df14b4f..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Notifications.m +++ /dev/null @@ -1,17 +0,0 @@ -// -// Notifications.m -// XcodeCapp -// -// Created by Aparajita on 4/27/13. -// -// - -#include "Notifications.h" - - -NSString * const XCCProjectDidFinishLoadingNotification = @"XCCProjectDidFinishLoadingNotification"; -NSString * const XCCBatchDidStartNotification = @"XCCBatchDidStartNotification"; -NSString * const XCCBatchDidEndNotification = @"XCCBatchDidEndNotification"; -NSString * const XCCConversionDidStartNotification = @"XCCConversionDidStartNotification"; -NSString * const XCCConversionDidEndNotification = @"XCCConversionDidStopNotification"; -NSString * const XCCConversionDidGenerateErrorNotification = @"XCCConversionDidGenerateErrorNotification"; \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/OperationsView.xib b/Tools/XcodeCapp/XcodeCapp/OperationsView.xib new file mode 100644 index 000000000..b2145b88e --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/OperationsView.xib @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/XcodeCapp/XcodeCapp/ProcessSourceOperation.h b/Tools/XcodeCapp/XcodeCapp/ProcessSourceOperation.h deleted file mode 100644 index e8254ddd4..000000000 --- a/Tools/XcodeCapp/XcodeCapp/ProcessSourceOperation.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// ProcessSourceOperation.h -// XcodeCapp -// -// Created by Aparajita on 4/27/13. -// Copyright (c) 2013 Cappuccino Project. All rights reserved. -// - -#import - -@class XcodeCapp; - - -@interface ProcessSourceOperation : NSOperation - -// sourcePath should be a path within the project (no resolved symlinks) -- (id)initWithXCC:(XcodeCapp *)xcc projectId:(NSNumber *)projectId sourcePath:(NSString *)sourcePath; - -@end diff --git a/Tools/XcodeCapp/XcodeCapp/ProcessSourceOperation.m b/Tools/XcodeCapp/XcodeCapp/ProcessSourceOperation.m deleted file mode 100644 index f41ffbddf..000000000 --- a/Tools/XcodeCapp/XcodeCapp/ProcessSourceOperation.m +++ /dev/null @@ -1,217 +0,0 @@ -// -// ProcessSourceOperation.m -// XcodeCapp -// -// Created by Aparajita on 4/27/13. -// Copyright (c) 2013 Cappuccino Project. All rights reserved. -// - -#import "ProcessSourceOperation.h" -#import "Notifications.h" -#import "XcodeCapp.h" - - -@interface ProcessSourceOperation () - -@property XcodeCapp *xcc; -@property NSNumber *projectId; -@property NSString *sourcePath; -@property NSString *projectPath; - -@end - - -@implementation ProcessSourceOperation - -- (id)initWithXCC:(XcodeCapp *)xcc projectId:(NSNumber *)projectId sourcePath:(NSString *)sourcePath -{ - self = [super init]; - - if (self) - { - self.xcc = xcc; - self.projectId = projectId; - self.sourcePath = sourcePath; - self.projectPath = xcc.projectPath; - } - - return self; -} - -- (void)main -{ - if (self.isCancelled) - return; - - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - - NSDictionary *info = @{ @"projectId":self.projectId, @"path":self.sourcePath}; - [center postNotificationName:XCCConversionDidStartNotification object:self userInfo:info]; - - DDLogVerbose(@"Conversion started: %@", self.sourcePath); - - NSString *launchPath = nil; - NSArray *arguments = nil; - NSString *response = nil; - NSString *projectRelativePath = [self.sourcePath substringFromIndex:self.projectPath.length + 1]; - NSString *notificationTitle = nil; - NSString *notificationMessage = projectRelativePath.lastPathComponent; - - if ([self.xcc isXibFile:self.sourcePath]) - { - launchPath = self.xcc.executablePaths[@"nib2cib"]; - arguments = @[ - @"--no-colors", - self.sourcePath - ]; - - notificationTitle = @"Xib converted"; - } - else if ([self.xcc isObjjFile:self.sourcePath]) - { - launchPath = self.xcc.executablePaths[@"objj"]; - arguments = @[ - self.xcc.parserPath, - self.projectPath, - self.sourcePath - ]; - - notificationTitle = @"Objective-J source processed"; - } - else if ([self.xcc isXCCIgnoreFile:self.sourcePath]) - { - if (self.isCancelled) - return; - - [self.xcc performSelectorOnMainThread:@selector(computeIgnoredPaths) withObject:nil waitUntilDone:NO]; - - notificationTitle = @"Parsed .xcodecapp-ignore"; - notificationMessage = @"Ignored paths updated"; - } - - // Run the task and get the response if needed - NSInteger status = 0; - - if (arguments) - { - if (self.isCancelled) - return; - - DDLogVerbose(@"Running processing task: %@", launchPath); - - NSDictionary *taskResult = [self.xcc runTaskWithLaunchPath:launchPath - arguments:arguments - returnType:kTaskReturnTypeAny]; - - status = [taskResult[@"status"] intValue]; - response = taskResult[@"response"]; - - DDLogInfo(@"Processed %@: [%ld, %@]", self.sourcePath, status, status ? response : @""); - - if (self.isCancelled) - return; - - if (status != 0) - { - if ([self.xcc isXibFile:self.sourcePath]) - { - if (response.length == 0) - response = @"An unspecified error occurred"; - - notificationTitle = @"Error converting xib"; - NSString *message = [NSString stringWithFormat:@"%@\n%@", self.sourcePath.lastPathComponent, response]; - - NSDictionary *info = - @{ - @"projectId":self.projectId, - @"message":message, - @"path":self.sourcePath, - @"status":taskResult[@"status"] - }; - - if (self.isCancelled) - return; - - [center postNotificationName:XCCConversionDidGenerateErrorNotification object:self userInfo:info]; - } - else - { - notificationTitle = [(status == XCCStatusCodeError ? @"Error" : @"Warning") stringByAppendingString:@" parsing Objective-J source"]; - - @try - { - NSArray *errors = [response propertyList]; - - for (NSDictionary *error in errors) - { - [self postErrorNotificationForPath:error[@"path"] line:[error[@"line"] intValue] message:error[@"message"] status:status]; - } - } - @catch (NSException *exception) - { - [self postErrorNotificationForPath:self.sourcePath line:0 message:response status:status]; - } - } - - if ([self.xcc shouldShowErrorNotification]) - [self notifyUserWithTitle:notificationTitle message:notificationMessage]; - } - else if (!self.xcc.isLoadingProject) - { - BOOL showFinalNotification = YES; - - // At this point, we should only detect warnings - if ([self.xcc shouldProcessWithObjjWarnings] && ![self.xcc isXibFile:self.sourcePath]) - { - showFinalNotification = [self.xcc checkObjjWarningsForPath:[NSArray arrayWithObject:self.sourcePath]]; - [self.xcc showObjjWarnings]; - } - - if ([self.xcc shouldProcessWithCappLint] && ![self.xcc isXibFile:self.sourcePath]) - { - showFinalNotification = [self.xcc checkCappLintForPath:[NSArray arrayWithObject:self.sourcePath]] && showFinalNotification; - [self.xcc showCappLintWarnings]; - } - - if (showFinalNotification) - [self notifyUserWithTitle:notificationTitle message:notificationMessage]; - } - } - - if (!self.isCancelled) - { - DDLogVerbose(@"Conversion ended: %@", self.sourcePath); - - [center postNotificationName:XCCConversionDidEndNotification object:self userInfo:@{ @"projectId":self.projectId, @"path":self.sourcePath }]; - } -} - -- (void)postErrorNotificationForPath:(NSString *)path line:(int)line message:(NSString *)message status:(NSInteger)status -{ - NSMutableDictionary *info = [NSMutableDictionary dictionaryWithObjectsAndKeys: - path, @"path", - [NSNumber numberWithInt:line], @"line", - [NSNumber numberWithInteger:status], @"status", - nil]; - - info[@"projectId"] = self.projectId; - info[@"message"] = [NSString stringWithFormat:@"Compilation issue: %@, line %d\n%@", [self.sourcePath lastPathComponent], 0, message]; - - if (self.isCancelled) - return; - - [[NSNotificationCenter defaultCenter] postNotificationName:XCCConversionDidGenerateErrorNotification object:self userInfo:info]; -} - -- (void)notifyUserWithTitle:(NSString *)title message:(NSString *)message -{ - NSDictionary *info = @{ @"projectId":self.projectId, @"title":title, @"message":message }; - - if (self.isCancelled) - return; - - // nib2cib can take a while to run, show a message while the conversion is happening - [self.xcc wantUserNotificationWithInfo:info]; -} - -@end diff --git a/Tools/XcodeCapp/XcodeCapp/Release.xcconfig b/Tools/XcodeCapp/XcodeCapp/Release.xcconfig index 047a9cf0d..2590a2132 100644 --- a/Tools/XcodeCapp/XcodeCapp/Release.xcconfig +++ b/Tools/XcodeCapp/XcodeCapp/Release.xcconfig @@ -13,7 +13,7 @@ ONLY_ACTIVE_ARCH = YES DEBUG_INFORMATION_FORMAT = dwarf COMBINE_HIDPI_IMAGES = YES INSTALL_PATH = $(LOCAL_APPS_DIR) -MACOSX_DEPLOYMENT_TARGET = 10.6.8 +MACOSX_DEPLOYMENT_TARGET = 10.10 COPY_PHASE_STRIP = YES INFOPLIST_FILE = XcodeCapp/Info.plist PRODUCT_NAME = XcodeCapp diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_128x128.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_128x128.png deleted file mode 100644 index ae7b61b39..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_128x128.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_128x128@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_128x128@2x.png deleted file mode 100644 index 2828424ba..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_128x128@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_16x16.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_16x16.png deleted file mode 100644 index 2d980b6e6..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_16x16.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_16x16@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_16x16@2x.png deleted file mode 100644 index d852f1502..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_16x16@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_256x256.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_256x256.png deleted file mode 100644 index 2828424ba..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_256x256.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_256x256@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_256x256@2x.png deleted file mode 100644 index 5459552f2..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_256x256@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_32x32.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_32x32.png deleted file mode 100644 index d852f1502..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_32x32.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_32x32@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_32x32@2x.png deleted file mode 100644 index d90892068..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_32x32@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_512x512.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_512x512.png deleted file mode 100644 index 8428a569f..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_512x512.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_512x512@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_512x512@2x.png deleted file mode 100644 index 8b2cc8ce7..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/XcodeCapp.iconset/icon_512x512@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/edit.png b/Tools/XcodeCapp/XcodeCapp/Resources/edit.png new file mode 100644 index 000000000..42d8da14f Binary files /dev/null and b/Tools/XcodeCapp/XcodeCapp/Resources/edit.png differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/help.pdf b/Tools/XcodeCapp/XcodeCapp/Resources/help.pdf deleted file mode 100644 index d0361b49d..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/help.pdf and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon-active.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon-active.png deleted file mode 100644 index 3d8fd512c..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon-active.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon-active@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon-active@2x.png deleted file mode 100644 index 63189ad30..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon-active@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon-error.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon-error.png deleted file mode 100644 index 1686d61eb..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon-error.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon-error@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon-error@2x.png deleted file mode 100644 index c91c63304..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon-error@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon-inactive.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon-inactive.png deleted file mode 100644 index 526d15262..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon-inactive.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon-inactive@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon-inactive@2x.png deleted file mode 100644 index dab411e5f..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon-inactive@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon-working.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon-working.png deleted file mode 100644 index 537e5d6f9..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon-working.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon-working@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon-working@2x.png deleted file mode 100644 index 24007f775..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon-working@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon_128x128.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon_128x128.png deleted file mode 100644 index ae7b61b39..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon_128x128.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Resources/icon_128x128@2x.png b/Tools/XcodeCapp/XcodeCapp/Resources/icon_128x128@2x.png deleted file mode 100644 index 2828424ba..000000000 Binary files a/Tools/XcodeCapp/XcodeCapp/Resources/icon_128x128@2x.png and /dev/null differ diff --git a/Tools/XcodeCapp/XcodeCapp/Scripts/parser.j b/Tools/XcodeCapp/XcodeCapp/Scripts/parser.j deleted file mode 100644 index 1d4a27fea..000000000 --- a/Tools/XcodeCapp/XcodeCapp/Scripts/parser.j +++ /dev/null @@ -1,613 +0,0 @@ -/* - * parser.j - * - * Created by Francisco Tolmasky. - * Modified by Antoine Mercadal, with great help from Martin Carlberg - * Copyright 2008-2013, 280 North, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -@import - -var FILE = require("file"), - OS = require("os"), - stream = require("narwhal/term").stream, - - SLASH_REPLACEMENT = "∕"; // DIVISION SLASH, Unicode: U+2215 - -// Debug function to print some JS objects -function dump(obj) -{ - print(JSON.stringify(obj)); -} - -function raise(pos, message) -{ - var syntaxError = new SyntaxError(message); - syntaxError.line = pos.line; - - throw syntaxError; -} - -var errors = [], - xcc = ObjectiveJ.acorn.walk.make( - { - ClassDeclarationStatement: function(node, st, c) - { - var className = node.classname.name, - superclassname = node.superclassname ? node.superclassname.name : "", - declaredOutletsName = [], - classInfo = { - "name": className, - "category": node.categoryname ? node.categoryname.name : "", - "superClass": superclassname, - "outlets": [], - "actions": [], - "actionNames": [] - }; - - if (node.ivardeclarations) - { - for (var i = 0; i < node.ivardeclarations.length; ++i) - { - var ivarDecl = node.ivardeclarations[i], - ivarType = ivarDecl.ivartype ? ivarDecl.ivartype.name : null, - ivarName = ivarDecl.id.name, - ivarHasOutlet = ivarDecl.outlet ? "@outlet" : null; - - if (ivarHasOutlet) - { - if (declaredOutletsName.indexOf(ivarName) !== -1) - raise(ivarDecl.loc.start, "Outlet '" + ivarName + "' declared more than once"); - - declaredOutletsName.push(ivarName); - classInfo.outlets.push({"type": ivarType, "name": ivarName}); - } - } - } - - st.push(classInfo) - - for (var i = 0; i < node.body.length; ++i) - c(node.body[i], classInfo, "Statement"); - }, - - MethodDeclarationStatement: function(node, st, c) - { - var selectors = node.selectors, - arguments = node.arguments, - methodReturnType = [node.returntype ? node.returntype.name : "id"], - methodHasAction = node.action ? "IBAction" : null, - selector = selectors[0].name, - actionInfo = {"name": selector, "arguments":[]}; - - if (methodHasAction) - { - if (arguments.length == 1) - { - if (st.actionNames.indexOf(selector) !== -1) - raise(node.loc.start, "Action '" + selector + "' declared more than once"); - - st.actionNames.push(selector); - - for (var i = 0; i < arguments.length; i++) - { - var argument = arguments[i], - argumentName = argument.identifier.name, - argumentType = argument.type ? argument.type.name : null; - - actionInfo.arguments.push({"type": argumentType, "name": argumentName}); - } - - st.actions.push(actionInfo) - } - else - raise(node.loc.start, "Action methods must have exactly one parameter"); - } - } - } -); - -function compile(node, state, visitor) -{ - function c(node, st, override) - { - visitor[override || node.type](node, st, c); - } - - c(node, state); -}; - -function shadowBaseNameForPath(projectBasePath, path) -{ - // Make the path project-relative - path = path.substring(projectBasePath.length + 1, path.length); - - // strip the extension and replace slashes - return path.substring(0, path.length - 2).replace(/[/]/g, SLASH_REPLACEMENT); -} - -/* - $1 Project base path - $2 Full project source path -*/ -function main(args) -{ - try - { - var projectBasePath = args[1], - sourcePath = args[2], - outputDirectory = [projectBasePath stringByAppendingPathComponent:@".XcodeSupport"], - baseFilename = shadowBaseNameForPath(projectBasePath, sourcePath), - outputHeaderURL = new CFURL([outputDirectory stringByAppendingPathComponent:baseFilename + ".h"]), - outputImplementationURL = new CFURL([outputDirectory stringByAppendingPathComponent:baseFilename + ".m"]), - source = FILE.read(sourcePath, { charset: "UTF-8" }), - flags = ObjectiveJ.Preprocessor.Flags.IncludeDebugSymbols | ObjectiveJ.Preprocessor.Flags.IncludeTypeSignatures, - tokens = ObjectiveJ.acorn.parse(source, { locations:true, sourceFile:sourcePath }), - classesInformation = [], - ObjectiveCSource = "", - ObjectiveCHeader = "", - hasErrors = NO; - - compile(tokens, classesInformation, xcc); - - // dump(classesInformation) - - ObjectiveCHeader += - "#import \n" + - '#import "xcc_general_include.h"\n'; - - ObjectiveCSource += "#import \"" + outputHeaderURL.lastPathComponent() + "\"\n"; - - // Traverse each found classes - classesInformation.forEach(function(aClass) - { - // add new class definition - if (aClass.superClass) - ObjectiveCHeader += [CPString stringWithFormat:@"\n@interface %@ : %@", aClass.name, NSCompatibleClassName(aClass.superClass)]; - else - ObjectiveCHeader += [CPString stringWithFormat:@"\n@interface %@ (%@)", aClass.name, aClass.category]; - - // add each outlet in header - if (aClass.outlets.length > 0) - ObjectiveCHeader += "\n"; - - aClass.outlets.forEach(function(anOutlet) - { - ObjectiveCHeader += [CPString stringWithFormat:@"\n@property (assign) IBOutlet %@ %@;", NSCompatibleClassName(anOutlet.type, YES), anOutlet.name]; - }); - - if (aClass.actions.length > 0) - ObjectiveCHeader += "\n"; - - // add each action in header - aClass.actions.forEach(function(anAction) - { - ObjectiveCHeader += [CPString stringWithFormat:@"\n- (IBAction)%@:(%@)%@;", anAction.name, anAction.arguments[0].type, anAction.arguments[0].name]; - }); - - if (aClass.outlets.length > 0 || aClass.actions.length > 0) - ObjectiveCHeader += "\n"; - - ObjectiveCHeader += "\n@end\n"; - - // fill up the implementation file - ObjectiveCSource += "\n@implementation " + aClass.name + "\n@end\n"; - }); - - if (ObjectiveCSource.length) - FILE.write(outputImplementationURL, ObjectiveCSource, { charset:"UTF-8" }); - - if (ObjectiveCHeader.length) - FILE.write(outputHeaderURL, ObjectiveCHeader, { charset:"UTF-8" }); - } - catch (e) - { - [errors addObject:@{ - @"message": e.message, - @"path": sourcePath, - @"line": e.line - }]; - - hasErrors = YES; - } - - if ([errors count]) - { - var plist = [CPPropertyListSerialization dataFromPropertyList:errors format:CPPropertyListXMLFormat_v1_0]; - - stream.printError([plist rawString]); - - // If there were category warnings, hasErrors is NO, so return a warning status - OS.exit(hasErrors ? 1 : 2); - } -} - -function NSCompatibleClassName(aClassName, asPointer) -{ - if (aClassName === "var" || aClassName === "id") - return "id"; - - var prefix = aClassName.substr(0, 2), - asterisk = asPointer ? "*" : ""; - - if (prefix !== "CP") - return aClassName + asterisk; - - var NSClassName = "NS" + aClassName.substr(2); - - if (NSClasses[NSClassName]) - return NSClassName + asterisk; - - if (ReplacementClasses[aClassName]) - return ReplacementClasses[aClassName] + asterisk; - - return aClassName + asterisk; -} - -var ReplacementClasses = { - "CPWebView": "WebView", - "CPRadio": "NSButtonCell", - "CPRadioGroup": "NSMatrix" - }; - -var NSClasses = { - "NSAffineTransform" : YES, - "NSAppleEventDescriptor" : YES, - "NSAppleEventManager" : YES, - "NSAppleScript" : YES, - "NSArchiver" : YES, - "NSArray" : YES, - "NSAssertionHandler" : YES, - "NSAttributedString" : YES, - "NSAutoreleasePool" : YES, - "NSBlockOperation" : YES, - "NSBundle" : YES, - "NSCache" : YES, - "NSCachedURLResponse" : YES, - "NSCalendar" : YES, - "NSCharacterSet" : YES, - "NSClassDescription" : YES, - "NSCloneCommand" : YES, - "NSCloseCommand" : YES, - "NSCoder" : YES, - "NSComparisonPredicate" : YES, - "NSCompoundPredicate" : YES, - "NSCondition" : YES, - "NSConditionLock" : YES, - "NSConnection" : YES, - "NSCountCommand" : YES, - "NSCountedSet" : YES, - "NSCreateCommand" : YES, - "NSData" : YES, - "NSDate" : YES, - "NSDateComponents" : YES, - "NSDateFormatter" : YES, - "NSDecimalNumber" : YES, - "NSDecimalNumberHandler" : YES, - "NSDeleteCommand" : YES, - "NSDeserializer" : YES, - "NSDictionary" : YES, - "NSDirectoryEnumerator" : YES, - "NSDistantObject" : YES, - "NSDistantObjectRequest" : YES, - "NSDistributedLock" : YES, - "NSDistributedNotificationCenter" : YES, - "NSEnumerator" : YES, - "NSError" : YES, - "NSException" : YES, - "NSExistsCommand" : YES, - "NSExpression" : YES, - "NSFileHandle" : YES, - "NSFileManager" : YES, - "NSFileWrapper" : YES, - "NSFormatter" : YES, - "NSGarbageCollector" : YES, - "NSGetCommand" : YES, - "NSHashTable" : YES, - "NSHost" : YES, - "NSHTTPCookie" : YES, - "NSHTTPCookieStorage" : YES, - "NSHTTPURLResponse" : YES, - "NSIndexPath" : YES, - "NSIndexSet" : YES, - "NSIndexSpecifier" : YES, - "NSInputStream" : YES, - "NSInvocation" : YES, - "NSInvocationOperation" : YES, - "NSKeyedArchiver" : YES, - "NSKeyedUnarchiver" : YES, - "NSLocale" : YES, - "NSLock" : YES, - "NSLogicalTest" : YES, - "NSMachBootstrapServer" : YES, - "NSMachPort" : YES, - "NSMapTable" : YES, - "NSMessagePort" : YES, - "NSMessagePortNameServer" : YES, - "NSMetadataItem" : YES, - "NSMetadataQuery" : YES, - "NSMetadataQueryAttributeValueTuple" : YES, - "NSMetadataQueryResultGroup" : YES, - "NSMethodSignature" : YES, - "NSMiddleSpecifier" : YES, - "NSMoveCommand" : YES, - "NSMutableArray" : YES, - "NSMutableAttributedString" : YES, - "NSMutableCharacterSet" : YES, - "NSMutableData" : YES, - "NSMutableDictionary" : YES, - "NSMutableIndexSet" : YES, - "NSMutableSet" : YES, - "NSMutableString" : YES, - "NSMutableURLRequest" : YES, - "NSNameSpecifier" : YES, - "NSNetService" : YES, - "NSNetServiceBrowser" : YES, - "NSNotification" : YES, - "NSNotificationCenter" : YES, - "NSNotificationQueue" : YES, - "NSNull" : YES, - "NSNumber" : YES, - "NSNumberFormatter" : YES, - "NSObject" : YES, - "NSOperation" : YES, - "NSOperationQueue" : YES, - "NSOrthography" : YES, - "NSOutputStream" : YES, - "NSPipe" : YES, - "NSPointerArray" : YES, - "NSPointerFunctions" : YES, - "NSPort" : YES, - "NSPortCoder" : YES, - "NSPortMessage" : YES, - "NSPortNameServer" : YES, - "NSPositionalSpecifier" : YES, - "NSPredicate" : YES, - "NSProcessInfo" : YES, - "NSPropertyListSerialization" : YES, - "NSPropertySpecifier" : YES, - "NSProtocolChecker" : YES, - "NSProxy" : YES, - "NSPurgeableData" : YES, - "NSQuitCommand" : YES, - "NSRandomSpecifier" : YES, - "NSRangeSpecifier" : YES, - "NSRecursiveLock" : YES, - "NSRelativeSpecifier" : YES, - "NSRunLoop" : YES, - "NSScanner" : YES, - "NSScriptClassDescription" : YES, - "NSScriptCoercionHandler" : YES, - "NSScriptCommand" : YES, - "NSScriptCommandDescription" : YES, - "NSScriptExecutionContext" : YES, - "NSScriptObjectSpecifier" : YES, - "NSScriptSuiteRegistry" : YES, - "NSScriptWhoseTest" : YES, - "NSSerializer" : YES, - "NSSet" : YES, - "NSSetCommand" : YES, - "NSSocketPort" : YES, - "NSSocketPortNameServer" : YES, - "NSSortDescriptor" : YES, - "NSSpecifierTest" : YES, - "NSSpellServer" : YES, - "NSStream" : YES, - "NSString" : YES, - "NSTask" : YES, - "NSTextCheckingResult" : YES, - "NSThread" : YES, - "NSTimer" : YES, - "NSTimeZone" : YES, - "NSUnarchiver" : YES, - "NSUndoManager" : YES, - "NSUniqueIDSpecifier" : YES, - "NSURL" : YES, - "NSURLAuthenticationChallenge" : YES, - "NSURLCache" : YES, - "NSURLConnection" : YES, - "NSURLCredential" : YES, - "NSURLCredentialStorage" : YES, - "NSURLDownload" : YES, - "NSURLHandle" : YES, - "NSURLProtectionSpace" : YES, - "NSURLProtocol" : YES, - "NSURLRequest" : YES, - "NSURLResponse" : YES, - "NSUserDefaults" : YES, - "NSValue" : YES, - "NSValueTransformer" : YES, - "NSWhoseSpecifier" : YES, - "NSXMLDocument" : YES, - "NSXMLDTD" : YES, - "NSXMLDTDNode" : YES, - "NSXMLElement" : YES, - "NSXMLNode" : YES, - "NSXMLParser" : YES, - "NSActionCell" : YES, - "NSAffineTransform Additions" : YES, - "NSAlert" : YES, - "NSAnimation" : YES, - "NSAnimationContext" : YES, - "NSAppleScript Additions" : YES, - "NSApplication" : YES, - "NSArrayController" : YES, - "NSATSTypesetter" : YES, - "NSAttributedString Application Kit Additions" : YES, - "NSBezierPath" : YES, - "NSBitmapImageRep" : YES, - "NSBox" : YES, - "NSBrowser" : YES, - "NSBrowserCell" : YES, - "NSBundle Additions" : YES, - "NSButton" : YES, - "NSButtonCell" : YES, - "NSCachedImageRep" : YES, - "NSCell" : YES, - "NSCIImageRep" : YES, - "NSClipView" : YES, - "NSCoder Application Kit Additions" : YES, - "NSCollectionView" : YES, - "NSCollectionViewItem" : YES, - "NSColor" : YES, - "NSColorList" : YES, - "NSColorPanel" : YES, - "NSColorPicker" : YES, - "NSColorSpace" : YES, - "NSColorWell" : YES, - "NSComboBox" : YES, - "NSComboBoxCell" : YES, - "NSControl" : YES, - "NSController" : YES, - "NSCursor" : YES, - "NSCustomImageRep" : YES, - "NSDatePicker" : YES, - "NSDatePickerCell" : YES, - "NSDictionaryController" : YES, - "NSDockTile" : YES, - "NSDocument" : YES, - "NSDocumentController" : YES, - "NSDrawer" : YES, - "NSEPSImageRep" : YES, - "NSEvent" : YES, - "NSFileWrapper" : YES, - "NSFont" : YES, - "NSFontDescriptor" : YES, - "NSFontManager" : YES, - "NSFontPanel" : YES, - "NSForm" : YES, - "NSFormCell" : YES, - "NSGlyphGenerator" : YES, - "NSGlyphInfo" : YES, - "NSGradient" : YES, - "NSGraphicsContext" : YES, - "NSHelpManager" : YES, - "NSImage" : YES, - "NSImageCell" : YES, - "NSImageRep" : YES, - "NSImageView" : YES, - "NSLayoutManager" : YES, - "NSLevelIndicator" : YES, - "NSLevelIndicatorCell" : YES, - "NSMatrix" : YES, - "NSMenu" : YES, - "NSMenuItem" : YES, - "NSMenuItemCell" : YES, - "NSMenuView" : YES, - "NSMutableAttributedString Additions" : YES, - "NSMutableParagraphStyle" : YES, - "NSNib" : YES, - "NSNibConnector" : YES, - "NSNibControlConnector" : YES, - "NSNibOutletConnector" : YES, - "NSObjectController" : YES, - "NSOpenGLContext" : YES, - "NSOpenGLLayer" : YES, - "NSOpenGLPixelBuffer" : YES, - "NSOpenGLPixelFormat" : YES, - "NSOpenGLView" : YES, - "NSOpenPanel" : YES, - "NSOutlineView" : YES, - "NSPageLayout" : YES, - "NSPanel" : YES, - "NSParagraphStyle" : YES, - "NSPasteboard" : YES, - "NSPasteboardItem" : YES, - "NSPathCell" : YES, - "NSPathComponentCell" : YES, - "NSPathControl" : YES, - "NSPDFImageRep" : YES, - "NSPersistentDocument" : YES, - "NSPICTImageRep" : YES, - "NSPopUpButton" : YES, - "NSPopUpButtonCell" : YES, - "NSPredicateEditor" : YES, - "NSPredicateEditorRowTemplate" : YES, - "NSPrinter" : YES, - "NSPrintInfo" : YES, - "NSPrintOperation" : YES, - "NSPrintPanel" : YES, - "NSProgressIndicator" : YES, - "NSResponder" : YES, - "NSRuleEditor" : YES, - "NSRulerMarker" : YES, - "NSRulerView" : YES, - "NSRunningApplication" : YES, - "NSSavePanel" : YES, - "NSScreen" : YES, - "NSScroller" : YES, - "NSScrollView" : YES, - "NSSearchField" : YES, - "NSSearchFieldCell" : YES, - "NSSecureTextField" : YES, - "NSSecureTextFieldCell" : YES, - "NSSegmentedCell" : YES, - "NSSegmentedControl" : YES, - "NSShadow" : YES, - "NSSlider" : YES, - "NSSliderCell" : YES, - "NSSound" : YES, - "NSSpeechRecognizer" : YES, - "NSSpeechSynthesizer" : YES, - "NSSpellChecker" : YES, - "NSSplitView" : YES, - "NSStatusBar" : YES, - "NSStatusItem" : YES, - "NSStepper" : YES, - "NSStepperCell" : YES, - "NSString Application Kit Additions" : YES, - "NSTableCellView" : YES, - "NSTableColumn" : YES, - "NSTableHeaderCell" : YES, - "NSTableHeaderView" : YES, - "NSTableView" : YES, - "NSTabView" : YES, - "NSTabViewItem" : YES, - "NSText" : YES, - "NSTextAttachment" : YES, - "NSTextAttachmentCell" : YES, - "NSTextBlock" : YES, - "NSTextContainer" : YES, - "NSTextField" : YES, - "NSTextFieldCell" : YES, - "NSTextInputContext" : YES, - "NSTextList" : YES, - "NSTextStorage" : YES, - "NSTextTab" : YES, - "NSTextTable" : YES, - "NSTextTableBlock" : YES, - "NSTextView" : YES, - "NSTokenField" : YES, - "NSTokenFieldCell" : YES, - "NSToolbar" : YES, - "NSToolbarItem" : YES, - "NSToolbarItemGroup" : YES, - "NSTouch" : YES, - "NSTrackingArea" : YES, - "NSTreeController" : YES, - "NSTreeNode" : YES, - "NSTypesetter" : YES, - "NSURL Additions" : YES, - "NSUserDefaultsController" : YES, - "NSView" : YES, - "NSViewAnimation" : YES, - "NSViewController" : YES, - "NSWindow" : YES, - "NSWindowController" : YES, - "NSWorkspace" : YES, - "NSPopover": YES - }; diff --git a/Tools/XcodeCapp/XcodeCapp/Scripts/pbxprojModifier.py b/Tools/XcodeCapp/XcodeCapp/Scripts/pbxprojModifier.py index ac2a21a82..0fdacd9af 100755 --- a/Tools/XcodeCapp/XcodeCapp/Scripts/pbxprojModifier.py +++ b/Tools/XcodeCapp/XcodeCapp/Scripts/pbxprojModifier.py @@ -8,7 +8,7 @@ from mod_pbxproj import XcodeProject class PBXModifier (object): XCODE_SUPPORT_FOLDER = u".XcodeSupport" - SLASH_REPLACEMENT = u"∕" # DIVISION SLASH Unicode U+2215 + SLASH_REPLACEMENT = u"::" FRAMEWORKS_RE = re.compile(ur"^(.+/Frameworks/(?:Debug|Source)/([^/]+))/.+$") XCC_GENERAL_INCLUDE = u"xcc_general_include.h" diff --git a/Tools/XcodeCapp/XcodeCapp/Scripts/supawhich b/Tools/XcodeCapp/XcodeCapp/Scripts/supawhich new file mode 100755 index 000000000..39b1dbbd7 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/Scripts/supawhich @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +ARGS=($@) + +echo "{" +for ((i = 0; i < $#; i++)); do + BINARY=${ARGS[$i]} + LOCATION=`which $BINARY` + + if [[ $? == 1 ]]; then + exit 1 + fi + + END="" + + if [[ $i != $(( $# - 1 )) ]]; then + END="," + fi + + echo " \"$BINARY\": \"$LOCATION\"$END" +done; +echo "}" \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/SettingsView.xib b/Tools/XcodeCapp/XcodeCapp/SettingsView.xib new file mode 100644 index 000000000..cbb0a9ae5 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/SettingsView.xib @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/XcodeCapp/XcodeCapp/UserDefaults.h b/Tools/XcodeCapp/XcodeCapp/UserDefaults.h deleted file mode 100644 index ee0539061..000000000 --- a/Tools/XcodeCapp/XcodeCapp/UserDefaults.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// UserDefaults.h -// XcodeCapp -// -// Created by Aparajita on 4/9/13. -// -// - -#ifndef XcodeCapp_UserDefaults_h -#define XcodeCapp_UserDefaults_h - -#import - -extern NSString * const kDefaultLastEventId; -extern NSString * const kDefaultFirstLaunch; -extern NSString * const kDefaultFirstLaunchVersion; -extern NSString * const kDefaultXCCAPIMode; -extern NSString * const kDefaultXCCReactToInodeMod; -extern NSString * const kDefaultXCCReopenLastProject; -extern NSString * const kDefaultXCCAutoOpenErrorsPanelOnErrors; -extern NSString * const kDefaultXCCAutoOpenErrorsPanelOnCappLint; -extern NSString * const kDefaultXCCAutoShowNotificationOnErrors; -extern NSString * const kDefaultXCCAutoShowNotificationOnCappLint; -extern NSString * const kDefaultXCCUseDebugFrameworkWithObjj; -extern NSString * const kDefaultXCCShouldProcessObjj; -extern NSString * const kDefaultXCCProjectHistory; -extern NSString * const kDefaultLastOpenedPath; -extern NSString * const kDefaultPathModificationDates; -extern NSString * const kDefaultMaxRecentProjects; -extern NSString * const kDefaultLogLevel; -extern NSString * const kDefaultAutoOpenXcodeProject; -extern NSString * const kDefaultUseSymlinkWhenCreatingProject; -extern NSString * const kDefaultUpdateCappuccinoWithLastVersionOfMasterBranch; -extern NSString * const kDefaultXCCPanelStyleUtility; -extern NSString * const kDefaultXCCPanelActiveAppWhenOpening; - -#endif diff --git a/Tools/XcodeCapp/XcodeCapp/UserDefaults.m b/Tools/XcodeCapp/XcodeCapp/UserDefaults.m deleted file mode 100644 index 88c919dd2..000000000 --- a/Tools/XcodeCapp/XcodeCapp/UserDefaults.m +++ /dev/null @@ -1,33 +0,0 @@ -// -// UserDefaults.m -// XcodeCapp -// -// Created by Aparajita on 4/9/13. -// -// - -#include "UserDefaults.h" - - -NSString * const kDefaultLastEventId = @"lastEventId"; -NSString * const kDefaultFirstLaunch = @"FirstLaunch"; -NSString * const kDefaultFirstLaunchVersion = @"firstLaunchVersion"; -NSString * const kDefaultXCCAPIMode = @"XCCAPIMode"; -NSString * const kDefaultXCCReactToInodeMod = @"XCCReactMode"; -NSString * const kDefaultXCCReopenLastProject = @"XCCReopenLastProject"; -NSString * const kDefaultXCCAutoOpenErrorsPanelOnErrors = @"XCCAutoOpenErrorsPanelOnErrors"; -NSString * const kDefaultXCCAutoOpenErrorsPanelOnCappLint = @"XCCAutoOpenErrorsPanelOnCappLint"; -NSString * const kDefaultXCCAutoShowNotificationOnErrors = @"XCCAutoOpenShowNotificationErrors"; -NSString * const kDefaultXCCAutoShowNotificationOnCappLint = @"XCCAutoShowNotificationOnCappLint"; -NSString * const kDefaultXCCUseDebugFrameworkWithObjj = @"XCCUseDebugFrameworkWithObjj"; -NSString * const kDefaultXCCShouldProcessObjj = @"XCCShouldProcessObjj"; -NSString * const kDefaultXCCProjectHistory = @"XCCProjectHistory"; -NSString * const kDefaultLastOpenedPath = @"LastOpenedPath"; -NSString * const kDefaultPathModificationDates = @"pathModificationDates"; -NSString * const kDefaultMaxRecentProjects = @"maxRecentProjects"; -NSString * const kDefaultLogLevel = @"logLevel"; -NSString * const kDefaultAutoOpenXcodeProject = @"autoOpenXcodeProject"; -NSString * const kDefaultUseSymlinkWhenCreatingProject = @"useSymlinkWhenCreatingProject"; -NSString * const kDefaultUpdateCappuccinoWithLastVersionOfMasterBranch = @"updateCappuccinoWithLastVersionOfMasterBranch"; -NSString * const kDefaultXCCPanelStyleUtility = @"XCCPanelStyleUtility"; -NSString * const kDefaultXCCPanelActiveAppWhenOpening = @"XCCPanelActiveAppWhenOpening"; \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/XCCAbstractOperation.h b/Tools/XcodeCapp/XcodeCapp/XCCAbstractOperation.h new file mode 100644 index 000000000..34ed0c25c --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCAbstractOperation.h @@ -0,0 +1,28 @@ +// +// XCCAbstractOperation.h +// XcodeCapp +// +// Created by Antoine Mercadal on 6/2/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import +#import "XCCCappuccinoProject.h" + +@class XCCCappuccinoProject; + +@interface XCCAbstractOperation : NSOperation +{ + XCCTaskLauncher *taskLauncher; +} + +@property NSString *operationName; +@property NSString *operationDescription; +@property XCCCappuccinoProject *cappuccinoProject; + +- (instancetype)initWithCappuccinoProject:(XCCCappuccinoProject *)aCappuccinoProject taskLauncher:(XCCTaskLauncher*)aTaskLauncher; +- (void)dispatchNotificationName:(NSString *)notificationName userInfo:(id)userInfo; +- (void)dispatchNotificationName:(NSString *)notificationName; +@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSMutableDictionary *operationInformations; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCAbstractOperation.m b/Tools/XcodeCapp/XcodeCapp/XCCAbstractOperation.m new file mode 100644 index 000000000..da3445b77 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCAbstractOperation.m @@ -0,0 +1,43 @@ +// +// XCCAbstractOperation.m +// XcodeCapp +// +// Created by Antoine Mercadal on 6/2/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCAbstractOperation.h" + + +@implementation XCCAbstractOperation + +- (instancetype)initWithCappuccinoProject:(XCCCappuccinoProject *)aCappuccinoProject taskLauncher:(XCCTaskLauncher*)aTaskLauncher +{ + if (self = [super init]) + { + self.cappuccinoProject = aCappuccinoProject; + self->taskLauncher = aTaskLauncher; + } + + return self; +} + +- (NSMutableDictionary *)operationInformations +{ + return [@{@"cappuccinoProject": self.cappuccinoProject} mutableCopy]; +} + +- (void)dispatchNotificationName:(NSString *)notificationName +{ + [self dispatchNotificationName:notificationName userInfo:[self operationInformations]]; +} + +- (void)dispatchNotificationName:(NSString *)notificationName userInfo:(id)userInfo +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:userInfo]; + }); +} + + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProject.h b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProject.h new file mode 100644 index 000000000..8b6351f06 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProject.h @@ -0,0 +1,78 @@ +// +// CappuccinoProject.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/6/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import +#import "XCCOperationError.h" + +@class XCCTaskLauncher; + +typedef NS_ENUM(NSInteger, XCCCappuccinoProjectStatus) +{ + XCCCappuccinoProjectStatusStopped, + XCCCappuccinoProjectStatusListening +}; + + +extern NSString * const XCCCompatibilityVersionKey; +extern NSString * const XCCCappuccinoProjectBinPathsKey; +extern NSString * const XCCCappuccinoProjectPreviousStatusKey; + + +@interface XCCCappuccinoProject : NSObject +{ + NSMutableDictionary *settings; +} + +@property NSString *supportPath; +@property NSString *projectPath; +@property NSString *name; +@property NSString *nickname; +@property NSString *XcodeProjectPath; +@property NSString *settingsPath; +@property NSString *XcodeCappIgnorePath; +@property NSNumber *lastEventID; +@property NSString *PBXModifierScriptPath; +@property NSMutableDictionary *projectPathsForSourcePaths; +@property NSMutableArray *ignoredPathPredicates; +@property NSString *version; +@property NSString *objjIncludePath; +@property NSMutableArray *binaryPaths; +@property NSString *XcodeCappIgnoreContent; +@property BOOL processObjjWarnings; +@property BOOL processCappLint; +@property BOOL processObjj2ObjcSkeleton; +@property BOOL processNib2Cib; +@property XCCCappuccinoProjectStatus status; +@property XCCCappuccinoProjectStatus previousSavedStatus; + + ++ (BOOL)isObjjFile:(NSString *)path; ++ (BOOL)isXibFile:(NSString *)path; ++ (BOOL)isCibFile:(NSString *)path; ++ (BOOL)isHeaderFile:(NSString *)path; ++ (BOOL)isXCCIgnoreFile:(NSString *)path cappuccinoProject:(XCCCappuccinoProject*)aCappuccinoProject; ++ (BOOL)isSourceFile:(NSString *)path cappuccinoProject:(XCCCappuccinoProject*)aCappuccinoProject; ++ (BOOL)pathMatchesIgnoredPaths:(NSString*)aPath cappuccinoProjectIgnoredPathPredicates:(NSMutableArray*)cappuccinoProjectIgnoredPathPredicates; ++ (BOOL)shouldIgnoreDirectoryNamed:(NSString *)filename; ++ (void)watchSymlinkedDirectoriesAtPath:(NSString *)projectPath pathsToWatch:(NSMutableArray *)pathsToWatch cappuccinoProject:(XCCCappuccinoProject*)aCappuccinoProject; ++ (NSArray *)defaultBinaryPaths; ++ (NSArray *)parseIgnorePaths:(NSArray *)paths basePath:(NSString *)basePath; ++ (NSArray *)getPathsToWatchForCappuccinoProject:(XCCCappuccinoProject*)aCappuccinoProject; + +- (instancetype)initWithPath:(NSString*)aPath; +- (void)reinitialize; +- (void)saveSettings; +- (void)reloadXcodeCappIgnoreFile; + +- (NSString *)projectRelativePathForPath:(NSString *)path; +- (NSString *)shadowBasePathForProjectSourcePath:(NSString *)path; +- (NSString *)sourcePathForShadowPath:(NSString *)path; +- (NSString *)projectPathForSourcePath:(NSString *)path; +- (NSString *)flattenedXcodeSupportFileNameForPath:(NSString *)aPath; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProject.m b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProject.m new file mode 100644 index 000000000..ffedcf1f4 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProject.m @@ -0,0 +1,475 @@ +// +// CappuccinoProject.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/6/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#include + +#import "XCCCappuccinoProject.h" +#import "XCCPath.h" + +static NSArray * XCCDefaultBinaryPaths; +static NSDictionary* XCCCappuccinoProjectDefaultSettings; +static NSString * const XCCSlashReplacement = @"::"; + +static NSPredicate * XCCDirectoriesToIgnorePredicate = nil; +static NSString * const XCCDirectoriesToIgnorePattern = @"^(?:Build|F(?:rameworks|oundation)|AppKit|Objective-J|(?:Browser|CommonJS)\\.environment|Resources|XcodeSupport|.+\\.xcodeproj)$"; + +static NSArray *XCCCappuccinoProjectDefaultIgnoredPaths = nil; + +NSString * const XCCCappuccinoProcessCappLintKey = @"XCCCappuccinoProcessCappLintKey"; +NSString * const XCCCappuccinoProcessObjjKey = @"XCCCappuccinoProcessObjjKey"; +NSString * const XCCCappuccinoProcessNib2CibKey = @"XCCCappuccinoProcessNib2CibKey"; +NSString * const XCCCappuccinoProcessObjj2ObjcSkeletonKey = @"XCCCappuccinoProcessObjj2ObjcSkeletonKey"; +NSString * const XCCCompatibilityVersionKey = @"XCCCompatibilityVersion"; +NSString * const XCCCappuccinoProjectBinPathsKey = @"XCCCappuccinoProjectBinPathsKey"; +NSString * const XCCCappuccinoObjjIncludePathKey = @"XCCCappuccinoObjjIncludePathKey"; +NSString * const XCCCappuccinoProjectNicknameKey = @"XCCCappuccinoProjectNicknameKey"; +NSString * const XCCCappuccinoProjectPreviousStatusKey = @"XCCCappuccinoProjectPreviousStatusKey"; +NSString * const XCCCappuccinoProjectLastEventIDKey = @"XCCCappuccinoProjectLastEventIDKey"; + + + + +@implementation XCCCappuccinoProject + +@synthesize XcodeCappIgnoreContent = _XcodeCappIgnoreContent; +@synthesize status = _status; + +#pragma mark - Class methods + ++ (void)initialize +{ + if (self != [XCCCappuccinoProject class]) + return; + + XCCDefaultBinaryPaths = @[[[XCCPath alloc] initWithName:@"~/bin"]]; + + NSNumber *appCompatibilityVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:XCCCompatibilityVersionKey]; + + XCCDirectoriesToIgnorePredicate = [NSPredicate predicateWithFormat:@"SELF matches %@", XCCDirectoriesToIgnorePattern]; + + XCCCappuccinoProjectDefaultSettings = @{XCCCompatibilityVersionKey: appCompatibilityVersion, + XCCCappuccinoProcessCappLintKey: @NO, + XCCCappuccinoProcessObjjKey: @NO, + XCCCappuccinoProcessNib2CibKey: @YES, + XCCCappuccinoProcessObjj2ObjcSkeletonKey: @YES, + XCCCappuccinoProjectBinPathsKey: [XCCDefaultBinaryPaths valueForKeyPath:@"name"], + XCCCappuccinoObjjIncludePathKey: @"", + XCCCappuccinoProjectNicknameKey: @"", + XCCCappuccinoProjectPreviousStatusKey: @0}; + + XCCCappuccinoProjectDefaultIgnoredPaths = @[ + @"Frameworks/*", + @"Build/*", + @"*.xcodeproj/*", + @".XcodeSupport/*", + @"NS_*.j", + @".xcodecapp-ignore", + @"*.git/*", + @".cappenvs/*", + @"main.j", + @"!Frameworks/Sources" + ]; +} + ++ (NSArray*)defaultBinaryPaths +{ + return XCCDefaultBinaryPaths; +} + ++ (BOOL)isObjjFile:(NSString *)path +{ + return [path.pathExtension.lowercaseString isEqual:@"j"]; +} + ++ (BOOL)isCibFile:(NSString *)path +{ + return [path.pathExtension.lowercaseString isEqual:@"cib"]; +} + ++ (BOOL)isHeaderFile:(NSString *)path +{ + return [path.pathExtension.lowercaseString isEqual:@"h"]; +} + ++ (BOOL)isXibFile:(NSString *)path +{ + NSString *extension = path.pathExtension.lowercaseString; + + if ([extension isEqual:@"xib"] || [extension isEqual:@"nib"]) + { + // Xcode creates temp files called ~.xib. Filter those out. + NSString *baseFilename = path.lastPathComponent.stringByDeletingPathExtension; + + return [baseFilename characterAtIndex:baseFilename.length - 1] != '~'; + } + + return NO; +} + ++ (BOOL)isXCCIgnoreFile:(NSString *)path cappuccinoProject:(XCCCappuccinoProject*)aCappuccinoProject +{ + return [path isEqualToString:aCappuccinoProject.XcodeCappIgnorePath]; +} + ++ (BOOL)isSourceFile:(NSString *)path cappuccinoProject:(XCCCappuccinoProject*)aCappuccinoProject +{ + return ([self isXibFile:path] || [self isObjjFile:path]) && ![self pathMatchesIgnoredPaths:path cappuccinoProjectIgnoredPathPredicates:aCappuccinoProject.ignoredPathPredicates]; +} + ++ (BOOL)shouldIgnoreDirectoryNamed:(NSString *)filename +{ + return [XCCDirectoriesToIgnorePredicate evaluateWithObject:filename]; +} + ++ (BOOL)pathMatchesIgnoredPaths:(NSString*)aPath cappuccinoProjectIgnoredPathPredicates:(NSMutableArray*)cappuccinoProjectIgnoredPathPredicates +{ + BOOL ignore = NO; + + for (NSDictionary *ignoreInfo in cappuccinoProjectIgnoredPathPredicates) + { + BOOL matches = [ignoreInfo[@"predicate"] evaluateWithObject:aPath]; + + if (matches) + ignore = [ignoreInfo[@"exclude"] boolValue]; + } + + return ignore; +} + ++ (NSArray *)parseIgnorePaths:(NSArray *)paths basePath:(NSString *)basePath +{ + NSMutableArray *parsedPaths = [@[] mutableCopy]; + NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet]; + + for (NSString *pattern in paths) + { + if ([pattern stringByTrimmingCharactersInSet:whitespace].length == 0) + continue; + + BOOL exclude = [pattern characterAtIndex:0] != '!'; + NSString *finalPattern = exclude ? pattern : [pattern substringFromIndex:1]; + + NSString *regexPattern = [self globToRegexPattern:[NSString stringWithFormat:@"%@/%@", basePath, finalPattern]]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF matches %@", regexPattern]; + [parsedPaths addObject:@{ @"predicate": predicate, + @"exclude": @(exclude)}]; + } + + return parsedPaths; +} + ++ (NSString *)globToRegexPattern:(NSString *)glob +{ + NSMutableString *regex = [glob mutableCopy]; + + if ([regex characterAtIndex:0] == '!') + [regex deleteCharactersInRange:NSMakeRange(0, 1)]; + + [regex replaceOccurrencesOfString:@"." + withString:@"\\." + options:0 + range:NSMakeRange(0, [regex length])]; + + [regex replaceOccurrencesOfString:@"*" + withString:@".*" + options:0 + range:NSMakeRange(0, [regex length])]; + + // If the glob ends with "/", match that directory and anything below it. + if ([regex characterAtIndex:regex.length - 1] == '/') + [regex replaceCharactersInRange:NSMakeRange(regex.length - 1, 1) withString:@"(?:/.*)?"]; + + return [NSString stringWithFormat:@"^%@$", regex]; +} + ++ (NSArray *)getPathsToWatchForCappuccinoProject:(XCCCappuccinoProject*)aCappuccinoProject +{ + NSMutableArray *pathsToWatch = [@[aCappuccinoProject.projectPath] mutableCopy]; + NSArray *otherPathsToWatch = @[@"", @"Frameworks/Debug", @"Frameworks/Source"]; + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSString *path in otherPathsToWatch) + { + NSString *fullPath = [aCappuccinoProject.projectPath stringByAppendingPathComponent:path]; + + BOOL exists, isDirectory; + exists = [fm fileExistsAtPath:fullPath isDirectory:&isDirectory]; + + if (exists && isDirectory) + [self watchSymlinkedDirectoriesAtPath:path pathsToWatch:pathsToWatch cappuccinoProject:aCappuccinoProject]; + } + + return [pathsToWatch copy]; +} + ++ (void)watchSymlinkedDirectoriesAtPath:(NSString *)projectPath pathsToWatch:(NSMutableArray *)pathsToWatch cappuccinoProject:(XCCCappuccinoProject*)aCappuccinoProject +{ + NSString *fullProjectPath = [aCappuccinoProject.projectPath stringByAppendingPathComponent:projectPath]; + NSError *error = NULL; + NSFileManager *fm = [NSFileManager defaultManager]; + + NSArray *urls = [fm contentsOfDirectoryAtURL:[NSURL fileURLWithPath:fullProjectPath] + includingPropertiesForKeys:@[NSURLIsDirectoryKey, NSURLIsSymbolicLinkKey] + options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants | NSDirectoryEnumerationSkipsSubdirectoryDescendants + error:&error]; + + for (NSURL *url in urls) + { + NSNumber *isSymlink; + [url getResourceValue:&isSymlink forKey:NSURLIsSymbolicLinkKey error:nil]; + + if (isSymlink.boolValue == NO) + continue; + + NSURL *resolvedURL = [url URLByResolvingSymlinksInPath]; + + if (![resolvedURL checkResourceIsReachableAndReturnError:nil]) + continue; + + NSNumber *isDirectory; + [resolvedURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil]; + + if (isDirectory.boolValue == NO) + continue; + + NSString *path = resolvedURL.path; + NSString *filename = path.lastPathComponent; + + if (![self shouldIgnoreDirectoryNamed:filename] && ![self pathMatchesIgnoredPaths:path cappuccinoProjectIgnoredPathPredicates:aCappuccinoProject.ignoredPathPredicates]) + { + DDLogVerbose(@"Watching symlinked directory: %@", path); + + [pathsToWatch addObject:path]; + } + } +} + + +#pragma mark - Init methods + +- (instancetype)initWithPath:(NSString*)aPath +{ + if (self = [super init]) + { + self.name = [aPath lastPathComponent]; + self.nickname = self.name; + self.projectPath = aPath; + self.PBXModifierScriptPath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:@"pbxprojModifier.py"]; + self.XcodeProjectPath = [self.projectPath stringByAppendingPathComponent:[[self.projectPath lastPathComponent] stringByAppendingString:@".xcodeproj"]]; + self.XcodeCappIgnorePath = [self.projectPath stringByAppendingPathComponent:@".xcodecapp-ignore"]; + self.supportPath = [self.projectPath stringByAppendingPathComponent:@".XcodeSupport"]; + self.settingsPath = [self.supportPath stringByAppendingPathComponent:@"Info.plist"]; + + [self _loadSettings]; + + [self reloadXcodeCappIgnoreFile]; + + [self reinitialize]; + } + + return self; +} + +- (void)reinitialize +{ + self.projectPathsForSourcePaths = [@{} mutableCopy]; + self.status = XCCCappuccinoProjectStatusStopped; +} + + +#pragma mark - Settings Management + +- (id)_defaultSettings +{ + NSMutableDictionary *defaultSettings = [XCCCappuccinoProjectDefaultSettings mutableCopy]; + + defaultSettings[XCCCappuccinoObjjIncludePathKey] = [NSString stringWithFormat:@"%@/%@", self.projectPath, @"Frameworks/Debug"]; + defaultSettings[XCCCappuccinoProjectNicknameKey] = self.nickname; + + return defaultSettings; +} + +- (void)_loadSettings +{ + self->settings = [[NSDictionary dictionaryWithContentsOfFile:self.settingsPath] mutableCopy]; + + if (!self->settings) + self->settings = [[self _defaultSettings] mutableCopy]; + + NSMutableArray *mutablePaths = [@[] mutableCopy]; + NSArray *paths = self->settings[XCCCappuccinoProjectBinPathsKey]; + + if (paths) + { + for (NSString *name in paths) + { + XCCPath *path = [XCCPath new]; + [path setName:name]; + [mutablePaths addObject:path]; + } + } + else + { + mutablePaths = [[[self class] defaultBinaryPaths] mutableCopy]; + } + + self.binaryPaths = mutablePaths; + self.nickname = self->settings[XCCCappuccinoProjectNicknameKey]; + self.objjIncludePath = self->settings[XCCCappuccinoObjjIncludePathKey]; + self.version = self->settings[XCCCompatibilityVersionKey]; + self.processObjjWarnings = [self->settings[XCCCappuccinoProcessObjjKey] boolValue]; + self.processCappLint = [self->settings[XCCCappuccinoProcessCappLintKey] boolValue]; + self.processObjj2ObjcSkeleton = [self->settings[XCCCappuccinoProcessObjj2ObjcSkeletonKey] boolValue]; + self.processNib2Cib = [self->settings[XCCCappuccinoProcessNib2CibKey] boolValue]; + self.previousSavedStatus = [self->settings[XCCCappuccinoProjectPreviousStatusKey] intValue]; + + if (self->settings[XCCCappuccinoProjectLastEventIDKey]) + self.lastEventID = self->settings[XCCCappuccinoProjectLastEventIDKey]; +} + +- (void)_writeSettings +{ + NSData *data = [NSPropertyListSerialization dataFromPropertyList:self->settings format:NSPropertyListXMLFormat_v1_0 errorDescription:nil]; + + [data writeToFile:self.settingsPath atomically:YES]; +} + +- (void)saveSettings +{ + self->settings[XCCCappuccinoProjectBinPathsKey] = [self.binaryPaths valueForKeyPath:@"name"]; + self->settings[XCCCappuccinoObjjIncludePathKey] = self.objjIncludePath; + self->settings[XCCCappuccinoProjectNicknameKey] = self.nickname; + self->settings[XCCCompatibilityVersionKey] = self.version; + self->settings[XCCCappuccinoProcessObjjKey] = @(self.processObjjWarnings); + self->settings[XCCCappuccinoProcessCappLintKey] = @(self.processCappLint); + self->settings[XCCCappuccinoProcessObjj2ObjcSkeletonKey] = @(self.processObjj2ObjcSkeleton); + self->settings[XCCCappuccinoProcessNib2CibKey] = @(self.processNib2Cib); + self->settings[XCCCappuccinoProjectPreviousStatusKey] = [NSNumber numberWithInt:self.status]; + + if ([self.lastEventID boolValue]) + self->settings[XCCCappuccinoProjectLastEventIDKey] = self.lastEventID; + + [self _writeXcodeCappIgnoreFile]; + [self _writeSettings]; +} + + +#pragma mark - XcodeCapp Ignore + +- (void)_writeXcodeCappIgnoreFile +{ + NSData *data = [NSPropertyListSerialization dataFromPropertyList:self->settings format:NSPropertyListXMLFormat_v1_0 errorDescription:nil]; + + [data writeToFile:self.settingsPath atomically:YES]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + if ([self.XcodeCappIgnoreContent length]) + [self.XcodeCappIgnoreContent writeToFile:self.XcodeCappIgnorePath atomically:YES encoding:NSASCIIStringEncoding error:nil]; + else if ([fm fileExistsAtPath:self.XcodeCappIgnorePath]) + [fm removeItemAtPath:self.XcodeCappIgnorePath error:nil]; +} + +- (void)_updateXcodeCappIgnorePredicates +{ + self.ignoredPathPredicates = [@[] mutableCopy]; + + @try + { + NSMutableArray *ignoredPatterns = [@[] mutableCopy]; + + for (NSString *pattern in XCCCappuccinoProjectDefaultIgnoredPaths) + [ignoredPatterns addObject:pattern]; + + for (NSString *pattern in [self.XcodeCappIgnoreContent componentsSeparatedByString:@"\n"]) + if ([pattern length]) + [ignoredPatterns addObject:pattern]; + + NSArray *parsedPaths = [XCCCappuccinoProject parseIgnorePaths:ignoredPatterns basePath:self.projectPath]; + [self.ignoredPathPredicates addObjectsFromArray:parsedPaths]; + + DDLogVerbose(@"Content of xcodecapp-ignorepath correctly updated %@", self.ignoredPathPredicates); + } + @catch(NSException *exception) + { + DDLogVerbose(@"Content of xcodecapp-ignorepath does not math the expected input"); + self.ignoredPathPredicates = [@[] mutableCopy]; + } +} + +- (void)reloadXcodeCappIgnoreFile +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + if ([fm fileExistsAtPath:self.XcodeCappIgnorePath]) + self.XcodeCappIgnoreContent = [NSString stringWithContentsOfFile:self.XcodeCappIgnorePath encoding:NSASCIIStringEncoding error:nil]; + else + self.XcodeCappIgnoreContent = @""; //otherwise we prepare the xcc ignore with the default values +} + + +#pragma mark Paths Management + +- (NSString *)projectRelativePathForPath:(NSString *)path +{ + return [path substringFromIndex:self.projectPath.length + 1]; +} + +- (NSString *)projectPathForSourcePath:(NSString *)path +{ + NSString *base = path.stringByDeletingLastPathComponent; + NSString *projectPath = self.projectPathsForSourcePaths[base]; + + return projectPath ? [projectPath stringByAppendingPathComponent:path.lastPathComponent] : path; +} + +- (NSString *)shadowBasePathForProjectSourcePath:(NSString *)path +{ + if (path.isAbsolutePath) + path = [self projectRelativePathForPath:path]; + + NSString *filename = [path.stringByDeletingPathExtension stringByReplacingOccurrencesOfString:@"/" withString:XCCSlashReplacement]; + + return [self.supportPath stringByAppendingPathComponent:filename]; +} + +- (NSString *)sourcePathForShadowPath:(NSString *)path +{ + NSString *filename = [path stringByReplacingOccurrencesOfString:XCCSlashReplacement withString:@"/"]; + filename = [filename.stringByDeletingPathExtension stringByAppendingPathExtension:@"j"]; + + return [self.projectPath stringByAppendingPathComponent:filename]; +} + +- (NSString *)flattenedXcodeSupportFileNameForPath:(NSString *)aPath +{ + NSString *relativePath = [[aPath stringByDeletingPathExtension] stringByReplacingOccurrencesOfString:[self.projectPath stringByAppendingString:@"/"] withString:@""]; + + return [relativePath stringByReplacingOccurrencesOfString:@"/" withString:XCCSlashReplacement]; +} + + +#pragma mark - Custom Getters and Setters + +- (NSString *)XcodeCappIgnoreContent +{ + return _XcodeCappIgnoreContent; +} + +- (void)setXcodeCappIgnoreContent:(NSString *)XcodeCappIgnoreContent +{ + if ([XcodeCappIgnoreContent isEqualToString:_XcodeCappIgnoreContent]) + return; + + [self willChangeValueForKey:@"XcodeCappIgnoreContent"]; + _XcodeCappIgnoreContent = XcodeCappIgnoreContent; + [self _updateXcodeCappIgnorePredicates]; + [self didChangeValueForKey:@"XcodeCappIgnoreContent"]; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectController.h b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectController.h new file mode 100644 index 000000000..c1616306b --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectController.h @@ -0,0 +1,58 @@ +// +// CappuccinoProjectController.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/7/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@class XCCAbstractOperation; +@class XCCCappuccinoProject; +@class XCCTaskLauncher; +@class XCCMainController; +@class XCCPPXOperation; +@class XCCSourcesFinderOperation; + + +@interface XCCCappuccinoProjectController : NSObject +{ + BOOL isListeningToOperationNotifications; + XCCTaskLauncher *taskLauncher; + NSOperationQueue *operationQueue; + FSEventStreamRef stream; + NSMutableDictionary *sourceProcessingOperations; + XCCPPXOperation *pendingPBXOperation; + XCCSourcesFinderOperation *currentFindSourceOperation; +} + +@property CGFloat operationsProgress; +@property NSInteger numberOfErrors; +@property NSInteger operationsTotal; +@property NSMutableDictionary *errors; +@property NSInteger operationsRemaining; +@property NSString *operationsRemainingString; +@property NSString *errorsCountString; +@property XCCCappuccinoProject *cappuccinoProject; +@property XCCMainController *mainXcodeCappController; + +- (instancetype)initWithPath:(NSString*)aPath controller:(id)aController; +- (void)reinitializeProjectFromSettings; +- (void)applicationIsClosing; +- (void)cleanUpBeforeDeletion; +- (void)operationDidStart:(XCCAbstractOperation*)anOperation type:(NSString*)aType userInfo:(NSDictionary*)userInfo; +- (void)operationDidEnd:(XCCAbstractOperation*)anOperation type:(NSString*)aType userInfo:(NSDictionary*)userInfo; +- (void)launchEditorForPath:(NSString*)path line:(NSInteger)line; +- (void)removeAllOperationErrors; +@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSArray *projectRelatedOperations; +; +- (IBAction)cancelAllOperations:(id)aSender; +- (IBAction)resetProject:(id)aSender; +- (IBAction)openProjectInXcode:(id)sender; +- (IBAction)openProjectInFinder:(id)sender; +- (IBAction)openProjectInEditor:(id)sender; +- (IBAction)openProjectInTerminal:(id)sender; +- (IBAction)switchProjectListeningStatus:(id)sender; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectController.m b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectController.m new file mode 100644 index 000000000..d49fca923 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectController.m @@ -0,0 +1,1272 @@ +// +// CappuccinoProjectController.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/7/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "AppDelegate.h" +#import "XCCCappuccinoProjectController.h" +#import "XCCCappuccinoProject.h" +#import "XCCFSEventLogUtils.h" +#import "XCCSourcesFinderOperation.h" +#import "XCCPPXOperation.h" +#import "XCCSourceProcessingOperation.h" +#import "XCCMainController.h" +#import "XCCOperationDataView.h" +#import "XCCOperationError.h" +#import "XCCOperationErrorDataView.h" +#import "XCCOperationErrorHeaderDataView.h" +#import "XCCTaskLauncher.h" +#import "XCCUserDefaults.h" +#import "XcodeProjectCloser.h" +#import "XCCOperationsViewController.h" +#import "XCCErrorsViewController.h" + +static FSEventStreamCreateFlags const XCCProjectControllerFSEventFlags = kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagWatchRoot + | kFSEventStreamCreateFlagIgnoreSelf | kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents; +typedef NS_ENUM(NSInteger, XCCLineSpecifier) +{ + kLineSpecifierNone, + kLineSpecifierColon, + kLineSpecifierMinusL, + kLineSpecifierPlus +}; + + +@interface XCCCappuccinoProjectController () +- (void)_handleFSEventsWithPaths:(NSArray *)paths flags:(const FSEventStreamEventFlags[])eventFlags ids:(const FSEventStreamEventId[])eventIds; +@end + +void fsevents_callback(ConstFSEventStreamRef streamRef, void *userData, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) +{ + XCCCappuccinoProjectController *controller = (__bridge XCCCappuccinoProjectController *)userData; + NSArray *paths = (__bridge NSArray *)eventPaths; + + [controller _handleFSEventsWithPaths:paths flags:eventFlags ids:eventIds]; +} + + + +@implementation XCCCappuccinoProjectController + +@synthesize numberOfErrors = _numberOfErrors; + +#pragma mark - Init methods + +- (instancetype)initWithPath:(NSString*)aPath controller:(id)aController +{ + if (self = [super init]) + { + [self _startListeningToOperationsNotifications]; + + self.cappuccinoProject = [[XCCCappuccinoProject alloc] initWithPath:aPath]; + self.mainXcodeCappController = aController; + self->sourceProcessingOperations = [@{} mutableCopy]; + self->operationQueue = [[NSApp delegate] mainOperationQueue]; + + [self _reinitializeProjectController]; + } + + return self; +} + +- (void)_reinitializeProjectController +{ + [self.cappuccinoProject reinitialize]; + [self _reinitializeOperationsCounters]; + [self _reinitializeOperationErrors]; + [self _prepareXcodeSupport]; +} + +- (void)_reinitializeTaskLauncher +{ + NSArray *binaryPaths = @[]; + + if ([self.cappuccinoProject.binaryPaths count]) + binaryPaths = [self.cappuccinoProject.binaryPaths valueForKeyPath:@"name"]; + + self->taskLauncher = [[XCCTaskLauncher alloc] initWithEnvironmentPaths:binaryPaths]; + + if (!self->taskLauncher.isValid) + { + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + + NSRunAlertPanel( + self.cappuccinoProject.nickname, + @"XcodeCapp was unable to find all necessary executables in your environment:\n\n" + @"%@\n\n" + @"You certainly need to change the binary paths in the project settings.", + @"OK", + nil, + nil, + [self->taskLauncher.executables componentsJoinedByString:@", "]); + + [self _reinitializeProjectController]; + } +} + + +#pragma mark - Project State Management + +- (void)_startListeningToProject +{ + if (![self _projectPathExists] || self.cappuccinoProject.status == XCCCappuccinoProjectStatusListening) + return; + + DDLogInfo(@"Start to listen project: %@", self.cappuccinoProject.projectPath); + + [self _synchronizeXcodeSupport]; + + if (self->taskLauncher.isValid) + { + [self _startFSEventStream]; + + // this is needed in order to ensure we get a FS event, so we actually get a valid last event ID. + [self->taskLauncher runTaskWithCommand:@"touch" arguments:@[self.cappuccinoProject.settingsPath] returnType:kTaskReturnTypeNone]; + + self.cappuccinoProject.status = XCCCappuccinoProjectStatusListening; + } + + [self.cappuccinoProject saveSettings]; +} + +- (void)_stopListeningToProject +{ + if (self.cappuccinoProject.status == XCCCappuccinoProjectStatusStopped) + return; + + [self _cancelAllProjectRelatedOperations]; + [self _stopFSEventStream]; + + [self.mainXcodeCappController.errorsViewController cleanProjectErrors:self]; + + self.cappuccinoProject.status = XCCCappuccinoProjectStatusStopped; + [self.cappuccinoProject saveSettings]; +} + + +#pragma mark - XcodeSupport Management + +- (BOOL)_projectPathExists +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + if (![fm fileExistsAtPath:self.cappuccinoProject.projectPath isDirectory:nil]) + { + NSRunAlertPanel(@"The project can’t be located.", @"It seems the project moved while XcodeCapp was not running.", @"Remove Project", nil, nil); + + [self.mainXcodeCappController unmanageCappuccinoProjectController:self]; + return NO; + } + + return YES; +} + +- (void)_synchronizeXcodeSupport +{ + DDLogInfo(@"Synchronize project: %@", self.cappuccinoProject.projectPath); + + [self _reinitializeProjectController]; + [self _reinitializeTaskLauncher]; + + if (!self->taskLauncher.isValid) + return; + + [self _synchronizeXcodeSupportFromPath:@""]; +} + +- (void)_prepareXcodeSupport +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + BOOL projectExists, projectIsDirectory; + projectExists = [fm fileExistsAtPath:self.cappuccinoProject.XcodeProjectPath isDirectory:&projectIsDirectory]; + + BOOL supportExists, supportIsDirectory; + supportExists = [fm fileExistsAtPath:self.cappuccinoProject.supportPath isDirectory:&supportIsDirectory]; + + if (!projectExists || !projectIsDirectory || !supportExists) + [self _createXcodeProject]; + + if (!supportExists || !supportIsDirectory || !projectExists || ![self _isXcodeSupportCompatible]) + [self _createXcodeSupportDirectory]; +} + +- (BOOL)_isXcodeSupportCompatible +{ + double appCompatibilityVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:XCCCompatibilityVersionKey] doubleValue]; + + NSNumber *projectCompatibilityVersion = @([self.cappuccinoProject.version intValue]); + + if (projectCompatibilityVersion == nil) + { + DDLogVerbose(@"No compatibility version in project"); + return NO; + } + + DDLogVerbose(@"XcodeCapp/project compatibility version: %0.1f/%0.1f", projectCompatibilityVersion.doubleValue, appCompatibilityVersion); + + return projectCompatibilityVersion.doubleValue >= appCompatibilityVersion; +} + +- (void)_createXcodeProject +{ + [self _removeXcodeProject]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + [fm createDirectoryAtPath:self.cappuccinoProject.XcodeProjectPath withIntermediateDirectories:YES attributes:nil error:nil]; + + NSString *pbxPath = [self.cappuccinoProject.XcodeProjectPath stringByAppendingPathComponent:@"project.pbxproj"]; + + [fm copyItemAtPath:[[NSBundle mainBundle] pathForResource:@"project" ofType:@"pbxproj"] toPath:pbxPath error:nil]; + + NSMutableString *content = [NSMutableString stringWithContentsOfFile:pbxPath encoding:NSUTF8StringEncoding error:nil]; + + [content writeToFile:pbxPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; + + DDLogInfo(@"Xcode support project created at: %@", self.cappuccinoProject.XcodeProjectPath); +} + +- (void)_removeXcodeProject +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + if ([fm fileExistsAtPath:self.cappuccinoProject.XcodeProjectPath]) + [fm removeItemAtPath:self.cappuccinoProject.XcodeProjectPath error:nil]; +} + +- (void)_createXcodeSupportDirectory +{ + [self _removeXcodeSupportDirectory]; + + [[NSFileManager defaultManager] createDirectoryAtPath:self.cappuccinoProject.supportPath withIntermediateDirectories:YES attributes:nil error:nil]; + + [self.cappuccinoProject saveSettings]; + + DDLogInfo(@".XcodeSupport directory created at: %@", self.cappuccinoProject.supportPath); +} + +- (void)_removeXcodeSupportDirectory +{ + [XcodeProjectCloser closeXcodeProjectForProject:self.cappuccinoProject.projectPath]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + if ([fm fileExistsAtPath:self.cappuccinoProject.supportPath]) + [fm removeItemAtPath:self.cappuccinoProject.supportPath error:nil]; +} + +- (void)_synchronizeXcodeSupportFromPath:(NSString *)path +{ + self->operationQueue.suspended = YES; + [self _cancelCurrentSourceFinderOperation]; + [self _scheduleFinderSourceOperationForPath:path]; + self->operationQueue.suspended = NO; +} + +- (void)_removeXcodeSupportOrphanFiles +{ + NSArray *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.cappuccinoProject.supportPath error:nil]; + NSMutableArray *orphanFiles = [@[] mutableCopy]; + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSString *path in subpaths) + { + if ([XCCCappuccinoProject isHeaderFile:path] && ![path.lastPathComponent isEqualToString:@"xcc_general_include.h"]) + { + NSString *sourcePath = [self.cappuccinoProject sourcePathForShadowPath:path]; + + if (![fm fileExistsAtPath:sourcePath]) + [orphanFiles addObject:sourcePath]; + } + } + + NSMutableArray *pathsToRemove = [@[] mutableCopy]; + + for (NSString *sourcePath in orphanFiles) + { + NSString *shadowBasePath = [self.cappuccinoProject shadowBasePathForProjectSourcePath:sourcePath]; + NSString *shadowHeaderPath = [shadowBasePath stringByAppendingPathExtension:@"h"]; + NSString *shadowImplementationPath = [shadowBasePath stringByAppendingPathExtension:@"m"]; + + [fm removeItemAtPath:shadowHeaderPath error:nil]; + [fm removeItemAtPath:shadowImplementationPath error:nil]; + + [self removeOperationErrorsRelatedToSourcePath:sourcePath errorType:XCCDefaultOperationErrorType]; + + [pathsToRemove addObject:sourcePath]; + } + + [self.mainXcodeCappController.errorsViewController reload]; + + if (self->pendingPBXOperation) + [self->pendingPBXOperation registerPathsToRemoveFromPBX:pathsToRemove]; + else + [self _schedulePBXOperationWithPathsToAdd:nil pathsToRemove:pathsToRemove]; + +} + +- (void)_updateXcodeSupportFilesWithModifiedPaths:(NSArray *)modifiedPaths +{ + DDLogVerbose(@"Modified files: %@", modifiedPaths); + + for (NSString *path in modifiedPaths) + { + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) + continue; + + [self _scheduleSourceProcessingOperationForPath:path]; + } + + [self _removeXcodeSupportOrphanFiles]; + + [self _updateOperationsProgress]; +} + +- (void)_updateXcodeSupportFilesWithRenamedDirectories:(NSArray *)directories +{ + DDLogVerbose(@"Renamed directories: %@", directories); + + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSString *directory in directories) + { + if ([directory isEqualToString:self.cappuccinoProject.projectPath]) + continue; + + if ([fm fileExistsAtPath:directory]) + { + if ([directory hasPrefix:self.cappuccinoProject.projectPath]) + [self _synchronizeXcodeSupportFromPath:[self.cappuccinoProject projectRelativePathForPath:directory]]; + else + { + [self _synchronizeXcodeSupportFromPath:@""]; + break; + } + } + } + + [self _removeXcodeSupportOrphanFiles]; +} + + +#pragma mark - Notifications + +- (void)_startListeningToOperationsNotifications +{ + if (self->isListeningToOperationNotifications) + return; + + self->isListeningToOperationNotifications = YES; + + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + + [center addObserver:self selector:@selector(_didReceiveConversionDidStartNotification:) name:XCCConversionDidStartNotification object:nil]; + [center addObserver:self selector:@selector(_didReceiveConversionDidEndNotification:) name:XCCConversionDidEndNotification object:nil]; + + [center addObserver:self selector:@selector(_didReceiveSourcesFinderOperationDidStartNotification:) name:XCCSourcesFinderOperationDidStartNotification object:nil]; + [center addObserver:self selector:@selector(_didReceiveSourcesFinderOperationDidEndNotification:) name:XCCSourcesFinderOperationDidEndNotification object:nil]; + [center addObserver:self selector:@selector(_didReceiveNeedSourceToProjectPathMappingNotification:) name:XCCNeedSourceToProjectPathMappingNotification object:nil]; + + [center addObserver:self selector:@selector(_didReceiveObjj2ObjcSkeletonDidStartNotification:) name:XCCObjj2ObjcSkeletonDidStartNotification object:nil]; + [center addObserver:self selector:@selector(_didReceiveObjj2ObjcSeleketonDidGenerateErrorNotification:) name:XCCObjj2ObjcSkeletonDidGenerateErrorNotification object:nil]; + + [center addObserver:self selector:@selector(_didReceiveNib2CibDidStartNotifcation:) name:XCCNib2CibDidStartNotification object:nil]; + [center addObserver:self selector:@selector(_didReceiveNib2CibDidGenerateErrorNotification:) name:XCCNib2CibDidGenerateErrorNotification object:nil]; + + [center addObserver:self selector:@selector(_didReceiveObjjDidStartNotification:) name:XCCObjjDidStartNotification object:nil]; + [center addObserver:self selector:@selector(_didReceiveObjjDidGenerateErrorNotification:) name:XCCObjjDidGenerateErrorNotification object:nil]; + + [center addObserver:self selector:@selector(_didReceiveCappLintDidStartNotification:) name:XCCCappLintDidStartNotification object:nil]; + [center addObserver:self selector:@selector(_didReceiveCappLintDidGenerateErrorNotification:) name:XCCCappLintDidGenerateErrorNotification object:nil]; + + [center addObserver:self selector:@selector(_didReceiveUpdatePbxFileDidStartNotification:) name:XCCPBXOperationDidStartNotification object:nil]; + [center addObserver:self selector:@selector(_didReceiveUpdatePbxFileDidEndNotification:) name:XCCPBXOperationDidEndNotification object:nil]; +} + +- (void)_stopListeningToOperationsNotifications +{ + if (!self->isListeningToOperationNotifications) + return; + + self->isListeningToOperationNotifications = NO; + + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + + [center removeObserver:self name:XCCConversionDidStartNotification object:nil]; + [center removeObserver:self name:XCCConversionDidEndNotification object:nil]; + + [center removeObserver:self name:XCCSourcesFinderOperationDidStartNotification object:nil]; + [center removeObserver:self name:XCCSourcesFinderOperationDidEndNotification object:nil]; + [center removeObserver:self name:XCCNeedSourceToProjectPathMappingNotification object:nil]; + + [center removeObserver:self name:XCCObjj2ObjcSkeletonDidStartNotification object:nil]; + [center removeObserver:self name:XCCObjj2ObjcSkeletonDidGenerateErrorNotification object:nil]; + + [center removeObserver:self name:XCCNib2CibDidStartNotification object:nil]; + [center removeObserver:self name:XCCNib2CibDidGenerateErrorNotification object:nil]; + + [center removeObserver:self name:XCCObjjDidStartNotification object:nil]; + [center removeObserver:self name:XCCObjjDidGenerateErrorNotification object:nil]; + + [center removeObserver:self name:XCCCappLintDidStartNotification object:nil]; + [center removeObserver:self name:XCCCappLintDidGenerateErrorNotification object:nil]; + + [center removeObserver:self name:XCCPBXOperationDidStartNotification object:nil]; + [center removeObserver:self name:XCCPBXOperationDidEndNotification object:nil]; + +} + +- (BOOL)_doesNotificationBelongToCurrentProject:(NSNotification *)note +{ + return note.userInfo[@"cappuccinoProject"] == self.cappuccinoProject; +} + +- (void)_didReceiveConversionDidStartNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self _schedulePBXOperation]; + [self->pendingPBXOperation registerPathsToAddInPBX:@[note.userInfo[@"sourcePath"]]]; + + [self operationDidStart:note.object type:note.name userInfo:note.userInfo]; +} + +- (void)_didReceiveConversionDidEndNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self.mainXcodeCappController reloadTotalNumberOfErrors]; + + [self operationDidEnd:note.object type:note.name userInfo:note.userInfo]; +} + +- (void)_didReceiveSourcesFinderOperationDidStartNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self operationDidStart:note.object type:note.name userInfo:note.userInfo]; +} + +- (void)_didReceiveSourcesFinderOperationDidEndNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self operationDidEnd:note.object type:note.name userInfo:note.userInfo]; +} + +- (void)_didReceiveNeedSourceToProjectPathMappingNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + self.cappuccinoProject.projectPathsForSourcePaths[note.userInfo[@"sourcePath"]] = note.userInfo[@"projectPath"]; +} + +- (void)_didReceiveObjj2ObjcSkeletonDidStartNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self removeOperationErrorsRelatedToSourcePath:note.userInfo[@"sourcePath"] errorType:XCCObjj2ObjcSkeletonOperationErrorType]; +} + +- (void)_didReceiveObjj2ObjcSeleketonDidGenerateErrorNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + for (XCCOperationError *operationError in [XCCOperationError operationErrorsFromObjj2ObjcSkeletonInfo:note.userInfo]) + [self addOperationError:operationError]; +} + +- (void)_didReceiveNib2CibDidStartNotifcation:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self removeOperationErrorsRelatedToSourcePath:note.userInfo[@"sourcePath"] errorType:XCCNib2CibOperationErrorType]; +} + +- (void)_didReceiveNib2CibDidGenerateErrorNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self addOperationError:[XCCOperationError operationErrorFromNib2CibInfo:note.userInfo]]; +} + +- (void)_didReceiveObjjDidStartNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self removeOperationErrorsRelatedToSourcePath:note.userInfo[@"sourcePath"] errorType:XCCObjjOperationErrorType]; +} + +- (void)_didReceiveObjjDidGenerateErrorNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + for (XCCOperationError *operationError in [XCCOperationError operationErrorsFromObjjInfo:note.userInfo]) + [self addOperationError:operationError]; +} + +- (void)_didReceiveCappLintDidStartNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self removeOperationErrorsRelatedToSourcePath:note.userInfo[@"sourcePath"] errorType:XCCCappLintOperationErrorType]; +} + +- (void)_didReceiveCappLintDidGenerateErrorNotification:(NSNotification *)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + for (XCCOperationError *operationError in [XCCOperationError operationErrorsFromCappLintInfo:note.userInfo]) + [self addOperationError:operationError]; +} + +- (void)_didReceiveUpdatePbxFileDidStartNotification:(NSNotification*)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self operationDidStart:note.object type:note.name userInfo:note.userInfo]; +} + +- (void)_didReceiveUpdatePbxFileDidEndNotification:(NSNotification*)note +{ + if (![self _doesNotificationBelongToCurrentProject:note]) + return; + + [self operationDidEnd:note.object type:note.name userInfo:note.userInfo]; +} + + +#pragma mark - OperationError Management + +- (void)addOperationError:(XCCOperationError *)operationError +{ + if (!operationError.fileName) + operationError.fileName = @"/No Filename"; + + [self willChangeValueForKey:@"errors"]; + + if (!self.errors[operationError.fileName]) + self.errors[operationError.fileName] = [@[] mutableCopy]; + + [self.errors[operationError.fileName] addObject:operationError]; + + [self didChangeValueForKey:@"errors"]; + self.numberOfErrors++; + + [self _notifyUserWithOperationError:operationError]; +} + +- (void)removeOperationError:(XCCOperationError *)operationError +{ + if (!operationError.fileName) + operationError.fileName = @"/No Filename"; + + [self willChangeValueForKey:@"errors"]; + + [self.errors[operationError.fileName] removeObject:operationError]; + + if (![self.errors[operationError.fileName] count]) + [self.errors removeObjectForKey:operationError.fileName]; + + [self didChangeValueForKey:@"errors"]; + self.numberOfErrors--; +} + +- (void)removeAllOperationErrors +{ + [self willChangeValueForKey:@"errors"]; + [self.errors removeAllObjects]; + [self didChangeValueForKey:@"errors"]; + self.numberOfErrors = 0; +} + +- (void)removeOperationErrorsRelatedToSourcePath:(NSString *)aPath errorType:(int)anErrorType +{ + NSMutableArray *errorsToRemove = [@[] mutableCopy]; + + for (XCCOperationError *operationError in self.errors[aPath]) + if ([operationError.fileName isEqualToString:aPath] && (operationError.errorType == anErrorType || anErrorType == XCCDefaultOperationErrorType)) + [errorsToRemove addObject:operationError]; + + for (XCCOperationError *error in errorsToRemove) + [self removeOperationError:error]; +} + +- (NSInteger)numberOfErrors +{ + return _numberOfErrors; +} + +- (void)setNumberOfErrors:(NSInteger)numberOfErrors +{ + if (numberOfErrors == _numberOfErrors) + return; + + [self willChangeValueForKey:@"numberOfErrors"]; + _numberOfErrors = numberOfErrors; + [self didChangeValueForKey:@"numberOfErrors"]; + + if (!_numberOfErrors) + self.errorsCountString = @""; + else + { + NSString *plural1 = self.numberOfErrors > 1 ? @"s" : @""; + NSString *plural2 = self.errors.count > 1 ? @"s" : @""; + self.errorsCountString = [NSString stringWithFormat:@"%d issue%@ in %d file%@", (int)self.numberOfErrors, plural1, (int)self.errors.count, plural2]; + } +} + +- (void)_reinitializeOperationErrors +{ + self.errors = [@{} mutableCopy]; + self.numberOfErrors = 0; +} + + +#pragma mark - Operation Management + +- (void)operationDidStart:(XCCAbstractOperation*)anOperation type:(NSString *)aType userInfo:(NSDictionary*)userInfo +{ + [self.mainXcodeCappController.operationsViewController reload]; + [self.mainXcodeCappController.errorsViewController reload]; +} + +- (void)operationDidEnd:(XCCAbstractOperation*)anOperation type:(NSString *)aType userInfo:(NSDictionary*)userInfo +{ + [self _dequeueOperation:anOperation]; + + if ([aType isEqualToString:XCCSourcesFinderOperationDidEndNotification]) + { + self->currentFindSourceOperation = nil; + [self _updateXcodeSupportFilesWithModifiedPaths:userInfo[@"sourcePaths"]]; + } + else if ([aType isEqualToString:XCCPBXOperationDidEndNotification]) + { + self->pendingPBXOperation = nil; + } + + if (self->stream) + self.cappuccinoProject.status = XCCCappuccinoProjectStatusListening; + + [self.mainXcodeCappController.operationsViewController reload]; + [self.mainXcodeCappController.errorsViewController reload]; +} + +- (void)_reinitializeOperationsCounters +{ + self.operationsProgress = 1.0; + self.operationsTotal = 0; + self.operationsRemaining = 0; +} + +- (void)_updateOperationsProgress +{ + if (!self.operationsTotal) + { + self.operationsRemaining = 0; + self.operationsProgress = 1.0; + } + else + { + self.operationsRemaining = (long)[[self projectRelatedOperations] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"cancelled = NO"]].count; + self.operationsProgress = 1.0 - (float)self.operationsRemaining / (float)self.operationsTotal; + } + + self.operationsRemainingString = [NSString stringWithFormat:@"%d total operations, %d remaining", (int)self.operationsTotal, (int)self.operationsRemaining]; + + if (self.operationsProgress == 1.0) + [self _reinitializeOperationsCounters]; +} + +- (void)_registerSourceProcessingOperation:(XCCSourceProcessingOperation *)sourceOperation +{ + if (!self->sourceProcessingOperations[sourceOperation.sourcePath]) + self->sourceProcessingOperations[sourceOperation.sourcePath] = [@[] mutableCopy]; + + NSMutableArray *operations = self->sourceProcessingOperations[sourceOperation.sourcePath]; + + if (![operations containsObject:sourceOperation]) + [operations addObject:sourceOperation]; +} + +- (void)_unregisterSourceProcessingOperation:(XCCSourceProcessingOperation *)sourceOperation +{ + [self->sourceProcessingOperations[sourceOperation.sourcePath] removeObject:sourceOperation]; + + if (!self->sourceProcessingOperations[sourceOperation.sourcePath]) + [self->sourceProcessingOperations removeObjectForKey:sourceOperation.sourcePath]; +} + +- (NSArray *)_sourceProcessingOperationsForPath:(NSString *)path +{ + return self->sourceProcessingOperations[path]; +} + +- (void)_enqueueOperation:(NSOperation *)anOperation +{ + if ([self->operationQueue.operations containsObject:anOperation]) + return; + + [self->operationQueue addOperation:anOperation]; + + if ([anOperation isKindOfClass:[XCCSourceProcessingOperation class]]) + [self _registerSourceProcessingOperation:(XCCSourceProcessingOperation *)anOperation]; + + self.operationsTotal++; + [self _updateOperationsProgress]; +} + +- (void)_dequeueOperation:(NSOperation *)anOperation +{ + if ([anOperation isKindOfClass:[XCCSourceProcessingOperation class]]) + [self _unregisterSourceProcessingOperation:(XCCSourceProcessingOperation *)anOperation]; + + [self _updateOperationsProgress]; +} + +- (void)_cancelSourceOperationsForPath:(NSString *)path +{ + NSArray *operations = [self _sourceProcessingOperationsForPath:path]; + + for (NSOperation * operation in operations) + { + [operation cancel]; + [self _dequeueOperation:operation]; + } +} + +- (void)_cancelAllProjectRelatedOperations +{ + [[self projectRelatedOperations] makeObjectsPerformSelector:@selector(cancel)]; + self->sourceProcessingOperations = [@{} mutableCopy]; + self->pendingPBXOperation = nil; +} + +- (NSArray*)projectRelatedOperations +{ + return [self->operationQueue.operations filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"cappuccinoProject.projectPath == %@", self.cappuccinoProject.projectPath]]; +} + +- (NSArray *)projectRelatedSourceProcessingOperations +{ + return [[self projectRelatedOperations] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [XCCSourceProcessingOperation class]]]; +} + +- (void)_cancelCurrentSourceFinderOperation +{ + if (!self->currentFindSourceOperation) + return; + + [[self projectRelatedSourceProcessingOperations] makeObjectsPerformSelector:@selector(removeDependency:) withObject:self->currentFindSourceOperation]; + [self->currentFindSourceOperation cancel]; + [self _dequeueOperation:self->currentFindSourceOperation]; + self->currentFindSourceOperation = nil; +} + +- (void)_scheduleFinderSourceOperationForPath:(NSString *)path +{ + if (self->currentFindSourceOperation) + return; + + self->currentFindSourceOperation = [[XCCSourcesFinderOperation alloc] initWithCappuccinoProject:self.cappuccinoProject taskLauncher:self->taskLauncher sourcePath:path]; + [[self projectRelatedSourceProcessingOperations] makeObjectsPerformSelector:@selector(addDependency:) withObject:self->currentFindSourceOperation]; + [self _enqueueOperation:self->currentFindSourceOperation]; +} + +- (void)_schedulePBXOperation +{ + [self _schedulePBXOperationWithPathsToAdd:nil pathsToRemove:nil]; +} + +- (void)_schedulePBXOperationWithPathsToAdd:(NSArray *)pathsToAdd pathsToRemove:(NSArray *)pathsToRemove; +{ + BOOL needsEnqueue = NO; + + if (!self->pendingPBXOperation) + { + self->pendingPBXOperation = [[XCCPPXOperation alloc] initWithCappuccinoProject:self.cappuccinoProject taskLauncher:self->taskLauncher]; + needsEnqueue = YES; + } + + if (pathsToAdd) + [self->pendingPBXOperation registerPathsToAddInPBX:pathsToAdd]; + + if (pathsToRemove) + [self->pendingPBXOperation registerPathsToRemoveFromPBX:pathsToRemove]; + + for (XCCSourceProcessingOperation *operation in [self projectRelatedSourceProcessingOperations]) + [self->pendingPBXOperation addDependency:operation]; + + if (needsEnqueue) + [self _enqueueOperation:self->pendingPBXOperation]; +} + +- (void)_scheduleSourceProcessingOperationForPath:(NSString *)path +{ + [self _cancelSourceOperationsForPath:path]; + + XCCSourceProcessingOperation *operation = [[XCCSourceProcessingOperation alloc] initWithCappuccinoProject:self.cappuccinoProject + taskLauncher:self->taskLauncher + sourcePath:[self.cappuccinoProject projectPathForSourcePath:path]]; + if (self->currentFindSourceOperation) + [operation addDependency:self->currentFindSourceOperation]; + + [self _enqueueOperation:operation]; +} + + +#pragma mark - FS Event Management + +- (void)_startFSEventStream +{ + if (self->stream) + return; + + NSArray *pathsToWatch = [XCCCappuccinoProject getPathsToWatchForCappuccinoProject:self.cappuccinoProject]; + void *appPointer = (__bridge void *)self; + FSEventStreamContext context = { 0, appPointer, NULL, NULL, NULL }; + CFTimeInterval latency = 0.5; + UInt64 lastEventID = self.cappuccinoProject.lastEventID ? self.cappuccinoProject.lastEventID.unsignedLongLongValue : kFSEventStreamEventIdSinceNow; + + self->stream = FSEventStreamCreate(NULL, &fsevents_callback, &context, (__bridge CFArrayRef) pathsToWatch, lastEventID, latency, XCCProjectControllerFSEventFlags); + + FSEventStreamScheduleWithRunLoop(self->stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + FSEventStreamStart(self->stream); + + DDLogVerbose(@"FSEventStream started for paths: %@", pathsToWatch); +} + +- (void)_stopFSEventStream +{ + if (!self->stream) + return; + + UInt64 lastEventID = FSEventStreamGetLatestEventId(self->stream); + + if (lastEventID != 0 && lastEventID != UINT64_MAX) + { + self.cappuccinoProject.lastEventID = @(lastEventID); + [self.cappuccinoProject saveSettings]; + } + + FSEventStreamStop(self->stream); + FSEventStreamUnscheduleFromRunLoop(self->stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + FSEventStreamInvalidate(self->stream); + FSEventStreamRelease(self->stream); + + self->stream = NULL; + + DDLogVerbose(@"FSEventStream stopped"); +} + +- (void)_handleFSEventsWithPaths:(NSArray *)paths flags:(const FSEventStreamEventFlags[])eventFlags ids:(const FSEventStreamEventId[])eventIds +{ + NSMutableArray *modifiedPaths = [@[] mutableCopy]; + NSMutableArray *renamedDirectories = [@[] mutableCopy]; + NSFileManager *fm = [NSFileManager defaultManager]; + + BOOL needUpdate = NO; + + for (size_t i = 0; i < paths.count; ++i) + { + FSEventStreamEventFlags flags = eventFlags[i]; + NSString *path = [paths[i] stringByStandardizingPath]; + + BOOL rootChanged = (flags & kFSEventStreamEventFlagRootChanged) != 0; + BOOL needRescan = (flags & kFSEventStreamEventFlagMustScanSubDirs) != 0; + + if (rootChanged || needRescan) + { + DDLogVerbose(@"Watched path changed: %@", path); + + [self _handleProjectPathChange:path]; + return; + } + + BOOL isHistoryDoneSentinalEvent = (flags & kFSEventStreamEventFlagHistoryDone) != 0; + + if (isHistoryDoneSentinalEvent) + { + DDLogVerbose(@"History done sentinal event"); + continue; + } + + BOOL isMountEvent = (flags & kFSEventStreamEventFlagMount) || (flags & kFSEventStreamEventFlagUnmount); + + if (isMountEvent) + { + DDLogVerbose(@"Volume %@: %@", (flags & kFSEventStreamEventFlagMount) ? @"mounted" : @"unmounted", path); + continue; + } + + + BOOL inodeMetaModified = (flags & kFSEventStreamEventFlagItemInodeMetaMod) != 0; + BOOL isFile = (flags & kFSEventStreamEventFlagItemIsFile) != 0; + BOOL isSymlink = (flags & kFSEventStreamEventFlagItemIsSymlink) != 0; + BOOL isDir = (flags & kFSEventStreamEventFlagItemIsDir) != 0; + BOOL renamed = (flags & kFSEventStreamEventFlagItemRenamed) != 0; + BOOL modified = (flags & kFSEventStreamEventFlagItemModified) != 0; + BOOL created = (flags & kFSEventStreamEventFlagItemCreated) != 0; + BOOL removed = (flags & kFSEventStreamEventFlagItemRemoved) != 0; + + if (isDir) + { + if (created && [path isEqualToString:self.cappuccinoProject.projectPath.stringByResolvingSymlinksInPath]) + return; + + if ((renamed || created || removed) && + ![XCCCappuccinoProject shouldIgnoreDirectoryNamed:path.lastPathComponent] && + ![XCCCappuccinoProject pathMatchesIgnoredPaths:path cappuccinoProjectIgnoredPathPredicates:self.cappuccinoProject.ignoredPathPredicates]) + { + DDLogVerbose(@"Renamed directory: %@", path); + + [renamedDirectories addObject:path]; + } + + continue; + } + else if ((isFile || isSymlink) && + (created || modified || renamed || removed || inodeMetaModified) && + [XCCCappuccinoProject isSourceFile:path cappuccinoProject:self.cappuccinoProject]) + { + DDLogVerbose(@"FSEvent accepted: %@ (%@)", path, [XCCFSEventLogUtils dumpFSEventFlags:flags]); + + if ([fm fileExistsAtPath:path]) + { + [modifiedPaths addObject:path]; + } + else if ([XCCCappuccinoProject isXibFile:path]) + { + // If a xib is deleted, delete its cib. There is no need to update when a xib is deleted, + // it is inside a folder in Xcode, which updates automatically. + + if (![fm fileExistsAtPath:path]) + { + NSString *cibPath = [path.stringByDeletingPathExtension stringByAppendingPathExtension:@"cib"]; + + if ([fm fileExistsAtPath:cibPath]) + [fm removeItemAtPath:cibPath error:nil]; + + continue; + } + } + + needUpdate = YES; + } + else if ((isFile || isSymlink) && (renamed || removed) && !(modified || created) && [XCCCappuccinoProject isCibFile:path]) + { + DDLogVerbose(@"FSEvent accepted: %@ (%@)", path, [XCCFSEventLogUtils dumpFSEventFlags:flags]); + + // If a cib is deleted, mark its xib as needing update so the cib is regenerated + NSString *xibPath = [path.stringByDeletingPathExtension stringByAppendingPathExtension:@"xib"]; + + if ([fm fileExistsAtPath:xibPath]) + { + [modifiedPaths addObject:xibPath]; + needUpdate = YES; + } + } + else if ((isFile || isSymlink) && + (created || modified || renamed || removed || inodeMetaModified) && + [XCCCappuccinoProject isXCCIgnoreFile:path cappuccinoProject:self.cappuccinoProject]) + { + DDLogVerbose(@"FSEvent accepted: %@ (%@)", path, [XCCFSEventLogUtils dumpFSEventFlags:flags]); + + [self.cappuccinoProject reloadXcodeCappIgnoreFile]; + } + } + + // If directories were renamed, we take the easy way out and reset the project + if (renamedDirectories.count) + [self _updateXcodeSupportFilesWithRenamedDirectories:renamedDirectories]; + else if (needUpdate) + [self _updateXcodeSupportFilesWithModifiedPaths:modifiedPaths]; +} + +- (void)_handleProjectPathChange:(NSString *)path +{ + NSRunAlertPanel(self.cappuccinoProject.nickname, @"The project directory changed. This project will be removed", @"OK", nil, nil, nil); + + [self.mainXcodeCappController unmanageCappuccinoProjectController:self]; +} + + +#pragma mark - Third Party Application Management + +- (NSString *)_managingApplicationIdenfierForFilePath:(NSString *)filePath +{ + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; + NSString *app, *type; + + BOOL success = [workspace getInfoForFile:filePath application:&app type:&type]; + + return success ? app : nil; +} + +- (void)launchEditorForPath:(NSString*)path line:(NSInteger)line +{ + NSString *applicationIdentifier = [self _managingApplicationIdenfierForFilePath:path]; + + [self launchEditorForPath:path line:line applicationIdentifier:applicationIdentifier]; +} + +- (void)launchEditorForPath:(NSString*)path line:(NSInteger)line applicationIdentifier:(NSString *)applicationIdentifier +{ + if (!applicationIdentifier) + return; + + NSFileManager *fm = [NSFileManager defaultManager]; + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; + NSBundle *bundle = [NSBundle bundleWithPath:applicationIdentifier]; + NSString *identifier = bundle.bundleIdentifier; + NSString *executablePath = nil; + XCCLineSpecifier lineSpecifier = kLineSpecifierNone; + + if ([identifier hasPrefix:@"com.sublimetext."]) + { + lineSpecifier = kLineSpecifierColon; + executablePath = [[bundle sharedSupportPath] stringByAppendingPathComponent:@"bin/subl"]; + } + else if ([identifier isEqualToString:@"com.barebones.textwrangler"]) + { + lineSpecifier = kLineSpecifierColon; + executablePath = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Helpers/edit"]; + } + else if ([identifier isEqualToString:@"com.barebones.bbedit"]) + { + lineSpecifier = kLineSpecifierColon; + executablePath = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Helpers/bbedit"]; + } + else if ([identifier isEqualToString:@"com.macromates.textmate"]) // TextMate 1.x + { + lineSpecifier = kLineSpecifierMinusL; + executablePath = [[bundle sharedSupportPath] stringByAppendingPathComponent:@"Support/bin/mate"]; + } + else if ([identifier hasPrefix:@"com.macromates.TextMate"]) // TextMate 2.x + { + lineSpecifier = kLineSpecifierMinusL; + executablePath = [bundle pathForResource:@"mate" ofType:@""]; + } + else if ([identifier isEqualToString:@"com.chocolatapp.Chocolat"]) + { + lineSpecifier = kLineSpecifierMinusL; + executablePath = [[bundle sharedSupportPath] stringByAppendingPathComponent:@"choc"]; + } + else if ([identifier isEqualToString:@"org.vim.MacVim"]) + { + lineSpecifier = kLineSpecifierPlus; + executablePath = @"/usr/local/bin/mvim"; + } + else if ([identifier isEqualToString:@"org.gnu.Aquamacs"]) + { + if ([fm isExecutableFileAtPath:@"/usr/bin/aquamacs"]) + executablePath = @"/usr/bin/aquamacs"; + else if ([fm isExecutableFileAtPath:@"/usr/local/bin/aquamacs"]) + executablePath = @"/usr/local/bin/aquamacs"; + } + else if ([identifier isEqualToString:@"com.apple.dt.Xcode"]) + { + executablePath = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Developer/usr/bin/xed"]; + } + + if (!executablePath || ![fm isExecutableFileAtPath:executablePath]) + { + [workspace openFile:path]; + return; + } + + NSArray *args; + + switch (lineSpecifier) + { + case kLineSpecifierNone: + args = @[path]; + break; + + case kLineSpecifierColon: + args = @[[NSString stringWithFormat:@"%1$@:%2$ld", path, line]]; + break; + + case kLineSpecifierMinusL: + args = @[@"-l", [NSString stringWithFormat:@"%ld", line], path]; + break; + + case kLineSpecifierPlus: + args = @[[NSString stringWithFormat:@"+%ld", line], path]; + break; + } + + [self->taskLauncher runTaskWithCommand:executablePath arguments:args returnType:kTaskReturnTypeNone]; +} + + +#pragma mark - NSUserNotificationCenter Utilities + +- (void)_notifyUserWithOperationError:(XCCOperationError*)anOperationError +{ + NSUserNotification *note = [NSUserNotification new]; + note.title = [[anOperationError.fileName stringByReplacingOccurrencesOfString:self.cappuccinoProject.projectPath withString:@""] substringFromIndex:1]; + note.informativeText = anOperationError.description; + note.actionButtonTitle = @"Show"; + note.otherButtonTitle = @"Close"; + note.userInfo = @{@"cappuccinoProjectPath" : self.cappuccinoProject.projectPath, @"sourcePath": anOperationError.fileName}; + + [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:note]; +} + + +#pragma mark - Public Utilities + +- (void)reinitializeProjectFromSettings +{ + DDLogVerbose(@"Saving Cappuccino configuration project %@", self.cappuccinoProject.projectPath); + + [self _cancelAllProjectRelatedOperations]; + [self.cappuccinoProject saveSettings]; + + int previousStatus = self.cappuccinoProject.status; + [self _stopListeningToProject]; + [self _reinitializeTaskLauncher]; + + if (!self->taskLauncher.isValid) + return; + + if (previousStatus == XCCCappuccinoProjectStatusListening) + [self _startListeningToProject]; + + DDLogVerbose(@"Cappuccino configuration project %@ has been saved", self.cappuccinoProject.projectPath); +} + +- (void)applicationIsClosing +{ + [self _stopFSEventStream]; +} + +- (void)cleanUpBeforeDeletion +{ + [self cancelAllOperations:self]; + [self _stopListeningToOperationsNotifications]; + [self _stopListeningToProject]; + [self _removeXcodeProject]; + [self _removeXcodeSupportDirectory]; + + [self.mainXcodeCappController.operationsViewController reload]; + [self.mainXcodeCappController.errorsViewController reload]; +} + + +#pragma mark - Actions + +- (IBAction)cancelAllOperations:(id)aSender +{ + [self _cancelAllProjectRelatedOperations]; + [self.mainXcodeCappController.operationsViewController reload]; +} + +- (IBAction)resetProject:(id)aSender +{ + [self _stopListeningToProject]; + [self _removeXcodeSupportDirectory]; + [self _removeXcodeProject]; + [self _reinitializeProjectController]; + [self _startListeningToProject]; +} + +- (IBAction)openProjectInXcode:(id)aSender +{ + BOOL isDirectory; + BOOL isOpened = YES; + NSFileManager *fm = [NSFileManager defaultManager]; + BOOL exists = [fm fileExistsAtPath:self.cappuccinoProject.XcodeProjectPath isDirectory:&isDirectory]; + + if (exists && isDirectory) + { + DDLogVerbose(@"Opening Xcode project at: %@", self.cappuccinoProject.XcodeProjectPath); + + isOpened = [[NSWorkspace sharedWorkspace] openFile:self.cappuccinoProject.XcodeProjectPath]; + } + + if (!exists || !isDirectory || !isOpened) + { + NSString *text; + + if (!isOpened) + text = @"The project exists, but failed to open."; + else + text = [NSString stringWithFormat:@"%@ %@.", self.cappuccinoProject.XcodeProjectPath, !exists ? @"does not exist" : @"is not an Xcode project"]; + + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + NSInteger response = NSRunAlertPanel(@"The project could not be opened.", @"%@\n\nWould you like to regenerate the project?", @"Yes", @"No", nil, text); + + if (response == NSAlertFirstButtonReturn) + [self resetProject:self]; + } +} + +- (IBAction)openProjectInFinder:(id)sender +{ + [[NSWorkspace sharedWorkspace] openFile:self.cappuccinoProject.projectPath]; +} + +- (IBAction)openProjectInEditor:(id)sender +{ + NSFileManager *fm = [NSFileManager defaultManager]; + NSArray *contents = [fm contentsOfDirectoryAtPath:self.cappuccinoProject.projectPath error:nil]; + NSString *firstObjjFile; + + for (NSString *file in contents) + { + if ([[file pathExtension] isEqualToString:@"j"]) + { + firstObjjFile = file; + break; + } + } + + if (!firstObjjFile) + return; + + NSString *applicationIdentifier = [self _managingApplicationIdenfierForFilePath:[self.cappuccinoProject.projectPath stringByAppendingPathComponent:firstObjjFile]]; + + if (!applicationIdentifier) + return; + + [self launchEditorForPath:self.cappuccinoProject.projectPath line:0 applicationIdentifier:applicationIdentifier]; +} + +- (IBAction)openProjectInTerminal:(id)sender; +{ + NSString *s = [NSString stringWithFormat:@"tell application \"Terminal\"\n do script \"cd %@; clear\" \n activate\n end tell", self.cappuccinoProject.projectPath]; + NSAppleScript *script = [[NSAppleScript alloc] initWithSource:s]; + [script executeAndReturnError:nil]; +} + +- (IBAction)switchProjectListeningStatus:(id)sender +{ + if (self.cappuccinoProject.status == XCCCappuccinoProjectStatusStopped) + [self _startListeningToProject]; + else + [self _stopListeningToProject]; +} + +@end + + diff --git a/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectControllerDataView.h b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectControllerDataView.h new file mode 100644 index 000000000..3b98fd646 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectControllerDataView.h @@ -0,0 +1,30 @@ +// +// CappuccinoProjectCellView.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/11/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import +#import "XCCCappuccinoProjectController.h" +#import "YRKSpinningProgressIndicator.h" + +@interface XCCCappuccinoProjectControllerDataView : NSTableCellView +{ + IBOutlet NSBox *lineBottom; + IBOutlet NSTextField *fieldNickname; + IBOutlet NSTextField *fieldPath; + IBOutlet NSButton *buttonSwitchStatus; + IBOutlet NSButton *buttonOpenXcodeProject; + IBOutlet NSButton *buttonResetProject; + IBOutlet NSButton *buttonOpenInFinder; + IBOutlet NSButton *buttonOpenInEditor; + IBOutlet NSButton *buttonOpenInTerminal; + IBOutlet NSBox *boxStatus; + IBOutlet YRKSpinningProgressIndicator *operationsProgressIndicator; +} + +@property XCCCappuccinoProjectController *controller; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectControllerDataView.m b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectControllerDataView.m new file mode 100644 index 000000000..524205f90 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCCappuccinoProjectControllerDataView.m @@ -0,0 +1,163 @@ +// +// CappuccinoProjectCellView.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/11/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCCappuccinoProjectControllerDataView.h" +#import "XCCCappuccinoProject.h" + +static NSColor * XCCCappuccinoProjectDataViewColorLoading; +static NSColor * XCCCappuccinoProjectDataViewColorStopped; +static NSColor * XCCCappuccinoProjectDataViewColorListening; +static NSColor * XCCCappuccinoProjectDataViewColorProcessing; +static NSColor * XCCCappuccinoProjectDataViewColorError; + + +@implementation XCCCappuccinoProjectControllerDataView + +@synthesize controller = _controller; + ++ (void)initialize +{ + XCCCappuccinoProjectDataViewColorLoading = [NSColor colorWithCalibratedRed:107.0/255.0 green:148.0/255.0 blue:236.0/255.0 alpha:1.0]; + XCCCappuccinoProjectDataViewColorStopped = [NSColor colorWithCalibratedRed:138.0/255.0 green:138.0/255.0 blue:138.0/255.0 alpha:1.0]; + XCCCappuccinoProjectDataViewColorListening = [NSColor colorWithCalibratedRed:179.0/255.0 green:214.0/255.0 blue:69.0/255.0 alpha:1.0]; + XCCCappuccinoProjectDataViewColorProcessing = [NSColor colorWithCalibratedRed:107.0/255.0 green:148.0/255.0 blue:236.0/255.0 alpha:1.0]; + XCCCappuccinoProjectDataViewColorError = [NSColor colorWithCalibratedRed:247.0/255.0 green:97.0/255.0 blue:89.0/255.0 alpha:1.0]; +} + +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + if (newWindow) + { + [self->buttonSwitchStatus setTarget:self.controller]; + [self->buttonSwitchStatus setAction:@selector(switchProjectListeningStatus:)]; + [self->buttonOpenXcodeProject setTarget:self.controller]; + [self->buttonOpenXcodeProject setAction:@selector(openProjectInXcode:)]; + [self->buttonResetProject setTarget:self.controller]; + [self->buttonResetProject setAction:@selector(resetProject:)]; + [self->buttonOpenInEditor setTarget:self.controller]; + [self->buttonOpenInEditor setAction:@selector(openProjectInEditor:)]; + [self->buttonOpenInFinder setTarget:self.controller]; + [self->buttonOpenInFinder setAction:@selector(openProjectInFinder:)]; + [self->buttonOpenInTerminal setTarget:self.controller]; + [self->buttonOpenInTerminal setAction:@selector(openProjectInTerminal:)]; + + self->boxStatus.borderColor = [NSColor clearColor]; + self->boxStatus.fillColor = [NSColor colorWithCalibratedRed:217.0/255.0 green:217.0/255.0 blue:217.0/255.0 alpha:1.0]; + + [self.controller.cappuccinoProject addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil]; + [self.controller addObserver:self forKeyPath:@"errors" options:NSKeyValueObservingOptionNew context:nil]; + [self.controller.cappuccinoProject addObserver:self forKeyPath:@"processing" options:NSKeyValueObservingOptionNew context:nil]; + [self.controller addObserver:self forKeyPath:@"operationsTotal" options:NSKeyValueObservingOptionNew context:nil]; + [self.controller addObserver:self forKeyPath:@"operationsProgress" options:NSKeyValueObservingOptionNew context:nil]; + + [self->fieldNickname bind:NSValueBinding toObject:self.controller.cappuccinoProject withKeyPath:@"nickname" options:nil]; + [self->fieldPath bind:NSValueBinding toObject:self.controller.cappuccinoProject withKeyPath:@"projectPath" options:nil]; + + [self->operationsProgressIndicator startAnimation:self]; + self->operationsProgressIndicator.maxValue = 1.0; + } + else + { + [self.controller.cappuccinoProject removeObserver:self forKeyPath:@"status"]; + [self.controller removeObserver:self forKeyPath:@"errors"]; + [self.controller.cappuccinoProject removeObserver:self forKeyPath:@"processing"]; + [self.controller removeObserver:self forKeyPath:@"operationsTotal"]; + [self.controller removeObserver:self forKeyPath:@"operationsProgress"]; + + [self->fieldNickname unbind:NSValueBinding]; + [self->fieldPath unbind:NSValueBinding]; + + [self->operationsProgressIndicator stopAnimation:self]; + } + + [self _updateDataView]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self _updateDataView]; + }); +} + +- (void)_updateDataView +{ + switch (self.controller.cappuccinoProject.status) + { + case XCCCappuccinoProjectStatusStopped: + self->boxStatus.fillColor = XCCCappuccinoProjectDataViewColorStopped; + self->buttonSwitchStatus.image = self.backgroundStyle == NSBackgroundStyleDark ? [NSImage imageNamed:@"run-white"] : [NSImage imageNamed:@"run"]; + self->operationsProgressIndicator.hidden = YES; + break; + + case XCCCappuccinoProjectStatusListening: + self->boxStatus.fillColor = [self.controller.errors count] ? XCCCappuccinoProjectDataViewColorError : XCCCappuccinoProjectDataViewColorListening; + self->buttonSwitchStatus.image = self.backgroundStyle == NSBackgroundStyleDark ? [NSImage imageNamed:@"stop-white"] : [NSImage imageNamed:@"stop"]; + + if (self.controller.operationsTotal == 0) + { + self->operationsProgressIndicator.hidden = YES; + [self->operationsProgressIndicator setNeedsDisplay:YES]; + } + else if (self.controller.operationsTotal <= 4) + { + self->operationsProgressIndicator.hidden = NO; + self->operationsProgressIndicator.indeterminate = YES; + [self->operationsProgressIndicator startAnimation:self]; + } + else if (self.controller.operationsTotal > 4) + { + self->operationsProgressIndicator.hidden = NO; + self->operationsProgressIndicator.indeterminate = NO; + self->operationsProgressIndicator.currentValue = self.controller.operationsProgress; + [self->operationsProgressIndicator setNeedsDisplay:YES]; + } + + break; + } +} + +- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle +{ + BOOL isStopped = self.controller.cappuccinoProject.status == XCCCappuccinoProjectStatusStopped; + + if (backgroundStyle == NSBackgroundStyleDark) + { + self->lineBottom.hidden = YES; + + self->operationsProgressIndicator.backgroundColor = [NSColor whiteColor]; + self->operationsProgressIndicator.color = [NSColor whiteColor]; + self->fieldNickname.textColor = [NSColor whiteColor]; + self->fieldPath.textColor = [NSColor whiteColor]; + self->buttonSwitchStatus.image = isStopped ? [NSImage imageNamed:@"run-white"] : [NSImage imageNamed:@"stop-white"]; + self->buttonOpenInFinder.image = [NSImage imageNamed:@"open-in-finder-white"]; + self->buttonOpenInEditor.image = [NSImage imageNamed:@"open-in-editor-white"]; + self->buttonOpenInTerminal.image = [NSImage imageNamed:@"open-in-terminal-white"]; + self->buttonOpenXcodeProject.image = [NSImage imageNamed:@"open-in-xcode-white"]; + self->buttonResetProject.image = [NSImage imageNamed:@"resync-white"]; + } + else + { + self->lineBottom.hidden = NO; + + self->operationsProgressIndicator.backgroundColor = [NSColor secondaryLabelColor]; + self->operationsProgressIndicator.color = [NSColor secondaryLabelColor]; + self->fieldNickname.textColor = [NSColor controlTextColor]; + self->fieldPath.textColor = [NSColor secondaryLabelColor]; + self->buttonSwitchStatus.image = isStopped ? [NSImage imageNamed:@"run"] : [NSImage imageNamed:@"stop"]; + self->buttonOpenInFinder.image = [NSImage imageNamed:@"open-in-finder"]; + self->buttonOpenInEditor.image = [NSImage imageNamed:@"open-in-editor"]; + self->buttonOpenInTerminal.image = [NSImage imageNamed:@"open-in-terminal"]; + self->buttonOpenXcodeProject.image = [NSImage imageNamed:@"open-in-xcode"]; + self->buttonResetProject.image = [NSImage imageNamed:@"resync"]; + } + + [super setBackgroundStyle:backgroundStyle]; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCErrorsViewController.h b/Tools/XcodeCapp/XcodeCapp/XCCErrorsViewController.h new file mode 100644 index 000000000..52a79e8ae --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCErrorsViewController.h @@ -0,0 +1,28 @@ +// +// XCCErrorsViewController.h +// XcodeCapp +// +// Created by Antoine Mercadal on 6/4/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@class XCCCappuccinoProjectController; + + +@interface XCCErrorsViewController : NSViewController +{ + IBOutlet NSOutlineView *errorOutlineView; + IBOutlet NSBox *maskingView; +} + +@property XCCCappuccinoProjectController *cappuccinoProjectController; + +- (void)selectItem:(id)anItem; +- (void)reload; + +- (IBAction)openErroredFileInEditor:(id)sender; +- (IBAction)cleanProjectErrors:(id)aSender; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCErrorsViewController.m b/Tools/XcodeCapp/XcodeCapp/XCCErrorsViewController.m new file mode 100644 index 000000000..8fdf3ac89 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCErrorsViewController.m @@ -0,0 +1,193 @@ +// +// XCCErrorsViewController.m +// XcodeCapp +// +// Created by Antoine Mercadal on 6/4/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCErrorsViewController.h" +#import "XCCCappuccinoProjectController.h" +#import "XCCCappuccinoProject.h" +#import "XCCOperationErrorDataView.h" +#import "XCCOperationErrorHeaderDataView.h" +#import "XCCMainController.h" +#import "XCCSourceProcessingOperation.h" + +@implementation XCCErrorsViewController + +#pragma mark - Initialization + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [self->errorOutlineView setTarget:self]; + [self->errorOutlineView setDoubleAction:@selector(openErroredFileInEditor:)]; +} + + +#pragma mark - Utilities + +- (void)_showMaskingView:(BOOL)shouldShow +{ + if (shouldShow) + { + if (self->maskingView.superview) + return; + + [self->errorOutlineView setHidden:YES]; + + self->maskingView.frame = [self.view bounds]; + [self.view addSubview:self->maskingView]; + } + else + { + if (!self->maskingView.superview) + return; + + [self->errorOutlineView setHidden:NO]; + + [self->maskingView removeFromSuperview]; + } +} + +- (void)reload +{ + [self->errorOutlineView reloadData]; + [self->errorOutlineView expandItem:nil expandChildren:YES]; + + [self _showMaskingView:!self.cappuccinoProjectController.errors.count]; +} + +- (void)selectItem:(id)anItem +{ + NSInteger indexOfItem = [self _indexOfItem:anItem]; + + if (indexOfItem == NSNotFound) + return; + + [self->errorOutlineView scrollRowToVisible:indexOfItem]; +} + +- (NSInteger)_indexOfItem:(id)anItem +{ + NSInteger index = 0; + + NSArray *keys = [self.cappuccinoProjectController.errors allKeys]; + + for (int i = 0; i < [keys count]; i++) + { + NSString *key = [[self.cappuccinoProjectController.errors allKeys] objectAtIndex:i]; + + if ([key isEqual:anItem]) + return index; + + index++; + + NSArray *operationErrors = [self.cappuccinoProjectController.errors objectForKey:key]; + + for (int j = 0; j < [operationErrors count]; j++) + { + XCCOperationError *operationError = [operationErrors objectAtIndex:j]; + + if ([operationError isEqual:anItem]) + return index; + + index++; + } + } + + return NSNotFound; +} + +#pragma mark - Actions + +- (IBAction)cleanProjectErrors:(id)aSender +{ + [self.cappuccinoProjectController removeAllOperationErrors]; + [self reload]; + [self.cappuccinoProjectController.mainXcodeCappController reloadTotalNumberOfErrors]; +} + +- (IBAction)openErroredFileInEditor:(NSView *)sender +{ + NSInteger index = (sender != self->errorOutlineView) ? [self->errorOutlineView rowForView:sender] : [self->errorOutlineView selectedRow]; + id dataView = [self->errorOutlineView viewAtColumn:0 row:index makeIfNecessary:NO]; + + if (![dataView isKindOfClass:[XCCOperationErrorDataView class]]) + return; + + NSString *path = ((XCCOperationErrorDataView*)dataView).errorOperation.fileName; + NSInteger line = ((XCCOperationErrorDataView*)dataView).errorOperation.lineNumber.intValue; + + [self.cappuccinoProjectController launchEditorForPath:path line:line]; +} + + +#pragma mark - outlineView data source and delegate + +- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item +{ + if (!item) + return self.cappuccinoProjectController.errors.allKeys.count; + + return ((NSArray *)self.cappuccinoProjectController.errors[item]).count; +} + +- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item +{ + return ![item isKindOfClass:[XCCOperationError class]]; +} + +- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item +{ + if (!item) + return self.cappuccinoProjectController.errors.allKeys[index]; + + return self.cappuccinoProjectController.errors[item][index]; +} + +- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item +{ + return item; +} + +- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + if ([item isKindOfClass:[XCCOperationError class]]) + { + XCCOperationErrorDataView *dataView = [outlineView makeViewWithIdentifier:@"OperationErrorCell" owner:nil]; + + dataView.errorOperation = item; + [dataView.buttonOpenInEditor setTarget:self]; + [dataView.buttonOpenInEditor setAction:@selector(openErroredFileInEditor:)]; + + return dataView; + } + else + { + XCCOperationErrorHeaderDataView *dataView = [outlineView makeViewWithIdentifier:@"OperationErrorHeaderCell" owner:nil]; + + dataView.fileName = [[item stringByReplacingOccurrencesOfString:self.cappuccinoProjectController.cappuccinoProject.projectPath withString:@""] substringFromIndex:1]; + + return dataView; + } +} + +- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(XCCOperationError *)item +{ + if ([item isKindOfClass:[XCCOperationError class]]) + { + CGRect frame = [item.message boundingRectWithSize:CGSizeMake([outlineView frame].size.width, CGFLOAT_MAX) + options:NSStringDrawingUsesLineFragmentOrigin + attributes:@{ NSFontAttributeName:[NSFont fontWithName:@"Menlo" size:11] }]; + + return frame.size.height + 38.0; + } + + else + return 20.0; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCFSEventLogUtils.h b/Tools/XcodeCapp/XcodeCapp/XCCFSEventLogUtils.h new file mode 100644 index 000000000..c5067f980 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCFSEventLogUtils.h @@ -0,0 +1,15 @@ +// +// LogUtils.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/8/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@interface XCCFSEventLogUtils : NSObject + ++ (NSString *)dumpFSEventFlags:(FSEventStreamEventFlags)flags; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCFSEventLogUtils.m b/Tools/XcodeCapp/XcodeCapp/XCCFSEventLogUtils.m new file mode 100644 index 000000000..ae35dc256 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCFSEventLogUtils.m @@ -0,0 +1,65 @@ +// +// LogUtils.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/8/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCFSEventLogUtils.h" + +@implementation XCCFSEventLogUtils + ++ (NSString *)dumpFSEventFlags:(FSEventStreamEventFlags)flags +{ + BOOL created = (flags & kFSEventStreamEventFlagItemCreated) != 0; + BOOL removed = (flags & kFSEventStreamEventFlagItemRemoved) != 0; + BOOL inodeMetaModified = (flags & kFSEventStreamEventFlagItemInodeMetaMod) != 0; + BOOL renamed = (flags & kFSEventStreamEventFlagItemRenamed) != 0; + BOOL modified = (flags & kFSEventStreamEventFlagItemModified) != 0; + BOOL finderInfoModified = (flags & kFSEventStreamEventFlagItemFinderInfoMod) != 0; + BOOL changedOwner = (flags & kFSEventStreamEventFlagItemChangeOwner) != 0; + BOOL xattrModified = (flags & kFSEventStreamEventFlagItemXattrMod) != 0; + BOOL isFile = (flags & kFSEventStreamEventFlagItemIsFile) != 0; + BOOL isDir = (flags & kFSEventStreamEventFlagItemIsDir) != 0; + BOOL isSymlink = (flags & kFSEventStreamEventFlagItemIsSymlink) != 0; + + NSMutableArray *flagNames = [@[] mutableCopy]; + + if (created) + [flagNames addObject:@"created"]; + + if (removed) + [flagNames addObject:@"removed"]; + + if (inodeMetaModified) + [flagNames addObject:@"inode"]; + + if (renamed) + [flagNames addObject:@"renamed"]; + + if (modified) + [flagNames addObject:@"modified"]; + + if (finderInfoModified) + [flagNames addObject:@"Finder info"]; + + if (changedOwner) + [flagNames addObject:@"owner"]; + + if (xattrModified) + [flagNames addObject:@"xattr"]; + + if (isFile) + [flagNames addObject:@"file"]; + + if (isDir) + [flagNames addObject:@"dir"]; + + if (isSymlink) + [flagNames addObject:@"symlink"]; + + return [flagNames componentsJoinedByString:@", "]; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCMainController.h b/Tools/XcodeCapp/XcodeCapp/XCCMainController.h new file mode 100644 index 000000000..35cf6fac3 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCMainController.h @@ -0,0 +1,49 @@ +// +// MainWindowController.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/20/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@class XCCCappuccinoProject; +@class XCCCappuccinoProjectController; +@class XCCOperationsViewController; +@class XCCErrorsViewController; +@class XCCSettingsViewController; +@class XCCWelcomeView; + +@interface XCCMainController : NSWindowController +{ + IBOutlet NSMenu *menuTableViewProject; + IBOutlet NSBox *maskingView; + IBOutlet NSSplitView *splitView; + IBOutlet NSTableView *projectTableView; + IBOutlet NSView *projectViewContainer; + IBOutlet NSTabView *tabViewProject; + IBOutlet NSButton *buttonSelectConfigurationTab; + IBOutlet NSButton *buttonSelectErrorsTab; + IBOutlet NSButton *buttonSelectOperationsTab; + IBOutlet XCCWelcomeView *welcomeViewMask; +} + +@property IBOutlet XCCSettingsViewController *settingsViewController; +@property IBOutlet XCCOperationsViewController *operationsViewController; +@property IBOutlet XCCErrorsViewController *errorsViewController; +@property NSMutableArray *cappuccinoProjectControllers; +@property XCCCappuccinoProjectController *currentCappuccinoProjectController; +@property int totalNumberOfErrors; + +- (void)manageCappuccinoProjectControllerForPath:(NSString *)aProjectPath; +- (void)unmanageCappuccinoProjectController:(XCCCappuccinoProjectController *)aController; +- (void)reloadTotalNumberOfErrors; +- (void)notifyCappuccinoControllersApplicationIsClosing; + +- (IBAction)cleanAllErrors:(id)aSender; +- (IBAction)addProject:(id)aSender; +- (IBAction)removeProject:(id)aSender; +- (IBAction)updateSelectedTab:(id)aSender; + +@end \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/XCCMainController.m b/Tools/XcodeCapp/XcodeCapp/XCCMainController.m new file mode 100644 index 000000000..31d074be0 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCMainController.m @@ -0,0 +1,497 @@ +// +// MainWindowController.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/20/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "NSMutableArray+moveIndexes.h" +#import "XCCMainController.h" +#import "XCCCappuccinoProject.h" +#import "XCCCappuccinoProjectController.h" +#import "XCCCappuccinoProjectControllerDataView.h" +#import "XCCUserDefaults.h" +#import "XCCOperationsViewController.h" +#import "XCCErrorsViewController.h" +#import "XCCSettingsViewController.h" +#import "XCCWelcomeView.h" + + +@implementation XCCMainController + +#pragma mark - Initialization + +- (void)windowDidLoad +{ + [self showWindow:self]; + + self->welcomeViewMask.mainXcodeCappController = self; + [self->welcomeViewMask showLoading:YES]; + [self _showWelcomeView:YES]; + [self _showMaskingView:YES]; + + NSTabViewItem *itemConfiguration = [[NSTabViewItem alloc] initWithIdentifier:@"configuration"]; + [itemConfiguration setView:self.settingsViewController.view]; + [self->tabViewProject addTabViewItem:itemConfiguration]; + + NSTabViewItem *itemErrors = [[NSTabViewItem alloc] initWithIdentifier:@"errors"]; + [itemErrors setView:self.errorsViewController.view]; + [self->tabViewProject addTabViewItem:itemErrors]; + + NSTabViewItem *itemOperations = [[NSTabViewItem alloc] initWithIdentifier:@"operations"]; + [itemOperations setView:self.operationsViewController.view]; + [self->tabViewProject addTabViewItem:itemOperations]; + + + [self _setTextColor:[NSColor controlTextColor] forButton:self->buttonSelectConfigurationTab]; + [self _setTextColor:[NSColor controlTextColor] forButton:self->buttonSelectErrorsTab]; + [self _setTextColor:[NSColor controlTextColor] forButton:self->buttonSelectOperationsTab]; + + + [self updateSelectedTab:self->buttonSelectConfigurationTab]; + + [self->projectTableView registerForDraggedTypes:@[@"projects", NSFilenamesPboardType]]; + [self->projectTableView setAllowsEmptySelection:YES]; + + [self->welcomeViewMask showLoading:NO]; + + [NSUserNotificationCenter defaultUserNotificationCenter].delegate = self; + + [self _restoreManagedProjects]; + [self _restoreLastSelectedProject]; +} + +- (void)_setTextColor:(NSColor *)color forButton:(NSButton *)button +{ + NSMutableParagraphStyle *paragraphStyle= [NSMutableParagraphStyle new]; + [paragraphStyle setAlignment:NSCenterTextAlignment]; + + NSDictionary *attrs = @{NSFontAttributeName: [NSFont systemFontOfSize:11], + NSForegroundColorAttributeName: color, + NSParagraphStyleAttributeName: paragraphStyle}; + + button.attributedTitle = [[NSMutableAttributedString alloc] initWithString:button.title attributes:attrs]; + +} + +#pragma mark - Private Utilities + +- (void)_showMaskingView:(BOOL)shouldShow +{ + if (shouldShow) + { + if (self->maskingView.superview) + return; + + self->projectViewContainer.hidden = YES; + + self->maskingView.frame = [[self->splitView subviews][1] bounds]; + [[self->splitView subviews][1] addSubview:self->maskingView positioned:NSWindowAbove relativeTo:nil]; + } + else + { + if (!self->maskingView.superview) + return; + + self->projectViewContainer.hidden = NO; + + [self->maskingView removeFromSuperview]; + } +} + +- (void)_showWelcomeView:(BOOL)shouldShow +{ + if (shouldShow) + { + if (self->welcomeViewMask.superview) + return; + + self->splitView.hidden = YES; + + self->welcomeViewMask.frame = [self->splitView.superview bounds]; + [self->splitView.superview addSubview:self->welcomeViewMask positioned:NSWindowAbove relativeTo:nil]; + } + else + { + if (!self->welcomeViewMask.superview) + return; + + self->splitView.hidden = NO; + + [self->welcomeViewMask removeFromSuperview]; + } +} + +- (void)_restoreLastSelectedProject +{ + DDLogVerbose(@"Start : selecting last selected project"); + + NSString *lastSelectedProjectPath = [[NSUserDefaults standardUserDefaults] valueForKey:XCCUserDefaultsSelectedProjectPath]; + + [self _selectCappuccinoProjectControllerWithPath:lastSelectedProjectPath]; + + DDLogVerbose(@"Stop : selecting last selected project"); +} + +- (void)_selectCappuccinoProjectControllerWithPath:(NSString*)aCappuccinoProjectPath +{ + NSInteger indexToSelect = 0; + + if ([aCappuccinoProjectPath length]) + { + for (XCCCappuccinoProjectController *controller in self.cappuccinoProjectControllers) + { + if ([controller.cappuccinoProject.projectPath isEqualToString:aCappuccinoProjectPath]) + { + indexToSelect = [self.cappuccinoProjectControllers indexOfObject:controller]; + break; + } + } + + [self->projectTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:indexToSelect] byExtendingSelection:NO]; + } +} + +- (void)_restoreManagedProjects +{ + DDLogVerbose(@"restore managed projects"); + self.cappuccinoProjectControllers = [@[] mutableCopy]; + + NSArray *projectHistory = [[NSUserDefaults standardUserDefaults] arrayForKey:XCCUserDefaultsManagedProjects]; + NSFileManager *fm = [NSFileManager defaultManager]; + NSMutableArray *missingProjects = [@[] mutableCopy]; + + for (NSString *path in projectHistory) + { + DDLogVerbose(@"Checking previously managed project at path: %@", path); + if (![fm fileExistsAtPath:path isDirectory:nil]) + { + [missingProjects addObject:path]; + DDLogVerbose(@"Not found: project at path: %@", path); + continue; + } + + XCCCappuccinoProjectController *cappuccinoProjectController = [[XCCCappuccinoProjectController alloc] initWithPath:path controller:self]; + [self.cappuccinoProjectControllers addObject:cappuccinoProjectController]; + } + + [self _reloadProjectsList]; + + if (missingProjects.count) + { + NSRunAlertPanel(@"Missing Projects", + @"Some managed projects could not be found and have been removed:\n\n" + @"%@\n\n", + @"OK", + nil, + nil, + [missingProjects componentsJoinedByString:@", "]); + } + + [self _saveManagedProjectsToUserDefaults]; + + for (XCCCappuccinoProjectController *controller in self.cappuccinoProjectControllers) + { + if (controller.cappuccinoProject.previousSavedStatus) + [controller switchProjectListeningStatus:self]; + } + + DDLogVerbose(@"managed projects restored"); +} + +- (void)_saveSelectedProject +{ + NSString *path = self.currentCappuccinoProjectController.cappuccinoProject.projectPath; + + if (!path) + path = @""; + + [[NSUserDefaults standardUserDefaults] setObject:path forKey:XCCUserDefaultsSelectedProjectPath]; +} + +- (void)_saveManagedProjectsToUserDefaults +{ + NSMutableArray *historyProjectPaths = [@[] mutableCopy]; + + for (XCCCappuccinoProjectController *controller in self.cappuccinoProjectControllers) + [historyProjectPaths addObject:controller.cappuccinoProject.projectPath]; + + [[NSUserDefaults standardUserDefaults] setObject:historyProjectPaths forKey:XCCUserDefaultsManagedProjects]; +} + +- (void)_reloadProjectsList +{ + [self->projectTableView reloadData]; + + if (self.cappuccinoProjectControllers.count == 0) + [self _showWelcomeView:YES]; + else + [self _showWelcomeView:NO]; + +} + + +#pragma mark - Public Utilities + +- (void)manageCappuccinoProjectControllerForPath:(NSString *)path +{ + if ([[self.cappuccinoProjectControllers filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"cappuccinoProject.projectPath == %@", path]] count]) + { + NSRunAlertPanel(@"This project is already managed.", @"Please remove the other project or use the reset button.", @"OK", nil, nil, nil); + return; + } + + XCCCappuccinoProjectController *controller = [[XCCCappuccinoProjectController alloc] initWithPath:path controller:self]; + + [self.cappuccinoProjectControllers addObject:controller]; + + NSInteger index = [self.cappuccinoProjectControllers indexOfObject:controller]; + + [self _reloadProjectsList]; + [self->projectTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO]; + [self->projectTableView scrollRowToVisible:index]; + + [self _saveManagedProjectsToUserDefaults]; + + [controller switchProjectListeningStatus:self]; +} + +- (void)unmanageCappuccinoProjectController:(XCCCappuccinoProjectController*)aController +{ + NSInteger selectedCappuccinoProject = [self.cappuccinoProjectControllers indexOfObject:aController]; + + if (selectedCappuccinoProject == -1) + return; + + [self->projectTableView deselectRow:selectedCappuccinoProject]; + [aController cleanUpBeforeDeletion]; + [self.cappuccinoProjectControllers removeObjectAtIndex:selectedCappuccinoProject]; + + [self _reloadProjectsList]; + + [self _saveManagedProjectsToUserDefaults]; +} + + +- (void)notifyCappuccinoControllersApplicationIsClosing +{ + [self.cappuccinoProjectControllers makeObjectsPerformSelector:@selector(applicationIsClosing)]; +} + +- (void)reloadTotalNumberOfErrors +{ + int totalErrors = 0; + + for (XCCCappuccinoProjectController *controller in self.cappuccinoProjectControllers) + totalErrors += controller.errors.count; + + [self willChangeValueForKey:@"totalNumberOfErrors"]; + self.totalNumberOfErrors = totalErrors; + [self didChangeValueForKey:@"totalNumberOfErrors"]; + + if (self.totalNumberOfErrors) + [[[NSApplication sharedApplication] dockTile] setBadgeLabel:@(self.totalNumberOfErrors).description]; + else + [[[NSApplication sharedApplication] dockTile] setBadgeLabel:nil]; +} + + +#pragma mark - Actions + +- (IBAction)cleanAllErrors:(id)aSender +{ + [self.cappuccinoProjectControllers makeObjectsPerformSelector:@selector(cleanProjectErrors:) withObject:self]; +} + +- (IBAction)addProject:(id)aSender +{ + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + openPanel.title = @"Add a new Cappuccino Project to XcodeCapp"; + openPanel.canCreateDirectories = YES; + openPanel.canChooseDirectories = YES; + openPanel.canChooseFiles = NO; + + if ([openPanel runModal] != NSFileHandlingPanelOKButton) + return; + + NSString *projectPath = [[openPanel.URLs[0] path] stringByStandardizingPath]; + + [self manageCappuccinoProjectControllerForPath:projectPath]; +} + +- (IBAction)removeProject:(id)aSender +{ + NSInteger selectedCappuccinoProject = [self->projectTableView selectedRow]; + + if (selectedCappuccinoProject == -1) + return; + + [self unmanageCappuccinoProjectController:(self.cappuccinoProjectControllers)[selectedCappuccinoProject]]; +} + +- (IBAction)updateSelectedTab:(NSButton *)sender +{ + self->buttonSelectConfigurationTab.state = NSOffState; + self->buttonSelectErrorsTab.state = NSOffState; + self->buttonSelectOperationsTab.state = NSOffState; + + [self _setTextColor:[NSColor controlTextColor] forButton:self->buttonSelectConfigurationTab]; + [self _setTextColor:[NSColor controlTextColor] forButton:self->buttonSelectErrorsTab]; + [self _setTextColor:[NSColor controlTextColor] forButton:self->buttonSelectOperationsTab]; + + sender.state = NSOnState; + [self _setTextColor:[NSColor colorWithCalibratedRed:107.0/255.0 green:148.0/255.0 blue:236.0/255.0 alpha:1.0] forButton:sender]; + + if (sender == self->buttonSelectConfigurationTab) + [self->tabViewProject selectTabViewItemAtIndex:0]; + if (sender == self->buttonSelectErrorsTab) + [self->tabViewProject selectTabViewItemAtIndex:1]; + if (sender == self->buttonSelectOperationsTab) + [self->tabViewProject selectTabViewItemAtIndex:2]; +} + + +#pragma mark - NSUserNotificationCenter delegate + +- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification +{ + NSDictionary *userInfo = [notification userInfo]; + [center removeDeliveredNotification:notification]; + + [self _selectCappuccinoProjectControllerWithPath:userInfo[@"cappuccinoProjectPath"]]; + [self updateSelectedTab:self->buttonSelectErrorsTab]; + [self.errorsViewController selectItem:userInfo[@"sourcePath"]]; +} + + +#pragma mark - SplitView delegate + +- (CGFloat)splitView:(NSSplitView *)aSplitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex +{ + return 300.0; +} + +- (CGFloat)splitView:(NSSplitView *)aSplitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex +{ + return 350.0; +} + +- (void)splitView:(NSSplitView *)aSplitView resizeSubviewsWithOldSize:(NSSize)oldSize +{ + [aSplitView adjustSubviews]; + + [aSplitView setPosition:((NSView *)splitView.subviews.firstObject).frame.size.width ofDividerAtIndex:0]; +} + +#pragma mark - TableView DataSource + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return [self.cappuccinoProjectControllers count]; +} + +#pragma mark - TableView Delegates + +- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + XCCCappuccinoProjectControllerDataView *dataView = [tableView makeViewWithIdentifier:@"MainCell" owner:nil]; + XCCCappuccinoProjectController *cappuccinoProjectController = (self.cappuccinoProjectControllers)[row]; + + dataView.controller = cappuccinoProjectController; + + return dataView; +} + +- (void)tableViewSelectionDidChange:(NSNotification *)notification +{ + NSInteger selectedIndex = [self->projectTableView selectedRow]; + + self.currentCappuccinoProjectController = (selectedIndex == -1) ? nil : (self.cappuccinoProjectControllers)[selectedIndex]; + + self.operationsViewController.cappuccinoProjectController = self.currentCappuccinoProjectController; + self.errorsViewController.cappuccinoProjectController = self.currentCappuccinoProjectController; + self.settingsViewController.cappuccinoProjectController = self.currentCappuccinoProjectController; + + [self.operationsViewController reload]; + [self.errorsViewController reload]; + [self.settingsViewController reload]; + + [self _showMaskingView:(selectedIndex == -1)]; + + [self _saveSelectedProject]; + +} + +- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowsIndexes toPasteboard:(NSPasteboard*)pasteboard +{ + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowsIndexes]; + [pasteboard declareTypes:@[@"projects"] owner:self]; + [pasteboard setData:data forType:@"projects"]; + + return YES; +} + +- (NSDragOperation)tableView:(NSTableView*)tableView validateDrop:(id )info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation +{ + NSPasteboard *pboard = [info draggingPasteboard]; + + if ([pboard.types containsObject:(NSString *)NSFilenamesPboardType]) + { + NSArray *draggedFiles = [pboard propertyListForType:(NSString *)NSFilenamesPboardType]; + + for (NSString *file in draggedFiles) + { + BOOL isDir; + [[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDir]; + + if (!isDir) + return NSDragOperationNone; + } + + return NSDragOperationCopy; + } + else if ([pboard.types containsObject:@"projects"]) + { + if (operation == NSTableViewDropOn) + return NSDragOperationNone; + + return NSDragOperationMove; + } + else + { + return NSDragOperationNone; + } +} + +- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id )info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation +{ + NSPasteboard *pboard = [info draggingPasteboard]; + + if ([pboard.types containsObject:(NSString *)NSFilenamesPboardType]) + { + NSArray *draggedFolders = [pboard propertyListForType:(NSString *)NSFilenamesPboardType]; + + for (NSString *folder in draggedFolders) + [self manageCappuccinoProjectControllerForPath:folder]; + + return YES; + } + else if ([pboard.types containsObject:@"projects"]) + { + NSData *rowData = [pboard dataForType:@"projects"]; + NSIndexSet *rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData]; + + [self.cappuccinoProjectControllers moveIndexes:rowIndexes toIndex:row]; + [self _reloadProjectsList]; + [self _saveManagedProjectsToUserDefaults]; + + return YES; + } + else + { + return NO; + } +} + +@end \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationDataView.h b/Tools/XcodeCapp/XcodeCapp/XCCOperationDataView.h new file mode 100644 index 000000000..7ceba2873 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationDataView.h @@ -0,0 +1,23 @@ +// +// OperationCellView.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/20/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@class XCCSourceProcessingOperation; + +@interface XCCOperationDataView : NSTableCellView +{ + IBOutlet NSBox *boxStatus; + IBOutlet NSTextField *fieldName; + IBOutlet NSTextField *fieldDescription; + +} + +@property XCCSourceProcessingOperation *operation; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationDataView.m b/Tools/XcodeCapp/XcodeCapp/XCCOperationDataView.m new file mode 100644 index 000000000..2065c54bc --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationDataView.m @@ -0,0 +1,69 @@ +// +// OperationCellView.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/20/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCOperationDataView.h" +#import "XCCSourceProcessingOperation.h" + +static NSColor * XCCOperationDataViewColorExecuting; +static NSColor * XCCOperationDataViewColorPending; +static NSColor * XCCOperationDataViewColorFinished; +static NSColor * XCCOperationDataViewColorCanceled; + + +@implementation XCCOperationDataView + ++ (void)initialize +{ + XCCOperationDataViewColorExecuting = [NSColor colorWithCalibratedRed:107.0/255.0 green:148.0/255.0 blue:236.0/255.0 alpha:1.0]; + XCCOperationDataViewColorPending = [NSColor colorWithCalibratedRed:236.0/255.0 green:236.0/255.0 blue:236.0/255.0 alpha:1.0]; + XCCOperationDataViewColorFinished = [NSColor colorWithCalibratedRed:179.0/255.0 green:214.0/255.0 blue:69.0/255.0 alpha:1.0]; + XCCOperationDataViewColorCanceled = [NSColor colorWithCalibratedRed:253.0/255.0 green:125/255.0 blue:8.0/255.0 alpha:1.0]; +} + +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + if (newWindow) + { + [self _updateDataView]; + [self.operation addObserver:self forKeyPath:@"operationName" options:NSKeyValueObservingOptionNew context:nil]; + [self.operation addObserver:self forKeyPath:@"operationDescription" options:NSKeyValueObservingOptionNew context:nil]; + [self.operation addObserver:self forKeyPath:@"isExecuting" options:NSKeyValueObservingOptionNew context:nil]; + } + else + { + [self.operation removeObserver:self forKeyPath:@"operationName"]; + [self.operation removeObserver:self forKeyPath:@"operationDescription"]; + [self.operation removeObserver:self forKeyPath:@"isExecuting"]; + } +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(XCCSourceProcessingOperation *)operation change:(NSDictionary *)change context:(void *)context +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self _updateDataView]; + }); +} + +- (void)_updateDataView +{ + self->fieldName.stringValue = self.operation.operationName; + self->fieldDescription.stringValue = self.operation.operationDescription; + + if (self.operation.isExecuting) + self->boxStatus.fillColor = XCCOperationDataViewColorExecuting; + else if (self.operation.isCancelled) + self->boxStatus.fillColor = XCCOperationDataViewColorCanceled; + else if (self.operation.isFinished) + self->boxStatus.fillColor = XCCOperationDataViewColorFinished; + else + self->boxStatus.fillColor = XCCOperationDataViewColorPending; +} + +@end + + diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationError.h b/Tools/XcodeCapp/XcodeCapp/XCCOperationError.h new file mode 100644 index 000000000..97a85c41c --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationError.h @@ -0,0 +1,34 @@ +// +// OperationError.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/21/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +typedef NS_ENUM(NSInteger, XCCOperationErrorType) +{ + XCCDefaultOperationErrorType, + XCCCappLintOperationErrorType, + XCCObjjOperationErrorType, + XCCObjj2ObjcSkeletonOperationErrorType, + XCCNib2CibOperationErrorType +}; + + +@interface XCCOperationError : NSObject + +@property (copy) NSString *fileName; +@property (copy) NSString *message; +@property (copy) NSString *command; +@property (copy) NSString *lineNumber; +@property int errorType; + ++ (NSArray *)operationErrorsFromObjj2ObjcSkeletonInfo:(NSDictionary*)info; ++ (NSArray *)operationErrorsFromObjjInfo:(NSDictionary*)info; ++ (NSArray *)operationErrorsFromCappLintInfo:(NSDictionary *)info; ++ (XCCOperationError *)operationErrorFromNib2CibInfo:(NSDictionary*)info; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationError.m b/Tools/XcodeCapp/XcodeCapp/XCCOperationError.m new file mode 100644 index 000000000..d2652020a --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationError.m @@ -0,0 +1,188 @@ +// +// OperationError.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/21/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCOperationError.h" + +static NSCharacterSet * XCCOperationErrorNonASCIICharactersSet; + +NSArray * parseCommandXMLString(NSString * aString) +{ + if (!XCCOperationErrorNonASCIICharactersSet) + { + NSMutableString *ASCIICharacters = [NSMutableString string]; + + for (NSInteger i = 32; i < 127; i++) + [ASCIICharacters appendFormat:@"%c", (char)i]; + + [ASCIICharacters appendString:@"\n\t"]; + + XCCOperationErrorNonASCIICharactersSet = [[NSCharacterSet characterSetWithCharactersInString:ASCIICharacters] invertedSet]; + + } + aString = [[aString componentsSeparatedByCharactersInSet:XCCOperationErrorNonASCIICharactersSet] componentsJoinedByString:@""]; + aString = [aString stringByReplacingOccurrencesOfString:@"[0m" withString:@""]; + + NSInteger i = 0; + while ((i < [aString length]) && [[NSCharacterSet newlineCharacterSet] characterIsMember:[aString characterAtIndex:i]]) + i++; + + NSArray *info; + + @try + { + info = [aString propertyList]; + } + @catch (NSException *exception) + { + info = @[ + @{ + @"lineNumber": @"0", + @"sourcePath": @"/Unknown", + @"message": [NSString stringWithFormat:@"Unable to parse: %@", aString] + } + ]; + } + + return info; +} + + + +@implementation XCCOperationError + +#pragma mark - Class Methods + ++ (instancetype)_operationErrorWithInfo:(NSDictionary*)info type:(int)type +{ + XCCOperationError *operationError = [self new]; + + operationError.fileName = info[@"sourcePath"]; + operationError.errorType = type; + + switch (type) + { + case XCCObjj2ObjcSkeletonOperationErrorType: + operationError.command = @"objj2objc2skeleton"; + operationError.lineNumber = info[@"line"]; + operationError.message = info[@"message"]; + break; + + case XCCObjjOperationErrorType: + operationError.command = @"objj"; + operationError.lineNumber = info[@"line"]; + operationError.message = info[@"message"]; + break; + + case XCCNib2CibOperationErrorType: + operationError.command = @"nib2cib"; + operationError.message = info[@"errors"]; + break; + + case XCCCappLintOperationErrorType: + operationError.command = @"capp_lint"; + operationError.message = info[@"message"]; + operationError.lineNumber = info[@"line"]; + break; + } + + return operationError; +} + ++ (NSArray*)operationErrorsFromObjj2ObjcSkeletonInfo:(NSDictionary*)info +{ + NSArray *errors = parseCommandXMLString(info[@"errors"]); + NSMutableArray *ret = [@[] mutableCopy]; + + for (NSDictionary *error in errors) + [ret addObject:[XCCOperationError _operationErrorWithInfo:error type:XCCObjj2ObjcSkeletonOperationErrorType]]; + + return ret; +} + ++ (NSArray*)operationErrorsFromObjjInfo:(NSDictionary*)info +{ + NSArray *errors = parseCommandXMLString(info[@"errors"]); + NSMutableArray *ret = [@[] mutableCopy]; + + for (NSDictionary *error in errors) + [ret addObject:[XCCOperationError _operationErrorWithInfo:error type:XCCObjjOperationErrorType]]; + + return ret; +} + ++ (NSArray*)operationErrorsFromCappLintInfo:(NSDictionary *)info +{ + NSString *response = info[@"errors"]; + NSString *sourcePath = info[@"sourcePath"]; + NSMutableArray *operationErrors = [@[] mutableCopy]; + NSMutableArray *errors = [[response componentsSeparatedByString:@"\n\n"] mutableCopy]; + + // We need to remove the first object who is the number of errors and the last object who is an empty line + [errors removeLastObject]; + [errors removeObjectAtIndex:0]; + + for (int i = 0; i < [errors count]; i++) + { + NSString *line; + NSMutableString *error = (NSMutableString*)errors[i]; + NSString *firstChar = [NSString stringWithFormat:@"%c" ,[error characterAtIndex:0]]; + + if ([[NSScanner scannerWithString:firstChar] scanInt:nil]) + error = (NSMutableString*)[NSString stringWithFormat:@"%@:%@", sourcePath, error]; + + NSInteger positionOfFirstColon = [error rangeOfString:@":"].location; + + NSString *errorWithoutPath = [error substringFromIndex:(positionOfFirstColon + 1)]; + NSInteger positionOfSecondColon = [errorWithoutPath rangeOfString:@":"].location; + line = [errorWithoutPath substringToIndex:positionOfSecondColon]; + + NSString *message = [NSString stringWithFormat:@"Code style issue at line %@ of file %@:\n%@", line, sourcePath.lastPathComponent, errorWithoutPath]; + + NSDictionary *info = @{@"line": line, + @"message": message, + @"sourcePath": sourcePath}; + + XCCOperationError *operationError = [XCCOperationError _operationErrorWithInfo:info type:XCCCappLintOperationErrorType]; + + [operationErrors addObject:operationError]; + } + + return operationErrors; +} + ++ (XCCOperationError *)operationErrorFromNib2CibInfo:(NSDictionary*)info +{ + return [XCCOperationError _operationErrorWithInfo:info type:XCCNib2CibOperationErrorType]; +} + + +#pragma mark - Overrides + +- (BOOL)isEqualTo:(XCCOperationError*)object +{ + return object.errorType == self.errorType && [object.fileName isEqualToString:self.fileName]; +} + +- (NSString*)description +{ + if (self.errorType == XCCNib2CibOperationErrorType) + return @"Converting Interface Files has failed"; + + if (self.errorType == XCCObjjOperationErrorType) + return @"Verifying compilation Warnings has failed"; + + if (self.errorType == XCCCappLintOperationErrorType) + return @"Verifying coding style has failed"; + + if (self.errorType == XCCObjj2ObjcSkeletonOperationErrorType) + return @"Creating Objective-C Class Pair has failed"; + + return @"An Unknown Error has been caught"; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorDataView.h b/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorDataView.h new file mode 100644 index 000000000..bcb8ff926 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorDataView.h @@ -0,0 +1,24 @@ +// +// OperationErrorCellView.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/21/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@class XCCOperationError; + +@interface XCCOperationErrorDataView : NSTableCellView +{ + IBOutlet NSTextField *fieldMessage; + IBOutlet NSTextField *fieldLineNumber; + IBOutlet NSTextField *labelLineNumber; + IBOutlet NSImageView *imageViewType; +} + +@property IBOutlet NSButton *buttonOpenInEditor; +@property XCCOperationError *errorOperation; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorDataView.m b/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorDataView.m new file mode 100644 index 000000000..37ce56feb --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorDataView.m @@ -0,0 +1,41 @@ +// +// OperationErrorCellView.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/21/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCOperationErrorDataView.h" +#import "XCCOperationError.h" + +@implementation XCCOperationErrorDataView + +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + if (!newWindow) + return; + + if (self.errorOperation.message) + self->fieldMessage.stringValue = self.errorOperation.message; + else + self->fieldMessage.stringValue = @"No message"; + + if (self.errorOperation.lineNumber) + self->fieldLineNumber.stringValue = self.errorOperation.lineNumber; + else + self->fieldLineNumber.stringValue = @"0"; + + switch (self.errorOperation.errorType) + { + case XCCCappLintOperationErrorType: + case XCCNib2CibOperationErrorType: + [self->imageViewType setImage:[NSImage imageNamed:@"NSStatusPartiallyAvailable"]]; + break; + + default: + [self->imageViewType setImage:[NSImage imageNamed:@"NSStatusUnavailable"]]; + } +} + +@end \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorHeaderDataView.h b/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorHeaderDataView.h new file mode 100644 index 000000000..b611e55f6 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorHeaderDataView.h @@ -0,0 +1,20 @@ +// +// OperationErrorHeaderCellView.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/22/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import +#import "XCCOperationError.h" + + +@interface XCCOperationErrorHeaderDataView : NSTableCellView +{ + IBOutlet NSTextField *fieldName; +} + +@property NSString *fileName; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorHeaderDataView.m b/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorHeaderDataView.m new file mode 100644 index 000000000..55fa566ce --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationErrorHeaderDataView.m @@ -0,0 +1,24 @@ +// +// OperationErrorHeaderCellView.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/22/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCOperationErrorHeaderDataView.h" + + +@implementation XCCOperationErrorHeaderDataView + +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + if (!newWindow) + return; + + if (self.fileName) + self->fieldName.stringValue = self.fileName; + else + self->fieldName.stringValue = @"No name"; +} +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationsViewController.h b/Tools/XcodeCapp/XcodeCapp/XCCOperationsViewController.h new file mode 100644 index 000000000..2b2cdc799 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationsViewController.h @@ -0,0 +1,27 @@ +// +// XCCOperationsViewController.h +// XcodeCapp +// +// Created by Antoine Mercadal on 6/4/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@class XCCCappuccinoProjectController; + + +@interface XCCOperationsViewController : NSViewController +{ + IBOutlet NSTableView *operationTableView; + IBOutlet NSBox *maskingView; + NSOperationQueue *operationQueue; + NSArray *operationsSnaphsot; +} + +@property XCCCappuccinoProjectController *cappuccinoProjectController; + +- (void)reload; +- (IBAction)cancelAllOperations:(id)sender; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCOperationsViewController.m b/Tools/XcodeCapp/XcodeCapp/XCCOperationsViewController.m new file mode 100644 index 000000000..61d4e3747 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCOperationsViewController.m @@ -0,0 +1,116 @@ +// +// XCCOperationsViewController.m +// XcodeCapp +// +// Created by Antoine Mercadal on 6/4/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCOperationsViewController.h" +#import "XCCCappuccinoProjectController.h" +#import "XCCCappuccinoProject.h" +#import "XCCOperationDataView.h" +#import "XCCSourcesFinderOperation.h" +#import "XCCSourceProcessingOperation.h" +#import "XCCPPXOperation.h" +#import "AppDelegate.h" + +@implementation XCCOperationsViewController + +@synthesize cappuccinoProjectController = _cappuccinoProjectController; + +#pragma nark - Initialization + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self->operationQueue = [((AppDelegate *)[NSApp delegate]) mainOperationQueue]; +} + + +#pragma nark - Utilities + +- (void)_showMaskingView:(BOOL)shouldShow +{ + if (shouldShow) + { + if (self->maskingView.superview) + return; + + [self->operationTableView setHidden:YES]; + + self->maskingView.frame = [self.view bounds]; + [self.view addSubview:self->maskingView]; + } + else + { + if (!self->maskingView.superview) + return; + + [self->operationTableView setHidden:NO]; + + [self->maskingView removeFromSuperview]; + } +} + +- (void)reload +{ + [self->operationTableView reloadData]; + + [self _showMaskingView:![self.cappuccinoProjectController projectRelatedOperations].count]; +} + + +#pragma mark - actions + +- (IBAction)cancelAllOperations:(id)sender +{ + [self.cappuccinoProjectController cancelAllOperations:sender]; + [self reload]; +} + + +#pragma mark - tableView delegate and datasource + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + // we create a snapshot at that moment, so if some operations are removed during the time between + // the count and reloadData, we don't crash. + self->operationsSnaphsot = [[[self.cappuccinoProjectController projectRelatedOperations] sortedArrayUsingComparator:^(NSOperation * op1, NSOperation * op2){ + + if (op1.isCancelled) + return NSOrderedDescending; + + if (op2.isCancelled) + return NSOrderedAscending; + + if ([op1.dependencies containsObject:op2]) + return NSOrderedDescending; + + if ([op2.dependencies containsObject:op1]) + return NSOrderedAscending; + + if (op1.isExecuting && !op2.isExecuting) + return NSOrderedAscending; + + if (!op1.isExecuting && op2.isExecuting) + return NSOrderedDescending; + + + + return NSOrderedSame; + }] copy]; + + return self->operationsSnaphsot.count; +} + +- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + XCCOperationDataView *dataView = [tableView makeViewWithIdentifier:@"OperationDataView" owner:nil]; + [dataView setOperation:self->operationsSnaphsot[row]]; + + return dataView; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCPPXOperation.h b/Tools/XcodeCapp/XcodeCapp/XCCPPXOperation.h new file mode 100644 index 000000000..6582fdbc4 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCPPXOperation.h @@ -0,0 +1,28 @@ +// +// XCCPbxCreationOperation.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 6/2/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import +#import "XCCAbstractOperation.h" + +@class XCCCappuccinoProject; +@class XCCTaskLauncher; + +extern NSString * const XCCPBXOperationDidStartNotification; +extern NSString * const XCCPbxCreationGenerateErrorNotification; +extern NSString * const XCCPBXOperationDidEndNotification; + +@interface XCCPPXOperation : XCCAbstractOperation +{ + NSMutableDictionary *PBXOperations; + NSTask *task; +} + +- (instancetype)initWithCappuccinoProject:(XCCCappuccinoProject *)aCappuccinoProject taskLauncher:(XCCTaskLauncher*)aTaskLauncher NS_DESIGNATED_INITIALIZER; +- (void)registerPathsToAddInPBX:(NSArray *)paths; +- (void)registerPathsToRemoveFromPBX:(NSArray *)paths; +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCPPXOperation.m b/Tools/XcodeCapp/XcodeCapp/XCCPPXOperation.m new file mode 100644 index 000000000..1a47b3122 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCPPXOperation.m @@ -0,0 +1,126 @@ +// +// XCCPbxCreationOperation.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 6/2/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCPPXOperation.h" +#import "XCCCappuccinoProject.h" +#import "XCCTaskLauncher.h" + +NSString * const XCCPBXOperationDidStartNotification = @"XCCPbxCreationDidStartNotification"; +NSString * const XCCPbxCreationGenerateErrorNotification = @"XCCPbxCreationDidGenerateErrorNotification"; +NSString * const XCCPBXOperationDidEndNotification = @"XCCPbxCreationDidEndNotification"; + + +@implementation XCCPPXOperation + +#pragma mark - Initialization + +- (instancetype)initWithCappuccinoProject:(XCCCappuccinoProject *)aCappuccinoProject taskLauncher:(XCCTaskLauncher*)aTaskLauncher +{ + if (self = [super initWithCappuccinoProject:aCappuccinoProject taskLauncher:aTaskLauncher]) + { + self.operationDescription = self.cappuccinoProject.projectPath; + self.operationName = @"Updating the Xcode project"; + + self->PBXOperations = [@{} mutableCopy]; + self->PBXOperations[@"add"] = [@[] mutableCopy]; + self->PBXOperations[@"remove"] = [@[] mutableCopy]; + } + + return self; +} + + +#pragma mark - PBX Operations + +- (void)registerPathsToAddInPBX:(NSArray *)paths +{ + NSMutableArray *finalPaths = [@[] mutableCopy]; + + for (NSString *path in paths) + if ([XCCCappuccinoProject isObjjFile:path]) + [finalPaths addObject:path]; + + [self->PBXOperations[@"add"] addObjectsFromArray:finalPaths]; +} + +- (void)registerPathsToRemoveFromPBX:(NSArray *)paths +{ + [self->PBXOperations[@"remove"] addObjectsFromArray:paths]; +} + + +#pragma mark - NSOperation API + +- (void)cancel +{ + if (self->task.isRunning) + [self->task terminate]; + + [super cancel]; +} + + +- (void)main +{ + [self dispatchNotificationName:XCCPBXOperationDidStartNotification]; + + DDLogVerbose(@"Pbx creation started: %@", self.cappuccinoProject.projectPath); + + @try + { + BOOL shouldLaunchTask = NO; + NSMutableArray *arguments = [@[self.cappuccinoProject.PBXModifierScriptPath, @"update", self.cappuccinoProject.projectPath] mutableCopy]; + + for (NSString *action in self->PBXOperations) + { + NSArray *paths = self->PBXOperations[action]; + + if (paths.count) + { + [arguments addObject:action]; + [arguments addObjectsFromArray:paths]; + + shouldLaunchTask = YES; + } + + DDLogVerbose(@"PBX: path to %@ : %@", action, paths); + } + + if (shouldLaunchTask) + { + self->task = [self->taskLauncher taskWithCommand:@"python" arguments:arguments]; + + NSDictionary *result = [self->taskLauncher runTask:self->task returnType:kTaskReturnTypeStdError]; + + if ([result[@"status"] intValue] != 0) + { + NSMutableDictionary *info = [self operationInformations]; + info[@"errors"] = result[@"message"]; + + [self dispatchNotificationName:XCCPbxCreationGenerateErrorNotification userInfo:info]; + } + } + } + @catch (NSException *exception) + { + [self dispatchNotificationName:XCCPbxCreationGenerateErrorNotification]; + DDLogVerbose(@"Pbx creation failed: %@", exception); + } + @finally + { + __block XCCPPXOperation *weakOperation = self; + + self.completionBlock = ^{ + [weakOperation dispatchNotificationName:XCCPBXOperationDidEndNotification]; + }; + } + + DDLogVerbose(@"Pbx creation ended: %@", self.cappuccinoProject.projectPath); +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCPath.h b/Tools/XcodeCapp/XcodeCapp/XCCPath.h new file mode 100644 index 000000000..393e815ba --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCPath.h @@ -0,0 +1,17 @@ +// +// Path.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/20/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@interface XCCPath : NSObject + +@property NSString *name; + +- (instancetype)initWithName:(NSString*)aName NS_DESIGNATED_INITIALIZER; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCPath.m b/Tools/XcodeCapp/XcodeCapp/XCCPath.m new file mode 100644 index 000000000..d3555c25e --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCPath.m @@ -0,0 +1,26 @@ +// +// Path.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/20/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCPath.h" + +@implementation XCCPath + +- (instancetype)initWithName:(NSString*)aName +{ + if (self = [super init]) + self.name = aName; + + return self; +} + +- (instancetype)init +{ + return [self initWithName:@"~/bin"]; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCSettingsViewController.h b/Tools/XcodeCapp/XcodeCapp/XCCSettingsViewController.h new file mode 100644 index 000000000..fb7388a8d --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCSettingsViewController.h @@ -0,0 +1,31 @@ +// +// XCCSettingsViewController.h +// XcodeCapp +// +// Created by Antoine Mercadal on 6/4/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@class XCCCappuccinoProjectController; + + +@interface XCCSettingsViewController : NSViewController +{ + IBOutlet NSTableView *tableViewBinaryPaths; + IBOutlet NSButton *checkBoxProcessNib2Cib; + IBOutlet NSButton *checkBoxProcessObjj; + IBOutlet NSButton *checkBoxProcessObjj2Skeleton; + IBOutlet NSButton *checkBoxProcessCappLint; + IBOutlet NSTextField *fieldObjjIncludePath; + IBOutlet NSTextField *fieldXcodeCappIgnoreContent; + + BOOL isObserving; +} + +@property XCCCappuccinoProjectController *cappuccinoProjectController; + +- (void)reload; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCSettingsViewController.m b/Tools/XcodeCapp/XcodeCapp/XCCSettingsViewController.m new file mode 100644 index 000000000..98faea416 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCSettingsViewController.m @@ -0,0 +1,155 @@ +// +// XCCSettingsViewController.m +// XcodeCapp +// +// Created by Antoine Mercadal on 6/4/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCSettingsViewController.h" +#import "XCCCappuccinoProjectController.h" +#import "XCCCappuccinoProject.h" +#import "XCCPath.h" + +@implementation XCCSettingsViewController + +@synthesize cappuccinoProjectController = _cappuccinoProjectController; + + +#pragma Initialization + +- (void)viewDidLoad +{ + [super viewDidLoad]; +} + + +#pragma Utilities + +- (void)reload +{ + XCCCappuccinoProject * project = self.cappuccinoProjectController.cappuccinoProject; + + if (project) + { + [self->fieldXcodeCappIgnoreContent bind:NSValueBinding toObject:project withKeyPath:@"XcodeCappIgnoreContent" options:nil]; + [self->fieldObjjIncludePath bind:NSValueBinding toObject:project withKeyPath:@"objjIncludePath" options:nil]; + [self->checkBoxProcessObjj2Skeleton bind:NSValueBinding toObject:project withKeyPath:@"processObjj2ObjcSkeleton" options:nil]; + [self->checkBoxProcessNib2Cib bind:NSValueBinding toObject:project withKeyPath:@"processNib2Cib" options:nil]; + [self->checkBoxProcessObjj bind:NSValueBinding toObject:project withKeyPath:@"processObjjWarnings" options:nil]; + [self->checkBoxProcessCappLint bind:NSValueBinding toObject:project withKeyPath:@"processCappLint" options:nil]; + } + else + { + [self->fieldXcodeCappIgnoreContent unbind:NSValueBinding]; + [self->fieldObjjIncludePath unbind:NSValueBinding]; + [self->checkBoxProcessObjj2Skeleton unbind:NSValueBinding]; + [self->checkBoxProcessNib2Cib unbind:NSValueBinding]; + [self->checkBoxProcessObjj unbind:NSValueBinding]; + [self->checkBoxProcessCappLint unbind:NSValueBinding]; + } + + [self->tableViewBinaryPaths reloadData]; +} + + +#pragma mark - Custom Getters and Setters + +- (void)setCappuccinoProjectController:(XCCCappuccinoProjectController *)cappuccinoProjectController +{ + if ([cappuccinoProjectController isEqualTo:_cappuccinoProjectController]) + return; + + [self _removeObservers]; + [self willChangeValueForKey:@"cappuccinoProjectController"]; + _cappuccinoProjectController = cappuccinoProjectController; + [self didChangeValueForKey:@"cappuccinoProjectController"]; + [self _addObservers]; +} + +- (XCCCappuccinoProjectController*)cappuccinoProjectController +{ + return _cappuccinoProjectController; +} + + +#pragma mark - Observers + +- (void)_addObservers +{ + if (self->isObserving) + return; + + self->isObserving = YES; + + [self.cappuccinoProjectController addObserver:self forKeyPath:@"cappuccinoProject.nickname" options:NSKeyValueObservingOptionNew context:nil]; + [self.cappuccinoProjectController addObserver:self forKeyPath:@"cappuccinoProject.XcodeCappIgnoreContent" options:NSKeyValueObservingOptionNew context:nil]; + [self.cappuccinoProjectController addObserver:self forKeyPath:@"cappuccinoProject.processObjj2ObjcSkeleton" options:NSKeyValueObservingOptionNew context:nil]; + [self.cappuccinoProjectController addObserver:self forKeyPath:@"cappuccinoProject.processNib2Cib" options:NSKeyValueObservingOptionNew context:nil]; + [self.cappuccinoProjectController addObserver:self forKeyPath:@"cappuccinoProject.processObjjWarnings" options:NSKeyValueObservingOptionNew context:nil]; + [self.cappuccinoProjectController addObserver:self forKeyPath:@"cappuccinoProject.processCappLint" options:NSKeyValueObservingOptionNew context:nil]; +} + +- (void)_removeObservers +{ + if (!self->isObserving) + return; + + self->isObserving = NO; + + [self.cappuccinoProjectController removeObserver:self forKeyPath:@"cappuccinoProject.nickname"]; + [self.cappuccinoProjectController removeObserver:self forKeyPath:@"cappuccinoProject.XcodeCappIgnoreContent"]; + [self.cappuccinoProjectController removeObserver:self forKeyPath:@"cappuccinoProject.processObjj2ObjcSkeleton"]; + [self.cappuccinoProjectController removeObserver:self forKeyPath:@"cappuccinoProject.processNib2Cib"]; + [self.cappuccinoProjectController removeObserver:self forKeyPath:@"cappuccinoProject.processObjjWarnings"]; + [self.cappuccinoProjectController removeObserver:self forKeyPath:@"cappuccinoProject.processCappLint"]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(XCCCappuccinoProjectController *)projectController change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:@"XcodeCappIgnoreContent"]) + [projectController reinitializeProjectFromSettings]; + else + [projectController.cappuccinoProject saveSettings]; +} + + +#pragma mark - Actions + +- (IBAction)addBinaryPath:(id)sender +{ + [self.cappuccinoProjectController.cappuccinoProject.binaryPaths addObject:[XCCPath new]]; + [self->tableViewBinaryPaths reloadData]; + + [self.cappuccinoProjectController reinitializeProjectFromSettings]; +} + +- (IBAction)removeSelectedBinaryPaths:(id)sender +{ + [self.cappuccinoProjectController.cappuccinoProject.binaryPaths removeObjectsAtIndexes:[self->tableViewBinaryPaths selectedRowIndexes]]; + [self->tableViewBinaryPaths reloadData]; + + [self.cappuccinoProjectController reinitializeProjectFromSettings]; +} + + +#pragma mark - tableView delegate and datasource + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return self.cappuccinoProjectController.cappuccinoProject.binaryPaths.count; +} + +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + return ((XCCPath *)(self.cappuccinoProjectController.cappuccinoProject.binaryPaths)[row]).name; +} + +- (void)tableView:(NSTableView *)tableView setObjectValue:(id)value forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + ((XCCPath *)(self.cappuccinoProjectController.cappuccinoProject.binaryPaths)[row]).name = value; + + [self.cappuccinoProjectController reinitializeProjectFromSettings]; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCSourceProcessingOperation.h b/Tools/XcodeCapp/XcodeCapp/XCCSourceProcessingOperation.h new file mode 100644 index 000000000..5a10961a4 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCSourceProcessingOperation.h @@ -0,0 +1,40 @@ +// +// ProcessSourceOperation.h +// XcodeCapp +// +// Created by Aparajita on 4/27/13. +// Copyright (c) 2013 Cappuccino Project. All rights reserved. +// + +#import +#import "XCCAbstractOperation.h" + +@class XCCCappuccinoProject; +@class XCCTaskLauncher; + +extern NSString * const XCCConversionDidStartNotification; +extern NSString * const XCCConversionDidEndNotification; +extern NSString * const XCCObjjDidStartNotification; +extern NSString * const XCCObjjDidEndNotification; +extern NSString * const XCCCappLintDidStartNotification; +extern NSString * const XCCCappLintDidEndNotification; +extern NSString * const XCCObjj2ObjcSkeletonDidStartNotification; +extern NSString * const XCCObjj2ObjcSkeletonDidEndNotification; +extern NSString * const XCCNib2CibDidStartNotification; +extern NSString * const XCCNib2CibDidEndNotification; +extern NSString * const XCCObjjDidGenerateErrorNotification; +extern NSString * const XCCCappLintDidGenerateErrorNotification; +extern NSString * const XCCObjj2ObjcSkeletonDidGenerateErrorNotification; +extern NSString * const XCCNib2CibDidGenerateErrorNotification; + + +@interface XCCSourceProcessingOperation : XCCAbstractOperation +{ + NSTask *task; +} + +@property NSString *sourcePath; + +- (instancetype)initWithCappuccinoProject:(XCCCappuccinoProject *)aCappuccinoProject taskLauncher:(XCCTaskLauncher*)aTaskLauncher sourcePath:(NSString *)sourcePath; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCSourceProcessingOperation.m b/Tools/XcodeCapp/XcodeCapp/XCCSourceProcessingOperation.m new file mode 100644 index 000000000..c16cfe606 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCSourceProcessingOperation.m @@ -0,0 +1,228 @@ + +// ProcessSourceOperation.m +// XcodeCapp +// +// Created by Aparajita on 4/27/13. +// Copyright (c) 2013 Cappuccino Project. All rights reserved. +// + +#import "XCCSourceProcessingOperation.h" +#import "XCCTaskLauncher.h" + +NSString * const XCCConversionDidEndNotification = @"XCCConversionDidStopNotification"; +NSString * const XCCConversionDidStartNotification = @"XCCConversionDidStartNotification"; +NSString * const XCCObjjDidStartNotification = @"XCCObjjDidStartNotification"; +NSString * const XCCObjjDidGenerateErrorNotification = @"XCCObjjDidGenerateErrorNotification"; +NSString * const XCCObjjDidEndNotification = @"XCCObjjDidEndNotification"; +NSString * const XCCCappLintDidStartNotification = @"XCCCappLintDidStartNotification"; +NSString * const XCCCappLintDidGenerateErrorNotification = @"XCCCappLintDidGenerateErrorNotification"; +NSString * const XCCCappLintDidEndNotification = @"XCCCappLintDidEndNotification"; +NSString * const XCCObjj2ObjcSkeletonDidStartNotification = @"XCCObjj2ObjcSkeletonDidStartNotification"; +NSString * const XCCObjj2ObjcSkeletonDidGenerateErrorNotification = @"XCCObjj2ObjcSkeletonDidGenerateErrorNotification"; +NSString * const XCCObjj2ObjcSkeletonDidEndNotification = @"XCCObjj2ObjcSkeletonDidEndNotification"; +NSString * const XCCNib2CibDidStartNotification = @"XCCNib2CibDidStartNotification"; +NSString * const XCCNib2CibDidGenerateErrorNotification = @"XCCNib2CibDidGenerateErrorNotification"; +NSString * const XCCNib2CibDidEndNotification = @"XCCNib2CibDidEndNotification"; + + +@implementation XCCSourceProcessingOperation + + +#pragma mark - Initialization + +- (instancetype)initWithCappuccinoProject:(XCCCappuccinoProject *)aCappuccinoProject taskLauncher:(XCCTaskLauncher*)aTaskLauncher sourcePath:(NSString *)sourcePath +{ + if (self = [super initWithCappuccinoProject:aCappuccinoProject taskLauncher:aTaskLauncher]) + { + NSString *projectPath = [NSString stringWithFormat:@"%@/", self.cappuccinoProject.projectPath]; + + self.sourcePath = sourcePath; + self.operationName = @"Pending source processing"; + self.operationDescription = [self.sourcePath stringByReplacingOccurrencesOfString:projectPath withString:@""]; + } + + return self; +} + + +#pragma mark - Utilities + +- (NSMutableDictionary *)operationInformations +{ + NSMutableDictionary *info = [super operationInformations]; + + info[@"sourcePath"] = self.sourcePath; + + return info; +} + +- (void)_updateOperationInformation +{ + NSString *commandName = self->task.launchPath.lastPathComponent; + + if ([commandName isEqualToString:@"objj2objcskeleton"]) + self.operationName = @"Creating Objective-C Class Pair"; + + else if ([commandName isEqualToString:@"nib2cib"]) + self.operationName = @"Converting Interface Files"; + + else if ([commandName isEqualToString:@"objj"]) + self.operationName = @"Verifying compilation Warnings"; + + else if ([commandName isEqualToString:@"capp_lint"]) + self.operationName = @"Verifying coding style"; + else + self.operationName = commandName; +} + +- (void)_postProcessingErrorNotificationName:(NSString *)notificationName error:(NSString *)errors +{ + if (self.isCancelled) + return; + + if (errors.length == 0) + errors = @"An unspecified error occurred"; + + NSMutableDictionary *info = [self operationInformations]; + info[@"errors"] = errors; + + [self dispatchNotificationName:notificationName userInfo:info]; +} + +- (NSDictionary*)_launchTaskWithCommand:(NSString*)aCommand arguments:(NSArray*)arguments +{ + DDLogVerbose(@"Running processing task: %@ on file: %@", aCommand, self.sourcePath); + + self->task = [self->taskLauncher taskWithCommand:aCommand arguments:arguments]; + + [self _updateOperationInformation]; + + return [self->taskLauncher runTask:self->task returnType:kTaskReturnTypeAny]; +} + + +#pragma Task Launcher + +- (BOOL)launchObjj2ObjcSkeletonCommandForPath:(NSString*)aPath +{ + [self dispatchNotificationName:XCCObjj2ObjcSkeletonDidStartNotification]; + + NSString *targetName = [self.cappuccinoProject flattenedXcodeSupportFileNameForPath:aPath]; + NSArray *arguments = @[aPath, self.cappuccinoProject.supportPath, @"-n", targetName]; + NSDictionary *result = [self _launchTaskWithCommand:@"objj2objcskeleton" arguments:arguments]; + int code = [result[@"status"] intValue]; + + if (code != 0) + [self _postProcessingErrorNotificationName:XCCObjj2ObjcSkeletonDidGenerateErrorNotification error:result[@"response"]]; + + [self dispatchNotificationName:XCCObjj2ObjcSkeletonDidEndNotification]; + + return code == 0; +} + +- (BOOL)launchNib2CibCommandForPath:(NSString*)aPath +{ + [self dispatchNotificationName:XCCNib2CibDidStartNotification]; + + NSArray *arguments = @[@"--no-colors", self.sourcePath]; + NSDictionary *result = [self _launchTaskWithCommand:@"nib2cib" arguments:arguments]; + int code = [result[@"status"] intValue]; + + if (code != 0) + [self _postProcessingErrorNotificationName:XCCNib2CibDidGenerateErrorNotification error:result[@"response"]]; + + [self dispatchNotificationName:XCCNib2CibDidEndNotification]; + + return code == 0; +} + +- (BOOL)launchObjjCommandForPath:(NSString*)aPath +{ + [self dispatchNotificationName:XCCObjjDidStartNotification]; + + NSArray *arguments = @[@"--xml", @"-I", [self.cappuccinoProject objjIncludePath], self.sourcePath]; + NSDictionary *result = [self _launchTaskWithCommand:@"objj" arguments:arguments]; + int code = [result[@"status"] intValue]; + + if (code != 0) + [self _postProcessingErrorNotificationName:XCCObjjDidGenerateErrorNotification error:result[@"response"]]; + + [self dispatchNotificationName:XCCObjjDidEndNotification]; + + return code == 0; +} + +- (BOOL)launchCappLintCommandForPath:(NSString*)aPath +{ + [self dispatchNotificationName:XCCCappLintDidStartNotification]; + + NSString *baseDirectory = [NSString stringWithFormat:@"--basedir='%@'", self.cappuccinoProject.projectPath]; + NSArray *arguments = @[baseDirectory, self.sourcePath]; + NSDictionary *result = [self _launchTaskWithCommand:@"capp_lint" arguments:arguments]; + int code = [result[@"status"] intValue]; + + if (code != 0) + [self _postProcessingErrorNotificationName:XCCCappLintDidGenerateErrorNotification error:result[@"response"]]; + + [self dispatchNotificationName:XCCCappLintDidEndNotification]; + + return code == 0; +} + + +#pragma mark - NSOperation Protocol + +- (void)cancel +{ + if (self->task.isRunning) + [self->task terminate]; + + self.operationName = @"Canceled source processing"; + + [super cancel]; +} + +- (void)main +{ + DDLogVerbose(@"Conversion started: %@", self.sourcePath); + + [self dispatchNotificationName:XCCConversionDidStartNotification]; + + @try + { + if ([XCCCappuccinoProject isXibFile:self.sourcePath]) + { + if (self.cappuccinoProject.processNib2Cib) + [self launchNib2CibCommandForPath:self.sourcePath]; + } + else if ([XCCCappuccinoProject isObjjFile:self.sourcePath]) + { + BOOL shouldContinue = YES; + + if (self.cappuccinoProject.processObjj2ObjcSkeleton) + shouldContinue = [self launchObjj2ObjcSkeletonCommandForPath:self.sourcePath]; + + if (shouldContinue && self.cappuccinoProject.processObjjWarnings) + shouldContinue = [self launchObjjCommandForPath:self.sourcePath]; + + if (shouldContinue && self.cappuccinoProject.processCappLint) + [self launchCappLintCommandForPath:self.sourcePath]; + } + } + @catch (NSException *exception) + { + DDLogVerbose(@"Conversion failed: %@", exception); + } + @finally + { + __block XCCSourceProcessingOperation *weakOperation = self; + + self.completionBlock = ^{ + [weakOperation dispatchNotificationName:XCCConversionDidEndNotification]; + }; + } + + DDLogVerbose(@"Conversion ended: %@", self.sourcePath); +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCSourcesFinderOperation.h b/Tools/XcodeCapp/XcodeCapp/XCCSourcesFinderOperation.h new file mode 100644 index 000000000..56e6f1a1e --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCSourcesFinderOperation.h @@ -0,0 +1,27 @@ +// +// FindSourceFilesOperation.h +// XcodeCapp +// +// Created by Aparajita on 4/27/13. +// Copyright (c) 2013 Cappuccino Project. All rights reserved. +// + +#import +#import "XCCAbstractOperation.h" + +@class XCCCappuccinoProject; +@class XCCTaskLauncher; + +extern NSString * const XCCNeedSourceToProjectPathMappingNotification; +extern NSString * const XCCSourcesFinderOperationDidStartNotification; +extern NSString * const XCCSourcesFinderOperationDidEndNotification; + + +@interface XCCSourcesFinderOperation : XCCAbstractOperation +{ + NSString *searchPath; +} + +- (instancetype)initWithCappuccinoProject:(XCCCappuccinoProject *)cappuccinoProject taskLauncher:(XCCTaskLauncher*)aTaskLauncher sourcePath:(NSString *)sourcePath; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCSourcesFinderOperation.m b/Tools/XcodeCapp/XcodeCapp/XCCSourcesFinderOperation.m new file mode 100644 index 000000000..844eb7a4b --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCSourcesFinderOperation.m @@ -0,0 +1,169 @@ +// +// FindSourceFilesOperation.m +// XcodeCapp +// +// Created by Aparajita on 4/27/13. +// Copyright (c) 2013 Cappuccino Project. All rights reserved. +// + +#import "XCCSourcesFinderOperation.h" +#import "XCCSourceProcessingOperation.h" +#import "XCCTaskLauncher.h" + +NSString * const XCCSourcesFinderOperationDidStartNotification = @"XCCSourcesFinderOperationDidStartNotification"; +NSString * const XCCSourcesFinderOperationDidEndNotification = @"XCCSourcesFinderOperationDidEndNotification"; +NSString * const XCCNeedSourceToProjectPathMappingNotification = @"XCCNeedSourceToProjectPathMappingNotification"; + + +@implementation XCCSourcesFinderOperation + + +#pragma mark - Initialization + +- (instancetype)initWithCappuccinoProject:(XCCCappuccinoProject *)aCappuccinoProject taskLauncher:(XCCTaskLauncher*)aTaskLauncher sourcePath:(NSString *)sourcePath +{ + if (self = [super initWithCappuccinoProject:aCappuccinoProject taskLauncher:aTaskLauncher]) + { + self.operationName = @"Searching for Objective-J files"; + self.operationDescription = self.cappuccinoProject.name; + self->searchPath = sourcePath; + } + + return self; +} + + +#pragma mark - Utilities + +- (NSArray *)_findSourceFilesAtProjectPath:(NSString *)aProjectPath +{ + NSError *error = NULL; + NSString *projectPath = [self.cappuccinoProject.projectPath stringByAppendingPathComponent:aProjectPath]; + NSFileManager *fm = [NSFileManager defaultManager]; + NSMutableArray *sourcePaths = [@[] mutableCopy]; + + NSArray *urls = [fm contentsOfDirectoryAtURL:[NSURL fileURLWithPath:projectPath.stringByResolvingSymlinksInPath] + includingPropertiesForKeys:@[NSURLIsDirectoryKey, NSURLIsSymbolicLinkKey] + options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants | NSDirectoryEnumerationSkipsSubdirectoryDescendants + error:&error]; + + if (!urls) + return [@[] mutableCopy]; + + for (NSURL *url in urls) + { + NSString *filename = url.lastPathComponent; + NSString *projectRelativePath = [aProjectPath stringByAppendingPathComponent:filename]; + NSString *realPath = url.path; + NSURL *resolvedURL = url; + NSNumber *isDirectory; + NSNumber *isSymlink; + + [url getResourceValue:&isSymlink forKey:NSURLIsSymbolicLinkKey error:nil]; + + if (isSymlink.boolValue == YES) + { + resolvedURL = [url URLByResolvingSymlinksInPath]; + + if ([resolvedURL checkResourceIsReachableAndReturnError:nil]) + { + filename = resolvedURL.lastPathComponent; + realPath = resolvedURL.path; + } + else + continue; + } + + [resolvedURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil]; + + if (isDirectory.boolValue == YES) + { + if ([XCCCappuccinoProject shouldIgnoreDirectoryNamed:filename]) + { + DDLogVerbose(@"%@: ignored symlinked directory: %@", self.cappuccinoProject.name, projectRelativePath); + continue; + } + + // If the resolved path is not within the project directory and is not ignored, add a mapping to it + // so we can map the resolved path back to the project directory later. + if (isSymlink.boolValue == YES) + { + NSString *fullProjectPath = [self.cappuccinoProject.projectPath stringByAppendingPathComponent:projectRelativePath]; + + if (![realPath hasPrefix:fullProjectPath] && ![XCCCappuccinoProject pathMatchesIgnoredPaths:fullProjectPath cappuccinoProjectIgnoredPathPredicates:self.cappuccinoProject.ignoredPathPredicates]) + { + DDLogVerbose(@"%@: symlinked directory: %@ -> %@", self.cappuccinoProject.name, projectRelativePath, realPath); + + NSMutableDictionary *info = [self operationInformations]; + info[@"sourcePath"] = realPath; + info[@"projectPath"] = fullProjectPath; + + [self dispatchNotificationName:XCCNeedSourceToProjectPathMappingNotification userInfo:info]; + } + else + DDLogVerbose(@"%@: ignored symlinked directory: %@", self.cappuccinoProject.name, projectRelativePath); + } + + DDLogVerbose(@"%@: found directory. checking for source files: %@", self.cappuccinoProject.name, filename); + + [sourcePaths addObjectsFromArray:[self _findSourceFilesAtProjectPath:projectRelativePath]]; + continue; + } + + if ([XCCCappuccinoProject pathMatchesIgnoredPaths:realPath cappuccinoProjectIgnoredPathPredicates:self.cappuccinoProject.ignoredPathPredicates]) + continue; + + NSString *projectSourcePath = [self.cappuccinoProject.projectPath stringByAppendingPathComponent:projectRelativePath]; + + if ([XCCCappuccinoProject isObjjFile:filename] || [XCCCappuccinoProject isXibFile:filename]) + { + DDLogVerbose(@"%@: found source file: %@", self.cappuccinoProject.name, filename); + + NSString *processedPath; + + if ([XCCCappuccinoProject isObjjFile:filename]) + processedPath = [[self.cappuccinoProject shadowBasePathForProjectSourcePath:projectSourcePath] stringByAppendingPathExtension:@"h"]; + else + processedPath = [projectSourcePath.stringByDeletingPathExtension stringByAppendingPathExtension:@"cib"]; + + if (![fm fileExistsAtPath:processedPath]) + [sourcePaths addObject:projectSourcePath]; + } + } + + return sourcePaths; +} + + +#pragma mark - NSOperation API + +- (void)main +{ + DDLogVerbose(@"Finding source files started"); + + NSArray *sourcesPaths; + + [self dispatchNotificationName:XCCSourcesFinderOperationDidStartNotification userInfo:@{@"cappuccinoProject": self.cappuccinoProject, @"sourcePaths" : @[]}]; + + @try + { + sourcesPaths = [self _findSourceFilesAtProjectPath:self->searchPath]; + } + @catch (NSException *exception) + { + DDLogVerbose(@"Finding source files failed: %@", exception); + } + @finally + { + __block XCCSourcesFinderOperation *weakOperation = self; + __block NSArray * weakSourcesPaths = sourcesPaths; + + self.completionBlock = ^{ + [weakOperation dispatchNotificationName:XCCSourcesFinderOperationDidEndNotification userInfo:@{@"cappuccinoProject": weakOperation.cappuccinoProject, @"sourcePaths" : weakSourcesPaths}]; + }; + } + + DDLogVerbose(@"Finding source files ended"); +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCTaskLauncher.h b/Tools/XcodeCapp/XcodeCapp/XCCTaskLauncher.h new file mode 100644 index 000000000..5b6d0fe56 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCTaskLauncher.h @@ -0,0 +1,40 @@ +// +// TaskLauncher.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/6/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +typedef NS_ENUM(NSInteger, XCCTaskReturnType) +{ + kTaskReturnTypeNone, + kTaskReturnTypeStdOut, + kTaskReturnTypeStdError, + kTaskReturnTypeAny +}; + + +@interface XCCTaskLauncher : NSObject + +@property BOOL isValid; + +@property NSMutableArray *binaryPaths; +@property NSMutableDictionary *environment; + +@property NSArray *executables; +@property NSMutableDictionary *executablePaths; + +- (instancetype)initWithEnvironmentPaths:(NSArray*)environementPaths NS_DESIGNATED_INITIALIZER; + +- (NSTask*)taskWithCommand:(NSString *)aCommand arguments:(NSArray *)arguments; +- (NSTask*)taskWithCommand:(NSString *)aCommand arguments:(NSArray *)arguments currentDirectoryPath:(NSString*)aCurrentDirectoryPath; + +- (NSDictionary *)runTaskWithCommand:(NSString *)aCommand arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType; +- (NSDictionary *)runTaskWithCommand:(NSString *)aCommand arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType currentDirectoryPath:(NSString*)aCurrentDirectoryPath; +- (NSDictionary*)runTask:(NSTask*)aTask returnType:(XCCTaskReturnType)returnType; +- (NSDictionary*)runJakeTaskWithArguments:(NSMutableArray*)arguments currentDirectoryPath:(NSString*)aCurrentDirectoryPath; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCTaskLauncher.m b/Tools/XcodeCapp/XcodeCapp/XCCTaskLauncher.m new file mode 100644 index 000000000..318fa2caf --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCTaskLauncher.m @@ -0,0 +1,246 @@ +// +// TaskLaunch.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/6/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCTaskLauncher.h" + +@implementation XCCTaskLauncher + +- (instancetype)init +{ + return [self initWithEnvironmentPaths:@[]]; +} + +- (instancetype)initWithEnvironmentPaths:(NSArray*)environementPaths +{ + if (self = [super init]) + { + // Add possible executable paths to PATH + self.environment = [NSProcessInfo processInfo].environment.mutableCopy; + self.binaryPaths = [environementPaths mutableCopy]; + + [self.binaryPaths addObject:@"/usr/bin"]; + [self.binaryPaths addObject:@"/usr/local/bin"]; + [self.binaryPaths addObject:@"~/bin"]; + [self.binaryPaths addObject:@"/usr/local/narwhal/bin"]; + [self.binaryPaths addObject:@"~/narwhal/bin"]; + + DDLogError(@"Init task manager with environements %@", self.binaryPaths); + + NSMutableArray *paths = [self.binaryPaths mutableCopy]; + + for (NSInteger i = 0; i < paths.count; ++i) + paths[i] = [paths[i] stringByExpandingTildeInPath]; + + self.environment[@"PATH"] = [[paths componentsJoinedByString:@":"] stringByAppendingFormat:@":%@", self.environment[@"PATH"]]; + self.environment[@"NARWHAL_ENGINE"] = @"jsc"; + self.environment[@"CAPP_NOSUDO"] = @"1"; + + self.executables = @[@"python", @"objj", @"nib2cib",@"objj2objcskeleton", @"capp_lint", @"touch"]; + + self.isValid = [self _checkExecutables]; + } + + return self; +} + +- (BOOL)_checkExecutables +{ + NSMutableArray *arguments = [@[] mutableCopy]; + + [arguments addObject:[[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:@"supawhich"]]; + [arguments addObjectsFromArray:self.executables]; + + NSDictionary *taskResult = [self runTaskWithCommand:@"/bin/bash" arguments:arguments returnType:kTaskReturnTypeStdOut]; + + if ([taskResult[@"status"] integerValue] != 0) + { + DDLogError(@"Could not find executable in PATH: %@", self.environment[@"PATH"]); + return NO; + } + + self.executablePaths = (NSMutableDictionary*)[NSJSONSerialization JSONObjectWithData:[taskResult[@"response"] dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil]; + + DDLogVerbose(@"Executable paths: %@", self.executablePaths); + + return YES; +} + +- (NSTask*)taskWithCommand:(NSString *)aCommand arguments:(NSArray *)arguments +{ + return [self taskWithCommand:aCommand arguments:arguments currentDirectoryPath:nil]; +} + +- (NSTask*)taskWithCommand:(NSString *)aCommand arguments:(NSArray *)arguments currentDirectoryPath:(NSString*)aCurrentDirectoryPath +{ + NSTask *task = [NSTask new]; + + // TODO : need to change + NSString *launchPath = self.executablePaths[aCommand]; + + if (!launchPath) + launchPath = aCommand; + + task.launchPath = launchPath; + task.arguments = arguments; + task.environment = self.environment; + task.standardOutput = [NSPipe pipe]; + task.standardError = [NSPipe pipe]; + + if (aCurrentDirectoryPath) + task.currentDirectoryPath = aCurrentDirectoryPath; + + return task; +} + +/*! + Run an NSTask with the given arguments + + @param aCommand The command to launch + @param arguments NSArray containing the NSTask arguments + @param returnType Determines whether to return stdout, stderr, either, or nothing in the response + @return NSDictionary containing the return status (NSNumber) and the response (NSString) + */ +- (NSDictionary *)runTaskWithCommand:(NSString *)aCommand arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType +{ + return [self runTaskWithCommand:aCommand arguments:arguments returnType:returnType currentDirectoryPath:nil]; +} + +/*! + Run an NSTask with the given arguments + + @param aCommand The command to launch + @param arguments NSArray containing the NSTask arguments + @param returnType Determines whether to return stdout, stderr, either, or nothing in the response + @param the currentDirectoryPath for the task + @return NSDictionary containing the return status (NSNumber) and the response (NSString) + */ +- (NSDictionary *)runTaskWithCommand:(NSString *)aCommand arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType currentDirectoryPath:(NSString*)aCurrentDirectoryPath +{ + NSTask *task = [NSTask new]; + + // TODO : need to change + NSString *launchPath = self.executablePaths[aCommand]; + + if (!launchPath) + launchPath = aCommand; + + task.launchPath = launchPath; + task.arguments = arguments; + task.environment = self.environment; + task.standardOutput = [NSPipe pipe]; + task.standardError = [NSPipe pipe]; + + if (aCurrentDirectoryPath) + task.currentDirectoryPath = aCurrentDirectoryPath; + + return [self runTask:task returnType:returnType]; +} + +- (NSDictionary*)runTask:(NSTask*)aTask returnType:(XCCTaskReturnType)returnType +{ + [aTask launch]; + + DDLogVerbose(@"Task launched: %@\n%@", aTask.launchPath, aTask.arguments); + + if (returnType != kTaskReturnTypeNone) + { + [aTask waitUntilExit]; + + DDLogVerbose(@"Task exited: %@\n%@\nExit code:%d", aTask.launchPath, aTask.arguments, aTask.terminationStatus); + + NSData *data = nil; + + if (returnType == kTaskReturnTypeStdOut || returnType == kTaskReturnTypeAny) + data = [[aTask.standardOutput fileHandleForReading] readDataToEndOfFile]; + + if (returnType == kTaskReturnTypeStdError || (returnType == kTaskReturnTypeAny && [data length] == 0)) + data = [[aTask.standardError fileHandleForReading] readDataToEndOfFile]; + + NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSNumber *status = @(aTask.terminationStatus); + + return @{ @"status":status, @"response":response }; + } + + return @{ @"status":@0, @"response":@"" }; +} + +/*! + Run a jake NSTask with the given arguments + + @param arguments NSArray containing the NSTask arguments + @param the currentDirectoryPath for the task + @return NSDictionary containing the return status (NSNumber) and the response (NSString) + */ +- (NSDictionary*)runJakeTaskWithArguments:(NSMutableArray*)arguments currentDirectoryPath:(NSString*)aCurrentDirectoryPath +{ + NSString *launchPath = self.executablePaths[@"jake"]; + + NSTask *task = [NSTask new]; + + task.launchPath = launchPath; + task.arguments = arguments; + task.environment = self.environment; + task.standardOutput = [NSPipe new]; + task.standardError = [NSPipe new]; + + if (aCurrentDirectoryPath) + task.currentDirectoryPath = aCurrentDirectoryPath; + + // This is needed to log the jake + NSFileHandle* fhOut = [task.standardOutput fileHandleForReading]; + [fhOut readInBackgroundAndNotify]; + NSFileHandle* fhErr = [task.standardError fileHandleForReading]; + [fhErr readInBackgroundAndNotify]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jakeReceivedData:) name:NSFileHandleReadCompletionNotification object:fhOut]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jakeReceivedError:) name:NSFileHandleReadCompletionNotification object:fhErr]; + + [task launch]; + + DDLogVerbose(@"Task launched: %@\n%@", launchPath, arguments); + + [task waitUntilExit]; + + DDLogVerbose(@"Task exited: %@:%d", launchPath, task.terminationStatus); + + NSNumber *status = @(task.terminationStatus); + NSData *data = nil; + + if ([status intValue] == 0) + data = [[task.standardOutput fileHandleForReading] availableData]; + else + data = [[task.standardError fileHandleForReading] availableData]; + + NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + + [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:fhOut]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:fhErr]; + + return @{@"status" : status, @"response" : response}; +} + +-(void)jakeReceivedData:(NSNotification*)notification +{ + NSData *data = [notification userInfo][NSFileHandleNotificationDataItem]; + NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + + DDLogVerbose(@"Jake receive data\n %@", string); + + [[notification object] readInBackgroundAndNotify]; +} + +-(void)jakeReceivedError:(NSNotification*)notification +{ + NSData *data = [notification userInfo][NSFileHandleNotificationDataItem]; + NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + + DDLogVerbose(@"Jake receive error\%@", string); +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCUserDefaults.h b/Tools/XcodeCapp/XcodeCapp/XCCUserDefaults.h new file mode 100644 index 000000000..bd416e4f2 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCUserDefaults.h @@ -0,0 +1,20 @@ +// +// XCCUserDefaults.h +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/6/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#ifndef XcodeCapp_XCCUserDefaults_h +#define XcodeCapp_XCCUserDefaults_h + +#import + +extern NSString * const XCCUserDefaultsAutoOpenXcodeProject; +extern NSString * const XCCUserDefaultsManagedProjects; +extern NSString * const XCCUserDefaultsLogLevel; +extern NSString * const XCCUserDefaultsSelectedProjectPath; +extern NSString * const XCCUserDefaultsMaxNumberOfConcurrentOperations; + +#endif diff --git a/Tools/XcodeCapp/XcodeCapp/XCCUserDefaults.m b/Tools/XcodeCapp/XcodeCapp/XCCUserDefaults.m new file mode 100644 index 000000000..9cc4470a4 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCUserDefaults.m @@ -0,0 +1,15 @@ +// +// UserDefaults.m +// XcodeCapp +// +// Created by Alexandre Wilhelm on 5/6/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#include "XCCUserDefaults.h" + +NSString * const XCCUserDefaultsAutoOpenXcodeProject = @"XCCUserDefaultsAutoOpenXcodeProject"; +NSString * const XCCUserDefaultsManagedProjects = @"XCCUserDefaultsManagedProjects"; +NSString * const XCCUserDefaultsLogLevel = @"XCCUserDefaultsLogLevel"; +NSString * const XCCUserDefaultsSelectedProjectPath = @"XCCUserDefaultsSelectedProjectPath"; +NSString * const XCCUserDefaultsMaxNumberOfConcurrentOperations = @"XCCUserDefaultsMaxNumberOfConcurrentOperations"; \ No newline at end of file diff --git a/Tools/XcodeCapp/XcodeCapp/XCCWelcomeView.h b/Tools/XcodeCapp/XcodeCapp/XCCWelcomeView.h new file mode 100644 index 000000000..189bb493e --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCWelcomeView.h @@ -0,0 +1,24 @@ +// +// XCCProjectsFolderDropView.h +// XcodeCapp +// +// Created by Antoine Mercadal on 6/4/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import + +@class XCCMainController; + + +@interface XCCWelcomeView : NSBox +{ + IBOutlet NSBox *boxImport; + IBOutlet NSProgressIndicator *loadingIndicator; +} + +@property XCCMainController *mainXcodeCappController; + +- (void)showLoading:(BOOL)shouldShow; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XCCWelcomeView.m b/Tools/XcodeCapp/XcodeCapp/XCCWelcomeView.m new file mode 100644 index 000000000..0643f2bd7 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/XCCWelcomeView.m @@ -0,0 +1,102 @@ +// +// XCCProjectsFolderDropView.m +// XcodeCapp +// +// Created by Antoine Mercadal on 6/4/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. +// + +#import "XCCWelcomeView.h" +#import "XCCMainController.h" + +@implementation XCCWelcomeView + + +#pragma mark - Initialization + +- (void)awakeFromNib +{ + [self registerForDraggedTypes:@[NSFilenamesPboardType]]; +} + + +#pragma mark - Utilities + +- (void)showLoading:(BOOL)shouldShow +{ + if (shouldShow) + { + self->boxImport.hidden = YES; + self->loadingIndicator.hidden = NO; + + [self->loadingIndicator startAnimation:self]; + } + else + { + self->boxImport.hidden = NO; + self->loadingIndicator.hidden = YES; + + [self->loadingIndicator stopAnimation:self]; + } +} + + +#pragma mark Drag and Drop + +- (NSDragOperation)draggingEntered:(id)info +{ + NSPasteboard *pboard = [info draggingPasteboard]; + + if ([pboard.types containsObject:(NSString *)NSFilenamesPboardType]) + { + NSArray *draggedFiles = [pboard propertyListForType:(NSString *)NSFilenamesPboardType]; + + for (NSString *file in draggedFiles) + { + BOOL isDir; + [[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDir]; + + if (!isDir) + return NSDragOperationNone; + } + + self.fillColor = [NSColor colorWithCalibratedRed:236.0/255.0 green:236.0/255.0 blue:236.0/255.0 alpha:1.0]; + return NSDragOperationCopy; + } + + return NSDragOperationNone; +} + +- (void)draggingExited:(id)info +{ + self.fillColor = [NSColor whiteColor]; +} + +- (BOOL)prepareForDragOperation:(id)info +{ + return YES; +} + +- (BOOL)performDragOperation:(id)info +{ + NSPasteboard *pboard = [info draggingPasteboard]; + + if ([pboard.types containsObject:(NSString *)NSFilenamesPboardType]) + { + NSArray *draggedFolders = [pboard propertyListForType:(NSString *)NSFilenamesPboardType]; + + for (NSString *folder in draggedFolders) + [self.mainXcodeCappController manageCappuccinoProjectControllerForPath:folder]; + + return YES; + } + + return NO; +} + +- (void)concludeDragOperation:(id)info +{ + self.fillColor = [NSColor whiteColor]; +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/XcodeCapp.h b/Tools/XcodeCapp/XcodeCapp/XcodeCapp.h deleted file mode 100644 index ef7b756c5..000000000 --- a/Tools/XcodeCapp/XcodeCapp/XcodeCapp.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * This file is a part of program XcodeCapp - * Copyright (C) 2011 Antoine Mercadal () - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import -#import - -// FSEvent listening mode we use -enum XCCAPIMode { - kXCCAPIModeAuto = 0, - kXCCAPIModeFile, - kXCCAPIModeFolder -}; - -// Type of output expected from runTaskWithLaunchPath:arguments:returnType: -enum XCCTaskReturnType { - kTaskReturnTypeNone, - kTaskReturnTypeStdOut, - kTaskReturnTypeStdError, - kTaskReturnTypeAny -}; -typedef enum XCCTaskReturnType XCCTaskReturnType; - -// Status codes returned by support scripts run as tasks -enum { - XCCStatusCodeError = 1, - XCCStatusCodeWarning = 2 -}; - -// Notifications we send -extern NSString * const XCCConversionDidStartNotification; -extern NSString * const XCCConversionDidEndNotification; -extern NSString * const XCCProjectDidFinishLoadingNotification; -extern NSString * const XCCCappLintDidStartNotification; -extern NSString * const XCCCappLintDidEndNotification; - -@interface XcodeCapp : NSObject - -/* - Every time the user opens or closes a project, this is incremented. It is passed to threaded operations - which load the project. These threaded operations generate notifications that get queued up - on the main thread. Because the user may cancel and start a new load while notifications are - still queued from the previous load, we compare the projectId returned by a notification - with the current projectId. If they don't match, we let the notification drain. -*/ -@property NSInteger projectId; - -// An array of paths we add to the NSTask environment -@property NSArray *environmentPaths; - -// An array of executable names we need to have available -@property NSArray *executables; - -// Full path to .XcodeSupport -@property NSString *supportPath; - -// Full path to the Cappuccino project root directory -@property NSString *projectPath; - -// Full path to the .xcodeproj -@property NSString *xcodeProjectPath; - -// Full path to parser.j -@property NSString *parserPath; - -// Full path to pbxprojModifier.py -@property NSString *pbxModifierScriptPath; - -// Tooltip for the radio button symlink -@property NSString *toolTipSymlinkRadioButton; - -// Full paths to the executables we rely on: jsc, objj, nib2cib, python -@property NSMutableDictionary *executablePaths; - -// Whether the current OS supports file-level FSEvents (10.7+) -@property BOOL supportsFileLevelAPI; - -// Whether we are actually using file-level FSEvents -@property BOOL isUsingFileLevelAPI; - -// Whether we should process source files that have inode-only modifications -@property BOOL reactToInodeModification; - -// Whether we are in the process of loading a project -@property BOOL isLoadingProject; - -// Whether we are currently processing source files -@property BOOL isProcessing; - -// Whether we are currently processing source files -@property BOOL isCappuccinoUpdating; - -// Whether $CAPP_BUILD is defined or not -@property BOOL isCappBuildDefined; - -// A mapping from full paths to project-relative paths -@property NSMutableDictionary *projectPathsForSourcePaths; - -// A list of errors generated from the current batch of source processing -@property NSMutableArray *errorList; - -// A list of files name who can be processed, based on xcapp-ignore and path pf the project -@property NSMutableArray *xCodeCappTargetedFiles; - -// Panel, table and controller used to display errors -@property (strong) IBOutlet NSPanel *errorsPanel; -@property (unsafe_unretained) IBOutlet NSTableView *errorTable; -@property (strong) IBOutlet NSArrayController *errorListController; - -@property (strong) IBOutlet NSProgressIndicator *progressIndicator; -@property (strong) IBOutlet NSTextField *fieldCurrentTask; -@property (strong) IBOutlet NSPanel *updatingCappuccinoPanel; - -- (IBAction)openErrorsPanel:(id)sender; -- (IBAction)clearErrors:(id)sender; -- (IBAction)openErrorInEditor:(id)sender; -- (IBAction)openXcodeProject:(id)aSender; -- (IBAction)synchronizeProject:(id)aSender; -- (IBAction)checkProjectWithCappLint:(id)aSender; - -- (BOOL)executablesAreAccessible; -- (void)stop; -- (void)loadProjectAtPath:(NSString *)path; -- (BOOL)pathMatchesIgnoredPaths:(NSString*)aPath; - -- (BOOL)notificationBelongsToCurrentProject:(NSNotification *)note; - -- (BOOL)isObjjFile:(NSString *)path; -- (BOOL)isXibFile:(NSString *)path; -- (BOOL)isXCCIgnoreFile:(NSString *)path; - -- (BOOL)shouldShowErrorNotification; - -- (NSString *)shadowBasePathForProjectSourcePath:(NSString *)path; -- (BOOL)hasErrors; - -- (void)computeIgnoredPaths; -- (BOOL)shouldIgnoreDirectoryNamed:(NSString *)filename; - -- (void)wantUserNotificationWithInfo:(NSDictionary *)info; -- (NSDictionary *)runTaskWithLaunchPath:(NSString *)launchPath arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType; - -- (NSDictionary*)createProject:(NSString*)aPath; - -- (void)showCappLintWarnings; -- (void)showObjjWarnings; - -- (BOOL)shouldProcessWithCappLint; -- (BOOL)checkCappLintForPath:(NSArray*)paths; - -- (BOOL)shouldProcessWithObjjWarnings; -- (BOOL)checkObjjWarningsForPath:(NSArray*)paths; - -- (void)updateCappuccino; - -@end - -@interface XcodeCapp (SnowLeopard) - -- (void)updateLastModificationDate:(NSDate *)date forPath:(NSString *)path; -- (NSDate *)lastModificationDateForPath:(NSString *)path; - -@end diff --git a/Tools/XcodeCapp/XcodeCapp/XcodeCapp.m b/Tools/XcodeCapp/XcodeCapp/XcodeCapp.m deleted file mode 100644 index 3e3b13bd7..000000000 --- a/Tools/XcodeCapp/XcodeCapp/XcodeCapp.m +++ /dev/null @@ -1,2460 +0,0 @@ -/* - * This file is a part of program XcodeCapp - * Copyright (C) 2011 Antoine Mercadal () - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#import - -#import "XcodeCapp.h" -#import "AppController.h" -#import "FindSourceFilesOperation.h" -#import "Notifications.h" -#import "ProcessSourceOperation.h" -#import "UserDefaults.h" -#import "XcodeProjectCloser.h" - - -#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_6 -# define kFSEventStreamCreateFlagFileEvents 0x00000010 -# define kFSEventStreamEventFlagItemIsFile 0x00010000 -# define kFSEventStreamEventFlagItemRemoved 0x00000200 -# define kFSEventStreamEventFlagItemCreated 0x00000200 -# define kFSEventStreamEventFlagItemModified 0x00001000 -# define kFSEventStreamEventFlagItemInodeMetaMod 0x00000400 -# define kFSEventStreamEventFlagItemRenamed 0x00000800 -# define kFSEventStreamEventFlagItemFinderInfoMod 0x00002000 -# define kFSEventStreamEventFlagItemChangeOwner 0x00004000 -# define kFSEventStreamEventFlagItemXattrMod 0x00008000 -#endif - - -enum XCCLineSpecifier { - kLineSpecifierNone, - kLineSpecifierColon, - kLineSpecifierMinusL, - kLineSpecifierPlus -}; -typedef enum XCCLineSpecifier XCCLineSpecifier; - -// Where we put the generated Cocoa class files -static NSString * const XCCSupportFolderName = @".XcodeSupport"; - -// We store a compatibility version in .XcodeSupport/Info.plist. -// If the version is less than the version in XcodeCapp's Info.plist, we regenerate .XcodeSupport. -static NSString * const XCCCompatibilityVersionKey = @"XCCCompatibilityVersion"; - -// We replace "/" in a path with this. It looks like "/", -// but is actually an obscure Unicode character we hope no one uses in a filename. -static NSString * const XCCSlashReplacement = @"∕"; // DIVISION SLASH, Unicode: U+2215 - -// When scanning the project, we immediately ignore directories that match this regex. -static NSString * const XCCDirectoriesToIgnorePattern = @"^(?:Build|F(?:rameworks|oundation)|AppKit|Objective-J|(?:Browser|CommonJS)\\.environment|Resources|XcodeSupport|.+\\.xcodeproj)$"; - -// The key for an Info.plist array of the mandatory executables XCC needs. -static NSString * const XCCMandatoryExecutablesKey = @"XCCMandatoryExecutables"; - -// The regex above is used with this predicate for testing. -static NSPredicate * XCCDirectoriesToIgnorePredicate = nil; - -// An array of the default predicates used to ignore paths. -static NSArray *XCCDefaultIgnoredPathPredicates = nil; - -NSString * const XCCCappLintDidStartNotification = @"XCCCappLintDidStartNotification"; -NSString * const XCCCappLintDidEndNotification = @"XCCCappLintDidEndNotification"; -NSString * const XCCObjjDidStartNotification = @"XCCObjjDidStartNotification"; -NSString * const XCCObjjDidEndNotification = @"XCCObjjDidEndNotification"; - -@interface XcodeCapp () - -// Only used with 10.6 when we don't have file-level FSEvents -@property (nonatomic) NSMutableDictionary *pathModificationDates; - -@property FSEventStreamRef stream; - -// Whether the FSEventStream is started or stopped. -@property BOOL streamStarted; - -// The last FSEvent id we received. This is stored in the user prefs -// so we can get all changes since the last time XcodeCapp was launched. -@property NSNumber *lastEventId; - -@property NSDate *appStartedTimestamp; - -@property NSFileManager *fm; - -// An NSString version of XCCCloseXcodeProjectScript -@property NSString *closeXcodeProjectScriptSource; - -// Full path to .xcodecapp-ignore -@property NSString *xcodecappIgnorePath; - -// The current array of predicates used to ignore paths -@property NSMutableArray *ignoredPathPredicates; - -// The environment we pass to tasks launched from XcodeCapp -@property NSMutableDictionary *environment; - -// We keep a file descriptor open for the project directory -// so we can locate it if it moves. -@property int projectPathFileDescriptor; - -// Coalesces the modifications that have to be made to the Xcode project -// after changes are made to source files. Keys are the actions "add" or "remove", -// values are arrays of full paths to source files that need to be added or removed. -@property NSMutableDictionary *pbxOperations; - -// A queue for threaded operations to perform -@property NSOperationQueue *operationQueue; - -// We have to declare this because it is referenced by the fsevents_callback function -- (void)handleFSEventsWithPaths:(NSArray *)paths flags:(const FSEventStreamEventFlags[])eventFlags ids:(const FSEventStreamEventId[])eventIds; - -@end - - -void fsevents_callback(ConstFSEventStreamRef streamRef, - void *userData, - size_t numEvents, - void *eventPaths, - const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId eventIds[]) -{ - XcodeCapp *xcc = (__bridge XcodeCapp *)userData; - NSArray *paths = (__bridge NSArray *)eventPaths; - - [xcc handleFSEventsWithPaths:paths flags:eventFlags ids:eventIds]; -} - - -@implementation XcodeCapp - -#pragma mark - Initialization - -+ (void)initialize -{ - if (self != [XcodeCapp class]) - return; - - // Initialize static values that can't be initialized in their declarations - - XCCDirectoriesToIgnorePredicate = [NSPredicate predicateWithFormat:@"SELF matches %@", XCCDirectoriesToIgnorePattern]; - - NSArray *defaultIgnoredPaths = @[ - @"*/Frameworks/", - @"!*/Frameworks/Debug/", - @"!*/Frameworks/Source/", - @"*/AppKit/", - @"*/Foundation/", - @"*/Objective-J/", - @"*/*.environment/", - @"*/Build/", - @"*/*.xcodeproj/", - @"*/.*/", - @"*/NS_*.j", - @"*/main.j", - @"*/.*", - @"!*/.xcodecapp-ignore" - ]; - - XCCDefaultIgnoredPathPredicates = [self parseIgnorePaths:defaultIgnoredPaths]; -} - -- (id)init -{ - self = [super init]; - - if (self) - { - self.errorList = [NSMutableArray arrayWithCapacity:10]; - self.fm = [NSFileManager defaultManager]; - self.ignoredPathPredicates = [NSMutableArray new]; - self.parserPath = [[NSBundle mainBundle].sharedSupportPath stringByAppendingPathComponent:@"parser.j"]; - self.appStartedTimestamp = [NSDate date]; - self.projectPathsForSourcePaths = [NSMutableDictionary new]; - self.xcodecappIgnorePath = @""; - self.operationQueue = [NSOperationQueue new]; - self.pbxOperations = [NSMutableDictionary new]; - self.executablePaths = [NSMutableDictionary new]; - self.projectPathFileDescriptor = -1; - self.isCappBuildDefined = YES; - self.toolTipSymlinkRadioButton = @"If this is checked, when a Cappuccino project is created, the frameworks of the new project will be symlinked from the $CAPP_BUILD"; - - [self initTaskEnvironment]; - - self.isUsingFileLevelAPI = NO; - self.isLoadingProject = NO; - self.isProcessing = NO; - - // File-level FSEvents are only supported on 10.7+ - SInt32 versionMajor = 0; - SInt32 versionMinor = 0; - Gestalt(gestaltSystemVersionMajor, &versionMajor); - Gestalt(gestaltSystemVersionMinor, &versionMinor); - - self.supportsFileLevelAPI = versionMajor >= 10 && versionMinor >= 7; - - // Uncomment to simulate 10.6 mode - // self.supportsFileLevelAPI = NO; - - [self configureFileAPI]; - - [NSUserNotificationCenter defaultUserNotificationCenter].delegate = self; - [GrowlApplicationBridge setGrowlDelegate:self]; - - [self initObservers]; - } - - return self; -} - -- (void)initTaskEnvironment -{ - // Add possible executable paths to PATH - self.environment = [NSProcessInfo processInfo].environment.mutableCopy; - - self.environmentPaths = - @[ - @"/usr/local/bin", - @"/usr/local/narwhal/bin", - @"~/narwhal/bin", - @"~/bin", - @"/usr/bin" - ]; - - NSMutableArray *paths = [self.environmentPaths mutableCopy]; - - for (NSInteger i = 0; i < paths.count; ++i) - paths[i] = [paths[i] stringByExpandingTildeInPath]; - - self.environment[@"PATH"] = [[paths componentsJoinedByString:@":"] stringByAppendingFormat:@":%@", self.environment[@"PATH"]]; - - // Make sure we are using jsc as the narwhal engine! - self.environment[@"NARWHAL_ENGINE"] = @"jsc"; - - // Make sure to not do something in sudo - self.environment[@"CAPP_NOSUDO"] = @"1"; - - self.executables = @[@"python", @"narwhal-jsc", @"objj", @"nib2cib", @"capp", @"capp_lint", @"jake", @"curl", @"unzip", @"rm"]; - - // This is used to get the env var of $CAPP_BUILD - NSDictionary *processEnvironment = [[NSProcessInfo processInfo] environment]; - NSArray *arguments = [NSArray arrayWithObjects:@"-l", @"-c", @"echo $CAPP_BUILD", nil]; - - NSDictionary *taskResult = [self runTaskWithLaunchPath:[processEnvironment objectForKey:@"SHELL"] - arguments:arguments - returnType:kTaskReturnTypeStdOut]; - - // Make sure to remove the \n at the end of the response - NSString *response = [taskResult[@"response"] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; - - self.environment[@"CAPP_BUILD"] = response; - - // Make sure we have found a CAPP_BUILD - if ([response length] == 0 || [taskResult[@"status"] intValue] == -1) - { - self.toolTipSymlinkRadioButton = @"To use this option you need to have the variable $CAPP_BUILD in your environement (export CAPP_BUILD='path/to/your/cappuccino/build')"; - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - [defaults setObject:@NO forKey:kDefaultUseSymlinkWhenCreatingProject]; - self.isCappBuildDefined = NO; - } -} - -- (void)initObservers -{ - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - - [center addObserver:self selector:@selector(addSourceToProjectPathMappingHandler:) name:XCCNeedSourceToProjectPathMappingNotification object:nil]; - [center addObserver:self selector:@selector(sourceConversionDidStartHandler:) name:XCCConversionDidStartNotification object:nil]; - [center addObserver:self selector:@selector(sourceConversionDidEndHandler:) name:XCCConversionDidEndNotification object:nil]; - [center addObserver:self selector:@selector(sourceConversionDidGenerateErrorHandler:) name:XCCConversionDidGenerateErrorNotification object:nil]; -} - -#pragma mark - Properties - -- (id)pathModificationDates -{ - if (!_pathModificationDates) - { - _pathModificationDates = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:kDefaultPathModificationDates] mutableCopy]; - - if (!_pathModificationDates) - _pathModificationDates = [NSMutableDictionary new]; - } - - return _pathModificationDates; -} - -- (BOOL)xcodeProjectCanBeOpened -{ - return (self.xcodeProjectPath && - !self.isProcessing && - [self.fm fileExistsAtPath:self.xcodeProjectPath]); -} - -#pragma mark - Project Management - -- (void)loadProjectAtPath:(NSString *)path -{ - DDLogInfo(@"Loading project: %@", path); - - self.isLoadingProject = YES; - ++self.projectId; - - [self notifyUserWithTitle:@"Loading project…" message:path.lastPathComponent]; - - self.projectPath = path; - self.xcodecappIgnorePath = [self.projectPath stringByAppendingPathComponent:@".xcodecapp-ignore"]; - self.projectPathsForSourcePaths = [NSMutableDictionary new]; - [self.pbxOperations removeAllObjects]; - self.lastEventId = [[NSUserDefaults standardUserDefaults] objectForKey:kDefaultLastEventId]; - - [self clearErrors:self]; - [self computeIgnoredPaths]; - - [self prepareXcodeSupport]; - [self populateXcodeProject]; - [self populatexCodeCappTargetedFiles]; - [self waitForOperationQueueToFinishWithSelector:@selector(projectDidFinishLoading)]; -} - -/*! - Create Xcode project and .XcodeSupport directory if necessary. - - @return YES if both exist -*/ -- (BOOL)prepareXcodeSupport -{ - NSString *projectName = [self.projectPath.lastPathComponent stringByAppendingString:@".xcodeproj"]; - - self.xcodeProjectPath = [self.projectPath stringByAppendingPathComponent:projectName]; - self.supportPath = [self.projectPath stringByAppendingPathComponent:XCCSupportFolderName]; - self.pbxModifierScriptPath = [[NSBundle mainBundle].sharedSupportPath stringByAppendingPathComponent:@"pbxprojModifier.py"]; - - // If either the project or the support directory are missing, recreate them both to ensure they are in sync - BOOL projectExists, projectIsDirectory; - projectExists = [self.fm fileExistsAtPath:self.xcodeProjectPath isDirectory:&projectIsDirectory]; - - BOOL supportExists, supportIsDirectory; - supportExists = [self.fm fileExistsAtPath:self.supportPath isDirectory:&supportIsDirectory]; - - if (!projectExists || !projectIsDirectory || !supportExists) - [self createXcodeProject]; - - // If the project did not exist, reset the XcodeSupport directory to force the new empty project to be populated - if (!supportExists || !supportIsDirectory || !projectExists || ![self xcodeSupportIsCompatible]) - [self createXcodeSupportDirectory]; - - return projectExists && supportExists; -} - -- (BOOL)xcodeSupportIsCompatible -{ - double appCompatibilityVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:XCCCompatibilityVersionKey] doubleValue]; - - NSString *infoPath = [self.supportPath stringByAppendingPathComponent:@"Info.plist"]; - NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:infoPath]; - NSNumber *projectCompatibilityVersion = info[XCCCompatibilityVersionKey]; - - if (projectCompatibilityVersion == nil) - { - DDLogVerbose(@"No compatibility version in project"); - return NO; - } - - DDLogVerbose(@"XcodeCapp/project compatibility version: %0.1f/%0.1f", projectCompatibilityVersion.doubleValue, appCompatibilityVersion); - - return projectCompatibilityVersion.doubleValue >= appCompatibilityVersion; -} - -- (void)populatexCodeCappTargetedFiles -{ - NSFileManager *fm = [NSFileManager defaultManager]; - NSDirectoryEnumerator *filesOfProject = [fm enumeratorAtPath:self.projectPath]; - NSString *filename; - - self.xCodeCappTargetedFiles = [NSMutableArray array]; - - while ((filename = [filesOfProject nextObject] )) { - - NSString *fullPath = [self.projectPath stringByAppendingPathComponent:filename]; - - if (![self isSourceFile:fullPath]) - continue; - - [self.xCodeCappTargetedFiles addObject:fullPath]; - } -} - -- (void)createXcodeProject -{ - if ([self.fm fileExistsAtPath:self.xcodeProjectPath]) - [self.fm removeItemAtPath:self.xcodeProjectPath error:nil]; - - [self.fm createDirectoryAtPath:self.xcodeProjectPath withIntermediateDirectories:YES attributes:nil error:nil]; - - NSString *pbxPath = [self.xcodeProjectPath stringByAppendingPathComponent:@"project.pbxproj"]; - - [self.fm copyItemAtPath:[[NSBundle mainBundle] pathForResource:@"project" ofType:@"pbxproj"] toPath:pbxPath error:nil]; - - NSMutableString *content = [NSMutableString stringWithContentsOfFile:pbxPath encoding:NSUTF8StringEncoding error:nil]; - - [content writeToFile:pbxPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; - - DDLogInfo(@"Xcode support project created at: %@", self.xcodeProjectPath); -} - -- (void)createXcodeSupportDirectory -{ - if ([self.fm fileExistsAtPath:self.supportPath]) - [self.fm removeItemAtPath:self.supportPath error:nil]; - - [self.fm createDirectoryAtPath:self.supportPath withIntermediateDirectories:YES attributes:nil error:nil]; - - NSNumber *appCompatibilityVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:XCCCompatibilityVersionKey]; - NSData *data = [NSPropertyListSerialization dataFromPropertyList:@{ XCCCompatibilityVersionKey:appCompatibilityVersion } - format:NSPropertyListXMLFormat_v1_0 - errorDescription:nil]; - [data writeToFile:[self.supportPath stringByAppendingPathComponent:@"Info.plist"] atomically:YES]; - - DDLogInfo(@".XcodeSupport directory created at: %@", self.supportPath); -} - -- (void)populateXcodeProject -{ - // Populate with all non-framework code - [self populateXcodeProjectWithProjectRelativePath:@""]; - - // Populate with any user source debug frameworks - [self populateXcodeProjectWithProjectRelativePath:@"Frameworks/Debug"]; - - // Populate with any source frameworks - [self populateXcodeProjectWithProjectRelativePath:@"Frameworks/Source"]; - - // Populate resources - [self populateXcodeProjectWithProjectRelativePath:@"Resources"]; -} - -- (void)populateXcodeProjectWithProjectRelativePath:(NSString *)path -{ - FindSourceFilesOperation *op = [[FindSourceFilesOperation alloc] initWithXCC:self projectId:[NSNumber numberWithInteger:self.projectId] path:path]; - [self.operationQueue addOperation:op]; -} - -- (IBAction)openXcodeProject:(id)aSender -{ - BOOL isDirectory, opened = YES; - BOOL exists = [self.fm fileExistsAtPath:self.xcodeProjectPath isDirectory:&isDirectory]; - - if (exists && isDirectory) - { - DDLogVerbose(@"Opening Xcode project at: %@", self.xcodeProjectPath); - - opened = [[NSWorkspace sharedWorkspace] openFile:self.xcodeProjectPath]; - } - - if (!exists || !isDirectory || !opened) - { - NSString *text; - - if (!opened) - text = @"The project exists, but failed to open."; - else - text = [NSString stringWithFormat:@"%@ %@.", self.xcodeProjectPath, !exists ? @"does not exist" : @"is not an Xcode project"]; - - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - NSInteger response = NSRunAlertPanel(@"The project could not be opened.", @"%@\n\nWould you like to regenerate the project?", @"Yes", @"No", nil, text); - - if (response == NSAlertDefaultReturn) - [self synchronizeProject:self]; - } -} - -- (void)resetProject -{ - NSString *projectPath = self.projectPath; - - [self stop]; - [self removeSupportFilesAtPath:projectPath]; - [self removeAllCibsAtPath:[projectPath stringByAppendingPathComponent:@"Resources"]]; - - self.projectPath = projectPath; -} - -- (IBAction)synchronizeProject:(id)aSender -{ - [self resetProject]; - [self loadProjectAtPath:self.projectPath]; -} - -- (void)removeAllCibsAtPath:(NSString *)path -{ - NSArray *paths = [self.fm contentsOfDirectoryAtPath:path error:nil]; - - for (NSString *filePath in paths) - { - if ([filePath.pathExtension.lowercaseString isEqualToString:@"cib"]) - [self.fm removeItemAtPath:[path stringByAppendingPathComponent:filePath] error:nil]; - } -} - -- (void)removeSupportFilesAtPath:(NSString *)projectPath -{ - [XcodeProjectCloser closeXcodeProjectForProject:projectPath]; - - [self.fm removeItemAtPath:self.xcodeProjectPath error:nil]; - [self.fm removeItemAtPath:self.supportPath error:nil]; -} - -- (void)stop -{ - // Increment the projectId to ensure remaining notifications in the queue for the current project are ignored - ++self.projectId; - - self.isLoadingProject = NO; - [self stopEventStream]; - [self.operationQueue cancelAllOperations]; - - self.projectPath = nil; - [self clearErrors:self]; - [self.ignoredPathPredicates removeAllObjects]; - - [[NSUserDefaults standardUserDefaults] synchronize]; -} - -#pragma mark - Processing - -- (void)waitForOperationQueueToFinishWithSelector:(SEL)selector -{ - self.isProcessing = YES; - - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidStartNotification object:self]; - - // Poll every half second to see if the queue has finished - [NSTimer scheduledTimerWithTimeInterval:0.5 - target:self - selector:@selector(didQueueTimerFinish:) - userInfo:NSStringFromSelector(selector) - repeats:YES]; -} - -- (void)didQueueTimerFinish:(NSTimer *)timer -{ - if (self.operationQueue.operationCount == 0) - { - SEL selector = NSSelectorFromString(timer.userInfo); - - [timer invalidate]; - - // Can't use plain performSelect: here because ARC doesn't know what the return value is - // because the selector is determined at runtime. So we use performSelectorOnMainThread: - // which has no return value. - [self performSelectorOnMainThread:selector withObject:nil waitUntilDone:NO]; - } -} - -- (void)batchDidFinish -{ - if (self.pbxOperations.count) - { - // See pbxprojModifier.py for info on the arguments - NSMutableArray *arguments = [[NSMutableArray alloc] initWithObjects:self.pbxModifierScriptPath, @"update", self.projectPath, nil]; - - for (NSString *action in self.pbxOperations) - { - NSArray *paths = self.pbxOperations[action]; - - if (paths.count) - { - [arguments addObject:action]; - [arguments addObjectsFromArray:paths]; - } - } - - // This task takes less than a second to execute, no need to put it a separate thread - - NSDictionary *taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"python"] - arguments:arguments - returnType:kTaskReturnTypeStdError]; - - NSInteger status = [taskResult[@"status"] intValue]; - NSString *response = taskResult[@"response"]; - - DDLogVerbose(@"Updated Xcode project: [%ld, %@]", status, status ? response : @""); - } - - [self showErrors]; - - // If the event stream was temporarily stopped, restart it - [self startFSEventStream]; - - self.isProcessing = NO; - - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self]; -} - -- (void)projectDidFinishLoading -{ - [self batchDidFinish]; - - DDLogVerbose(@"Project finished loading"); - - self.isLoadingProject = NO; - - [[NSNotificationCenter defaultCenter] postNotificationName:XCCProjectDidFinishLoadingNotification object:self]; - [[NSUserDefaults standardUserDefaults] setObject:self.projectPath forKey:kDefaultLastOpenedPath]; - - [self notifyUserWithTitle:@"Project loaded" message:self.projectPath.lastPathComponent]; - - [self startEventStream]; - - if ([[NSUserDefaults standardUserDefaults] boolForKey:kDefaultAutoOpenXcodeProject]) - [self openXcodeProject:self]; -} - -- (NSDictionary*)createProject:(NSString*)aPath -{ - NSDictionary *taskResult; - NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"gen", aPath ,@"-t", @"NibApplication", nil]; - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - // This is used when an user wants to replace an existing project - NSArray *argumentsRemove = [NSArray arrayWithObjects:@"-rf", aPath, nil]; - [self runTaskWithLaunchPath:@"/bin/rm" arguments:argumentsRemove returnType:kTaskReturnTypeAny]; - - if ([defaults boolForKey:kDefaultUseSymlinkWhenCreatingProject]) - [arguments addObject:@"-l"]; - - taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"capp"] - arguments:arguments - returnType:kTaskReturnTypeStdOut]; - - NSInteger status = [taskResult[@"status"] intValue]; - NSString *response = taskResult[@"response"]; - - if (!status) - { - DDLogVerbose(@"Created Xcode project: [%ld, %@]", status, status ? response : @""); - [self notifyUserWithTitle:@"Project created" message:aPath.lastPathComponent]; - } - else - { - DDLogVerbose(@"Created Xcode project failed: [%ld, %@]", status, status ? response : @""); - NSDictionary *dictionary = [NSDictionary dictionaryWithObject:response forKey:@"message"]; - [self.errorListController addObject:dictionary]; - [self showErrors]; - } - - return taskResult; -} - -#pragma mark - Notification handlers - -/* - NOTE: All methods in this section which end with "Handler" are called - from threaded NSOperations. -*/ - -/* - Notifications sent by operations contain an int projectId. - The notifications are queued up on the main thread. When the main thread - handles them, it first checks to see if the current projectId - matches the notification's projectId. If not, the notification is ignored. -*/ -- (BOOL)notificationBelongsToCurrentProject:(NSNotification *)note -{ - return [note.userInfo[@"projectId"] intValue] == self.projectId; -} - -- (void)addSourceToProjectPathMappingHandler:(NSNotification *)note -{ - [self performSelectorOnMainThread:@selector(addSourceToProjectPathMapping:) withObject:note waitUntilDone:NO]; -} - -- (void)addSourceToProjectPathMapping:(NSNotification *)note -{ - if (![self notificationBelongsToCurrentProject:note]) - return; - - NSDictionary *info = note.userInfo; - NSString *sourcePath = info[@"sourcePath"]; - - DDLogVerbose(@"Adding source to project mapping: %@ -> %@", sourcePath, info[@"projectPath"]); - - self.projectPathsForSourcePaths[info[@"sourcePath"]] = info[@"projectPath"]; -} - -- (void)sourceConversionDidStartHandler:(NSNotification *)note -{ - [self performSelectorOnMainThread:@selector(sourceConversionDidStart:) withObject:note waitUntilDone:NO]; -} - -- (void)sourceConversionDidStart:(NSNotification *)note -{ - if (![self notificationBelongsToCurrentProject:note]) - return; - - NSDictionary *info = note.userInfo; - NSString *projectPath = info[@"path"]; - - DDLogVerbose(@"%@ %@", NSStringFromSelector(_cmd), projectPath); - - [self pruneProcessingErrorsForProjectPath:projectPath]; -} - -- (void)sourceConversionDidGenerateErrorHandler:(NSNotification *)note -{ - [self performSelectorOnMainThread:@selector(sourceConversionDidGenerateError:) withObject:note waitUntilDone:NO]; -} - -- (void)sourceConversionDidGenerateError:(NSNotification *)note -{ - if (![self notificationBelongsToCurrentProject:note]) - return; - - NSMutableDictionary *info = [note.userInfo mutableCopy]; - - DDLogVerbose(@"%@ %@", NSStringFromSelector(_cmd), info[@"path"]); - - [self.errorListController addObject:info]; -} - -- (void)sourceConversionDidEndHandler:(NSNotification *)note -{ - [self performSelectorOnMainThread:@selector(sourceConversionDidEnd:) withObject:note waitUntilDone:NO]; -} - -- (void)sourceConversionDidEnd:(NSNotification *)note -{ - if (![self notificationBelongsToCurrentProject:note]) - return; - - NSString *path = note.userInfo[@"path"]; - - if ([self isObjjFile:path]) - { - NSMutableArray *addPaths = [self.pbxOperations[@"add"] mutableCopy]; - - if (!addPaths) - self.pbxOperations[@"add"] = @[path]; - else - { - [addPaths addObject:path]; - self.pbxOperations[@"add"] = addPaths; - } - } - - DDLogVerbose(@"%@ %@", NSStringFromSelector(_cmd), path); -} - -#pragma mark - Event Stream - -- (void)startEventStream -{ - if (self.stream) - return; - - [self stopEventStream]; - - FSEventStreamCreateFlags flags = kFSEventStreamCreateFlagUseCFTypes | - kFSEventStreamCreateFlagWatchRoot | - kFSEventStreamCreateFlagIgnoreSelf | - kFSEventStreamCreateFlagNoDefer; - - if (self.supportsFileLevelAPI) - flags |= kFSEventStreamCreateFlagFileEvents; - - // Get a file descriptor to the project directory so we can locate it if it moves - self.projectPathFileDescriptor = open(self.projectPath.UTF8String, O_EVTONLY); - - NSArray *pathsToWatch = [self getPathsToWatch]; - - void *appPointer = (__bridge void *)self; - FSEventStreamContext context = { 0, appPointer, NULL, NULL, NULL }; - CFTimeInterval latency = 2.0; - UInt64 lastEventId = self.lastEventId.unsignedLongLongValue; - - self.stream = FSEventStreamCreate(NULL, - &fsevents_callback, - &context, - (__bridge CFArrayRef) pathsToWatch, - lastEventId, - latency, - flags); - - FSEventStreamScheduleWithRunLoop(self.stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - [self startFSEventStream]; - - DDLogVerbose(@"FSEventStream started for paths: %@", pathsToWatch); -} - -- (void)startFSEventStream -{ - if (self.stream && !self.streamStarted) - { - FSEventStreamStart(self.stream); - self.streamStarted = YES; - } -} - -- (NSArray *)getPathsToWatch -{ - NSMutableArray *pathsToWatch = [NSMutableArray arrayWithObject:self.projectPath]; - NSArray *otherPathsToWatch = @[@"", @"Frameworks/Debug", @"Frameworks/Source"]; - - for (NSString *path in otherPathsToWatch) - { - NSString *fullPath = [self.projectPath stringByAppendingPathComponent:path]; - - BOOL exists, isDirectory; - exists = [self.fm fileExistsAtPath:fullPath isDirectory:&isDirectory]; - - if (exists && isDirectory) - [self watchSymlinkedDirectoriesAtPath:path pathsToWatch:pathsToWatch]; - } - - return [pathsToWatch copy]; -} - -- (void)watchSymlinkedDirectoriesAtPath:(NSString *)projectPath pathsToWatch:(NSMutableArray *)pathsToWatch -{ - NSString *fullProjectPath = [self.projectPath stringByAppendingPathComponent:projectPath]; - NSError *error = NULL; - - NSArray *urls = [self.fm contentsOfDirectoryAtURL:[NSURL fileURLWithPath:fullProjectPath] - includingPropertiesForKeys:@[NSURLIsDirectoryKey, NSURLIsSymbolicLinkKey] - options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants | NSDirectoryEnumerationSkipsSubdirectoryDescendants - error:&error]; - - for (NSURL *url in urls) - { - NSNumber *isSymlink; - [url getResourceValue:&isSymlink forKey:NSURLIsSymbolicLinkKey error:nil]; - - if (isSymlink.boolValue == NO) - continue; - - NSURL *resolvedURL = [url URLByResolvingSymlinksInPath]; - - if (![resolvedURL checkResourceIsReachableAndReturnError:nil]) - continue; - - NSNumber *isDirectory; - [resolvedURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil]; - - if (isDirectory.boolValue == NO) - continue; - - NSString *path = resolvedURL.path; - NSString *filename = path.lastPathComponent; - - if (![self shouldIgnoreDirectoryNamed:filename] && ![self pathMatchesIgnoredPaths:path]) - { - DDLogVerbose(@"Watching symlinked directory: %@", path); - - [pathsToWatch addObject:path]; - } - } -} - -- (void)stopEventStream -{ - if (self.stream) - { - [self updateUserDefaultsWithLastEventId]; - - [self stopFSEventStream]; - FSEventStreamUnscheduleFromRunLoop(self.stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - FSEventStreamInvalidate(self.stream); - FSEventStreamRelease(self.stream); - self.stream = NULL; - } - - if (self.projectPathFileDescriptor >= 0) - { - close(self.projectPathFileDescriptor); - self.projectPathFileDescriptor = -1; - } -} - -- (void)stopFSEventStream -{ - if (self.stream && self.streamStarted) - { - FSEventStreamStop(self.stream); - self.streamStarted = NO; - } -} - -- (void)configureFileAPI -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - if (!self.supportsFileLevelAPI) - { - DDLogInfo(@"System doesn't support file level API, user folder level API"); - - [defaults setObject:[NSNumber numberWithInt:kXCCAPIModeFolder] forKey:kDefaultXCCAPIMode]; - } - - switch ([defaults integerForKey:kDefaultXCCAPIMode]) - { - case kXCCAPIModeAuto: - self.isUsingFileLevelAPI = self.supportsFileLevelAPI; - break; - - case kXCCAPIModeFolder: - self.isUsingFileLevelAPI = NO; - break; - } - - self.reactToInodeModification = self.isUsingFileLevelAPI ? [defaults boolForKey:kDefaultXCCReactToInodeMod] : NO; -} - -- (void)updateUserDefaultsWithLastEventId -{ - UInt64 lastEventId = FSEventStreamGetLatestEventId(self.stream); - - // Just in case the stream callback was never called... - if (lastEventId != 0) - self.lastEventId = [NSNumber numberWithUnsignedLongLong:lastEventId]; - - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - [defaults setObject:self.lastEventId forKey:kDefaultLastEventId]; - [defaults synchronize]; -} - -- (NSString *)dumpFSEventFlags:(FSEventStreamEventFlags)flags -{ - BOOL created = (flags & kFSEventStreamEventFlagItemCreated) != 0; - BOOL removed = (flags & kFSEventStreamEventFlagItemRemoved) != 0; - BOOL inodeMetaModified = (flags & kFSEventStreamEventFlagItemInodeMetaMod) != 0; - BOOL renamed = (flags & kFSEventStreamEventFlagItemRenamed) != 0; - BOOL modified = (flags & kFSEventStreamEventFlagItemModified) != 0; - BOOL finderInfoModified = (flags & kFSEventStreamEventFlagItemFinderInfoMod) != 0; - BOOL changedOwner = (flags & kFSEventStreamEventFlagItemChangeOwner) != 0; - BOOL xattrModified = (flags & kFSEventStreamEventFlagItemXattrMod) != 0; - BOOL isFile = (flags & kFSEventStreamEventFlagItemIsFile) != 0; - BOOL isDir = (flags & kFSEventStreamEventFlagItemIsDir) != 0; - BOOL isSymlink = (flags & kFSEventStreamEventFlagItemIsSymlink) != 0; - - NSMutableArray *flagNames = [NSMutableArray new]; - - if (created) - [flagNames addObject:@"created"]; - - if (removed) - [flagNames addObject:@"removed"]; - - if (inodeMetaModified) - [flagNames addObject:@"inode"]; - - if (renamed) - [flagNames addObject:@"renamed"]; - - if (modified) - [flagNames addObject:@"modified"]; - - if (finderInfoModified) - [flagNames addObject:@"Finder info"]; - - if (changedOwner) - [flagNames addObject:@"owner"]; - - if (xattrModified) - [flagNames addObject:@"xattr"]; - - if (isFile) - [flagNames addObject:@"file"]; - - if (isDir) - [flagNames addObject:@"dir"]; - - if (isSymlink) - [flagNames addObject:@"symlink"]; - - return [flagNames componentsJoinedByString:@", "]; -} - -#pragma mark - Event Handlers - -- (void)handleFSEventsWithPaths:(NSArray *)paths flags:(const FSEventStreamEventFlags[])eventFlags ids:(const FSEventStreamEventId[])eventIds -{ - DDLogVerbose(@"FSEvents: %ld path(s)", paths.count); - - [self.pbxOperations removeAllObjects]; - - NSMutableArray *modifiedPaths = [NSMutableArray new]; - NSMutableArray *renamedDirectories = [NSMutableArray new]; - - BOOL needUpdate = NO; - - for (size_t i = 0; i < paths.count; ++i) - { - FSEventStreamEventFlags flags = eventFlags[i]; - NSString *path = [paths[i] stringByStandardizingPath]; - - BOOL rootChanged = (flags & kFSEventStreamEventFlagRootChanged) != 0; - - if (rootChanged) - { - DDLogVerbose(@"Watched path changed: %@", path); - - [self resetProjectForWatchedPath:path]; - return; - } - - BOOL isHistoryDoneSentinalEvent = (flags & kFSEventStreamEventFlagHistoryDone) != 0; - - if (isHistoryDoneSentinalEvent) - { - DDLogVerbose(@"History done sentinal event"); - continue; - } - - BOOL isMountEvent = (flags & kFSEventStreamEventFlagMount) || (flags & kFSEventStreamEventFlagUnmount); - - if (isMountEvent) - { - DDLogVerbose(@"Volume %@: %@", (flags & kFSEventStreamEventFlagMount) ? @"mounted" : @"unmounted", path); - continue; - } - - BOOL needRescan = (flags & kFSEventStreamEventFlagMustScanSubDirs) != 0; - - if (needRescan) - { - // A rescan requires a reset - [self resetProjectForWatchedPath:path]; - - return; - } - - if (self.isUsingFileLevelAPI) - { - // BOOL finderInfoModified = (flags & kFSEventStreamEventFlagItemFinderInfoMod) != 0; - // BOOL changedOwner = (flags & kFSEventStreamEventFlagItemChangeOwner) != 0; - // BOOL xattrModified = (flags & kFSEventStreamEventFlagItemXattrMod) != 0; - // BOOL isSymlink = (flags & kFSEventStreamEventFlagItemIsSymlink) != 0; - BOOL inodeMetaModified = (flags & kFSEventStreamEventFlagItemInodeMetaMod) != 0; - BOOL isFile = (flags & kFSEventStreamEventFlagItemIsFile) != 0; - BOOL isDir = (flags & kFSEventStreamEventFlagItemIsDir) != 0; - BOOL renamed = (flags & kFSEventStreamEventFlagItemRenamed) != 0; - BOOL modified = (flags & kFSEventStreamEventFlagItemModified) != 0; - BOOL created = (flags & kFSEventStreamEventFlagItemCreated) != 0; - BOOL removed = (flags & kFSEventStreamEventFlagItemRemoved) != 0; - - DDLogVerbose(@"FSEvent: %@ (%@)", path, [self dumpFSEventFlags:flags]); - - if (isDir) - { - /* - When a project is opened for the first time after it is created, - we get an event where the first path is a create for the root directory. - In that case all of the paths have been processed, and we ignore the event. - */ - if (created && [path isEqualToString:self.projectPath.stringByResolvingSymlinksInPath]) - return; - - if (renamed && - !(created || removed) && - ![self shouldIgnoreDirectoryNamed:path.lastPathComponent] && - ![self pathMatchesIgnoredPaths:path]) - { - DDLogVerbose(@"Renamed directory: %@", path); - - [renamedDirectories addObject:path]; - } - - continue; - } - else if (isFile && - (created || modified || renamed || removed || (self.reactToInodeModification && inodeMetaModified)) && - [self isSourceFile:path]) - { - DDLogVerbose(@"FSEvent accepted"); - - if ([self.fm fileExistsAtPath:path]) - [modifiedPaths addObject:path]; - else if ([path.pathExtension isEqualToString:@"xib"]) - { - // If a xib is deleted, delete its cib. There is no need to update when a xib is deleted, - // it is inside a folder in Xcode, which updates automatically. - - if (![self.fm fileExistsAtPath:path]) - { - NSString *cibPath = [path.stringByDeletingPathExtension stringByAppendingPathExtension:@"cib"]; - - if ([self.fm fileExistsAtPath:cibPath]) - [self.fm removeItemAtPath:cibPath error:nil]; - - continue; - } - } - - needUpdate = YES; - } - else if (isFile && (renamed || removed) && !(modified || created) && [path.pathExtension isEqualToString:@"cib"]) - { - // If a cib is deleted, mark its xib as needing update so the cib is regenerated - NSString *xibPath = [path.stringByDeletingPathExtension stringByAppendingPathExtension:@"xib"]; - - if ([self.fm fileExistsAtPath:xibPath]) - { - [modifiedPaths addObject:xibPath]; - needUpdate = YES; - } - } - } - else // directory-based listening - { - // We should drop support for Snow Leopard soon. - - BOOL isDirectory = NO; - [self.fm fileExistsAtPath:path isDirectory:&isDirectory]; - - // If for some reason the path is not a directory, - // we don't want to deal with it in this mode. - if (!isDirectory) - continue; - - NSFileManager *fm = [NSFileManager defaultManager]; - NSArray *subpaths = [fm contentsOfDirectoryAtPath:path error:NULL]; - - for (NSString *subpath in subpaths) - { - NSString *fullPath = [path stringByAppendingPathComponent:subpath]; - - if (![self isSourceFile:fullPath]) - continue; - - NSDate *lastModifiedDate = [self lastModificationDateForPath:fullPath]; - NSDictionary *fileAttributes = [fm attributesOfItemAtPath:fullPath error:nil]; - NSDate *fileModDate = [fileAttributes objectForKey:NSFileModificationDate]; - - if ([fileModDate compare:lastModifiedDate] == NSOrderedDescending) - { - [self updateLastModificationDate:fileModDate forPath:fullPath]; - [modifiedPaths addObject:fullPath]; - needUpdate = YES; - } - } - } - } - - // If directories were renamed, we take the easy way out and reset the project - if (renamedDirectories.count) - [self handleRenamedDirectories:renamedDirectories]; - else if (needUpdate) - [self updateSupportFilesWithModifiedPaths:modifiedPaths]; -} - -- (void)handleRenamedDirectories:(NSArray *)directories -{ - // Make sure we don't get any more events while handling these events - [self stopFSEventStream]; - - DDLogVerbose(@"Renamed directories: %@", directories); - - [self tidyShadowedFiles]; - - for (NSString *directory in directories) - { - // If it doesn't exist, it's the old name. Nothing to do. - // If it does exist, populate the project with the directory. - - if ([self.fm fileExistsAtPath:directory]) - { - // If the directory is within the project, we can populate it directly. - // Otherwise we have to start at the top level and repopulate everything. - if ([directory hasPrefix:self.projectPath]) - [self populateXcodeProjectWithProjectRelativePath:[self projectRelativePathForPath:directory]]; - else - { - [self populateXcodeProject]; - - // Since everything has been repopulated, no point in continuing - break; - } - } - } - - [self waitForOperationQueueToFinishWithSelector:@selector(batchDidFinish)]; -} - -- (void)updateSupportFilesWithModifiedPaths:(NSArray *)modifiedPaths -{ - // Make sure we don't get any more events while handling these events - [self stopFSEventStream]; - - NSArray *removedFiles = [self tidyShadowedFiles]; - - if (removedFiles.count || modifiedPaths.count) - { - for (NSString *path in modifiedPaths) - [self handleFileModificationAtPath:path]; - - [self waitForOperationQueueToFinishWithSelector:@selector(batchDidFinish)]; - } -} - -- (void)resetProjectForWatchedPath:(NSString *)path -{ - // If a watched path changes we don't have much choice but to reset the project. - [self stopFSEventStream]; - - if ([path isEqualToString:self.projectPath]) - { - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - NSInteger response = NSRunAlertPanel(@"The project moved.", @"Your project directory has moved. Would you like to reload the project or quit XcodeCapp?", @"Reload", @"Quit", nil); - - BOOL shouldQuit = YES; - - if (response == NSAlertDefaultReturn) - { - char newPathBuf[MAXPATHLEN + 1]; - - int result = fcntl(self.projectPathFileDescriptor, F_GETPATH, newPathBuf); - - if (result == 0) - { - self.projectPath = [NSString stringWithUTF8String:newPathBuf]; - shouldQuit = NO; - } - else - NSRunAlertPanel(@"The project can’t be located.", @"I’m sorry Dave, but I don’t know where the project went. I’m afraid I have to quit now.", @"OK, HAL", nil, nil); - } - - if (shouldQuit) - { - [[NSApplication sharedApplication] terminate:self]; - return; - } - } - - [self synchronizeProject:self]; -} - -/*! - Handle a file modification. If it's a .j or xib/nib, - perform the appropriate conversion. If it's .xcodecapp-ignore, it will - update the list of ignored files. - - @param path The full resolved path of the modified file -*/ -- (void)handleFileModificationAtPath:(NSString*)resolvedPath -{ - if (![self.fm fileExistsAtPath:resolvedPath]) - return; - - NSString *projectPath = [self projectPathForSourcePath:resolvedPath]; - - ProcessSourceOperation *op = [[ProcessSourceOperation alloc] initWithXCC:self - projectId:[NSNumber numberWithInteger:self.projectId] - sourcePath:projectPath]; - [self.operationQueue addOperation:op]; -} - -#pragma mark - Shell Helpers - -/*! - Run an NSTask with the given arguments - - @param launchPath The executable to launch - @param arguments NSArray containing the NSTask arguments - @param returnType Determines whether to return stdout, stderr, either, or nothing in the response - @return NSDictionary containing the return status (NSNumber) and the response (NSString) - */ -- (NSDictionary *)runTaskWithLaunchPath:(NSString *)launchPath arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType -{ - return [self runTaskWithLaunchPath:launchPath arguments:arguments returnType:returnType currentDirectoryPath:nil]; -} - -/*! - Run an NSTask with the given arguments - - @param launchPath The executable to launch - @param arguments NSArray containing the NSTask arguments - @param returnType Determines whether to return stdout, stderr, either, or nothing in the response - @param the currentDirectoryPath for the task - @return NSDictionary containing the return status (NSNumber) and the response (NSString) - */ -- (NSDictionary *)runTaskWithLaunchPath:(NSString *)launchPath arguments:(NSArray *)arguments returnType:(XCCTaskReturnType)returnType currentDirectoryPath:(NSString*)aCurrentDirectoryPath -{ - NSTask *task = [NSTask new]; - - task.launchPath = launchPath; - task.arguments = arguments; - task.environment = self.environment; - task.standardOutput = [NSPipe pipe]; - task.standardError = [NSPipe pipe]; - - if (aCurrentDirectoryPath) - task.currentDirectoryPath = aCurrentDirectoryPath; - - [task launch]; - - DDLogVerbose(@"Task launched: %@\n%@", launchPath, arguments); - - if (returnType != kTaskReturnTypeNone) - { - [task waitUntilExit]; - - DDLogVerbose(@"Task exited: %@:%d", launchPath, task.terminationStatus); - - NSData *data = nil; - - if (returnType == kTaskReturnTypeStdOut || returnType == kTaskReturnTypeAny) - data = [[task.standardOutput fileHandleForReading] availableData]; - - if (returnType == kTaskReturnTypeStdError || (returnType == kTaskReturnTypeAny && [data length] == 0)) - data = [[task.standardError fileHandleForReading] availableData]; - - NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSNumber *status = [NSNumber numberWithInt:task.terminationStatus]; - - return @{ @"status":status, @"response":response }; - } - else - { - return @{ @"status":@0, @"response":@"" }; - } -} - -- (BOOL)executablesAreAccessible -{ - for (NSString *executable in self.executables) - { - NSDictionary *response = [self runTaskWithLaunchPath:@"/usr/bin/which" - arguments:@[executable] - returnType:kTaskReturnTypeStdOut]; - - NSString *path = [response[@"response"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - - if (path.length) - self.executablePaths[executable] = path; - else - { - DDLogError(@"Could not find executable '%@' in PATH: %@", executable, self.environment[@"PATH"]); - return NO; - } - } - - DDLogVerbose(@"Executable paths: %@", self.executablePaths); - - return YES; -} - - -#pragma mark - Source Files Management - -- (BOOL)isObjjFile:(NSString *)path -{ - return [path.pathExtension.lowercaseString isEqual:@"j"]; -} - -- (BOOL)isXibFile:(NSString *)path -{ - NSString *extension = path.pathExtension.lowercaseString; - - if ([extension isEqual:@"xib"] || [extension isEqual:@"nib"]) - { - // Xcode creates temp files called ~.xib. Filter those out. - NSString *baseFilename = path.lastPathComponent.stringByDeletingPathExtension; - - return [baseFilename characterAtIndex:baseFilename.length - 1] != '~'; - } - - return NO; -} - -- (BOOL)isXCCIgnoreFile:(NSString *)path -{ - return [path isEqualToString:self.xcodecappIgnorePath]; -} - -- (BOOL)isSourceFile:(NSString *)path -{ - return ([self isXibFile:path] || [self isObjjFile:path] || [self isXCCIgnoreFile:path]) && ![self pathMatchesIgnoredPaths:path]; -} - -- (NSString *)projectPathForSourcePath:(NSString *)path -{ - NSString *base = path.stringByDeletingLastPathComponent; - NSString *projectPath = self.projectPathsForSourcePaths[base]; - - return projectPath ? [projectPath stringByAppendingPathComponent:path.lastPathComponent] : path; -} - -- (NSString *)projectRelativePathForPath:(NSString *)path -{ - return [path substringFromIndex:self.projectPath.length + 1]; -} - - -#pragma mark - Shadow Files Management - -- (NSString *)shadowBasePathForProjectSourcePath:(NSString *)path -{ - if (path.isAbsolutePath) - path = [self projectRelativePathForPath:path]; - - NSString *filename = [path.stringByDeletingPathExtension stringByReplacingOccurrencesOfString:@"/" withString:XCCSlashReplacement]; - - return [self.supportPath stringByAppendingPathComponent:filename]; -} - -- (NSString *)sourcePathForShadowPath:(NSString *)path -{ - NSString *filename = [path stringByReplacingOccurrencesOfString:XCCSlashReplacement withString:@"/"]; - filename = [filename.stringByDeletingPathExtension stringByAppendingPathExtension:@"j"]; - - return [self.projectPath stringByAppendingPathComponent:filename]; -} - -/*! - Clean up any shadow files and PBX entries related to given the Cappuccino source file path -*/ -- (void)removeReferencesToSourcePaths:(NSArray *)sourcePaths -{ - BOOL updateLastModDate = !self.supportsFileLevelAPI && [self respondsToSelector:@selector(updateLastModificationDate:forPath:)]; - - for (NSString *sourcePath in sourcePaths) - { - if (updateLastModDate) - [self updateLastModificationDate:nil forPath:sourcePath]; - - NSString *shadowBasePath = [self shadowBasePathForProjectSourcePath:sourcePath]; - NSString *shadowHeaderPath = [shadowBasePath stringByAppendingPathExtension:@"h"]; - NSString *shadowImplementationPath = [shadowBasePath stringByAppendingPathExtension:@"m"]; - - [self.fm removeItemAtPath:shadowHeaderPath error:nil]; - [self.fm removeItemAtPath:shadowImplementationPath error:nil]; - - [self pruneProcessingErrorsForProjectPath:sourcePath]; - } - - if (sourcePaths.count) - DDLogVerbose(@"Removed shadow references to: %@", sourcePaths); -} - -- (NSArray *)tidyShadowedFiles -{ - NSArray *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.supportPath error:nil]; - NSMutableArray *pathsToRemove = [NSMutableArray new]; - - for (NSString *path in subpaths) - { - NSString *extension = path.pathExtension; - - if ([extension isEqualToString:@"h"] && ![path.lastPathComponent isEqualToString:@"xcc_general_include.h"]) - { - NSString *sourcePath = [self sourcePathForShadowPath:path]; - - if (![self.fm fileExistsAtPath:sourcePath]) - [pathsToRemove addObject:sourcePath]; - } - } - - [self removeReferencesToSourcePaths:pathsToRemove]; - - if (pathsToRemove.count) - self.pbxOperations[@"remove"] = pathsToRemove; - - return pathsToRemove; -} - -#pragma mark - XCC Ignore management - -+ (NSString *)globToRegexPattern:(NSString *)glob -{ - NSMutableString *regex = [glob mutableCopy]; - - if ([regex characterAtIndex:0] == '!') - [regex deleteCharactersInRange:NSMakeRange(0, 1)]; - - [regex replaceOccurrencesOfString:@"." - withString:@"\\." - options:0 - range:NSMakeRange(0, [regex length])]; - - [regex replaceOccurrencesOfString:@"*" - withString:@".*" - options:0 - range:NSMakeRange(0, [regex length])]; - - // If the glob ends with "/", match that directory and anything below it. - if ([regex characterAtIndex:regex.length - 1] == '/') - [regex replaceCharactersInRange:NSMakeRange(regex.length - 1, 1) withString:@"(?:/.*)?"]; - - return [NSString stringWithFormat:@"^%@$", regex]; -} - -+ (NSArray *)parseIgnorePaths:(NSArray *)paths -{ - NSMutableArray *parsedPaths = [NSMutableArray array]; - NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet]; - - for (NSString *pattern in paths) - { - if ([pattern stringByTrimmingCharactersInSet:whitespace].length == 0) - continue; - - NSString *regexPattern = [self globToRegexPattern:pattern]; - NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF matches %@", regexPattern]; - [parsedPaths addObject:@{ @"predicate": predicate, @"exclude": @([pattern characterAtIndex:0] != '!') }]; - } - - return parsedPaths; -} - -/*! - Compute the ignored paths according to any existing .xcodecapp-ignore file -*/ -- (void)computeIgnoredPaths -{ - self.ignoredPathPredicates = [XCCDefaultIgnoredPathPredicates mutableCopy]; - NSString *ignorePath = [self.projectPath stringByAppendingPathComponent:@".xcodecapp-ignore"]; - - if ([self.fm fileExistsAtPath:ignorePath]) - { - NSString *ignoreFileContent = [NSString stringWithContentsOfFile:ignorePath encoding:NSUTF8StringEncoding error:nil]; - NSArray *ignoredPatterns = [ignoreFileContent componentsSeparatedByString:@"\n"]; - NSArray *parsedPaths = [[self class] parseIgnorePaths:ignoredPatterns]; - [self.ignoredPathPredicates addObjectsFromArray:parsedPaths]; - } - - DDLogVerbose(@"Ignoring file paths: %@", self.ignoredPathPredicates); -} - -- (BOOL)pathMatchesIgnoredPaths:(NSString*)aPath -{ - BOOL ignore = NO; - - for (NSDictionary *ignoreInfo in self.ignoredPathPredicates) - { - BOOL matches = [ignoreInfo[@"predicate"] evaluateWithObject:aPath]; - - if (matches) - ignore = [ignoreInfo[@"exclude"] boolValue]; - } - - return ignore; -} - -- (BOOL)shouldIgnoreDirectoryNamed:(NSString *)filename -{ - return [XCCDirectoriesToIgnorePredicate evaluateWithObject:filename]; -} - -#pragma mark - Errors - -- (IBAction)openErrorsPanel:(id)aSender -{ - [self.errorsPanel setFloatingPanel:[[NSUserDefaults standardUserDefaults] boolForKey:kDefaultXCCPanelStyleUtility]]; - - if ([[NSUserDefaults standardUserDefaults] boolForKey:kDefaultXCCPanelActiveAppWhenOpening]) - { - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [self.errorsPanel makeKeyAndOrderFront:nil]; - } - else - { - [self.errorsPanel orderFrontRegardless]; - } -} - -- (IBAction)openErrorInEditor:(id)sender -{ - id info = self.errorListController.selection; - - NSString *path = [info valueForKey:@"realPath"] ? [info valueForKey:@"realPath"] : [info valueForKey:@"path"]; - - if (path == NSNoSelectionMarker) - return; - - if ([self isObjjFile:path]) - { - [self openObjjFile:path line:[[info valueForKey:@"line"] intValue]]; - } - else // xib - { - [[NSWorkspace sharedWorkspace] openFile:path]; - } -} - -- (void)openObjjFile:(NSString *)path line:(NSInteger)line -{ - NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; - - NSString *app, *type; - BOOL success = [workspace getInfoForFile:path application:&app type:&type]; - - if (!success) - { - NSBeep(); - return; - } - - NSBundle *bundle = [NSBundle bundleWithPath:app]; - NSString *identifier = bundle.bundleIdentifier; - NSString *executablePath = nil; - XCCLineSpecifier lineSpecifier = kLineSpecifierNone; - - if ([identifier hasPrefix:@"com.sublimetext."]) - { - lineSpecifier = kLineSpecifierColon; - executablePath = [[bundle sharedSupportPath] stringByAppendingPathComponent:@"bin/subl"]; - } - else if ([identifier isEqualToString:@"com.barebones.textwrangler"]) - { - lineSpecifier = kLineSpecifierColon; - executablePath = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Helpers/edit"]; - } - else if ([identifier isEqualToString:@"com.barebones.bbedit"]) - { - lineSpecifier = kLineSpecifierColon; - executablePath = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Helpers/bbedit"]; - } - else if ([identifier isEqualToString:@"com.macromates.textmate"]) // TextMate 1.x - { - lineSpecifier = kLineSpecifierMinusL; - executablePath = [[bundle sharedSupportPath] stringByAppendingPathComponent:@"Support/bin/mate"]; - } - else if ([identifier hasPrefix:@"com.macromates.TextMate"]) // TextMate 2.x - { - lineSpecifier = kLineSpecifierMinusL; - executablePath = [bundle pathForResource:@"mate" ofType:@""]; - } - else if ([identifier isEqualToString:@"com.chocolatapp.Chocolat"]) - { - lineSpecifier = kLineSpecifierMinusL; - executablePath = [[bundle sharedSupportPath] stringByAppendingPathComponent:@"choc"]; - } - else if ([identifier isEqualToString:@"org.vim.MacVim"]) - { - lineSpecifier = kLineSpecifierPlus; - executablePath = @"/usr/local/bin/mvim"; - } - else if ([identifier isEqualToString:@"org.gnu.Aquamacs"]) - { - if ([self.fm isExecutableFileAtPath:@"/usr/bin/aquamacs"]) - executablePath = @"/usr/bin/aquamacs"; - else if ([self.fm isExecutableFileAtPath:@"/usr/local/bin/aquamacs"]) - executablePath = @"/usr/local/bin/aquamacs"; - } - else if ([identifier isEqualToString:@"com.apple.dt.Xcode"]) - { - executablePath = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Developer/usr/bin/xed"]; - } - - if (!executablePath || ![self.fm isExecutableFileAtPath:executablePath]) - { - [workspace openFile:path]; - return; - } - - NSArray *args; - - switch (lineSpecifier) - { - case kLineSpecifierNone: - args = @[path]; - break; - - case kLineSpecifierColon: - args = @[[NSString stringWithFormat:@"%1$@:%2$ld", path, line]]; - break; - - case kLineSpecifierMinusL: - args = @[@"-l", [NSString stringWithFormat:@"%ld", line], path]; - break; - - case kLineSpecifierPlus: - args = @[[NSString stringWithFormat:@"+%ld", line], path]; - break; - } - - [self runTaskWithLaunchPath:executablePath arguments:args returnType:kTaskReturnTypeNone]; -} - -- (BOOL)shouldShowErrorNotification -{ - return [[NSUserDefaults standardUserDefaults] boolForKey:kDefaultXCCAutoShowNotificationOnErrors]; -} - -- (BOOL)shouldProcessWithCappLint -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - return [defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnCappLint] - || [defaults boolForKey:kDefaultXCCAutoShowNotificationOnCappLint]; -} - -- (BOOL)shouldProcessWithObjjWarnings -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - return ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnErrors] || [defaults boolForKey:kDefaultXCCAutoShowNotificationOnErrors]) && [defaults boolForKey:kDefaultXCCShouldProcessObjj]; -} - -- (void)showErrors -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - if ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnErrors] && self.errorList.count) - { - [self openErrorsPanel:self]; - } -} - -- (void)showCappLintWarnings -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - NSUInteger numberError = [self.errorList count]; - NSDictionary *firstError; - NSUInteger i = 0; - - for (i = 0; i < numberError; i++) - { - NSDictionary *dict = [self.errorList objectAtIndex:i]; - - if ([[dict valueForKey:@"type"] isEqualToString: @"capp_lint"]) - { - firstError = dict; - break; - } - } - - if ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnCappLint] && firstError) - [self openErrorsPanel:self]; - - if ([defaults boolForKey:kDefaultXCCAutoShowNotificationOnCappLint] && firstError) - { - NSDictionary *error = [self.errorList objectAtIndex:0]; - NSString *filename = [error objectForKey:@"path"]; - - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInteger:self.projectId] , @"projectId", - @"Code Style Issues", @"title", - filename.lastPathComponent , @"message", - nil]; - - [self wantUserNotificationWithInfo:dict]; - } -} - -- (void)showObjjWarnings -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - NSUInteger numberError = [self.errorList count]; - NSDictionary *firstError; - NSUInteger i = 0; - - for (i = 0; i < numberError; i++) - { - NSDictionary *dict = [self.errorList objectAtIndex:i]; - - if ([[dict valueForKey:@"type"] isEqualToString: @"objj"]) - { - firstError = dict; - break; - } - } - - if ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnErrors] && firstError) - [self openErrorsPanel:self]; - - if ([defaults boolForKey:kDefaultXCCAutoShowNotificationOnErrors] && firstError) - { - NSDictionary *error = [self.errorList objectAtIndex:0]; - NSString *filename = [error objectForKey:@"path"]; - - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInteger:self.projectId] , @"projectId", - @"Compiling Issues", @"title", - filename.lastPathComponent , @"message", - nil]; - - [self wantUserNotificationWithInfo:dict]; - } -} - -- (void)pruneProcessingErrorsForProjectPath:(NSString *)path -{ - [self pruneProcessingErrorsForProjectPath:path type:nil]; -} - -- (void)pruneProcessingErrorsForProjectPath:(NSString *)path type:(NSString*)type -{ - // Remove all errors for the path being processed - NSIndexSet *matchingErrors = [self.errorList indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) - { - if (type) - return ([[obj valueForKey:@"path"] isEqualToString:path] || [[obj valueForKey:@"realPath"] isEqualToString:path]) && [[obj valueForKey:@"type"] isEqualToString:type]; - else - return [[obj valueForKey:@"path"] isEqualToString:path] || [[obj valueForKey:@"realPath"] isEqualToString:path]; - }]; - - [self.errorListController removeObjectsAtArrangedObjectIndexes:matchingErrors]; -} - -- (IBAction)clearErrors:(id)sender -{ - [self.errorList removeAllObjects]; - self.errorListController.content = self.errorList; -} - -- (BOOL)hasErrors -{ - NSInteger index = [self.errorList indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) - { - return [[obj valueForKey:@"status"] intValue] == XCCStatusCodeError; - }]; - - return index != NSNotFound; -} - -#pragma mark - objjj check - -- (NSString*)_getObjjIncludePaths -{ - NSRegularExpression *regulareExpressionFramework = [NSRegularExpression regularExpressionWithPattern:@"OBJJ_INCLUDE_PATHS ?= ?\\[\"(.*)\"\\," options:0 error:nil]; - - NSString *indexPath; - - if ([[NSUserDefaults standardUserDefaults] boolForKey:kDefaultXCCUseDebugFrameworkWithObjj]) - indexPath = [NSString stringWithFormat:@"%@/index-debug.html", self.projectPath]; - else - indexPath = [NSString stringWithFormat:@"%@/index.html", self.projectPath]; - - NSDictionary *taskResult = [self runTaskWithLaunchPath:@"/bin/cat" arguments:[NSMutableArray arrayWithObject:indexPath] returnType:kTaskReturnTypeAny]; - - NSString *response = taskResult[@"response"]; - - NSArray *matches = [regulareExpressionFramework matchesInString:response options:0 range:NSMakeRange(0, [response length])]; - - for (NSTextCheckingResult *match in matches) - return [NSString stringWithFormat:@"%@/%@", self.projectPath, [response substringWithRange:[match rangeAtIndex:1]]]; - - return [NSString stringWithFormat:@"%@/%@", self.projectPath ,@"Frameworks/"]; -} - -- (BOOL)checkObjjWarningsForPath:(NSArray*)paths -{ - DDLogVerbose(@"Checking path %@ with objj", paths); - - NSUInteger numberOfFiles = [paths count]; - NSUInteger i = 0; - NSMutableArray *objjPaths = [NSMutableArray array]; - - // We only want the objj files - for (i = 0; i < numberOfFiles; i++) - { - NSString *path = [paths objectAtIndex:i]; - - if ([self isObjjFile:path]) - [objjPaths addObject:path]; - } - - if (![objjPaths count]) - return YES; - - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidStartNotification object:self]; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCObjjDidStartNotification object:self]; - - NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"-I", [self _getObjjIncludePaths], @"-m", nil]; - [arguments addObjectsFromArray:objjPaths]; - - NSDictionary *taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"objj"] - arguments:arguments - returnType:kTaskReturnTypeStdOut]; - - NSInteger status = [taskResult[@"status"] intValue]; - NSString *response = taskResult[@"response"]; - - if (status == 0 && [response length] == 0) - { - [[NSNotificationCenter defaultCenter] postNotificationName:XCCObjjDidEndNotification object:self]; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self]; - return YES; - } - - NSMutableArray *errors = [NSMutableArray arrayWithArray:[response componentsSeparatedByString:@"\n\n"]]; - - NSInteger numberOfErrors = [errors count]; - NSMutableArray *dicts = [NSMutableArray array]; - - // When checking of the entire project, we have to be ready to find errors - NSRegularExpression *regulareExpressionFramework = [NSRegularExpression regularExpressionWithPattern:@"([\\S\\s]*)(WARNING|ERROR) line ([0-9]*) in file\\:(.*)\\: ([\\S\\s]*)" options:0 error:nil]; - - NSString *filePath; - - if ([paths count] == 1) - filePath = [paths firstObject]; - - i = 0; - - for (i = 0; i < numberOfErrors; i++) - { - NSMutableString *error = (NSMutableString*)[errors objectAtIndex:i]; - NSString *line; - NSString *path; - NSString *messageError; - - // We have an extra new line for the first error - if (i == 0) - error = (NSMutableString*)[error substringFromIndex:1]; - - NSArray *matches = [regulareExpressionFramework matchesInString:error options:0 range:NSMakeRange(0, [error length])]; - NSInteger j = 0; - - if (![matches count]) - { - // This shouldn't happen - DDLogVerbose(@"Error %@ doesn't respect any pattern", error); - - path = @""; - line = 0; - messageError = [NSString stringWithFormat:@"Compiling issue at line %@ of file %@:\n%@", line, path.lastPathComponent, error]; - } - - for (NSTextCheckingResult *match in matches) - { - for (j = 0; j < [match numberOfRanges]; j++) - { - switch (j) { - case 1: - messageError = [error substringWithRange:[match rangeAtIndex:j]]; - break; - - case 3: - line = [error substringWithRange:[match rangeAtIndex:j]]; - break; - - case 4: - path = [error substringWithRange:[match rangeAtIndex:j]]; - break; - - case 5: - messageError = [NSString stringWithFormat:@"Compiling issue at line %@ of file %@:\n%@ \n%@", line, path.lastPathComponent, [error substringWithRange:[match rangeAtIndex:j]], messageError]; - break; - - default: - break; - } - } - } - - // Make sure to delete all the compilations issue form the tableView - [self pruneProcessingErrorsForProjectPath:path type:@"objj"]; - - // Path and realPath are needed, we can get error on ViewController2.j while checking ViewController.j. - // When recompiling ViewController.j, realPath is used to know which errors have to be erased form the table - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:[line intValue]], @"line", - messageError , @"message", - (filePath ? filePath:path), @"path", - @"objj", @"type", - path , @"realPath", - nil]; - - // Block to compare dicts - BOOL (^dictComparaison)(id obj, NSUInteger idx, BOOL *stop) = ^(id obj, NSUInteger idx, BOOL *stop){ - if ([obj valueForKey:@"line"] == [dict valueForKey:@"line"]) - { - // For an unknown reason, trim doesn't work - NSString *messsageObj = [obj valueForKey:@"message"]; - NSString *messsageDict = [dict valueForKey:@"message"]; - - messsageDict = [messsageDict stringByReplacingOccurrencesOfString:@" " withString:@""]; - messsageDict = [messsageDict stringByReplacingOccurrencesOfString:@"\n" withString:@""]; - - messsageObj = [messsageObj stringByReplacingOccurrencesOfString:@" " withString:@""]; - messsageObj = [messsageObj stringByReplacingOccurrencesOfString:@"\n" withString:@""]; - - if ([messsageDict isEqualToString:messsageObj]) - { - *stop = YES; - return YES; - } - } - - return NO; - }; - - NSUInteger isInDict = [dicts indexOfObjectPassingTest:dictComparaison]; - NSUInteger isInList = [self.errorList indexOfObjectPassingTest:dictComparaison]; - - // Compiler can show several times the same errors - if (isInDict == NSNotFound && isInList == NSNotFound) - [dicts addObject:dict]; - } - - [self performSelectorOnMainThread:@selector(objjCompilerDidGenerateError:) withObject:dicts waitUntilDone:YES]; - - self.isProcessing = NO; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCObjjDidEndNotification object:self]; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self]; - - return NO; -} - -- (IBAction)checkProjectWithObjj:(id)sender -{ - [self clearErrors:self]; - - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - [center addObserver:self selector:@selector(objjDidEndNotification:) name:XCCObjjDidEndNotification object:nil]; - - [self performSelectorInBackground:@selector(checkObjjWarningsForPath:) withObject:self.xCodeCappTargetedFiles]; -} - -- (void)objjDidEndNotification:(NSNotification*)aNotification -{ - [self showObjjWarnings]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:XCCObjjDidEndNotification object:nil]; -} - -- (void)objjCompilerDidGenerateError:(NSArray*)errors -{ - [self.errorListController addObjects:errors]; -} - - -#pragma mark - capp_lint - -- (IBAction)checkProjectWithCappLint:(id)aSender -{ - [self clearErrors:self]; - - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - [center addObserver:self selector:@selector(cappLintDidEndNotification:) name:XCCCappLintDidEndNotification object:nil]; - - [self performSelectorInBackground:@selector(checkCappLintForPath:) withObject:self.xCodeCappTargetedFiles]; -} - -- (void)cappLintDidEndNotification:(NSNotification*)aNotification -{ - [self showCappLintWarnings]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:XCCCappLintDidEndNotification object:nil]; -} - -- (BOOL)checkCappLintForPath:(NSArray*)paths -{ - DDLogVerbose(@"Checking path %@ with capp_lint", paths); - - NSUInteger numberOfFiles = [paths count]; - - if (!numberOfFiles) - return YES; - - self.isProcessing = YES; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidStartNotification object:self]; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCCappLintDidStartNotification object:self]; - - NSString *baseDirectory = [NSString stringWithFormat:@"--basedir='%@'", self.projectPath]; - NSMutableArray *arguments = [NSMutableArray arrayWithObjects:baseDirectory, nil]; - [arguments addObjectsFromArray:paths]; - - NSDictionary *taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"capp_lint"] - arguments:arguments - returnType:kTaskReturnTypeStdOut]; - - NSInteger status = [taskResult[@"status"] intValue]; - - if (status == 0) - { - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self]; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCCappLintDidEndNotification object:self]; - return YES; - } - - NSString *response = taskResult[@"response"]; - NSMutableArray *errors = [NSMutableArray arrayWithArray:[response componentsSeparatedByString:@"\n\n"]]; - - // We need to remove the first object who is the number of errors and the last object who is an empty line - [errors removeLastObject]; - [errors removeObjectAtIndex:0]; - - NSInteger numberOfErrors = [errors count]; - NSInteger i = 0; - NSString *path; - NSMutableArray *dicts = [NSMutableArray array]; - - if (numberOfFiles == 1) - path = [paths objectAtIndex:0]; - - for (i = 0; i < numberOfErrors; i++) - { - NSMutableString *error = (NSMutableString*)[errors objectAtIndex:i]; - NSString *line; - NSString *firstCaract = [NSString stringWithFormat:@"%c" ,[error characterAtIndex:0]]; - - if ([[NSScanner scannerWithString:firstCaract] scanInt:nil]) - error = (NSMutableString*)[NSString stringWithFormat:@"%@:%@", path, error]; - - NSInteger positionOfFirstColon = [error rangeOfString:@":"].location; - - if (numberOfFiles > 1) - path = [error substringToIndex:positionOfFirstColon]; - - NSString *errorWithoutPath = [error substringFromIndex:(positionOfFirstColon + 1)]; - NSInteger positionOfSecondColon = [errorWithoutPath rangeOfString:@":"].location; - line = [errorWithoutPath substringToIndex:positionOfSecondColon]; - - NSString *messageError = [NSString stringWithFormat:@"Code style issue at line %@ of file %@:\n%@", line, path.lastPathComponent, errorWithoutPath]; - - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:[line intValue]], @"line", - messageError , @"message", - path, @"path", - @"capp_lint", @"type", - nil]; - - [dicts addObject:dict]; - } - - [self performSelectorOnMainThread:@selector(cappLintConversionDidGenerateError:) withObject:dicts waitUntilDone:YES]; - - self.isProcessing = NO; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self]; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCCappLintDidEndNotification object:self]; - - return NO; -} - -- (void)cappLintConversionDidGenerateError:(NSArray*)errors -{ - [self.errorListController addObjects:errors]; -} - -#pragma mark - Cappuccino update - -- (void)updateCappuccino -{ - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidStartNotification object:self]; - - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [self.updatingCappuccinoPanel makeKeyAndOrderFront:self]; - - self.isCappuccinoUpdating = YES; - - [self.progressIndicator startAnimation:self]; - [self.progressIndicator setMaxValue:4]; - [self.progressIndicator setDoubleValue:0]; - - NSString *temporaryFolder = NSTemporaryDirectory(); - - if(![self _hasInitializedUpdateCappuccinoFromFolder:temporaryFolder] || - ![self _hasCleanedInstallOfCappuccinoFromFolder:temporaryFolder] || - ![self _hasInstalledCappuccinoFromFolder:temporaryFolder]) - return; - - [self notifyUserWithTitle:@"Update Cappuccino" message:@"Updating of Cappuccino completed"]; - [self _incrementeProgressBarAndUpdateInformationFieldWithMessage:@"Updating completed"]; - [self.progressIndicator stopAnimation:self]; - self.isCappuccinoUpdating = NO; - - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self]; -} - -- (BOOL)_hasInitializedUpdateCappuccinoFromFolder:(NSString*)aFolder -{ - //Be sure to remove an old install - NSMutableArray *rmArguments = [NSMutableArray arrayWithObjects:@"-r", @"cappuccino", nil]; - [self runTaskWithLaunchPath:self.executablePaths[@"rm"] - arguments:rmArguments - returnType:kTaskReturnTypeAny - currentDirectoryPath:aFolder]; - - - [self _incrementeProgressBarAndUpdateInformationFieldWithMessage:@"Downloading Cappuccino"]; - - // Download the file - NSString *cappuccinoURL; - - if ([[NSUserDefaults standardUserDefaults] boolForKey:kDefaultUpdateCappuccinoWithLastVersionOfMasterBranch]) - cappuccinoURL = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"XCCLastCappuccinoMasterBranchURL"]; - else - cappuccinoURL = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"XCCLastCappuccinoReleaseURL"]; - - NSString *destination = [NSString stringWithFormat:@"%@cappuccino.zip", aFolder]; - NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"-Lk", cappuccinoURL, @"-o", destination, nil]; - NSDictionary *taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"curl"] - arguments:arguments - returnType:kTaskReturnTypeStdOut]; - - NSInteger status = [taskResult[@"status"] intValue]; - - if (status > 1) - { - [self _updatingCappuccinoFailedWithMessage:@"Unable to download Cappuccino"]; - return NO; - } - - //Unzip the file - NSMutableArray *unzipArguments = [NSMutableArray arrayWithObjects:@"-u", @"-o", @"-q", @"-d", @"cappuccino", @"cappuccino.zip", nil]; - NSDictionary *unzipTaskResult = [self runTaskWithLaunchPath:self.executablePaths[@"unzip"] - arguments:unzipArguments - returnType:kTaskReturnTypeAny - currentDirectoryPath:aFolder]; - - NSInteger unzipStatus = [unzipTaskResult[@"status"] intValue]; - - if (unzipStatus >= 1) - { - DDLogVerbose(@"Unable to unzip Cappuccino"); - [self _updatingCappuccinoFailedWithMessage:@"Unable to unzip Cappuccino"]; - return NO; - } - - return YES; -} - -- (BOOL)_hasCleanedInstallOfCappuccinoFromFolder:(NSString*)aFolder -{ - NSString* path = [self _cappuccinoPathForFolder:aFolder]; - - [self _incrementeProgressBarAndUpdateInformationFieldWithMessage:@"Jake clobber"]; - - //Jake clobber - NSMutableArray *jakeClobberArguments = [NSMutableArray arrayWithObjects:@"clobber", nil]; - NSDictionary *jakeClobberTaskResult = [self runJakeTaskWithArguments:jakeClobberArguments currentDirectoryPath:path]; - - NSInteger jakeInstallStatus = [jakeClobberTaskResult[@"status"] intValue]; - - if (jakeInstallStatus == 1) - { - DDLogVerbose(@"Jake clobber failed: %@", jakeClobberTaskResult[@"response"]); - [self _updatingCappuccinoFailedWithMessage:@"Jake clobber failed"]; - return NO; - } - - return YES; -} - -- (BOOL)_hasInstalledCappuccinoFromFolder:(NSString*)aFolder -{ - NSString* path = [self _cappuccinoPathForFolder:aFolder]; - - [self _incrementeProgressBarAndUpdateInformationFieldWithMessage:@"Jake install"]; - - //Jake install - NSMutableArray *jakeInstallArguments = [NSMutableArray arrayWithObjects:@"install", nil]; - NSDictionary *jakeInstallTaskResult = [self runJakeTaskWithArguments:jakeInstallArguments currentDirectoryPath:path]; - - NSInteger jakeInstallStatus = [jakeInstallTaskResult[@"status"] intValue]; - - if (jakeInstallStatus == 1) - { - DDLogVerbose(@"Jake install failed: %@", jakeInstallTaskResult[@"response"]); - [self _updatingCappuccinoFailedWithMessage:@"Jake install failed"]; - return NO; - } - - return YES; -} - -- (NSDictionary*)runJakeTaskWithArguments:(NSMutableArray*)arguments currentDirectoryPath:(NSString*)aCurrentDirectoryPath -{ - NSString *launchPath = self.executablePaths[@"jake"]; - - NSTask *task = [NSTask new]; - - task.launchPath = launchPath; - task.arguments = arguments; - task.environment = self.environment; - task.standardOutput = [NSPipe new]; - task.standardError = [NSPipe new]; - - if (aCurrentDirectoryPath) - task.currentDirectoryPath = aCurrentDirectoryPath; - - // This is needed to log the jake - NSFileHandle* fhOut = [task.standardOutput fileHandleForReading]; - [fhOut readInBackgroundAndNotify]; - NSFileHandle* fhErr = [task.standardError fileHandleForReading]; - [fhErr readInBackgroundAndNotify]; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jakeReceivedData:) name:NSFileHandleReadCompletionNotification object:fhOut]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jakeReceivedError:) name:NSFileHandleReadCompletionNotification object:fhErr]; - - [task launch]; - - DDLogVerbose(@"Task launched: %@\n%@", launchPath, arguments); - - [task waitUntilExit]; - - DDLogVerbose(@"Task exited: %@:%d", launchPath, task.terminationStatus); - - NSNumber *status = [NSNumber numberWithInt:task.terminationStatus]; - NSData *data = nil; - - if ([status intValue] == 0) - data = [[task.standardOutput fileHandleForReading] availableData]; - else - data = [[task.standardError fileHandleForReading] availableData]; - - NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - - [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:fhOut]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:fhErr]; - - return @{@"status" : status, @"response" : response}; -} - --(void)jakeReceivedData:(NSNotification*)notification -{ - NSData *data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem]; - NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; - - DDLogVerbose(@"%@", string); - - [[notification object] readInBackgroundAndNotify]; -} - --(void)jakeReceivedError:(NSNotification*)notification -{ - NSData *data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem]; - NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; - - DDLogVerbose(@"%@", string); -} - -/*! - This return the current path where the tmp cappuccino was downloaded - */ -- (NSString*)_cappuccinoPathForFolder:(NSString*)aFolder -{ - NSFileManager *fileManger = [NSFileManager defaultManager]; - NSString *contentOfCappuccinoFolder = [[fileManger contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@cappuccino", aFolder] error:nil] firstObject]; - - return [NSString stringWithFormat:@"%@cappuccino/%@", aFolder, contentOfCappuccinoFolder]; -} - -- (void)_incrementeProgressBarAndUpdateInformationFieldWithMessage:(NSString*)aString -{ - double currentValue = [self.progressIndicator doubleValue]; - [self.progressIndicator setDoubleValue:++currentValue]; - - [self.fieldCurrentTask setStringValue:[NSString stringWithFormat:@"Step %.0f/%.0f : %@", [self.progressIndicator doubleValue], [self.progressIndicator maxValue], aString]]; -} - -- (void)_updatingCappuccinoFailedWithMessage:(NSString*)aMessage -{ - [self.progressIndicator stopAnimation:self]; - [self.progressIndicator setDoubleValue:0]; - [self.fieldCurrentTask setStringValue:[NSString stringWithFormat:@"Issue : %@", aMessage]]; - - [self notifyUserWithTitle:@"Error updating Cappuccino" message:aMessage]; - - self.isCappuccinoUpdating = NO; - [[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self]; -} - - -#pragma mark - User notifications - -- (NSString *)applicationNameForGrowl -{ - return @"XcodeCapp"; -} - -- (void)notifyUserWithTitle:(NSString *)aTitle message:(NSString *)aMessage -{ - if ([NSUserNotificationCenter class]) - { - NSUserNotification *note = [NSUserNotification new]; - note.title = aTitle; - note.informativeText = aMessage; - - [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:note]; - } - else - { - [GrowlApplicationBridge notifyWithTitle:aTitle - description:aMessage - notificationName:GROWL_NOTIFICATIONS_DEFAULT - iconData:nil - priority:0 - isSticky:NO - clickContext:nil]; - } -} - -- (void)wantUserNotificationWithInfo:(NSDictionary *)info -{ - [self performSelectorOnMainThread:@selector(notifyUserWithInfo:) withObject:info waitUntilDone:NO]; -} - -- (void)notifyUserWithInfo:(NSDictionary *)info -{ - if ([info[@"projectId"] intValue] != self.projectId) - return; - - [self notifyUserWithTitle:info[@"title"] message:info[@"message"]]; -} - -- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification -{ - // Notification Center may decide not to show a notification. We always want them to show. - return YES; -} - -- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification -{ - if ([self.errorList count]) - [self openErrorsPanel:self]; - - [center removeDeliveredNotification:notification]; -} - -@end - - -@implementation XcodeCapp (SnowLeopard) - -- (void)updateLastModificationDate:(NSDate *)date forPath:(NSString *)path -{ - if (date) - [self.pathModificationDates setObject:date forKey:path]; - else - [self.pathModificationDates removeObjectForKey:path]; - - [[NSUserDefaults standardUserDefaults] setObject:self.pathModificationDates forKey:kDefaultPathModificationDates]; -} - -- (NSDate *)lastModificationDateForPath:(NSString *)path -{ - if (!self.pathModificationDates) - { - self.pathModificationDates = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:kDefaultPathModificationDates] mutableCopy]; - - if (!self.pathModificationDates) - self.pathModificationDates = [NSMutableDictionary new]; - } - - if ([self.pathModificationDates valueForKey:path] != nil) - return [self.pathModificationDates valueForKey:path]; - else - return self.appStartedTimestamp; -} - -@end diff --git a/Tools/XcodeCapp/XcodeCapp/XcodeProjectCloser.m b/Tools/XcodeCapp/XcodeCapp/XcodeProjectCloser.m index 325df5feb..d6d8f165d 100644 --- a/Tools/XcodeCapp/XcodeCapp/XcodeProjectCloser.m +++ b/Tools/XcodeCapp/XcodeCapp/XcodeProjectCloser.m @@ -29,12 +29,11 @@ static const char *kCloseXcodeProjectScript = + (void)closeXcodeProjectForProject:(NSString *)projectPath { - NSString *format = [NSString stringWithUTF8String:kCloseXcodeProjectScript]; - NSString *source = [NSString stringWithFormat:format, projectPath]; - NSAppleScript *script = [[NSAppleScript alloc] initWithSource:source]; + NSString *format = @(kCloseXcodeProjectScript); + NSString *source = [NSString stringWithFormat:format, projectPath]; + NSAppleScript *script = [[NSAppleScript alloc] initWithSource:source]; - NSAppleEventDescriptor *descriptor; - descriptor = [script executeAndReturnError:nil]; + [script executeAndReturnError:nil]; } @end diff --git a/Tools/XcodeCapp/XcodeCapp/YRKSpinningProgressIndicator.h b/Tools/XcodeCapp/XcodeCapp/YRKSpinningProgressIndicator.h new file mode 100755 index 000000000..8b7ff78d6 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/YRKSpinningProgressIndicator.h @@ -0,0 +1,26 @@ +// +// YRKSpinningProgressIndicator.h +// +// Copyright 2009 Kelan Champagne. All rights reserved. +// + +@import Cocoa; + + +@interface YRKSpinningProgressIndicator : NSView + +@property (nonatomic, copy) NSColor *color; +@property (nonatomic, copy) NSColor *backgroundColor; +@property (nonatomic, assign) BOOL drawsBackground; + +@property (nonatomic, assign, getter=isDisplayedWhenStopped) BOOL displayedWhenStopped; +@property (nonatomic, assign) BOOL usesThreadedAnimation; + +@property (nonatomic, assign, getter=isIndeterminate) BOOL indeterminate; +@property (nonatomic, assign) CGFloat currentValue; +@property (nonatomic, assign) CGFloat maxValue; + +- (void)stopAnimation:(id)sender; +- (void)startAnimation:(id)sender; + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/YRKSpinningProgressIndicator.m b/Tools/XcodeCapp/XcodeCapp/YRKSpinningProgressIndicator.m new file mode 100755 index 000000000..2e2b36763 --- /dev/null +++ b/Tools/XcodeCapp/XcodeCapp/YRKSpinningProgressIndicator.m @@ -0,0 +1,392 @@ +// +// YRKSpinningProgressIndicator.m +// +// Copyright 2009 Kelan Champagne. All rights reserved. +// + +#import "YRKSpinningProgressIndicator.h" + +// Some constants to control the animation +const CGFloat kAlphaWhenStopped = 0.15; +const CGFloat kFadeMultiplier = 0.85l; +const NSUInteger kNumberOfFins = 12; +const NSTimeInterval kFadeOutTime = 0.7; // seconds + +@interface YRKSpinningProgressIndicator () +@end + + +@implementation YRKSpinningProgressIndicator +{ + + BOOL _isAnimating; + BOOL _isFadingOut; + int _currentPosition; + NSMutableArray* _finColors; + NSTimer* _animationTimer; + NSThread* _animationThread; + NSDate* _fadeOutStartTime; +} + +#pragma mark - Init + +- (void)awakeFromNib +{ + [self _init]; +} + +- (instancetype)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + + if (self) + { + [self _init]; + } + + return self; +} + +- (void)_init +{ + _currentPosition = 0; + _finColors = [[NSMutableArray alloc] initWithCapacity:kNumberOfFins]; + + _isAnimating = NO; + _isFadingOut = NO; + + // user setter, to generate all fin colors + self.color = [NSColor blackColor]; + _backgroundColor = [NSColor clearColor]; + _drawsBackground = NO; + + _displayedWhenStopped = YES; + _usesThreadedAnimation = YES; + + _indeterminate = YES; + _currentValue = 0.0; + _maxValue = 100.0; +} + +#pragma mark - NSView overrides + +- (void)viewDidMoveToWindow +{ + [super viewDidMoveToWindow]; + + // No window? View hierarchy may be going away. Dispose timer to clear circular retain of timer to self to timer. + if (![self window]) + [self actuallyStopAnimation]; + else if (_isAnimating) + [self actuallyStartAnimation]; +} + +- (void)drawRect:(NSRect)rect +{ + const CGSize size = self.bounds.size; + const CGFloat length = MIN(size.height, size.width); + + // fill the background, if set + if (_drawsBackground) + { + [_backgroundColor set]; + [NSBezierPath fillRect:[self bounds]]; + } + + CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + + // Move the CTM so 0,0 is at the center of our bounds + CGContextTranslateCTM(ctx, size.width/2, size.height/2); + + if (_indeterminate) + { + NSBezierPath *path = [[NSBezierPath alloc] init]; + // magic constants determined empirically, to make it look like the NS version. + const CGFloat lineWidth = 0.0859375 * length; // should be 2.75 for 32x32 + const CGFloat lineStart = 0.234375 * length; // should be 7.5 for 32x32 + const CGFloat lineEnd = 0.421875 * length; // should be 13.5 for 32x32 + [path setLineWidth:lineWidth]; + [path setLineCapStyle:NSRoundLineCapStyle]; + [path moveToPoint:NSMakePoint(0, lineStart)]; + [path lineToPoint:NSMakePoint(0, lineEnd)]; + + // Draw all the fins by rotating the CTM, then just redraw the same path again. + for (NSUInteger i = 0; i < kNumberOfFins; i++) + { + NSColor *c = _isAnimating ? _finColors[i] : [_color colorWithAlphaComponent:kAlphaWhenStopped]; + [c set]; + [path stroke]; + + CGContextRotateCTM(ctx, 2 * M_PI/kNumberOfFins); + } + } + else + { + CGFloat lineWidth = 1 + (0.01 * length); + CGFloat circleRadius = (length - lineWidth) / 2.1; + NSPoint circleCenter = NSMakePoint(0, 0); + [_color set]; + NSBezierPath *path = [[NSBezierPath alloc] init]; + [path setLineWidth:lineWidth]; + [path appendBezierPathWithOvalInRect:NSMakeRect(-circleRadius, + -circleRadius, + circleRadius * 2, + circleRadius * 2)]; + [path stroke]; + path = [[NSBezierPath alloc] init]; + [path appendBezierPathWithArcWithCenter:circleCenter radius:circleRadius startAngle:90 endAngle:90-(360*(_currentValue/_maxValue)) clockwise:YES]; + [path lineToPoint:circleCenter] ; + [path fill]; + } +} + + +#pragma mark - NSProgressIndicator API + +- (void)startAnimation:(id)sender +{ + if (!_indeterminate || (_isAnimating && !_isFadingOut)) + return; + + [self actuallyStartAnimation]; +} + +- (void)stopAnimation:(id)sender +{ + // animate to stopped state + _isFadingOut = YES; + _fadeOutStartTime = [NSDate date]; +} + +/// Only the spinning style is implemented +- (void)setStyle:(NSProgressIndicatorStyle)style +{ + if (NSProgressIndicatorSpinningStyle != style) + NSAssert(NO, @"Non-spinning styles not available."); +} + + +#pragma mark - Custom Accessors + +- (void)setColor:(NSColor *)value +{ + if (_color != value) + { + _color = [value copy]; + + // Set all the fin colors, with their current alpha components. + for (NSUInteger i = 0; i < kNumberOfFins; i++) + { + CGFloat alpha = [self alphaValueForPosition:i]; + _finColors[i] = [_color colorWithAlphaComponent:alpha]; + } + + [self setNeedsDisplay:YES]; + } +} + +- (void)setBackgroundColor:(NSColor *)value +{ + if (_backgroundColor != value) + { + _backgroundColor = [value copy]; + [self setNeedsDisplay:YES]; + } +} + +- (void)setDrawsBackground:(BOOL)value +{ + if (_drawsBackground != value) + _drawsBackground = value; + + [self setNeedsDisplay:YES]; +} + +- (void)setIsIndeterminate:(BOOL)isIndeterminate +{ + _indeterminate = isIndeterminate; + + if (!_indeterminate && _isAnimating) + [self stopAnimation:self]; + + [self setNeedsDisplay:YES]; +} + +- (void)setCurrentValue:(CGFloat)currentValue +{ + // Automatically put it into determinate mode if it's not already. + if (_indeterminate) + self.indeterminate = NO; + + _currentValue = currentValue; + [self setNeedsDisplay:YES]; +} + +- (void)setMaxValue:(CGFloat)maxValue +{ + _maxValue = maxValue; + [self setNeedsDisplay:YES]; +} + +- (void)setUsesThreadedAnimation:(BOOL)useThreaded +{ + if (_usesThreadedAnimation != useThreaded) + { + _usesThreadedAnimation = useThreaded; + + if (_isAnimating) { + // restart the timer to use the new mode + [self stopAnimation:self]; + [self startAnimation:self]; + } + } +} + +- (void)setDisplayedWhenStopped:(BOOL)displayedWhenStopped +{ + _displayedWhenStopped = displayedWhenStopped; + + // Show/hide ourself if necessary + if (!_isAnimating) + self.hidden = !_displayedWhenStopped; +} + + +#pragma mark - Private + +- (void)updateFrameFromTimer:(NSTimer *)timer +{ + // update the colors + const CGFloat minAlpha = _displayedWhenStopped ? kAlphaWhenStopped : 0.0; + + for (NSUInteger i = 0; i < kNumberOfFins; i++) + { + CGFloat newAlpha = MAX([self alphaValueForPosition:i], minAlpha); + _finColors[i] = [_color colorWithAlphaComponent:newAlpha]; + } + + if (_isFadingOut) + { + // check if the fadeout is done + if ([_fadeOutStartTime timeIntervalSinceNow] < -kFadeOutTime) + [self actuallyStopAnimation]; + } + + // draw now instead of waiting for setNeedsDisplay (that's the whole reason + // we're animating from background thread) + if (_usesThreadedAnimation) + [self display]; + else + [self setNeedsDisplay:YES]; + + // update the currentPosition for next time, unless fading out + if (!_isFadingOut) + _currentPosition = (_currentPosition + 1) % kNumberOfFins; +} + +/// Returns the alpha value for the given position. +/// Each fin should fade exponentially over _numberOfFins frames of animation. +/// @param position is [0,kNumberOfFins) +- (CGFloat)alphaValueForPosition:(NSUInteger)position +{ + CGFloat normalValue = pow(kFadeMultiplier, (position + _currentPosition) % kNumberOfFins); + + if (_isFadingOut) + { + NSTimeInterval timeSinceStop = -[_fadeOutStartTime timeIntervalSinceNow]; + normalValue *= kFadeOutTime - timeSinceStop; + } + + return normalValue; +} + +- (void)actuallyStartAnimation +{ + // Just to be safe kill any existing timer. + [self actuallyStopAnimation]; + + _isAnimating = YES; + _isFadingOut = NO; + + // always start from the top + _currentPosition = 0; + + if (!_displayedWhenStopped) + [self setHidden:NO]; + + if ([self window]) + { + // Why animate if not visible? viewDidMoveToWindow will re-call this method when needed. + if (_usesThreadedAnimation) + { + _animationThread = [[NSThread alloc] initWithTarget:self selector:@selector(animateInBackgroundThread) object:nil]; + [_animationThread start]; + } + else + { + _animationTimer = [NSTimer timerWithTimeInterval:(NSTimeInterval)0.05 + target:self + selector:@selector(updateFrameFromTimer:) + userInfo:nil + repeats:YES]; + + [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSRunLoopCommonModes]; + [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSDefaultRunLoopMode]; + [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSEventTrackingRunLoopMode]; + } + } +} + +- (void)actuallyStopAnimation +{ + _isAnimating = NO; + _isFadingOut = NO; + + if (!_displayedWhenStopped) + [self setHidden:YES]; + + if (_animationThread) + { + // we were using threaded animation + [_animationThread cancel]; + + if (![_animationThread isFinished]) { + [[NSRunLoop currentRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.05]]; + } + + _animationThread = nil; + } + else if (_animationTimer) + { + // we were using timer-based animation + [_animationTimer invalidate]; + _animationTimer = nil; + } + + [self setNeedsDisplay:YES]; +} + +- (void)animateInBackgroundThread +{ + @autoreleasepool + { + // Set up the animation speed to subtly change with size > 32. + // int animationDelay = 38000 + (2000 * ([self bounds].size.height / 32)); + + // Set the rev per minute here + int omega = 100; // RPM + int animationDelay = 60 * 1000000 / omega / kNumberOfFins; + int poolFlushCounter = 0; + + do { + [self updateFrameFromTimer:nil]; + usleep(animationDelay); + poolFlushCounter++; + if (poolFlushCounter > 256) { + poolFlushCounter = 0; + } + } while (![[NSThread currentThread] isCancelled]); + } +} + +@end diff --git a/Tools/XcodeCapp/XcodeCapp/en.lproj/InfoPlist.strings b/Tools/XcodeCapp/XcodeCapp/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28ff8..000000000 --- a/Tools/XcodeCapp/XcodeCapp/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/Tools/XcodeCapp/XcodeCapp/en.lproj/MainMenu.xib b/Tools/XcodeCapp/XcodeCapp/en.lproj/MainMenu.xib deleted file mode 100644 index 1b8e7e2ac..000000000 --- a/Tools/XcodeCapp/XcodeCapp/en.lproj/MainMenu.xib +++ /dev/null @@ -1,3964 +0,0 @@ - - - - 1060 - 14C94b - 6254 - 1344.60 - 757.30 - - 6254 - 6254 - - - NSArrayController - NSBox - NSButton - NSButtonCell - NSCustomObject - NSImageCell - NSImageView - NSMenu - NSMenuItem - NSPopUpButton - NSPopUpButtonCell - NSProgressIndicator - NSScrollView - NSScroller - NSTableColumn - NSTableView - NSTextField - NSTextFieldCell - NSUserDefaultsController - NSView - NSWindowTemplate - PDFView - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.pdfkit.ibplugin - - - PluginDependencyRecalculationVersion - - - - - NSApplication - - - FirstResponder - - - NSApplication - - - NSFontManager - - - - - - - Create Project... - - 2147483647 - - NSImage - NSMenuCheckmark - - - NSImage - NSMenuMixedState - - - - - Open Project… - - 2147483647 - - - - - - Open Recent - - 2147483647 - - - - - - Open Xcode Project - - 2147483647 - - - 1 - - - - YES - YES - - - 2147483647 - - - - - - Check Compilation Issues - - 2147483647 - - - - - - Check Project Code Style - - 2147483647 - - - - - - Synchronize Project - - 2147483647 - - - - - - Show in %@ - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Show Errors & Warnings - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Update Cappuccino - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - About XcodeCapp... - - 2147483647 - - - - - - Preferences… - - 2147483647 - - - - - - XcodeCapp Help - - 2147483647 - - - 7 - - - - YES - YES - - - 2147483647 - - - - - - Quit XcodeCapp - - 2147483647 - - - - - - - AppController - - - 3 - 2 - {{196, 240}, {402, 247}} - 1618478080 - About - NSPanel - - - - - 256 - - - - 268 - {{164, 20}, {203, 143}} - - - - YES - - 68157504 - 4326400 - WGNvZGVDYXBwIDMgZGV2ZWxvcGVkIGJ5OgogICAgQXBhcmFqaXRhIEZpc2htYW4KICAgIGFwYXJhaml0 -YUBhcGFyYWppdGEuY29tCiAgICAKICAgIEFsZXhhbmRyZSBXaWxoZWxtCiAgICBhbGV4YW5kcmUud2ls -aGVsbWZyQGdtYWlsLmNvbQoKT3JpZ2luYWwgQ29jb2EgdmVyc2lvbiBkZXZlbG9wZWQgYnk6CiAgICBB -bnRvaW5lIE1lcmNhZGFsCiAgICBhbnRvaW5lLm1lcmNhZGFsQGdtYWlsLmNvbQ - - YES - 11 - 3100 - - - - 6 - System - textBackgroundColor - - 3 - MQA - - - - 3 - MC4zMTM0MzA2NDI2AA - - - NO - 1 - - - - 266 - {{164, 171}, {221, 74}} - - - - YES - - 68157504 - 4326400 - XcodeCapp 3.0.0 - - Zapfino - 18 - 16 - - - - 6 - System - controlColor - - 3 - MC42NjY2NjY2NjY3AA - - - - 6 - System - textColor - - 3 - MAA - - - - NO - 1 - - - - 268 - - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple PNG pasteboard type - NSFilenamesPboardType - NeXT Encapsulated PostScript v1.2 pasteboard type - NeXT TIFF v4.0 pasteboard type - - {{17, 108}, {128, 128}} - - - - YES - - 0 - 33554432 - - NSImage - icon_128x128 - - 0 - 0 - 0 - NO - - NO - YES - - - {402, 247} - - - - - {{0, 0}, {1440, 877}} - {10000000000000, 10000000000000} - NO - - - 143 - 2 - {{890, 663}, {550, 237}} - 1613759488 - Reporting - NSPanel - - - {315, 77} - - - 256 - - - - 274 - - - - 2322 - - - - 256 - {550, 201} - - - - YES - NO - YES - - - 256 - {15, 20} - - - - error - 536 - 40 - 1000 - - 75497536 - 2048 - Error - - - 3 - MC4zMzMzMzI5ODU2AA - - - 6 - System - headerTextColor - - - - - 69206081 - 2304 - Text Cell - - - - 6 - System - controlBackgroundColor - - - - 6 - System - controlTextColor - - - - 1 - YES - - - - 14 - 10 - - - 1 - MSAxIDEgMAA - - 30 - -1832910848 - - - 5 - -1 - 0 - NO - 0 - 1 - - - {{1, 1}, {550, 201}} - - - - - - 4 - YES - - - - -2147483392 - {{1, 273}, {512, 16}} - - - - NO - _doScroller: - - 1 - - _doScroller: - - - - -2147483392 - {{535, 1}, {16, 45}} - - - - NO - _doScroller: - - - _doScroller: - - - {{-1, 35}, {552, 203}} - - - - 133682 - - - - QSAAAEEgAABCIAAAQiAAAA - 0.25 - 4 - 1 - - - - 289 - {{352, 8}, {85, 19}} - - - - {250, 750} - YES - - -2080374784 - 134217728 - Clear - - YES - 12 - 787 - - - -2038284288 - 164 - - - - 400 - 75 - - NO - - - - 292 - {{20, 8}, {85, 19}} - - - - {250, 750} - YES - - -1543503872 - 134217728 - Open - - - -2038284288 - 164 - - - - 400 - 75 - - NO - - - - 289 - {{445, 8}, {85, 19}} - - - - {250, 750} - YES - - -2080374784 - 134217728 - Close - - - -2038284288 - 164 - - - - 400 - 75 - - NO - - - {550, 237} - - - - - {{0, 0}, {1440, 877}} - {315, 99} - {10000000000000, 10000000000000} - - YES - - - 3 - 2 - {{534, 231}, {389, 528}} - 1613235200 - Preferences - NSWindow - - - - - 256 - - - - 12 - - - - 274 - - - - 268 - {{16, 136}, {271, 18}} - - - - YES - - -2080374784 - 0 - Load the most recent project on launch - - YES - 13 - 1044 - - - 1211912448 - 2 - - NSImage - NSSwitch - - - NSSwitch - - - - 400 - 75 - - NO - - - - 268 - {{16, 106}, {241, 18}} - - - - YES - - -2080374784 - 0 - Automatically open Xcode projects - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{16, 76}, {260, 18}} - - - - YES - - -2080374784 - 0 - Errors & Warnings panel always on top - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{16, 45}, {330, 18}} - - - - YES - - -2080374784 - 0 - Active xCodeCapp when opening the Errors panel - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{16, 164}, {298, 18}} - - - - YES - - -2080374784 - 0 - Symlink frameworks when creating projects - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{16, 17}, {106, 17}} - - - - YES - - 68157504 - 272630784 - Recent projects: - - - - - - NO - 1 - - - - 268 - {{125, 11}, {56, 26}} - - - - YES - - -2076180416 - 2048 - - YES - 13 - 1301 - - - 109199360 - 129 - - .LucidaGrandeUI - 13 - 16 - - - - 400 - 75 - - - 30 - - 1048576 - 2147483647 - 1 - - - _popUpItemAction: - - - YES - - OtherViews - - - - 10 - - 1048576 - 2147483647 - - - _popUpItemAction: - - - - - 20 - - 1048576 - 2147483647 - - - _popUpItemAction: - - - - - - 2 - 1 - YES - YES - 2 - - NO - - - {{1, 1}, {353, 194}} - - - - - - {{17, 303}, {355, 210}} - - - - {0, 0} - - 67108864 - 134217728 - Projects - - - - 6 - System - labelColor - - - - - 1 - 0 - 2 - NO - - - - 12 - - - - 274 - - - - 268 - {{149, 12}, {171, 18}} - - - - YES - - -2080374784 - 0 - Open reporting window - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{16, 40}, {126, 17}} - - - - YES - - 68157504 - 272630784 - Compilation issues: - - - - - - NO - 1 - - - - 268 - {{149, 37}, {171, 18}} - - - - YES - - -2080374784 - 0 - Show notification - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{16, 93}, {192, 18}} - - - - YES - - -2080374784 - 0 - Look for compilation issues - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{16, 67}, {301, 18}} - - - - YES - - -2080374784 - 0 - Use include path from the index-debug file - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - {{1, 1}, {353, 124}} - - - - - - {{17, 159}, {355, 140}} - - - - {0, 0} - - 67108864 - 134217728 - File processing - - - - - - 1 - 0 - 2 - NO - - - - 12 - - - - 274 - - - - 268 - {{146, 12}, {171, 18}} - - - - YES - - -2080374784 - 0 - Open reporting window - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{146, 37}, {171, 18}} - - - - YES - - -2080374784 - 0 - Show notification - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - - 268 - {{16, 38}, {126, 17}} - - - - YES - - 68157504 - 272630784 - Code style issues: - - - - - - NO - 1 - - - {{1, 1}, {353, 65}} - - - - _NS:11 - - - {{17, 74}, {355, 81}} - - - - _NS:9 - {0, 0} - - 67108864 - 0 - Code style - - - - - - 1 - 0 - 2 - NO - - - - 12 - - - - 274 - - - - 268 - {{16, 12}, {226, 18}} - - - - YES - - -2080374784 - 0 - Use latest master branch version - - - 1211912448 - 2 - - - - - 400 - 75 - - NO - - - {{1, 1}, {353, 38}} - - - - - - {{17, 16}, {355, 54}} - - - - {0, 0} - - 67108864 - 134217728 - Update - - - - - - 1 - 0 - 2 - NO - - - {389, 528} - - - - - {{0, 0}, {1440, 877}} - {10000000000000, 10000000000000} - xcc-prefs - YES - - - 15 - 2 - {{163, 199}, {716, 662}} - 1618478080 - XcodeCapp Help - NSWindow - - - - - 256 - - - - 18 - - - NSFilenamesPboardType - - {{0, 8}, {716, 654}} - - - - YES - 1 - NO - 1 - YES - - - {716, 662} - - - - - {{0, 0}, {1440, 877}} - {10000000000000, 10000000000000} - YES - - - YES - - - XcodeCapp - - - - message - file - - YES - - YES - YES - YES - - - 7 - 2 - {{139, 81}, {357, 84}} - 1685586944 - Updating Cappuccino - NSPanel - - - - - 256 - - - - 268 - {{18, 22}, {251, 17}} - - - - _NS:397 - {251, 750} - YES - - 68157504 - 272630784 - Step 1/5 : Downloading Cappuccino - - _NS:397 - - - - - NO - 1 - - - - 268 - {{269, 13}, {74, 32}} - - - - _NS:9 - YES - - 67108864 - 134217728 - Close - - _NS:9 - - -2038284288 - 129 - - Gw - 200 - 25 - - NO - - - - 268 - {{20, 45}, {317, 20}} - - - - _NS:9 - {250, 250} - 16397 - 5 - - - {357, 84} - - - - _NS:21 - - {{0, 0}, {1440, 877}} - {10000000000000, 10000000000000} - updatingCappuccinoPanel - YES - - - - NO - - - - delegate - - - - 694 - - - - terminate: - - - - 695 - - - - delegate - - - - 874 - - - - createProject: - - - - kGC-iR-GHt - - - - loadProject: - - - - 864 - - - - showInFinder: - - - - 872 - - - - openAbout: - - - - 615 - - - - openPreferences: - - - - 796 - - - - openHelp: - - - - 612 - - - - aboutWindow - - - - 613 - - - - helpView - - - - 858 - - - - helpWindow - - - - 610 - - - - menuItemHistory - - - - 621 - - - - menuItemOpenProject - - - - 869 - - - - menuItemOpenXcodeProject - - - - 873 - - - - menuItemShowInFinder - - - - 871 - - - - preferencesController - - - - 616 - - - - preferencesWindow - - - - 795 - - - - statusMenu - - - - 607 - - - - xcc - - - - 617 - - - - updateCappuccino: - - - - M7T-qw-MgB - - - - performClose: - - - - 625 - - - - save: - - - - 634 - - - - save: - - - - 841 - - - - save: - - - - Qld-lL-7rM - - - - save: - - - - 849 - - - - save: - - - - 821 - - - - save: - - - - Buu-6t-pce - - - - save: - - - - XTE-kN-O4x - - - - save: - - - - 6Xe-Bt-eXK - - - - save: - - - - 30N-ga-LBo - - - - save: - - - - kBr-PF-Ng7 - - - - save: - - - - HyN-S0-KXD - - - - save: - - - - A92-fj-Uci - - - - save: - - - - 0Il-yd-iuZ - - - - openXcodeProject: - - - - 866 - - - - synchronizeProject: - - - - 867 - - - - openErrorsPanel: - - - - 774 - - - - clearErrors: - - - - 751 - - - - openErrorInEditor: - - - - 786 - - - - clearErrors - - - - 749 - - - - errorListController - - - - 760 - - - - errorsPanel - - - - 775 - - - - symlinkRadioButton - - - - UhG-7c-NP8 - - - - errorTable - - - - 748 - - - - fieldCurrentTask - - - - P4O-YG-v1J - - - - progressIndicator - - - - Z7k-63-Ujv - - - - updatingCappuccinoPanel - - - - HJ3-bt-3EP - - - - checkProjectWithCappLint: - - - - bwf-Gu-ART - - - - checkProjectWithObjj: - - - - oPW-bl-Ydt - - - - values.XCCReopenLastProject - - - - - - value: values.XCCReopenLastProject - value - values.XCCReopenLastProject - - NSValidatesImmediately - - - 2 - - - 636 - - - - errorTable - - - - - - doubleClickArgument: errorTable - doubleClickArgument - errorTable - - NSSelectorName - openErrorInEditor: - - 2 - - - 787 - - - - delegate - - - - 753 - - - - self - - - - - - doubleClickTarget: self - doubleClickTarget - self - - NSSelectorName - openErrorInEditor: - - - 2 - - - 788 - - - - dataSource - - - - 752 - - - - arrangedObjects.message - - - - - - value: arrangedObjects.message - value - arrangedObjects.message - 2 - - - 770 - - - - bundleVersion - - - - - - displayPatternValue1: bundleVersion - displayPatternValue1 - bundleVersion - - NSDisplayPattern - XcodeCapp %{value1}@ - - 2 - - - 800 - - - - projectPath.length - - - - - - enabled: projectPath.length - enabled - projectPath.length - 2 - - - 875 - - - - xcodeProjectCanBeOpened - - - - - - enabled: xcodeProjectCanBeOpened - enabled - xcodeProjectCanBeOpened - - 2 - - - 876 - - - - selection.@count - - - - - - enabled: selection.@count - enabled - selection.@count - 2 - - - 765 - - - - errorList - - - - - - contentArray: errorList - contentArray - errorList - 2 - - - 762 - - - - values.maxRecentProjects - - - - - - selectedValue: values.maxRecentProjects - selectedValue - values.maxRecentProjects - 2 - - - 810 - - - - projectPath.length - - - - - - enabled: projectPath.length - enabled - projectPath.length - 2 - - - 812 - - - - values.XCCAutoOpenErrorsPanelOnErrors - - - - - - value: values.XCCAutoOpenErrorsPanelOnErrors - value - values.XCCAutoOpenErrorsPanelOnErrors - - NSValidatesImmediately - - - 2 - - - 824 - - - - values.autoOpenXcodeProject - - - - - - value: values.autoOpenXcodeProject - value - values.autoOpenXcodeProject - - NSValidatesImmediately - - - 2 - - - 851 - - - - projectPath.length - - - - - - enabled: projectPath.length - enabled - projectPath.length - 2 - - - 861 - - - - isCappBuildDefined - - - - - - enabled: isCappBuildDefined - enabled - isCappBuildDefined - 2 - - - HUA-hI-eLR - - - - toolTipSymlinkRadioButton - - - - - - toolTip: toolTipSymlinkRadioButton - toolTip - toolTipSymlinkRadioButton - 2 - - - bWz-Mw-z56 - - - - values.useSymlinkWhenCreatingProject - - - - - - value: values.useSymlinkWhenCreatingProject - value - values.useSymlinkWhenCreatingProject - - NSValidatesImmediately - - - 2 - - - aRN-Fd-MPN - - - - value: values.XCCAutoOpenErrorsPanelOnCappLint - - - - - - value: values.XCCAutoOpenErrorsPanelOnCappLint - value - values.XCCAutoOpenErrorsPanelOnCappLint - - NSValidatesImmediately - - - 2 - - - du5-hg-MfC - - - - orderOut: - - - - dP2-Fc-one - - - - value: values.XCCPanelActiveAppWhenOpening - - - - - - value: values.XCCPanelActiveAppWhenOpening - value - values.XCCPanelActiveAppWhenOpening - - NSValidatesImmediately - - - 2 - - - kgU-89-aRS - - - - value: values.XCCPanelStyleUtility - - - - - - value: values.XCCPanelStyleUtility - value - values.XCCPanelStyleUtility - - NSValidatesImmediately - - - 2 - - - uUW-Ro-3aA - - - - value: values.updateCappuccinoWithLastVersionOfMasterBranch - - - - - - value: values.updateCappuccinoWithLastVersionOfMasterBranch - value - values.updateCappuccinoWithLastVersionOfMasterBranch - - NSValidatesImmediately - - - 2 - - - 1fo-ym-Q0u - - - - projectPath.length - - - - - - enabled: projectPath.length - enabled - projectPath.length - 2 - - - b84-dT-kSk - - - - value: values.XCCAutoShowNotificationOnCappLint - - - - - - value: values.XCCAutoShowNotificationOnCappLint - value - values.XCCAutoShowNotificationOnCappLint - - NSValidatesImmediately - - - 2 - - - uwx-aq-p86 - - - - enabled: projectPath.length - - - - - - enabled: projectPath.length - enabled - projectPath.length - 2 - - - a7g-oH-Wxj - - - - value: values.XCCAutoOpenShowNotificationErrors - - - - - - value: values.XCCAutoOpenShowNotificationErrors - value - values.XCCAutoOpenShowNotificationErrors - - NSValidatesImmediately - - - 2 - - - j0c-o6-KBW - - - - enabled: isCappuccinoUpdating - - - - - - enabled: isCappuccinoUpdating - enabled - isCappuccinoUpdating - - NSValueTransformerName - NSNegateBoolean - - 2 - - - aof-Pn-nzf - - - - value: values.kDefaultXCCUseDebugFrameworkWithObjj - - - - - - value: values.kDefaultXCCUseDebugFrameworkWithObjj - value - values.kDefaultXCCUseDebugFrameworkWithObjj - - NSValidatesImmediately - - - 2 - - - 8Eb-cw-Tsj - - - - value: values.XCCShouldProcessObjj - - - - - - value: values.XCCShouldProcessObjj - value - values.XCCShouldProcessObjj - - NSValidatesImmediately - - - 2 - - - 4tf-7Y-tid - - - - - - 0 - - - - - - -2 - - - File's Owner - - - -1 - - - First Responder - - - -3 - - - Application - - - 420 - - - - - 538 - - - - - - - - - - - - - - - - - - - - - - - - - - itE-v1-Sv4 - - - - - 605 - - - - - 597 - - - - - 606 - - - - - 859 - - - - - 811 - - - - - 860 - - - - - 603 - - - - - 604 - - - - - PcB-xW-jUW - - - - - 598 - - - - - 600 - - - - - 537 - - - - - 601 - - - - - 599 - - - - - 602 - - - - - 539 - - - - - 540 - - - - - - - - 592 - - - - - - - - - - 593 - - - - - - - - 596 - - - - - 594 - - - - - - - - 595 - - - - - 797 - - - - - - - - 798 - - - - - 541 - - - - - - - - 581 - - - - - - - - - - - 582 - - - - - - - - - - 588 - - - - - 589 - - - - - 584 - - - - - - - - 585 - - - - - 754 - - - - - - - - 755 - - - - - 583 - - - - - - - - 586 - - - - - 542 - - - - - - - - 558 - - - - - - - - - - - 847 - - - - - - - - - - - - - - 563 - - - - - - - - 576 - - - - - 839 - - - - - - - - 840 - - - - - 1qI-ol-J5k - - - - - - - - 272-W8-Ygy - - - - - 801 - - - - - - - - 802 - - - - - 803 - - - - - - - - 804 - - - - - - - - 805 - - - - - - - - - - 806 - - - - - 807 - - - - - 808 - - - - - 848 - - - - - - - - - - - - 819 - - - - - - - - 820 - - - - - 817 - - - - - - - - 818 - - - - - 544 - - - - - 545 - - - XCodeCapp - - - 759 - - - Errors Controller - - - 587 - - - - - - - - 590 - - - - - - - - 591 - - - - - 543 - - - - - - - - 553 - - - - - - - - 857 - - - - - iiD-Nj-M6o - - - - - - - - BYW-Rk-rZ4 - - - - - qFm-3c-NH7 - - - - - - - - - - 2M5-3o-Zwl - - - - - - - - sZm-jR-Tet - - - - - QAd-SJ-XIV - - - - - - - - ptR-WM-qet - - - - - cwr-C6-dkY - - - - - - - - dTw-kK-6IJ - - - - - M7S-MC-N7d - - - - - - - - GR3-Dn-qSe - - - - - - - - LOW-1X-7ih - - - - - om5-3M-ZoK - - - - - ubl-jf-ybu - - - - - 8BD-V9-Gcp - - - - - - - - E18-tY-KOl - - - - - - - - - - 9wn-zh-iT9 - - - - - - - - 5vI-kk-gfO - - - - - D0i-5i-RLQ - - - - - - - - KxJ-gX-jZV - - - - - o12-G8-NOm - - - - - wDc-Ir-hmE - - - - - - - - beY-m1-Aia - - - - - wGK-ie-cgv - - - - - - - - fJB-o4-AhU - - - - - SNH-t4-Ay7 - - - - - GDP-7Q-0W5 - - - - - - - - QpC-n8-rmF - - - - - CQP-MN-ubd - - - - - - - - GLQ-ZT-xXR - - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - ToolTip - - ToolTip - - When an error or warning occurs, automatically open the Errors & Warnings panel - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - {182, 582.5} - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - {345, 214.5} - com.apple.InterfaceBuilder.CocoaPlugin - - - - {-173.5, 372} - com.apple.InterfaceBuilder.CocoaPlugin - - - - {650, 268} - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - ToolTip - - ToolTip - - When an error or warning occurs, automatically open the Errors & Warnings panel - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - ToolTip - - ToolTip - - If this is checked, when a Cappuccino project is opened, the project’s Xcode support project will be opened automatically - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.pdfkit.ibplugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - ToolTip - - ToolTip - - If this is checked, xCodeCapp will be the main application of the system when the errors & warnings panel is about to open - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - ToolTip - - ToolTip - - If this is checked, the error panel will be a floating panel. - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - ToolTip - - ToolTip - - If this is checked, xCodeCapp will take the last version of Cappuccino on the master branch to install Cappuccino - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - ToolTip - - ToolTip - - When an error or warning occurs, automatically open the Errors & Warnings panel - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - - ToolTip - - ToolTip - - When an error or warning occurs, automatically open the Errors & Warnings panel - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - ToolTip - - ToolTip - - When an error or warning occurs, automatically open the Errors & Warnings panel - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - ToolTip - - ToolTip - - When an error or warning occurs, automatically open the Errors & Warnings panel - - - - com.apple.InterfaceBuilder.CocoaPlugin - - - - - - - - - - - - AppController - NSObject - - id - id - id - id - - - - createProject: - id - - - loadProject: - id - - - openAbout: - id - - - openHelp: - id - - - - NSPanel - PDFView - NSWindow - NSMenuItem - NSMenuItem - NSMenuItem - NSUserDefaultsController - NSWindow - NSMenu - XcodeCapp - - - - aboutWindow - NSPanel - - - helpView - PDFView - - - helpWindow - NSWindow - - - menuItemHistory - NSMenuItem - - - menuItemOpenProject - NSMenuItem - - - menuItemShowInFinder - NSMenuItem - - - preferencesController - NSUserDefaultsController - - - preferencesWindow - NSWindow - - - statusMenu - NSMenu - - - xcc - XcodeCapp - - - - IBProjectSource - ../XcodeCapp/AppController.h - - - - AppController - - id - id - id - id - id - id - id - - - - createProject: - id - - - loadProject: - id - - - openAbout: - id - - - openHelp: - id - - - openPreferences: - id - - - showInFinder: - id - - - updateCappuccino: - id - - - - IBProjectSource - ../XcodeCapp/AppController.m - - - - XcodeCapp - NSObject - - id - id - id - id - id - id - - - - checkProjectWithCappLint: - id - - - clearErrors: - id - - - openErrorInEditor: - id - - - openErrorsPanel: - id - - - openXcodeProject: - id - - - synchronizeProject: - id - - - - NSArrayController - NSTableView - NSPanel - NSTextField - NSProgressIndicator - NSPanel - - - - errorListController - NSArrayController - - - errorTable - NSTableView - - - errorsPanel - NSPanel - - - fieldCurrentTask - NSTextField - - - progressIndicator - NSProgressIndicator - - - updatingCappuccinoPanel - NSPanel - - - - IBProjectSource - ../XcodeCapp/XcodeCapp.h - - - - XcodeCapp - - id - id - id - id - id - id - id - - - - checkProjectWithCappLint: - id - - - checkProjectWithObjj: - id - - - clearErrors: - id - - - openErrorInEditor: - id - - - openErrorsPanel: - id - - - openXcodeProject: - id - - - synchronizeProject: - id - - - - IBProjectSource - ../XcodeCapp/XcodeCapp.m - - - - - - NSActionCell - NSCell - - IBFrameworkSource - AppKit.framework/Headers/NSActionCell.h - - - - NSApplication - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSApplication.h - - - - NSArrayController - NSObjectController - - IBFrameworkSource - AppKit.framework/Headers/NSArrayController.h - - - - NSBox - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSBox.h - - - - NSButton - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSButton.h - - - - NSButtonCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSButtonCell.h - - - - NSCell - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSCell.h - - - - NSControl - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSControl.h - - - - NSController - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSController.h - - - - NSFontManager - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSFontManager.h - - - - NSFormatter - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFormatter.h - - - - NSImageCell - NSCell - - IBFrameworkSource - AppKit.framework/Headers/NSImageCell.h - - - - NSImageView - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSImageView.h - - - - NSManagedObjectContext - NSObject - - IBFrameworkSource - CoreData.framework/Headers/NSManagedObjectContext.h - - - - NSMenu - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSMenu.h - - - - NSMenuItem - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSMenuItem.h - - - - NSMenuItemCell - NSButtonCell - - IBFrameworkSource - AppKit.framework/Headers/NSMenuItemCell.h - - - - NSObjectController - NSController - - IBFrameworkSource - AppKit.framework/Headers/NSObjectController.h - - - - NSPanel - NSWindow - - IBFrameworkSource - AppKit.framework/Headers/NSPanel.h - - - - NSPopUpButton - NSButton - - IBFrameworkSource - AppKit.framework/Headers/NSPopUpButton.h - - - - NSPopUpButtonCell - NSMenuItemCell - - IBFrameworkSource - AppKit.framework/Headers/NSPopUpButtonCell.h - - - - NSProgressIndicator - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSProgressIndicator.h - - - - NSResponder - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSResponder.h - - - - NSScrollView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSScrollView.h - - - - NSScroller - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSScroller.h - - - - NSTableColumn - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSTableColumn.h - - - - NSTableView - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSTableView.h - - - - NSTextField - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSTextField.h - - - - NSTextFieldCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSTextFieldCell.h - - - - NSUserDefaultsController - NSController - - IBFrameworkSource - AppKit.framework/Headers/NSUserDefaultsController.h - - - - NSView - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSView.h - - - - NSWindow - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSWindow.h - - - - PDFView - NSView - - id - id - id - id - id - id - id - id - id - id - - - - goBack: - id - - - goForward: - id - - - goToFirstPage: - id - - - goToLastPage: - id - - - goToNextPage: - id - - - goToPreviousPage: - id - - - selectAll: - id - - - takeBackgroundColorFrom: - id - - - zoomIn: - id - - - zoomOut: - id - - - - IBFrameworkSource - Quartz.framework/Frameworks/PDFKit.framework/Headers/PDFView.h - - - - - 0 - IBCocoaFramework - YES - - com.apple.InterfaceBuilder.CocoaPlugin.macosx - - - - com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 - - - YES - 3 - - {12, 12} - {10, 2} - {15, 15} - {128, 128} - - - diff --git a/Tools/XcodeCapp/XcodeCapp/main.m b/Tools/XcodeCapp/XcodeCapp/main.m index c4385ce48..dc637170b 100644 --- a/Tools/XcodeCapp/XcodeCapp/main.m +++ b/Tools/XcodeCapp/XcodeCapp/main.m @@ -2,13 +2,12 @@ // main.m // XcodeCapp // -// Created by Aparajita on 4/18/13. -// Copyright (c) 2013 Cappuccino Project. All rights reserved. +// Created by Alexandre Wilhelm on 5/5/15. +// Copyright (c) 2015 cappuccino-project. All rights reserved. // #import -int main(int argc, char *argv[]) -{ - return NSApplicationMain(argc, (const char **)argv); +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); } diff --git a/Tools/XcodeCapp/xcc/main.m b/Tools/XcodeCapp/xcc/main.m deleted file mode 100644 index 451663896..000000000 --- a/Tools/XcodeCapp/xcc/main.m +++ /dev/null @@ -1,147 +0,0 @@ -// -// main.m -// xcc -// -// Created by Aparajita on 5/9/13. -// Copyright (c) 2013 Cappuccino Project. All rights reserved. -// - -#import - -#import "XcodeProjectCloser.h" - - -static void usage() -{ - fprintf(stderr, "Usage: xcc [options] [directory]\n" - "\n" - "Options:\n" - " --help Show this help and exit\n" - " --reset Resets Xcode support files before opening\n\n"); -} - -static bool handleOptions(NSMutableArray *options, NSString *path) -{ - NSFileManager *fm = [NSFileManager defaultManager]; - - path = path.stringByStandardizingPath.stringByResolvingSymlinksInPath; - - while (options.count) - { - NSString *option = options.lastObject; - [options removeLastObject]; - - if ([options containsObject:option]) - return false; - - if ([option isEqualToString:@"--reset"]) - { - if (!path) - return false; - - NSString *xcodePath = [path stringByAppendingPathComponent:@".XcodeSupport"]; - [fm removeItemAtPath:xcodePath error:nil]; - - NSString *projectName = [NSString stringWithFormat:@"%@.xcodeproj", path.lastPathComponent]; - xcodePath = [path stringByAppendingPathComponent:projectName]; - - [XcodeProjectCloser closeXcodeProjectForProject:xcodePath]; - - [fm removeItemAtPath:xcodePath error:nil]; - printf("Reset %s\n", path.UTF8String); - } - else - return false; - } - - return true; -} - -static NSString* validatePath(NSString *path) -{ - // Use an NSURL to resolve paths that start with "." - NSURL *url = [NSURL fileURLWithPath:path]; - path = url.path; - - NSFileManager *fm = [NSFileManager defaultManager]; - BOOL isDirectory; - BOOL exists = [fm fileExistsAtPath:path isDirectory:&isDirectory]; - - if (exists && isDirectory) - return path; - else - { - if (!exists) - fprintf(stderr, "The directory %s does not exist.\n", path.UTF8String); - else - fprintf(stderr, "%s is not a directory.\n", path.UTF8String); - - return nil; - } -} - - -int main(int argc, const char * argv[]) -{ - @autoreleasepool - { - NSArray *args = [[NSProcessInfo processInfo] arguments]; - BOOL validArgs = args.count == 1; - NSString *path = nil; - NSMutableArray *options = [NSMutableArray new]; - - for (NSInteger i = 1; i < args.count; ++i) - { - NSString *arg = args[i]; - - // Once we get a directory, no other arguments are valid - if (path) - { - validArgs = NO; - break; - } - - if ([arg hasPrefix:@"-"]) - { - [options addObject:arg]; - } - else if (!path) - { - path = validatePath(arg); - - if (path) - validArgs = YES; - else - return 1; - } - else - { - validArgs = NO; - break; - } - } - - if (validArgs) - { - if (handleOptions(options, path)) - { - NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"-b", @"org.cappuccino.xcodecapp", @"-g", nil]; - - if (path) - [arguments addObject:path]; - - NSTask *task = [[NSTask alloc] init]; - task.launchPath = @"/usr/bin/open"; - task.arguments = arguments; - [task launch]; - } - else - usage(); - } - else - usage(); - } - - return 0; -} - diff --git a/Tools/XcodeCapp/xcc/xcc-Prefix.pch b/Tools/XcodeCapp/xcc/xcc-Prefix.pch deleted file mode 100644 index 3ab4e33a8..000000000 --- a/Tools/XcodeCapp/xcc/xcc-Prefix.pch +++ /dev/null @@ -1,7 +0,0 @@ -// -// Prefix header for all source files of the 'xcc' target in the 'xcc' project -// - -#ifdef __OBJC__ - #import -#endif