diff --git a/BuildSettingExtractor.xcodeproj/project.pbxproj b/BuildSettingExtractor.xcodeproj/project.pbxproj index da3255b..e72928a 100644 --- a/BuildSettingExtractor.xcodeproj/project.pbxproj +++ b/BuildSettingExtractor.xcodeproj/project.pbxproj @@ -48,7 +48,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 532C57C7234BB32700FA0872 /* BSE-CodeSigning.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BSE-CodeSigning.xcconfig"; sourceTree = ""; }; + 532C57C7234BB32700FA0872 /* ProjectConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ProjectConfig.xcconfig; sourceTree = ""; }; 5359360E24687FF800445F95 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Preferences.storyboard; sourceTree = ""; }; 536AA121235293B600A0FE29 /* BuildSettingExtractor.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BuildSettingExtractor.entitlements; sourceTree = ""; }; 53719E8F19BF4C6D005D3DE0 /* BuildSettingExtractor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BuildSettingExtractor.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -72,6 +72,7 @@ 5395AF4D1A7C6BB60028BE88 /* ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; sourceTree = ""; }; 539A0205234EFA4300193374 /* BuildSettingInfoSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BuildSettingInfoSource.h; sourceTree = ""; }; 539A0206234EFA4300193374 /* BuildSettingInfoSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BuildSettingInfoSource.m; sourceTree = ""; }; + 53B3D1EA256031280071ED64 /* BuildSettingInfoSubpathsNotes.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = BuildSettingInfoSubpathsNotes.md; sourceTree = ""; }; 53B3D7EE23F6EB6F0039C5B0 /* PreferencesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesViewController.m; sourceTree = ""; }; 53B3D7EF23F6EB6F0039C5B0 /* PreferencesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesViewController.h; sourceTree = ""; }; 53B3D7F423F6EDB70039C5B0 /* FileLayoutPreferencesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FileLayoutPreferencesViewController.h; sourceTree = ""; }; @@ -82,6 +83,9 @@ 53BC11301A817447005E2FD2 /* BuildSettingCommentGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BuildSettingCommentGenerator.m; sourceTree = ""; }; 53C7618023F85AE20024B432 /* SampleFileStructureGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SampleFileStructureGenerator.h; sourceTree = ""; }; 53C7618123F85AE20024B432 /* SampleFileStructureGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SampleFileStructureGenerator.m; sourceTree = ""; }; + 53CCCAC62A34B876009C699E /* ci_post_clone.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_post_clone.sh; sourceTree = ""; }; + 53D8DADE291EAD230092FF3E /* AppConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppConfig.xcconfig; sourceTree = ""; }; + 53DCD48924D6440400D512FB /* BuildSettingExtractor.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = BuildSettingExtractor.xctestplan; sourceTree = ""; }; 53F372EB1A7BC6A7006118CB /* DragFileView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DragFileView.h; sourceTree = ""; }; 53F372EC1A7BC6A7006118CB /* DragFileView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DragFileView.m; sourceTree = ""; }; 53F372EE1A7C042F006118CB /* BuildSettingExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BuildSettingExtractor.h; sourceTree = ""; }; @@ -122,7 +126,8 @@ 532C57C6234BB32700FA0872 /* Config */ = { isa = PBXGroup; children = ( - 532C57C7234BB32700FA0872 /* BSE-CodeSigning.xcconfig */, + 532C57C7234BB32700FA0872 /* ProjectConfig.xcconfig */, + 53D8DADE291EAD230092FF3E /* AppConfig.xcconfig */, ); path = Config; sourceTree = ""; @@ -133,6 +138,7 @@ 53719E9819BF4C6D005D3DE0 /* BuildSettingExtractor */, 53719EB619BF4C6D005D3DE0 /* BuildSettingExtractorTests */, 532C57C6234BB32700FA0872 /* Config */, + 53CCCAC82A34B88B009C699E /* ci_scripts */, 53719E9119BF4C6D005D3DE0 /* Frameworks */, 53719E9019BF4C6D005D3DE0 /* Products */, 5395AF4D1A7C6BB60028BE88 /* ReadMe.md */, @@ -190,6 +196,7 @@ 53719EA719BF4C6D005D3DE0 /* MainMenu.xib */, 53719EAA19BF4C6D005D3DE0 /* Assets.xcassets */, 538196C41A851BB40033CB65 /* BuildSettingInfoSubpaths.plist */, + 53B3D1EA256031280071ED64 /* BuildSettingInfoSubpathsNotes.md */, 53719E9919BF4C6D005D3DE0 /* Supporting Files */, ); path = BuildSettingExtractor; @@ -208,6 +215,7 @@ 53719EB619BF4C6D005D3DE0 /* BuildSettingExtractorTests */ = { isa = PBXGroup; children = ( + 53DCD48924D6440400D512FB /* BuildSettingExtractor.xctestplan */, 53719EBC19BF4C6D005D3DE0 /* BuildSettingExtractorTests.m */, 53F372F61A7C3164006118CB /* TestFiles */, 53719EB719BF4C6D005D3DE0 /* Supporting Files */, @@ -240,6 +248,14 @@ path = Preferences; sourceTree = ""; }; + 53CCCAC82A34B88B009C699E /* ci_scripts */ = { + isa = PBXGroup; + children = ( + 53CCCAC62A34B876009C699E /* ci_post_clone.sh */, + ); + path = ci_scripts; + sourceTree = ""; + }; 53F372F61A7C3164006118CB /* TestFiles */ = { isa = PBXGroup; children = ( @@ -297,7 +313,7 @@ 53719E8719BF4C6D005D3DE0 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1140; + LastUpgradeCheck = 1400; ORGANIZATIONNAME = "Tapas Software"; TargetAttributes = { 53719EAF19BF4C6D005D3DE0 = { @@ -429,7 +445,7 @@ /* Begin XCBuildConfiguration section */ 53719EBE19BF4C6D005D3DE0 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 532C57C7234BB32700FA0872 /* BSE-CodeSigning.xcconfig */; + baseConfigurationReference = 532C57C7234BB32700FA0872 /* ProjectConfig.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; @@ -450,12 +466,14 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -482,7 +500,7 @@ }; 53719EBF19BF4C6D005D3DE0 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 532C57C7234BB32700FA0872 /* BSE-CodeSigning.xcconfig */; + baseConfigurationReference = 532C57C7234BB32700FA0872 /* ProjectConfig.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; @@ -503,12 +521,14 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -528,15 +548,16 @@ }; 53719EC119BF4C6D005D3DE0 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 53D8DADE291EAD230092FF3E /* AppConfig.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = BuildSettingExtractor/BuildSettingExtractor.entitlements; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 16; - ENABLE_HARDENED_RUNTIME = YES; + CURRENT_PROJECT_VERSION = 24; + DEAD_CODE_STRIPPING = YES; + ENABLE_HARDENED_RUNTIME = NO; INFOPLIST_FILE = "BuildSettingExtractor/BuildSettingExtractor-Info.plist"; - MARKETING_VERSION = 1.4; - PRODUCT_BUNDLE_IDENTIFIER = "net.tapas-software.${PRODUCT_NAME:rfc1034identifier}"; + MARKETING_VERSION = 1.4.8; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -544,15 +565,16 @@ }; 53719EC219BF4C6D005D3DE0 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 53D8DADE291EAD230092FF3E /* AppConfig.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = BuildSettingExtractor/BuildSettingExtractor.entitlements; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 16; + CURRENT_PROJECT_VERSION = 24; + DEAD_CODE_STRIPPING = YES; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = "BuildSettingExtractor/BuildSettingExtractor-Info.plist"; - MARKETING_VERSION = 1.4; - PRODUCT_BUNDLE_IDENTIFIER = "net.tapas-software.${PRODUCT_NAME:rfc1034identifier}"; + MARKETING_VERSION = 1.4.8; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -563,6 +585,7 @@ buildSettings = { BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/BuildSettingExtractor.app/Contents/MacOS/BuildSettingExtractor"; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", @@ -584,6 +607,7 @@ buildSettings = { BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/BuildSettingExtractor.app/Contents/MacOS/BuildSettingExtractor"; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", diff --git a/BuildSettingExtractor.xcodeproj/xcshareddata/xcschemes/BuildSettingExtractor.xcscheme b/BuildSettingExtractor.xcodeproj/xcshareddata/xcschemes/BuildSettingExtractor.xcscheme index 1ef233c..a80b8d2 100644 --- a/BuildSettingExtractor.xcodeproj/xcshareddata/xcschemes/BuildSettingExtractor.xcscheme +++ b/BuildSettingExtractor.xcodeproj/xcshareddata/xcschemes/BuildSettingExtractor.xcscheme @@ -1,7 +1,7 @@ + LastUpgradeVersion = "1400" + version = "1.7"> @@ -27,6 +27,12 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + diff --git a/BuildSettingExtractor/AppConstants+Categories.m b/BuildSettingExtractor/AppConstants+Categories.m index 57d0537..f5b788a 100644 --- a/BuildSettingExtractor/AppConstants+Categories.m +++ b/BuildSettingExtractor/AppConstants+Categories.m @@ -37,7 +37,7 @@ - (void)tps_registerApplicationDefaults { TPSLinesBetweenBuildSettingsWithInfo : @3, TPSTargetFoldersEnabled : @(NO), TPSProjectFolderEnabled : @(NO), - TPSDestinationFolderName : @"xcconfig", + TPSDestinationFolderName : BuildSettingExtractor.defaultDestinationFolderName, TPSAutosaveInProjectFolder: @(NO), TPSAlignBuildSettingValues: @(NO) }; diff --git a/BuildSettingExtractor/AppDelegate.m b/BuildSettingExtractor/AppDelegate.m index e6b4258..982fad8 100644 --- a/BuildSettingExtractor/AppDelegate.m +++ b/BuildSettingExtractor/AppDelegate.m @@ -26,6 +26,11 @@ @interface AppDelegate () @implementation AppDelegate ++ (void)initialize { + EmptyStringTransformer *transformer = [[EmptyStringTransformer alloc] init]; + [NSValueTransformer setValueTransformer:transformer forName:@"EmptyStringTransformer"]; +} + - (void)awakeFromNib { self.dragFileView.target = self; self.dragFileView.action = @selector(handleDroppedFile:); @@ -235,9 +240,13 @@ - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender return YES; } -- (void)applicationDidFinishLaunching:(NSNotification *)notification { +- (void)applicationWillFinishLaunching:(NSNotification *)notification { [[NSUserDefaults standardUserDefaults] tps_registerApplicationDefaults]; } +- (void)application:(NSApplication *)application openURLs:(NSArray *)urls { + NSURL *fileURL = urls.firstObject; + if (fileURL) { [self processXcodeProjectAtURL:fileURL]; } +} @end diff --git a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-1024.png b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-1024.png index fa5e4cb..b392127 100644 Binary files a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-1024.png and b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-1024.png differ diff --git a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-128.png b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-128.png index 236c6fe..3fba7d2 100644 Binary files a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-128.png and b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-128.png differ diff --git a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-16.png b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-16.png index c13ae94..0b59d57 100644 Binary files a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-16.png and b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-16.png differ diff --git a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-256.png b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-256.png index d0783cc..10a50b5 100644 Binary files a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-256.png and b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-256.png differ diff --git a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-32.png b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-32.png index e0fbcf0..41441eb 100644 Binary files a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-32.png and b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-32.png differ diff --git a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-512.png b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-512.png index 9ee93a0..b10e263 100644 Binary files a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-512.png and b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-512.png differ diff --git a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-64.png b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-64.png index e00152b..aa06924 100644 Binary files a/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-64.png and b/BuildSettingExtractor/Assets.xcassets/AppIcon.appiconset/BuildSettingExtractorIcon-64.png differ diff --git a/BuildSettingExtractor/BuildSettingCommentGenerator.h b/BuildSettingExtractor/BuildSettingCommentGenerator.h index 11a62c3..1e49aad 100644 --- a/BuildSettingExtractor/BuildSettingCommentGenerator.h +++ b/BuildSettingExtractor/BuildSettingCommentGenerator.h @@ -16,6 +16,6 @@ - (NSString *)commentForBuildSettingWithName:(NSString *)buildSettingName; -- (BOOL)loadBuildSettingInfo; // Primarily for testing +- (BOOL)loadBuildSettingInfo:(NSError **)error; // In public interface for testing @end diff --git a/BuildSettingExtractor/BuildSettingCommentGenerator.m b/BuildSettingExtractor/BuildSettingCommentGenerator.m index 27f8d4d..cfe1530 100644 --- a/BuildSettingExtractor/BuildSettingCommentGenerator.m +++ b/BuildSettingExtractor/BuildSettingCommentGenerator.m @@ -70,7 +70,7 @@ - (NSString *)commentForBuildSettingWithName:(NSString *)buildSettingName { - (NSString *)presentationNameForKey:(NSString *)key { if (!self.buildSettingInfoDictionary) { - [self loadBuildSettingInfo]; + [self loadBuildSettingInfo:nil]; } NSString *processedKey = [key tps_baseBuildSettingName]; // strip any conditional part of build setting @@ -81,7 +81,7 @@ - (NSString *)presentationNameForKey:(NSString *)key { - (NSString *)descriptionForKey:(NSString *)key { if (!self.buildSettingInfoDictionary) { - [self loadBuildSettingInfo]; + [self loadBuildSettingInfo:nil]; } NSString *processedKey = [key tps_baseBuildSettingName]; // strip any conditional part of build setting @@ -156,9 +156,10 @@ - (NSString *)processedDescriptionString:(NSString *)string forKey:(NSString *)k return processedString; } -- (BOOL)loadBuildSettingInfo { +// Returns an array of error strings describing unread build setting info files +- (BOOL)loadBuildSettingInfo:(NSError **)error { - BOOL allSubpathsReadSuccessfully = YES; + NSMutableArray *subpathReadingErrorStrings = [[NSMutableArray alloc] init]; NSString *defaultXcodePath = self.infoSource.resolvedURL.path; NSInteger xcodeVersion = self.infoSource.resolvedVersion; @@ -189,6 +190,23 @@ - (BOOL)loadBuildSettingInfo { if (subpathsToAdd) { buildSettingInfoSubpaths = [buildSettingInfoSubpaths arrayByAddingObjectsFromArray:subpathsToAdd]; } + + // Add introduced subpaths that are valid in the version of Xcode we are using + subpathsToAdd = nil; + NSDictionary *introducedSubpaths = buildSettingInfoDict[@"introducedSubpathsByVersion"]; + for (NSString *versionKey in [introducedSubpaths allKeys]) { + NSInteger minVersion = [versionKey integerValue]; + if (xcodeVersion >= minVersion) { + if (!subpathsToAdd) { + subpathsToAdd = [NSMutableArray array]; + } + [subpathsToAdd addObjectsFromArray:introducedSubpaths[versionKey]]; + } + } + if (subpathsToAdd) { + buildSettingInfoSubpaths = [buildSettingInfoSubpaths arrayByAddingObjectsFromArray:subpathsToAdd]; + } + // Rather than track exactly what Xcode versions contain which files, group versions of an expected file in an array. // Log if no file in the group can be read in. @@ -204,27 +222,36 @@ - (BOOL)loadBuildSettingInfo { dictionary = [self xcspecFileBuildSettingInfoForPath:fullpath]; } if (dictionary) { - [infoStringFile addEntriesFromDictionary:dictionary]; + // Remove empty string values that may be masking backstop values + NSDictionary *processedDictionary = [dictionary tps_dictionaryByRemovingEmptyStringValues]; + [infoStringFile addEntriesFromDictionary:processedDictionary]; } if (dictionary || foundOne) { foundOne = YES; } } if (!foundOne) { + NSString *errorString = nil; if (buildSettingInfoSubpathList.count == 0) { - NSLog(@"Empty array of subpaths at index %lu", [buildSettingInfoSubpaths indexOfObject:buildSettingInfoSubpathList]); + errorString = [NSString stringWithFormat: @"Empty array of subpaths at index %lu", [buildSettingInfoSubpaths indexOfObject:buildSettingInfoSubpathList]]; } else if (buildSettingInfoSubpathList.count == 1) { - NSLog(@"Could not read settings strings at path: %@", buildSettingInfoSubpathList[0]); + errorString = [NSString stringWithFormat:@"Could not read settings strings at path: %@", buildSettingInfoSubpathList[0]]; } else { - NSLog(@"Could not read settings strings at these paths: %@", buildSettingInfoSubpathList); + errorString = [NSString stringWithFormat:@"Could not read settings strings at these paths: %@", buildSettingInfoSubpathList]; } - allSubpathsReadSuccessfully = NO; + [subpathReadingErrorStrings addObject:errorString]; } } _buildSettingInfoDictionary = infoStringFile; + + BOOL success = subpathReadingErrorStrings.count == 0; + + if (!success && error) { + *error = [NSError errorForSettingInfoFilesNotFound:subpathReadingErrorStrings]; + } - return allSubpathsReadSuccessfully; + return success; } - (NSDictionary *)xcspecFileBuildSettingInfoForPath:(NSString *)path { diff --git a/BuildSettingExtractor/BuildSettingExtractor-Info.plist b/BuildSettingExtractor/BuildSettingExtractor-Info.plist index 40e8dae..8c5345c 100644 --- a/BuildSettingExtractor/BuildSettingExtractor-Info.plist +++ b/BuildSettingExtractor/BuildSettingExtractor-Info.plist @@ -4,6 +4,21 @@ CFBundleDevelopmentRegion en + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + xcodeproj + + CFBundleTypeRole + Editor + LSItemContentTypes + + com.apple.xcode.project + + + CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile @@ -27,7 +42,7 @@ LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright - Copyright © 2014-2018 Tapas Software. All rights reserved. + Copyright © 2014-2025 Tapas Software. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass diff --git a/BuildSettingExtractor/BuildSettingExtractor.h b/BuildSettingExtractor/BuildSettingExtractor.h index c3fc550..cc25630 100644 --- a/BuildSettingExtractor/BuildSettingExtractor.h +++ b/BuildSettingExtractor/BuildSettingExtractor.h @@ -30,6 +30,7 @@ NS_ASSUME_NONNULL_BEGIN + (NSString *)defaultSharedConfigName; // "Shared" is the default. + (NSString *)defaultProjectConfigName; // "Project" is the default. + (NSString *)defaultNameSeparator; // "-" (hyphen) is the default. ++ (NSString *)defaultDestinationFolderName; // "xcconfig" is the default. // The name that will be used to name common / shared config files. diff --git a/BuildSettingExtractor/BuildSettingExtractor.m b/BuildSettingExtractor/BuildSettingExtractor.m index ce15630..d28d592 100644 --- a/BuildSettingExtractor/BuildSettingExtractor.m +++ b/BuildSettingExtractor/BuildSettingExtractor.m @@ -11,15 +11,24 @@ #import "BuildSettingInfoSource.h" #import "Constants+Categories.h" -static NSSet *XcodeCompatibilityVersionStringSet() { +static NSSet *XcodeCompatibilityVersionStringSet(void) { static NSSet *_compatibilityVersionStringSet; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - _compatibilityVersionStringSet = [NSSet setWithObjects:@"Xcode 3.2", @"Xcode 6.3", @"Xcode 8.0", @"Xcode 9.3", @"Xcode 10.0", @"Xcode 11.0", nil]; + _compatibilityVersionStringSet = [NSSet setWithObjects:@"Xcode 3.2", @"Xcode 6.3", @"Xcode 8.0", @"Xcode 9.3", @"Xcode 10.0", @"Xcode 11.0", @"Xcode 11.4", @"Xcode 12.0", @"Xcode 13.0", @"Xcode 14.0", @"Xcode 15.0", @"Xcode 15.3", @"Xcode 16.0", nil]; }); return _compatibilityVersionStringSet; } +static NSSet *XcodeObjectVersionStringSet(void) { + static NSSet *_objectVersionStringSet; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _objectVersionStringSet = [NSSet setWithObjects:@"77", @"70", nil]; + }); + return _objectVersionStringSet; +} + @interface BuildSettingExtractor () @property (strong) NSMutableDictionary *buildSettingsByTarget; @property (strong) NSDictionary *objects; @@ -43,6 +52,10 @@ + (NSString *)defaultNameSeparator { return @"-"; } ++ (NSString *)defaultDestinationFolderName { + return @"xcconfig"; +} + - (instancetype)init { self = [super init]; if (self) { @@ -139,13 +152,17 @@ - (NSArray *)extractBuildSettingsFromProject:(NSURL *)projectWrapperURL error:(N return nil; } + // Get object version + NSString *objectVersion = projectPlist[@"objectVersion"]; + // Get root object (project) self.objects = projectPlist[@"objects"]; NSDictionary *rootObject = self.objects[projectPlist[@"rootObject"]]; // Check compatibility version NSString *compatibilityVersion = rootObject[@"compatibilityVersion"]; - if (![XcodeCompatibilityVersionStringSet() containsObject:compatibilityVersion]) { + + if (![XcodeCompatibilityVersionStringSet() containsObject:compatibilityVersion] && ![XcodeObjectVersionStringSet() containsObject:objectVersion]){ if (error) { *error = [NSError errorForUnsupportedProjectURL:projectWrapperURL fileVersion:compatibilityVersion]; } @@ -171,14 +188,14 @@ - (NSArray *)extractBuildSettingsFromProject:(NSURL *)projectWrapperURL error:(N self.buildSettingsByTarget[self.validatedProjectConfigName] = projectSettings; // Begin check that the project file has some settings - BOOL projectFileHasSettings = projectSettings.containsBuildSettings; + BOOL projectFileHasSettings = projectSettings.tps_containsBuildSettings; // Add project targets for (NSDictionary *target in targets) { NSString *targetName = target[@"name"]; buildConfigurationListID = target[@"buildConfigurationList"]; NSDictionary *targetSettings = [self buildSettingStringsByConfigurationForBuildConfigurationListID:buildConfigurationListID]; - if (!projectFileHasSettings) { projectFileHasSettings = targetSettings.containsBuildSettings; } + if (!projectFileHasSettings) { projectFileHasSettings = targetSettings.tps_containsBuildSettings; } self.buildSettingsByTarget[targetName] = targetSettings; @@ -260,6 +277,9 @@ - (BOOL)writeConfigFilesToDestinationFolder:(NSURL *)destinationURL error:(NSErr // Trim whitespace and newlines configFileString = [configFileString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + // Add a newline at end of file + configFileString = [configFileString stringByAppendingString:@"\n"]; + BOOL isProcessingProjectConfigFiles = [targetName isEqualToString:self.validatedProjectConfigName]; BOOL currentTargetCanUseFolder = isProcessingProjectConfigFiles ? self.projectFolderEnabled : YES; @@ -315,7 +335,7 @@ - (NSString *)headerCommentForFilename:(NSString *)filename { headerComment = [headerComment stringByAppendingFormat:@"// %@\n", filename]; headerComment = [headerComment stringByAppendingString:@"//\n"]; headerComment = [headerComment stringByAppendingFormat:@"// Generated by BuildSettingExtractor on %@\n", dateString]; - headerComment = [headerComment stringByAppendingString:@"// https://github.com/dempseyatgithub/BuildSettingExtractor\n"]; + headerComment = [headerComment stringByAppendingString:@"// https://buildsettingextractor.com\n"]; headerComment = [headerComment stringByAppendingString:@"//"]; return headerComment; @@ -342,16 +362,21 @@ + (NSString *)stringRepresentationOfBuildSettings:(NSDictionary *)buildSettings } BOOL firstKey = YES; + NSString *previousKey = nil; for (NSString *key in sortedKeys) { id value = buildSettings[key]; + + // If same base setting name as previous key, this is a conditional build setting. + // Don't put newlines between them and don't repeat the build setting info comment. + BOOL sameBaseSettingName = [previousKey tps_baseBuildSettingNameIsEqualTo:key]; // nil previousKey returns nil aka NO - if (!firstKey){ + if (!firstKey && !sameBaseSettingName){ for (NSInteger i = 0; i < linesBetweenSettings; i++) { [string appendString:@"\n"]; } } - if (includeBuildSettingInfoComments) { + if (includeBuildSettingInfoComments && !sameBaseSettingName) { NSString *comment = [buildSettingCommentGenerator commentForBuildSettingWithName:key]; [string appendString:comment]; } @@ -372,6 +397,7 @@ + (NSString *)stringRepresentationOfBuildSettings:(NSDictionary *)buildSettings [NSException raise:@"Should not get here!" format:@"Unexpected class: %@ in %s", [value class], __PRETTY_FUNCTION__]; } + previousKey = key; firstKey = NO; } diff --git a/BuildSettingExtractor/BuildSettingInfoSubpaths.plist b/BuildSettingExtractor/BuildSettingInfoSubpaths.plist index 3e2a512..4613193 100644 --- a/BuildSettingExtractor/BuildSettingInfoSubpaths.plist +++ b/BuildSettingExtractor/BuildSettingInfoSubpaths.plist @@ -32,9 +32,20 @@ Code will load on this and later versions of watchOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs. [WATCHOS_DEPLOYMENT_TARGET]-name watchOS Deployment Target + [SWIFT_VERSION]-name + Swift Language Version + [SWIFT_VERSION]-description + Interpret input according to a specific Swift language version number. deprecatedSubpathsByVersion + 1200 + + + Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/Native Build System.strings + Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/Native Build System.xcspec + + 0900 @@ -42,11 +53,26 @@ + introducedSubpathsByVersion + + 1200 + + + Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Metal.xcplugin/Contents/Resources/MetalLinker.strings + Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Metal.xcplugin/Contents/Resources/en.lproj/com.apple.compilers.metal-linker.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.metal-linker.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.metal-linker.strings + + + subpaths Contents/PlugIns/Xcode3Core.ideplugin/Contents/Frameworks/DevToolsCore.framework/Versions/Current/Resources/en.lproj/CoreBuildSystem.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/Frameworks/DevToolsCore.framework/Versions/Current/Resources/English.lproj/CoreBuildSystem.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/CoreBuildSystem.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/CoreBuildSystem.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/CoreBuildSystem.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Clang LLVM 1.0.xcplugin/Contents/Resources/English.lproj/Apple LLVM 6.0.strings @@ -58,64 +84,116 @@ Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Clang LLVM 1.0.xcplugin/Contents/Resources/English.lproj/Apple LLVM 9.0.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Clang LLVM 1.0.xcplugin/Contents/Resources/English.lproj/Apple Clang.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Clang LLVM 1.0.xcplugin/Contents/Resources/en.lproj/Apple Clang.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Apple Clang.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/Apple Clang.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Apple Clang.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/XCLanguageSupport.xcplugin/Contents/Resources/en.lproj/Swift Compiler.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Swift Compiler.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/Swift Compiler.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Swift Compiler.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/XCLanguageSupport.xcplugin/Contents/Resources/SwiftBuildSettings.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/SwiftBuildSettings.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/SwiftBuildSettings.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/SwiftBuildSettings.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Metal.xcplugin/Contents/Resources/Metal Compiler.strings + Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Metal.xcplugin/Contents/Resources/MetalCompiler.strings + Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Metal.xcplugin/Contents/Resources/en.lproj/com.apple.compilers.metal.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.metal.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.metal.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.metal.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Core Data.xcplugin/Contents/Resources/en.lproj/com.apple.compilers.model.coredata.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Core Data.xcplugin/Contents/Resources/English.lproj/com.apple.compilers.model.coredata.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.coredata.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.coredata.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.coredata.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Core Data.xcplugin/Contents/Resources/en.lproj/com.apple.compilers.model.coredatamapping.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Core Data.xcplugin/Contents/Resources/English.lproj/com.apple.compilers.model.coredatamapping.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.coredatamapping.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.coredatamapping.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.coredatamapping.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Core Data.xcplugin/Contents/Resources/en.lproj/com.apple.compilers.model.persistence.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/Core Data.xcplugin/Contents/Resources/English.lproj/com.apple.compilers.model.persistence.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.persistence.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.persistence.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.model.persistence.strings + + + Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/AssetCatalogCompiler.xcspec + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/AssetCatalogCompiler.xcspec + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/AssetCatalogCompiler.xcspec + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/AssetCatalogCompiler.xcspec Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/en.lproj/com.apple.compilers.assetcatalog.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/English.lproj/com.apple.compilers.assetcatalog.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.assetcatalog.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.assetcatalog.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.compilers.assetcatalog.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/en.lproj/com.apple.xcode.tools.ibtool.compiler.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/English.lproj/com.apple.xcode.tools.ibtool.compiler.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.xcode.tools.ibtool.compiler.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/com.apple.xcode.tools.ibtool.compiler.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.xcode.tools.ibtool.compiler.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/en.lproj/com.apple.xcode.tools.ibtool.postprocessor.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/English.lproj/com.apple.xcode.tools.ibtool.postprocessor.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.xcode.tools.ibtool.postprocessor.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/com.apple.xcode.tools.ibtool.postprocessor.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/com.apple.xcode.tools.ibtool.postprocessor.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/en.lproj/Interface Builder Storyboard Compiler.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/English.lproj/Interface Builder Storyboard Compiler.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Interface Builder Storyboard Compiler.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/Interface Builder Storyboard Compiler.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Interface Builder Storyboard Compiler.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/en.lproj/Interface Builder Storyboard Postprocessor.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/IBCompilerPlugin.xcplugin/Contents/Resources/English.lproj/Interface Builder Storyboard Postprocessor.strings - - - Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/Native Build System.strings - Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/Native Build System.xcspec + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Interface Builder Storyboard Postprocessor.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/Interface Builder Storyboard Postprocessor.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Interface Builder Storyboard Postprocessor.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/en.lproj/OpenCL.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/English.lproj/OpenCL.strings + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/OpenCL.strings + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/OpenCL.strings + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/OpenCL.strings Contents/PlugIns/Xcode3Core.ideplugin/Contents/Frameworks/DevToolsCore.framework/Versions/A/Resources/CoreBuildSystem.xcspec + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/CoreBuildSystem.xcspec + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/CoreBuildSystem.xcspec + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/CoreBuildSystem.xcspec Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/PrivatePlugIns/IDEiOSPlatformSupportCore.ideplugin/Contents/Resources/Device.xcspec + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Embedded-Shared.xcspec + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/Embedded-Shared.xcspec + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Embedded-Shared.xcspec Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/XCLanguageSupport.xcplugin/Contents/Resources/Swift.xcspec + Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Swift.xcspec + Contents/Developer/Library/Xcode/Plug-ins/XCBSpecifications.ideplugin/Contents/Resources/Swift.xcspec + Contents/SharedFrameworks/XCBuild.framework/Versions/A/PlugIns/XCBBuildService.bundle/Contents/PlugIns/XCBSpecifications.ideplugin/Contents/Resources/Swift.xcspec diff --git a/BuildSettingExtractor/BuildSettingInfoSubpathsNotes.md b/BuildSettingExtractor/BuildSettingInfoSubpathsNotes.md new file mode 100644 index 0000000..ebca920 --- /dev/null +++ b/BuildSettingExtractor/BuildSettingInfoSubpathsNotes.md @@ -0,0 +1,48 @@ +# BuildSettingInfoSubpaths + +An overview of the structure and keys in the BuildSettingInfoSubpaths.plist file. + +## Overview +BuildSettingExtractor gleans information about build settings from files within the Xcode app bundle. The `BuildSettingInfoSubpaths.plist` file is a listing of the paths to those files. All paths in the plist file are relative to the `Xcode.app` app wrapper. + +The build setting info is sometimes contained in `.strings` files and sometimes in `.xcspec` files. + +## Arrays of subpaths +From release to release of Xcode, sometimes the same logical file will have a new path or file name. For instance, many had _English.lproj_ as part of the path, which was changed to _en.lproj_ in subsequent releases. More recently, file names have been gradually being renamed to use a reverse-DNS naming style. + +Rather than keep detailed versioning bookkeeping, each array contains a list of paths, at least one of which should be found. If what is conceptually the same file has a different path or file name in a new release, the new path should be added to the array. Ideally it should be added to the beginning of the array, since it will be found sooner when searching more recent Xcode versions. In practice, these arrays are so short the difference is negligible. + +## Keys +### subpaths +#### An array of arrays of subpath strings +Each item is an array of paths representing one logical file containing build setting info. The assumption is that at least one of these paths is valid across all versions of Xcode. + +Add an entry to a subpath array in this key if the path or filename of an existing entry has changed in a new version of Xcode. Theoretically, any new file containing build setting info would be added to the _ introducedSubpathsByVersion_ key since the file does not exist in prior versions of Xcode. + +### deprecatedSubpathsByVersion +#### A dictionary with Xcode version as the key and an array of arrays of subpath strings as the value. +Each key is a version string matching the version string found for the key `DTXcode` in the Xcode `Info.plist` file. The version number matches the version the file was first removed. + +The value for each key is an array that works in the same manner as an entry in the subpaths array. + +Add to this key when a build setting info file is removed completely. This prevents a warning / error / test failure when using newer Xcode versions as the build info source, but still allows the file to be successfully included when using older Xcode versions as the build info source. + +### introducedSubpathsByVersion +#### A dictionary with Xcode version as the key and an array of arrays of subpath strings as the value. +Each key is a version string matching the version string found for the key `DTXcode` the Xcode `Info.plist` file. The version number matches the version the file first appeared. + +The value for each key is an array that works in the same manner as an entry in the subpaths array. + +Add to this key when a completely new build setting info file is added. This prevents a warning / error / test failure when using older Xcode versions as the build info source, but allows the file to be successfully included when using newer Xcode versions as the build info source. + +Note that, just as with the subpaths values, any subpath introduced here is represented as an array. If the path or filename changes for the same logical file, the new subpath should be added to the array. + +### backstopSettingInfo +#### A dictionary with string keys and values +Sometimes Xcode does not have a title or description defined for a build setting, or alternately, the file that provides that information has been elusive. + +This dictionary provides that missing information as a backstop in case the information is not found by searching the build info files specified by the other keys. + +The keys take the form `\[_BuildSettingName_\]-name` for the human-readable title of the build setting and `\[_BuildSettingName_\]-description` for the description of the setting. + +The keys match the format of keys found in the various `.strings` files containing build setting info. diff --git a/BuildSettingExtractor/Constants+Categories.h b/BuildSettingExtractor/Constants+Categories.h index 288b9a5..6b51124 100644 --- a/BuildSettingExtractor/Constants+Categories.h +++ b/BuildSettingExtractor/Constants+Categories.h @@ -8,15 +8,18 @@ @import Foundation; -typedef NS_ENUM(NSUInteger, AppErrorCodes) { +typedef NS_ENUM(NSUInteger, BuildSettingExtractorErrorCodes) { UnsupportedXcodeVersion = 100, DirectoryContainsBuildConfigFiles = 101, ProjectSettingsNamingConflict = 102, NoSettingsFoundInProjectFile = 103, BuildSettingInfoSourceNotFound = 104, + BuildSettingInfoFilesNotFound = 105, + BuildSettingInfoSubpathNotFound = 106, }; extern NSErrorDomain const TPSBuildSettingExtractorErrorDomain; +extern NSString * TPSMultipleUnderlyingErrorsKey(void); #pragma mark - @@ -28,6 +31,7 @@ extern NSErrorDomain const TPSBuildSettingExtractorErrorDomain; @interface NSString (TPS_BuildSettingAdditions) - (NSString *)tps_baseBuildSettingName; // Removes any conditional section of a build setting +- (BOOL)tps_baseBuildSettingNameIsEqualTo:(NSString *)buildSettingName; // returns YES if provided build setting name has the same base as the receiver @end #pragma mark - @@ -36,7 +40,11 @@ extern NSErrorDomain const TPSBuildSettingExtractorErrorDomain; // Assumes that a dictionary of build settings always has NSString values // Returns NO if all the values in a dictionary are an empty string // Raises an exception if used on a dictionary with any non-NSString value -- (BOOL)containsBuildSettings; +- (BOOL)tps_containsBuildSettings; + +// Returns a new dictionary containing all entries in the receiver except for +// entries with an empty string value. +- (NSDictionary *)tps_dictionaryByRemovingEmptyStringValues; @end #pragma mark - @@ -58,4 +66,13 @@ extern NSErrorDomain const TPSBuildSettingExtractorErrorDomain; // Notify the user the destination folder already contains build config files + (NSError *)errorForDestinationContainsBuildConfigFiles; +// Error that one or more expected build setting info files were not found +// User info includes NSMultipleUnderlyingErrorsKey to report underlying errors ++ (NSError *)errorForSettingInfoFilesNotFound:(NSArray *)subpathErrorStrings; + +@end + +#pragma mark - + +@interface EmptyStringTransformer: NSValueTransformer {} @end diff --git a/BuildSettingExtractor/Constants+Categories.m b/BuildSettingExtractor/Constants+Categories.m index b9292db..134ed4a 100644 --- a/BuildSettingExtractor/Constants+Categories.m +++ b/BuildSettingExtractor/Constants+Categories.m @@ -50,26 +50,40 @@ - (NSString *)tps_baseBuildSettingName { return baseBuildSettingName; } +- (BOOL)tps_baseBuildSettingNameIsEqualTo:(NSString *)buildSettingName { + return [[self tps_baseBuildSettingName] isEqualToString:[buildSettingName tps_baseBuildSettingName]]; +} + @end #pragma mark - @implementation NSDictionary (TPS_BuildSettingAdditions) - - (BOOL)containsBuildSettings { - BOOL foundNonEmptyString = NO; - for (id value in self.allValues) { - if ([value isKindOfClass:[NSString class]]) { - if (![(NSString *)value isEqualToString:@""]) { - foundNonEmptyString = YES; - break; - } - } else { - [NSException raise:(NSInternalInconsistencyException) format:@"-containsBuildSetting is expected to be called on a dictionary with NSString values."]; +- (BOOL)tps_containsBuildSettings { + BOOL foundNonEmptyString = NO; + for (id value in self.allValues) { + if ([value isKindOfClass:[NSString class]]) { + if (![(NSString *)value isEqualToString:@""]) { + foundNonEmptyString = YES; + break; } + } else { + [NSException raise:(NSInternalInconsistencyException) format:@"-containsBuildSetting is expected to be called on a dictionary with NSString values."]; } - return foundNonEmptyString; } + return foundNonEmptyString; +} + +- (NSDictionary *)tps_dictionaryByRemovingEmptyStringValues { + NSMutableDictionary *temp = [[NSMutableDictionary alloc] init]; + [self enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull value, BOOL * _Nonnull stop) { + if (![value isEqualTo:@""]) { + [temp setValue:value forKey:key]; + } + }]; + return temp; +} @end @@ -124,4 +138,54 @@ + (NSError *)errorForDestinationContainsBuildConfigFiles { return error; } ++ (NSError *)errorForSettingInfoFilesNotFound:(NSArray *)subpathErrorStrings { + if (subpathErrorStrings.count == 0) { + [NSException raise:NSInternalInconsistencyException format:@"Attempt to create BuildSettingInfoSubpathNotFound error with no underlying errors"]; + } + NSMutableArray *underlyingErrors = [[NSMutableArray alloc] init]; + for (NSString *errorString in subpathErrorStrings) { + NSDictionary *subpathErrorUserInfo = @{NSLocalizedDescriptionKey:errorString}; + NSError *subpathError = [NSError errorWithDomain:TPSBuildSettingExtractorErrorDomain code:BuildSettingInfoSubpathNotFound userInfo:subpathErrorUserInfo]; + [underlyingErrors addObject:subpathError]; + } + + NSDictionary *userInfo = @{NSLocalizedDescriptionKey:@"Some build info files not found.", TPSMultipleUnderlyingErrorsKey():underlyingErrors}; + + NSError *error = [NSError errorWithDomain:TPSBuildSettingExtractorErrorDomain code:BuildSettingInfoFilesNotFound userInfo:userInfo]; + + return error; +} + @end + +// Can remove once deployment target is macOS 11.3 or later +NSString * TPSMultipleUnderlyingErrorsKey(void) { + if (@available(macOS 11.3, *)) { + return NSMultipleUnderlyingErrorsKey; + } else { + return @"NSMultipleUnderlyingErrorsKey"; + } +} + +#pragma mark - + +@implementation EmptyStringTransformer ++ (Class)transformedValueClass { return [NSString class]; } ++ (BOOL)allowsReverseTransformation { return YES; } + +- (id)transformedValue:(id)value { + if ([value isKindOfClass:[NSString class]] && [value isEqualToString:@""]) { + return nil; + } else if (value == nil) { + return @""; + } else { + return value; + } +} + +- (id)reversedTransformedValue:(id)value { + if (value == nil) { return @""; } + else { return value; } +} +@end + diff --git a/BuildSettingExtractor/Preferences/Base.lproj/Preferences.storyboard b/BuildSettingExtractor/Preferences/Base.lproj/Preferences.storyboard index f735302..419e68a 100644 --- a/BuildSettingExtractor/Preferences/Base.lproj/Preferences.storyboard +++ b/BuildSettingExtractor/Preferences/Base.lproj/Preferences.storyboard @@ -1,8 +1,8 @@ - + - + @@ -13,7 +13,7 @@ - + @@ -31,8 +31,8 @@ - - + + @@ -57,53 +57,53 @@ - + - + - - + + - + - - + + - + - + - + - + - + - + @@ -146,7 +146,7 @@ - + @@ -168,7 +168,7 @@ - + @@ -181,7 +181,7 @@ - + @@ -190,8 +190,8 @@ - - + + @@ -205,11 +205,12 @@ - + + @@ -217,7 +218,7 @@ - + @@ -226,8 +227,8 @@ - - + + @@ -243,6 +244,7 @@ + @@ -250,7 +252,7 @@ - + @@ -259,8 +261,8 @@ - - + + @@ -271,9 +273,11 @@ - + + None + EmptyStringTransformer @@ -283,7 +287,7 @@ - + @@ -293,7 +297,7 @@