From 9d5342d301bbf5476331ffaf9625c96f67fdfbaf Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Wed, 26 Jul 2017 23:06:34 +0200 Subject: [PATCH] buildPresets --- .../project.pbxproj | 234 +++++++----------- .../xcshareddata/xcschemes/MyScheme.xcscheme | 28 --- Fixtures/TestProject/spec.yml | 20 +- Fixtures/settings_test.yml | 50 ++++ README.md | 97 +++++++- Sources/XcodeGenKit/BuildSettingsPreset.swift | 50 ---- Sources/XcodeGenKit/PBXProjGenerator.swift | 29 +-- Sources/XcodeGenKit/ProjectExtensions.swift | 16 +- Sources/XcodeGenKit/ProjectGenerator.swift | 36 ++- Sources/XcodeGenKit/SettingsBuilder.swift | 85 +++++++ Sources/XcodeGenKit/Spec/BuildSetting.swift | 39 --- .../XcodeGenKit/Spec/BuildSettingGroup.swift | 29 --- Sources/XcodeGenKit/Spec/Config.swift | 23 +- Sources/XcodeGenKit/Spec/SettingPreset.swift | 58 +++++ Sources/XcodeGenKit/Spec/Settings.swift | 73 ++++++ Sources/XcodeGenKit/Spec/Spec.swift | 15 +- Sources/XcodeGenKit/Spec/Target.swift | 11 +- .../ProjectGeneratorTests.swift | 32 ++- Tests/XcodeGenKitTests/SpecLoadingTests.swift | 17 ++ 19 files changed, 560 insertions(+), 382 deletions(-) delete mode 100644 Fixtures/TestProject/GeneratedProject.xcodeproj/xcshareddata/xcschemes/MyScheme.xcscheme create mode 100644 Fixtures/settings_test.yml delete mode 100644 Sources/XcodeGenKit/BuildSettingsPreset.swift create mode 100644 Sources/XcodeGenKit/SettingsBuilder.swift delete mode 100644 Sources/XcodeGenKit/Spec/BuildSetting.swift delete mode 100644 Sources/XcodeGenKit/Spec/BuildSettingGroup.swift create mode 100644 Sources/XcodeGenKit/Spec/SettingPreset.swift create mode 100644 Sources/XcodeGenKit/Spec/Settings.swift diff --git a/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj b/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj index 09594ae9..ea46122a 100644 --- a/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj +++ b/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj @@ -272,26 +272,12 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - OBJECT_2 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_WARN_SUSPICIOUS_MOVE = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - GCC_OPTIMIZATION_LEVEL = s; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - OBJECT_20 /* Release */ = { + OBJECT_2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -306,102 +292,69 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = 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; - INFOPLIST_FILE = TestProject/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.test; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - OBJECT_21 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - 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_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = 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; - INFOPLIST_FILE = TestProject/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.test; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - OBJECT_3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); + GCC_WARN_64_TO_32_BIT_CONVERSION = 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; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; - OBJECT_38 /* Release */ = { + OBJECT_20 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = TestProject/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.test; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + OBJECT_21 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = TestProject/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.test; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + OBJECT_3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -416,91 +369,72 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = s; GCC_WARN_64_TO_32_BIT_CONVERSION = 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; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + OBJECT_38 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + ENABLE_TESTABILITY = YES; + INFOPLIST_FILE = MyFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + OBJECT_39 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + ENABLE_TESTABILITY = YES; INFOPLIST_FILE = MyFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; - OBJECT_39 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - 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_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = 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; - INFOPLIST_FILE = MyFramework/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ OBJECT_22 /* Build configuration list for PBXNativeTarget "TestProject" */ = { isa = XCConfigurationList; buildConfigurations = ( - OBJECT_21 /* Debug */, - OBJECT_20 /* Release */, + OBJECT_21 /* Release */, + OBJECT_20 /* Debug */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = ""; @@ -508,17 +442,17 @@ OBJECT_4 /* Build configuration list for PBXProject */ = { isa = XCConfigurationList; buildConfigurations = ( - OBJECT_3 /* Debug */, - OBJECT_2 /* Release */, + OBJECT_3 /* Release */, + OBJECT_2 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; OBJECT_40 /* Build configuration list for PBXNativeTarget "MyFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( - OBJECT_38 /* Release */, - OBJECT_39 /* Debug */, + OBJECT_38 /* Debug */, + OBJECT_39 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = ""; diff --git a/Fixtures/TestProject/GeneratedProject.xcodeproj/xcshareddata/xcschemes/MyScheme.xcscheme b/Fixtures/TestProject/GeneratedProject.xcodeproj/xcshareddata/xcschemes/MyScheme.xcscheme deleted file mode 100644 index 709f9f0b..00000000 --- a/Fixtures/TestProject/GeneratedProject.xcodeproj/xcshareddata/xcschemes/MyScheme.xcscheme +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Fixtures/TestProject/spec.yml b/Fixtures/TestProject/spec.yml index 89505322..d3af7ff2 100644 --- a/Fixtures/TestProject/spec.yml +++ b/Fixtures/TestProject/spec.yml @@ -1,21 +1,10 @@ name: GeneratedProject -settingGroups: - testGroup: - TEST_SETTING: test value -configs: - Debug: - type: debug - settingGroups: - - testGroup - buildSettings: - Release: - type: release targets: - name: TestProject type: application platform: iOS sources: TestProject - buildSettings: + settings: INFOPLIST_FILE: TestProject/Info.plist PRODUCT_BUNDLE_IDENTIFIER: com.test dependencies: @@ -24,10 +13,5 @@ targets: type: framework platform: iOS sources: MyFramework - buildSettings: + settings: INFOPLIST_FILE: MyFramework/Info.plist -schemes: - MyScheme: - build: - targets: - TestProject: all diff --git a/Fixtures/settings_test.yml b/Fixtures/settings_test.yml new file mode 100644 index 00000000..64258e52 --- /dev/null +++ b/Fixtures/settings_test.yml @@ -0,0 +1,50 @@ +name: SettingsTest +settingPresets: + preset1: + settingPresets: + - preset2 + settings: + SETTING 1: value 1 + preset2: + SETTING 2: value 2 + preset3: + settingPresets: + - preset2 + settings: + default: + SETTING 9: value 9 + configs: + config1: + SETTING 8: value 8 +configs: + config1: + type: debug + settingPresets: + - preset1 + settings: + SETTING 3: value 3 + config2: + type: release + settingPresets: + - preset2 + settings: + SETTING 4: value 4 +targets: + - name: Target1 + type: application + platform: iOS + settingPresets: + - preset1 + settings: + SETTING 5: value 5 + - name: Target2 + type: application + platform: iOS + settingPresets: + - preset3 + settings: + default: + SETTING 7: value 7 + configs: + config1: + SETTING 6: value 6 diff --git a/README.md b/README.md index 585b2bd0..2b23ebb3 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A command line tool that generates your Xcode project from a YAML project spec a This allows for easy configuration which is git friendly, and means your project structure represents exacty what's on disk. The project can be re-generated on demand which means you can remove your xcode project from git and say goodbye to .xcodeproj merge conflicts! Given a simple project spec file: + ```yaml name: My Project configs: @@ -20,7 +21,7 @@ targets: type: application platform: iOS sources: MyApp - buildSettings: + settings: INFOPLIST_FILE: MyApp/Info.plist PRODUCT_BUNDLE_IDENTIFIER: com.myapp dependencies: @@ -60,23 +61,49 @@ Use `XcodeGen -help` to see the list of options: - **project**: (optional): This is an optional path the generated xcode project file. If it is left out, the file will be written to the same directory as the spec, and with the same name as the spec file # XcodeGen project spec +Each spec must contain a name which is used for the generated project name ## configs Configs specify the configurations in your project. -Each config can specify a `type` of either `debug` or `release` which will then apply the default build settings for those types. A config can also specify its own list of `buildSettings` +Each config can specify a `type` of either `debug` or `release` which will then apply the default build settings for those types. A config can also specify its own list of `settings ` + ```yaml configs: Debug: type: debug - buildSettings: + settings: MY_COOL_SETTING: value Release: type: release ``` If no configs are specified, default `Debug` and `Release` configs will be created for you +## settingPresets +Setting presets can be used to group build settings together and reuse them elsewhere. Each preset specifies a list of settings. It can also list other setting presets that will be merged in. + +```yaml +settingPresets: + preset: + BUILD_SETTING: value + preset2: + settings: + BUILD_SETTING: value + settingPresets: + - preset + preset3: + settings: + base: + BUILD_SETTING: value + configs: + debug: + BUILD_SETTING: value + settingPresets: + - preset +``` + ## targets This is list of targets + ```yaml targets: - name: MyTarget @@ -111,6 +138,7 @@ Specifies the platform for the target. This will provide default build settings #### sources Specifies the source directories for the target. This can either be a single path or a list of paths. Applicable source files, resources, headers, and lproj files will be parsed appropriately + ```yaml targets: - name: MyTarget @@ -121,8 +149,9 @@ targets: - MyOtherTargetSource2 ``` -#### buildSettings -Species the build settings for the target. This can either be a simple map of build settings, or they can be broken down into specific configurations. If supplying configuration specific settings, a `$base` configuration may be used to provide default build settings that apply accross all configurations +#### settings +Species the build settings for the target. This can either be a simple list of build settings, or you can specify a map of configs to settings. If supplying such config specific settings, then a `default` settings list can be provided for build settings that apply across all configurations + ```yaml configs: test: @@ -133,17 +162,27 @@ configs: type: release targets: - name: MyTarget - buildSettings: + settings: INFO_PLIST: Info.plist - name: MyOtherTarget - buildSettings: - $base: + settings: + default: MY_SETTING: default MY_OTHER_SETTING: value - test: - MY_SETTING: test value - staging: - MY_SETTING: staging value + configs: + test: + MY_SETTING: test value +``` + +#### settingPresets +Specifies the target specific settingPresets. This is a simple list that maps to the top level setting presets. These settings will be merged in before any custom settings + +```yaml +targets: + - name: MyTarget + settingPresets: + - mypreset1 + - mypreset2 ``` #### dependencies @@ -164,6 +203,7 @@ targets: #### configs Specifies `.xcconfig` files for each configuration for the target. + ```yaml targets: - name: MyTarget @@ -172,6 +212,39 @@ targets: Release: config_files/release.xcconfig ``` +#### generateSchemes +This is a conveniance used to automatically generate schemes for a target based on large amount of configs. A list of names is provided, then for each of these names a scheme is created, using configs that contain the name with debug and release variants. This is useful for having different environment schemes. + +For example, the following spec would create 3 schemes called: + +- MyApp Test +- MyApp Staging +- MyApp Production + +Each scheme would use different build configuration for the different build types, specifically debug configs for `run`, `test`, and `anaylze`, and release configs for `profile` and `archive` + +``` +configs: + Test Debug: + type: debug + Staging Debug: + type: debug + Production Debug: + type: debug + Test Release: + type: release + Staging Release: + type: release + Production Release: + type: release +targets + - name: MyApp + generateSchemes: + - Test + - Staging + - Production +``` + --- ## Attributions diff --git a/Sources/XcodeGenKit/BuildSettingsPreset.swift b/Sources/XcodeGenKit/BuildSettingsPreset.swift deleted file mode 100644 index 5209a74d..00000000 --- a/Sources/XcodeGenKit/BuildSettingsPreset.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// BuildSettingGroupType.swift -// XcodeGen -// -// Created by Yonas Kolb on 23/7/17. -// -// - -import Foundation -import xcodeproj -import PathKit -import Yams -import JSONUtilities - -enum BuildSettingsPreset { - case config(ConfigType) - case platform(Platform) - case product(PBXProductType) - case base - - var path: String { - switch self { - case let .config(config): return "Configs/\(config.rawValue)" - case let .platform(platform): return "Platforms/\(platform.rawValue)" - case let .product(product): return "Products/\(product.rawValue)" - case .base: return "base" - } - } - - private static var buildSettings: [String: BuildSettings] = [:] - - func getBuildSettings() throws -> BuildSettings? { - if let group = BuildSettingsPreset.buildSettings[path] { - return group - } - let settingsPath = Path(#file).parent().parent().parent() + "SettingPresets/\(path).yml" - guard settingsPath.exists, - let buildSettings = try? BuildSettings(path: settingsPath) else { return nil } - BuildSettingsPreset.buildSettings[path] = buildSettings - return buildSettings - } -} - -extension BuildSettings: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - self.init(dictionary: jsonDictionary) - } -} - diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 242c793b..0949815e 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -48,12 +48,8 @@ public class PBXProjGenerator { } public func generate() throws -> PBXProj { - let buildConfigs: [XCBuildConfiguration] = try spec.configs.map { config in - - var buildSettings = config.buildSettings - if let type = config.type, let typeBuildSettings = try BuildSettingsPreset.config(type).getBuildSettings() { - buildSettings = typeBuildSettings.merged(buildSettings) - } + let buildConfigs: [XCBuildConfiguration] = spec.configs.map { config in + let buildSettings = spec.getProjectBuildSettings(config: config) return XCBuildConfiguration(reference: id(), name: config.name, baseConfigurationReference: nil, buildSettings: buildSettings) } @@ -135,9 +131,10 @@ public class PBXProjGenerator { sourceFilePaths += sourceGroups.filePaths } - let configs: [XCBuildConfiguration] = try spec.configs.map { config in - let buildSettings = try getTargetBuildSettings(config: config.name, target: target) + let configs: [XCBuildConfiguration] = spec.configs.map { config in + let buildSettings = spec.getTargetBuildSettings(target: target, config: config) var baseConfigurationReference: String? + if let configPath = target.configs[config.name] { let path = basePath + configPath baseConfigurationReference = fileReferencesByPath[path] @@ -287,22 +284,6 @@ public class PBXProjGenerator { return nil } - func getTargetBuildSettings(config: String, target: Target) throws -> BuildSettings { - var buildSettings = BuildSettings() - - func getBuildSettingPreset(_ type: BuildSettingsPreset) throws -> BuildSettings? { - return try type.getBuildSettings() - } - - buildSettings += try getBuildSettingPreset(.base) - buildSettings += try getBuildSettingPreset(.platform(target.platform)) - buildSettings += try getBuildSettingPreset(.product(target.type)) - buildSettings += target.buildSettings?.buildSettings - buildSettings += target.buildSettings?.configSettings[config] - - return buildSettings - } - func getFileReference(path: Path, inPath: Path) -> String { if let fileReference = fileReferencesByPath[path] { return fileReference diff --git a/Sources/XcodeGenKit/ProjectExtensions.swift b/Sources/XcodeGenKit/ProjectExtensions.swift index 21455458..b3eb6752 100644 --- a/Sources/XcodeGenKit/ProjectExtensions.swift +++ b/Sources/XcodeGenKit/ProjectExtensions.swift @@ -21,28 +21,32 @@ extension Array where Element: ProjectElement { } } -extension BuildSettings { +extension BuildSettings: CustomStringConvertible { - init() { + public init() { dictionary = [:] } - static var empty = BuildSettings() + public static let empty = BuildSettings() - func merged(_ buildSettings: BuildSettings) -> BuildSettings { + public func merged(_ buildSettings: BuildSettings) -> BuildSettings { var mergedSettings = self mergedSettings.merge(buildSettings) return mergedSettings } - mutating func merge(_ buildSettings: BuildSettings) { + public mutating func merge(_ buildSettings: BuildSettings) { for (key, value) in buildSettings.dictionary { dictionary[key] = value } } + + public var description: String { + return dictionary.map { "\($0) = \($1)" }.joined(separator: "\n") + } } -func +=( lhs: inout BuildSettings, rhs: BuildSettings?) { +public func +=( lhs: inout BuildSettings, rhs: BuildSettings?) { guard let rhs = rhs else { return } lhs.merge(rhs) } diff --git a/Sources/XcodeGenKit/ProjectGenerator.swift b/Sources/XcodeGenKit/ProjectGenerator.swift index 6324953f..e6e5f08d 100644 --- a/Sources/XcodeGenKit/ProjectGenerator.swift +++ b/Sources/XcodeGenKit/ProjectGenerator.swift @@ -40,19 +40,39 @@ public class ProjectGenerator { var errors: [SpecValidationError.Error] = [] + func validateSettingPresets(_ settingsPresets: [String]) -> [SpecValidationError.Error] { + var errors: [SpecValidationError.Error] = [] + for preset in settingsPresets { + if let settingsPreset = spec.settingPresets[preset] { + errors += validateSettingPresets(settingsPreset.settingPresets) + } else { + errors.append(.invalidSettingsPreset(preset)) + } + } + return errors + } + + for settingPreset in spec.settingPresets.values { + errors += validateSettingPresets(settingPreset.settingPresets) + } + + for config in spec.configs { + errors += validateSettingPresets(config.settingPresets) + } + for target in spec.targets { for dependency in target.dependencies { if case .target(let targetName) = dependency, spec.getTarget(targetName) == nil { errors.append(.invalidTargetDependency(target: target.name, dependency: targetName)) } } - if let buildSettings = target.buildSettings { - for config in buildSettings.configSettings.keys { - if spec.getConfig(config) == nil { - errors.append(.invalidBuildSettingConfig(config: config)) - } + + for config in target.settings.configSettings.keys { + if spec.getConfig(config) == nil { + errors.append(.invalidBuildSettingConfig(config)) } } + for source in target.sources { let sourcePath = path + source if !sourcePath.exists { @@ -68,6 +88,8 @@ public class ProjectGenerator { errors.append(.invalidTargetGeneratedSchema(target: target.name, scheme: generatedScheme, configType: .release)) } } + + errors += validateSettingPresets(target.settingPresets) } for scheme in spec.schemes { @@ -185,7 +207,8 @@ public struct SpecValidationError: Error, CustomStringConvertible { case invalidTargetDependency(target: String, dependency: String) case invalidSchemeTarget(scheme: String, target: String) case invalidSchemeConfig(scheme: String, config: String) - case invalidBuildSettingConfig(config: String) + case invalidBuildSettingConfig(String) + case invalidSettingsPreset(String) case missingTargetSource(target: String, source: String) case invalidTargetGeneratedSchema(target: String, scheme: String, configType: ConfigType) @@ -196,6 +219,7 @@ public struct SpecValidationError: Error, CustomStringConvertible { case let .invalidSchemeConfig(scheme, config): return "Scheme \(scheme.quoted) has invalid build configuration \(config.quoted)" case let .invalidBuildSettingConfig(config): return "Build setting has invalid build configuration \(config.quoted)" case let .missingTargetSource(target, source): return "Target \(target.quoted) has a missing source directory \(source.quoted)" + case let .invalidSettingsPreset(preset): return "Invalid settings preset \(preset.quoted)" case let .invalidTargetGeneratedSchema(target, scheme, configType): return "Target \(target.quoted) has an invalid schema generation name which requires a config that has a \(configType.rawValue.quoted) type and contains the name \(scheme.quoted)" } } diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift new file mode 100644 index 00000000..63e8b0cc --- /dev/null +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -0,0 +1,85 @@ +// +// SettingsBuilder.swift +// XcodeGen +// +// Created by Yonas Kolb on 26/7/17. +// +// + +import Foundation +import xcodeproj +import PathKit + +extension Spec { + + public func getProjectBuildSettings(config: Config) -> BuildSettings { + + var buildSettings: BuildSettings = .empty + buildSettings += SettingsPresetFile.base.getBuildSettings() + + if let type = config.type { + buildSettings += SettingsPresetFile.config(type).getBuildSettings() + } + + for preset in config.settingPresets { + buildSettings += getBuildSettings(preset: preset, config: config) + } + + buildSettings += config.settings + + return buildSettings + } + + public func getTargetBuildSettings(target: Target, config: Config) -> BuildSettings { + + var buildSettings = BuildSettings() + + buildSettings += SettingsPresetFile.platform(target.platform).getBuildSettings() + buildSettings += SettingsPresetFile.product(target.type).getBuildSettings() + + for preset in target.settingPresets { + buildSettings += getBuildSettings(preset: preset, config: config) + } + + buildSettings += getBuildSettings(settings: target.settings, config: config) + + return buildSettings + } + + public func getBuildSettings(preset: String, config: Config) -> BuildSettings { + var buildSettings: BuildSettings = .empty + let settingPreset = settingPresets[preset]! + buildSettings += getBuildSettings(settings: settingPreset.settings, config: config) + + for preset in settingPreset.settingPresets { + buildSettings += getBuildSettings(preset: preset, config: config) + } + return buildSettings + } + + public func getBuildSettings(settings: Settings, config: Config) -> BuildSettings { + var buildSettings: BuildSettings = .empty + + buildSettings += settings.buildSettings + buildSettings += settings.configSettings[config.name] + + return buildSettings + } +} + + +private var buildSettingFiles: [String: BuildSettings] = [:] + +extension SettingsPresetFile { + + public func getBuildSettings() -> BuildSettings? { + if let group = buildSettingFiles[path] { + return group + } + let settingsPath = Path(#file).parent().parent().parent() + "SettingPresets/\(path).yml" + guard settingsPath.exists, + let buildSettings = try? BuildSettings(path: settingsPath) else { return nil } + buildSettingFiles[path] = buildSettings + return buildSettings + } +} diff --git a/Sources/XcodeGenKit/Spec/BuildSetting.swift b/Sources/XcodeGenKit/Spec/BuildSetting.swift deleted file mode 100644 index 4e9c410e..00000000 --- a/Sources/XcodeGenKit/Spec/BuildSetting.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// BuildSetting.swift -// XcodeGen -// -// Created by Yonas Kolb on 21/7/17. -// -// - -import Foundation -import JSONUtilities -import xcodeproj - -public struct TargetBuildSettings: JSONObjectConvertible { - - public let buildSettings: BuildSettings - public let configSettings: [String: BuildSettings] - - public init(buildSettings: BuildSettings, configSettings: [String: BuildSettings] = [:]) { - self.buildSettings = buildSettings - self.configSettings = configSettings - } - - public init(jsonDictionary: JSONDictionary) throws { - if jsonDictionary["$base"] != nil { - buildSettings = BuildSettings(dictionary: try jsonDictionary.json(atKeyPath: "$base")) - var configSettings: [String: BuildSettings] = [:] - for (key, value) in jsonDictionary { - if key != "baseSettings", let buildSettings = value as? JSONDictionary { - configSettings["key"] = BuildSettings(dictionary: buildSettings) - } - } - self.configSettings = configSettings - } else { - buildSettings = BuildSettings(dictionary: jsonDictionary) - configSettings = [:] - } - } -} - diff --git a/Sources/XcodeGenKit/Spec/BuildSettingGroup.swift b/Sources/XcodeGenKit/Spec/BuildSettingGroup.swift deleted file mode 100644 index e05c3c68..00000000 --- a/Sources/XcodeGenKit/Spec/BuildSettingGroup.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// BuildSettings.swift -// XcodeGen -// -// Created by Yonas Kolb on 20/7/17. -// -// - -import Foundation -import xcodeproj -import JSONUtilities - -public struct BuildSettingGroup { - public var name: String - public var buildSettings: BuildSettings - - public init(name: String, buildSettings: BuildSettings) { - self.name = name - self.buildSettings = buildSettings - } -} - -extension BuildSettingGroup: NamedJSONDictionaryConvertible { - - public init(name: String, jsonDictionary: JSONDictionary) throws { - self.name = name - self.buildSettings = BuildSettings(dictionary: jsonDictionary) - } -} diff --git a/Sources/XcodeGenKit/Spec/Config.swift b/Sources/XcodeGenKit/Spec/Config.swift index 9d2aacc2..94fad59b 100644 --- a/Sources/XcodeGenKit/Spec/Config.swift +++ b/Sources/XcodeGenKit/Spec/Config.swift @@ -10,18 +10,25 @@ import Foundation import xcodeproj import JSONUtilities -public struct Config { +public struct Config: Equatable { public var name: String public var type: ConfigType? - public var buildSettingGroups: [BuildSettingGroup] - public var buildSettings: BuildSettings + public var settings: BuildSettings + public var settingPresets: [String] - public init(name: String, type: ConfigType? = nil, buildSettingGroups: [BuildSettingGroup] = [], buildSettings: BuildSettings = .init()) { + public init(name: String, type: ConfigType? = nil, settings: BuildSettings = .empty, settingPresets: [String] = []) { self.name = name - self.buildSettingGroups = buildSettingGroups - self.buildSettings = buildSettings + self.settings = settings + self.settingPresets = settingPresets self.type = type } + + public static func ==(lhs: Config, rhs: Config) -> Bool { + return lhs.name == rhs.name && + lhs.type == rhs.type && + lhs.settings == rhs.settings && + lhs.settingPresets == rhs.settingPresets + } } @@ -35,7 +42,7 @@ extension Config: NamedJSONDictionaryConvertible { public init(name: String, jsonDictionary: JSONDictionary) throws { self.name = name type = jsonDictionary.json(atKeyPath: "type") - buildSettingGroups = try jsonDictionary.json(atKeyPath: "settingGroups") - buildSettings = BuildSettings(dictionary: jsonDictionary.json(atKeyPath: "buildSettings") ?? [:]) + settings = BuildSettings(dictionary: jsonDictionary.json(atKeyPath: "settings") ?? [:]) + settingPresets = jsonDictionary.json(atKeyPath: "settingPresets") ?? [] } } diff --git a/Sources/XcodeGenKit/Spec/SettingPreset.swift b/Sources/XcodeGenKit/Spec/SettingPreset.swift new file mode 100644 index 00000000..391d64c4 --- /dev/null +++ b/Sources/XcodeGenKit/Spec/SettingPreset.swift @@ -0,0 +1,58 @@ +// +// SettingPreset.swift +// XcodeGen +// +// Created by Yonas Kolb on 26/7/17. +// +// + +import Foundation +import JSONUtilities +import xcodeproj + +public struct SettingPreset: Equatable, CustomStringConvertible { + public var settings: Settings + public var settingPresets: [String] + + public init(settings: Settings, settingPresets: [String] = []) { + self.settings = settings + self.settingPresets = settingPresets + } + + public static func ==(lhs: SettingPreset, rhs: SettingPreset) -> Bool { + return lhs.settings == rhs.settings && lhs.settingPresets == rhs.settingPresets + } + + public var description: String { + return "\(settings)\nPresets: \(settingPresets)" + } +} + +public enum SettingsPresetFile { + case config(ConfigType) + case platform(Platform) + case product(PBXProductType) + case base + + var path: String { + switch self { + case let .config(config): return "Configs/\(config.rawValue)" + case let .platform(platform): return "Platforms/\(platform.rawValue)" + case let .product(product): return "Products/\(product.rawValue)" + case .base: return "base" + } + } +} + +extension SettingPreset: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + if jsonDictionary["settings"] == nil { + settings = try Settings(jsonDictionary: jsonDictionary) + settingPresets = [] + } else { + settings = try jsonDictionary.json(atKeyPath: "settings") + settingPresets = jsonDictionary.json(atKeyPath: "settingPresets") ?? [] + } + } +} diff --git a/Sources/XcodeGenKit/Spec/Settings.swift b/Sources/XcodeGenKit/Spec/Settings.swift new file mode 100644 index 00000000..30b2a1d0 --- /dev/null +++ b/Sources/XcodeGenKit/Spec/Settings.swift @@ -0,0 +1,73 @@ +// +// BuildSetting.swift +// XcodeGen +// +// Created by Yonas Kolb on 21/7/17. +// +// + +import Foundation +import JSONUtilities +import xcodeproj + +public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertible { + + public let buildSettings: BuildSettings + public let configSettings: [String: BuildSettings] + + public init(buildSettings: BuildSettings, configSettings: [String: BuildSettings] = [:]) { + self.buildSettings = buildSettings + self.configSettings = configSettings + } + + public init(dictionary: [String: Any]) { + self.buildSettings = BuildSettings(dictionary: dictionary) + self.configSettings = [:] + } + + static let empty: Settings = Settings(buildSettings: BuildSettings()) + + public init(jsonDictionary: JSONDictionary) throws { + if let configSettings: [String: BuildSettings] = jsonDictionary.json(atKeyPath: "configs") { + buildSettings = jsonDictionary.json(atKeyPath: "default") ?? [:] + self.configSettings = configSettings + } else { + buildSettings = BuildSettings(dictionary: jsonDictionary) + configSettings = [:] + } + } + + public static func ==(lhs: Settings, rhs: Settings) -> Bool { + return lhs.buildSettings == rhs.buildSettings && lhs.configSettings == rhs.configSettings + } + + public var description: String { + var string: String = "" + if !buildSettings.dictionary.isEmpty { + string += buildSettings.description + } + for (config, buildSettings) in configSettings { + if !buildSettings.dictionary.isEmpty { + string += "\n\(config)\n\t" + buildSettings.description.replacingOccurrences(of: "\n", with: "\n\t") + } + } + return string + } +} + +extension Settings: ExpressibleByDictionaryLiteral { + + public init(dictionaryLiteral elements: (String, Any)...) { + var dictionary: [String: Any] = [:] + elements.forEach { dictionary[$0.0] = $0.1 } + self.init(dictionary: dictionary) + } + +} + +extension BuildSettings: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + self.init(dictionary: jsonDictionary) + } +} diff --git a/Sources/XcodeGenKit/Spec/Spec.swift b/Sources/XcodeGenKit/Spec/Spec.swift index a3c7a40b..243ad3a0 100644 --- a/Sources/XcodeGenKit/Spec/Spec.swift +++ b/Sources/XcodeGenKit/Spec/Spec.swift @@ -16,23 +16,25 @@ public struct Spec { public var name: String public var targets: [Target] - public var settingGroups: [BuildSettingGroup] + public var settings: Settings + public var settingPresets: [String: SettingPreset] public var configs: [Config] public var schemes: [Scheme] - public init(name: String, configs: [Config] = [], targets: [Target] = [], settingGroups: [BuildSettingGroup] = [], schemes: [Scheme] = []) { + public init(name: String, configs: [Config] = [], targets: [Target] = [], settings: Settings = .empty, settingPresets: [String: SettingPreset] = [:], schemes: [Scheme] = []) { self.name = name self.targets = targets self.configs = configs - self.settingGroups = settingGroups + self.settings = settings + self.settingPresets = settingPresets self.schemes = schemes } - func getTarget(_ targetName: String) -> Target? { + public func getTarget(_ targetName: String) -> Target? { return targets.first { $0.name == targetName } } - func getConfig(_ configName: String) -> Config? { + public func getConfig(_ configName: String) -> Config? { return configs.first { $0.name == configName } } } @@ -53,7 +55,8 @@ extension Spec { public init(jsonDictionary: JSONDictionary) throws { name = try jsonDictionary.json(atKeyPath: "name") - settingGroups = try jsonDictionary.json(atKeyPath: "settingGroups") + settings = jsonDictionary.json(atKeyPath: "settings") ?? .empty + settingPresets = jsonDictionary.json(atKeyPath: "settingPresets") ?? [:] configs = try jsonDictionary.json(atKeyPath: "configs") if jsonDictionary["targets"] == nil { targets = [] diff --git a/Sources/XcodeGenKit/Spec/Target.swift b/Sources/XcodeGenKit/Spec/Target.swift index 45ae4641..2d7f42df 100644 --- a/Sources/XcodeGenKit/Spec/Target.swift +++ b/Sources/XcodeGenKit/Spec/Target.swift @@ -14,7 +14,8 @@ public struct Target { public var name: String public var type: PBXProductType public var platform: Platform - public var buildSettings: TargetBuildSettings? + public var settings: Settings + public var settingPresets: [String] public var sources: [String] public var sourceExludes: [String] public var dependencies: [Dependency] @@ -31,11 +32,12 @@ public struct Target { return name } - public init(name: String, type: PBXProductType, platform: Platform, buildSettings: TargetBuildSettings?, configs: [String: String] = [:], sources: [String] = [], sourceExludes: [String] = [], dependencies: [Dependency] = [], prebuildScripts: [String] = [], postbuildScripts: [String] = [], generateSchemes: [String] = []) { + public init(name: String, type: PBXProductType, platform: Platform, settings: Settings = .empty, settingPresets: [String] = [], configs: [String: String] = [:], sources: [String] = [], sourceExludes: [String] = [], dependencies: [Dependency] = [], prebuildScripts: [String] = [], postbuildScripts: [String] = [], generateSchemes: [String] = []) { self.name = name self.type = type self.platform = platform - self.buildSettings = buildSettings + self.settings = settings + self.settingPresets = settingPresets self.configs = configs self.sources = sources self.sourceExludes = sourceExludes @@ -62,7 +64,8 @@ extension Target: JSONObjectConvertible { } else { throw SpecError.unknownTargetPlatform(platformString) } - buildSettings = jsonDictionary.json(atKeyPath: "buildSettings") + settings = jsonDictionary.json(atKeyPath: "settings") ?? .empty + settingPresets = jsonDictionary.json(atKeyPath: "settingsPresets") ?? [] configs = jsonDictionary.json(atKeyPath: "configs") ?? [:] if let source: String = jsonDictionary.json(atKeyPath: "sources") { sources = [source] diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index b339386b..49b6ddc6 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -17,11 +17,11 @@ func projectGeneratorTests() { describe("Project Generator") { let application = Target(name: "MyApp", type: .application, platform: .iOS, - buildSettings: TargetBuildSettings(buildSettings: BuildSettings(dictionary: ["SETTING_1": "VALUE"])), + settings: Settings(buildSettings: BuildSettings(dictionary: ["SETTING_1": "VALUE"])), dependencies: [.target("MyFramework")]) let framework = Target(name: "MyFramework", type: .framework, platform: .iOS, - buildSettings: TargetBuildSettings(buildSettings: BuildSettings(dictionary: ["SETTING_2": "VALUE"]))) + settings: Settings(buildSettings: BuildSettings(dictionary: ["SETTING_2": "VALUE"]))) $0.describe("Config") { @@ -42,6 +42,34 @@ func projectGeneratorTests() { try expect(configs).contains(name: "config1") try expect(configs).contains(name: "config2") } + + $0.it("merges settings") { + let spec = try Spec(path: fixturePath + "settings_test.yml") + let project = try getProject(spec) + let configs = project.pbxproj.objects.buildConfigurations + try expect(configs.count) == 6 + guard let config = spec.getConfig("config1") else { throw failure("Couldn't find config1") } + let debugProjectSettings = spec.getProjectBuildSettings(config: config) + guard let target = spec.getTarget("Target2") else { throw failure("Couldn't find Target2") } + let targetDebugSettings = spec.getTargetBuildSettings(target: target, config: config) + + var buildSettings = BuildSettings() + buildSettings += SettingsPresetFile.base.getBuildSettings() + buildSettings += SettingsPresetFile.config(.debug).getBuildSettings() + + buildSettings += ["SETTING 1": "value 1", + "SETTING 2": "value 2", + "SETTING 3": "value 3"] + try expect(debugProjectSettings) == buildSettings + + var expectedTargetDebugSettings = BuildSettings() + expectedTargetDebugSettings += SettingsPresetFile.product(.application).getBuildSettings() + expectedTargetDebugSettings += SettingsPresetFile.platform(.iOS).getBuildSettings() + expectedTargetDebugSettings += ["SETTING 7": "value 7", "SETTING 6": "value 6"] + + try expect(targetDebugSettings) == expectedTargetDebugSettings + + } } $0.describe("Targets") { diff --git a/Tests/XcodeGenKitTests/SpecLoadingTests.swift b/Tests/XcodeGenKitTests/SpecLoadingTests.swift index b2aa9362..64302043 100644 --- a/Tests/XcodeGenKitTests/SpecLoadingTests.swift +++ b/Tests/XcodeGenKitTests/SpecLoadingTests.swift @@ -73,6 +73,23 @@ func specLoadingTests() { try expect(target.target) == "Target" try expect(target.buildTypes) == [.running, .testing, .profiling, .analyzing, .archiving] } + + $0.it("parses settings") { + let spec = try Spec(path: fixturePath + "settings_test.yml") + try expect(spec.settingPresets.count) == 3 + let preset1 = SettingPreset(settings: ["SETTING 1": "value 1"], settingPresets: ["preset2"]) + let preset2 = SettingPreset(settings: ["SETTING 2": "value 2"]) + let preset3 = SettingPreset(settings: Settings(buildSettings: ["SETTING 9": "value 9"], configSettings: ["config1": ["SETTING 8": "value 8"]]), settingPresets: ["preset2"]) + + let config1 = Config(name: "config1", type: .debug, settings: BuildSettings(dictionary: ["SETTING 3": "value 3"]), settingPresets: ["preset1"]) + let config2 = Config(name: "config2", type: .release, settings: BuildSettings(dictionary: ["SETTING 4": "value 4"]), settingPresets: ["preset2"]) + try expect(spec.settingPresets["preset1"]) == preset1 + try expect(spec.settingPresets["preset2"]) == preset2 + try expect(spec.settingPresets["preset3"]) == preset3 + + try expect(spec.getConfig("config1")) == config1 + try expect(spec.getConfig("config2")) == config2 + } } }