From de8f885ae3b0e9722753c0c62152d23e58717c76 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Sun, 24 Sep 2017 21:21:57 +0200 Subject: [PATCH 1/3] add bundleIdPrefix for generating PRODUCT_BUNDLE_IDENTIFIER --- .../GeneratedProject.xcodeproj/project.pbxproj | 10 ++++++---- Fixtures/TestProject/spec.yml | 3 +-- Sources/ProjectSpec/ProjectSpec.swift | 9 +++++++-- Sources/XcodeGenKit/PBXProjGenerator.swift | 4 ++++ docs/ProjectSpec.md | 1 + 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj b/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj index e629d9ee..582bda7a 100644 --- a/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj +++ b/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj @@ -390,7 +390,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.test.framework; + PRODUCT_BUNDLE_IDENTIFIER = com.test.MyFramework; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -409,7 +409,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.test.application; + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestProject; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -483,6 +483,7 @@ "$(inherited)", "@executable_path/Frameworks @loader_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestProjectTests; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestProject.app/TestProject"; @@ -500,7 +501,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.test.application; + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestProject; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -566,6 +567,7 @@ "$(inherited)", "@executable_path/Frameworks @loader_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestProjectTests; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestProject.app/TestProject"; @@ -586,7 +588,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.test.framework; + PRODUCT_BUNDLE_IDENTIFIER = com.test.MyFramework; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; diff --git a/Fixtures/TestProject/spec.yml b/Fixtures/TestProject/spec.yml index d06c0d57..a2e2a15e 100644 --- a/Fixtures/TestProject/spec.yml +++ b/Fixtures/TestProject/spec.yml @@ -1,4 +1,5 @@ name: GeneratedProject +bundleIdPrefix: com.test fileGroups: - Configs targets: @@ -8,7 +9,6 @@ targets: sources: TestProject settings: INFOPLIST_FILE: TestProject/Info.plist - PRODUCT_BUNDLE_IDENTIFIER: com.test.application dependencies: - target: MyFramework scheme: @@ -33,7 +33,6 @@ targets: sources: MyFramework settings: INFOPLIST_FILE: MyFramework/Info.plist - PRODUCT_BUNDLE_IDENTIFIER: com.test.framework postbuildScripts: - name: Swiftlint path: scripts/swiftlint.sh diff --git a/Sources/ProjectSpec/ProjectSpec.swift b/Sources/ProjectSpec/ProjectSpec.swift index 60c79548..7114a495 100644 --- a/Sources/ProjectSpec/ProjectSpec.swift +++ b/Sources/ProjectSpec/ProjectSpec.swift @@ -24,6 +24,7 @@ public struct ProjectSpec { public var attributes: [String: Any] public var fileGroups: [String] public var configFiles: [String: String] + public var bundleIdPrefix: String? public struct Options { public var carthageBuildPath: String? @@ -33,7 +34,7 @@ public struct ProjectSpec { } } - public init(name: String, configs: [Config] = [], targets: [Target] = [], settings: Settings = .empty, settingGroups: [String: Settings] = [:], schemes: [Scheme] = [], options: Options = Options(), fileGroups: [String] = [], configFiles: [String: String] = [:], attributes: [String: Any] = [:]) { + public init(name: String, configs: [Config] = [], targets: [Target] = [], settings: Settings = .empty, settingGroups: [String: Settings] = [:], schemes: [Scheme] = [], options: Options = Options(), fileGroups: [String] = [], configFiles: [String: String] = [:], attributes: [String: Any] = [:], bundleIdPrefix: String? = nil) { self.name = name self.targets = targets self.configs = configs @@ -44,6 +45,7 @@ public struct ProjectSpec { self.fileGroups = fileGroups self.configFiles = configFiles self.attributes = attributes + self.bundleIdPrefix = bundleIdPrefix } public func getTarget(_ targetName: String) -> Target? { @@ -66,7 +68,9 @@ extension ProjectSpec: Equatable { lhs.schemes == rhs.schemes && lhs.fileGroups == rhs.fileGroups && lhs.configFiles == rhs.configFiles && - lhs.options == rhs.options + lhs.options == rhs.options && + NSDictionary(dictionary: lhs.attributes).isEqual(to: rhs.attributes) && + lhs.bundleIdPrefix == rhs.bundleIdPrefix } } @@ -91,6 +95,7 @@ extension ProjectSpec: JSONObjectConvertible { fileGroups = jsonDictionary.json(atKeyPath: "fileGroups") ?? [] configFiles = jsonDictionary.json(atKeyPath: "configFiles") ?? [:] attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [:] + bundleIdPrefix = jsonDictionary.json(atKeyPath: "bundleIdPrefix") if jsonDictionary["options"] != nil { options = try jsonDictionary.json(atKeyPath: "options") } else { diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 5e92d662..c4010355 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -180,6 +180,10 @@ public class PBXProjGenerator { buildSettings["INFOPLIST_FILE"] = plistPath.byRemovingBase(path: basePath) } + if let bundleIdPrefix = spec.bundleIdPrefix, !spec.targetHasBuildSetting("PRODUCT_BUNDLE_IDENTIFIER", basePath: basePath, target: target, config: config) { + buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] = bundleIdPrefix + "." + target.name + } + // set Carthage search paths if !carthageFrameworks.isEmpty { let frameworkSearchPaths = "FRAMEWORK_SEARCH_PATHS" diff --git a/docs/ProjectSpec.md b/docs/ProjectSpec.md index 817bc526..8a33c7d4 100644 --- a/docs/ProjectSpec.md +++ b/docs/ProjectSpec.md @@ -34,6 +34,7 @@ Required properties are marked 🔵 and optional properties with ⚪️. - ⚪️ **settingGroups**: [Setting Groups](#setting-groups) - Setting groups mapped by name - ⚪️ **targets**: [Target](#target) - The list of targets in the project mapped by name - ⚪️ **fileGroups**: `[String]` - A list of paths to add to the top level groups. These are files that aren't build files but that you'd like in the project hierachy. For example a folder xcconfig files that aren't already added by any target sources. +- ⚪️ **bundleIdPrefix**: `String` - If this is specified then any target that doesn't have an `PRODUCT_BUNDLE_IDENTIFIER` (via all levels of build settings) will get an autogenerated one by combining `bundleIdPrefix` and the target name: `bundleIdPrefix.name` ### Options - ⚪️ **carthageBuildPath**: `String` - The path to the carthage build directory. Defaults to `Carthage/Build`. This is used when specifying target carthage dependencies From c9e8e68bc5540a29df0740991fc6f557c51747f4 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Mon, 25 Sep 2017 15:30:11 +0200 Subject: [PATCH 2/3] move bundleIdPrefix to options --- Fixtures/TestProject/spec.yml | 3 ++- Sources/ProjectSpec/ProjectSpec.swift | 14 ++++++-------- Sources/XcodeGenKit/PBXProjGenerator.swift | 2 +- Tests/XcodeGenKitTests/SpecLoadingTests.swift | 7 +++++-- docs/ProjectSpec.md | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Fixtures/TestProject/spec.yml b/Fixtures/TestProject/spec.yml index a2e2a15e..da59c0a8 100644 --- a/Fixtures/TestProject/spec.yml +++ b/Fixtures/TestProject/spec.yml @@ -1,5 +1,6 @@ name: GeneratedProject -bundleIdPrefix: com.test +options: + bundleIdPrefix: com.test fileGroups: - Configs targets: diff --git a/Sources/ProjectSpec/ProjectSpec.swift b/Sources/ProjectSpec/ProjectSpec.swift index 7114a495..11c477b8 100644 --- a/Sources/ProjectSpec/ProjectSpec.swift +++ b/Sources/ProjectSpec/ProjectSpec.swift @@ -24,17 +24,17 @@ public struct ProjectSpec { public var attributes: [String: Any] public var fileGroups: [String] public var configFiles: [String: String] - public var bundleIdPrefix: String? public struct Options { public var carthageBuildPath: String? + public var bundleIdPrefix: String? + + public init() { - public init(carthageBuildPath: String? = nil) { - self.carthageBuildPath = carthageBuildPath } } - public init(name: String, configs: [Config] = [], targets: [Target] = [], settings: Settings = .empty, settingGroups: [String: Settings] = [:], schemes: [Scheme] = [], options: Options = Options(), fileGroups: [String] = [], configFiles: [String: String] = [:], attributes: [String: Any] = [:], bundleIdPrefix: String? = nil) { + public init(name: String, configs: [Config] = [], targets: [Target] = [], settings: Settings = .empty, settingGroups: [String: Settings] = [:], schemes: [Scheme] = [], options: Options = Options(), fileGroups: [String] = [], configFiles: [String: String] = [:], attributes: [String: Any] = [:]) { self.name = name self.targets = targets self.configs = configs @@ -45,7 +45,6 @@ public struct ProjectSpec { self.fileGroups = fileGroups self.configFiles = configFiles self.attributes = attributes - self.bundleIdPrefix = bundleIdPrefix } public func getTarget(_ targetName: String) -> Target? { @@ -69,8 +68,7 @@ extension ProjectSpec: Equatable { lhs.fileGroups == rhs.fileGroups && lhs.configFiles == rhs.configFiles && lhs.options == rhs.options && - NSDictionary(dictionary: lhs.attributes).isEqual(to: rhs.attributes) && - lhs.bundleIdPrefix == rhs.bundleIdPrefix + NSDictionary(dictionary: lhs.attributes).isEqual(to: rhs.attributes) } } @@ -95,7 +93,6 @@ extension ProjectSpec: JSONObjectConvertible { fileGroups = jsonDictionary.json(atKeyPath: "fileGroups") ?? [] configFiles = jsonDictionary.json(atKeyPath: "configFiles") ?? [:] attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [:] - bundleIdPrefix = jsonDictionary.json(atKeyPath: "bundleIdPrefix") if jsonDictionary["options"] != nil { options = try jsonDictionary.json(atKeyPath: "options") } else { @@ -112,5 +109,6 @@ extension ProjectSpec.Options: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { carthageBuildPath = jsonDictionary.json(atKeyPath: "carthageBuildPath") + bundleIdPrefix = jsonDictionary.json(atKeyPath: "bundleIdPrefix") } } diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index c4010355..7410ac4e 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -180,7 +180,7 @@ public class PBXProjGenerator { buildSettings["INFOPLIST_FILE"] = plistPath.byRemovingBase(path: basePath) } - if let bundleIdPrefix = spec.bundleIdPrefix, !spec.targetHasBuildSetting("PRODUCT_BUNDLE_IDENTIFIER", basePath: basePath, target: target, config: config) { + if let bundleIdPrefix = spec.options.bundleIdPrefix, !spec.targetHasBuildSetting("PRODUCT_BUNDLE_IDENTIFIER", basePath: basePath, target: target, config: config) { buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] = bundleIdPrefix + "." + target.name } diff --git a/Tests/XcodeGenKitTests/SpecLoadingTests.swift b/Tests/XcodeGenKitTests/SpecLoadingTests.swift index 8a10deaf..024eb1c5 100644 --- a/Tests/XcodeGenKitTests/SpecLoadingTests.swift +++ b/Tests/XcodeGenKitTests/SpecLoadingTests.swift @@ -172,8 +172,11 @@ func specLoadingTests() { } $0.it("parses options") { - let expected = ProjectSpec(name: "test", options: .init(carthageBuildPath: "../Carthage/Build")) - let parsedSpec = try getProjectSpec(["options": ["carthageBuildPath": "../Carthage/Build"]]) + var options = ProjectSpec.Options() + options.carthageBuildPath = "../Carthage/Build" + options.bundleIdPrefix = "com.test" + let expected = ProjectSpec(name: "test", options: options) + let parsedSpec = try getProjectSpec(["options": ["carthageBuildPath": "../Carthage/Build", "bundleIdPrefix": "com.test"]]) try expect(parsedSpec) == expected } } diff --git a/docs/ProjectSpec.md b/docs/ProjectSpec.md index 8a33c7d4..046a771f 100644 --- a/docs/ProjectSpec.md +++ b/docs/ProjectSpec.md @@ -34,10 +34,10 @@ Required properties are marked 🔵 and optional properties with ⚪️. - ⚪️ **settingGroups**: [Setting Groups](#setting-groups) - Setting groups mapped by name - ⚪️ **targets**: [Target](#target) - The list of targets in the project mapped by name - ⚪️ **fileGroups**: `[String]` - A list of paths to add to the top level groups. These are files that aren't build files but that you'd like in the project hierachy. For example a folder xcconfig files that aren't already added by any target sources. -- ⚪️ **bundleIdPrefix**: `String` - If this is specified then any target that doesn't have an `PRODUCT_BUNDLE_IDENTIFIER` (via all levels of build settings) will get an autogenerated one by combining `bundleIdPrefix` and the target name: `bundleIdPrefix.name` ### Options - ⚪️ **carthageBuildPath**: `String` - The path to the carthage build directory. Defaults to `Carthage/Build`. This is used when specifying target carthage dependencies +- ⚪️ **bundleIdPrefix**: `String` - If this is specified then any target that doesn't have an `PRODUCT_BUNDLE_IDENTIFIER` (via all levels of build settings) will get an autogenerated one by combining `bundleIdPrefix` and the target name: `bundleIdPrefix.name` ### Configs Each config maps to a build type of either `debug` or `release` which will then apply default build settings. Any value other than `debug` or `release` (for example "none"), will mean no default build settings will be applied. From d20d6b56bf3db10a218983d4a7c32280498cce7e Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Mon, 25 Sep 2017 15:30:28 +0200 Subject: [PATCH 3/3] add bundleIdPrefix tests --- .../ProjectGeneratorTests.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index e416e914..8300ada9 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -26,6 +26,23 @@ func projectGeneratorTests() { let targets = [application, framework] + $0.describe("Options") { + + $0.it("generates bundle id") { + var options = ProjectSpec.Options() + options.bundleIdPrefix = "com.test" + let spec = ProjectSpec(name: "test", targets: [framework], options: options) + let project = try getProject(spec) + guard let target = project.pbxproj.nativeTargets.first, + let buildConfigs = project.pbxproj.configurationLists.getReference(target.buildConfigurationList), + let buildConfigReference = buildConfigs.buildConfigurations.first, + let buildConfig = project.pbxproj.buildConfigurations.getReference(buildConfigReference) else { + throw failure("Build Config not found") + } + try expect(buildConfig.buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] as? String) == "com.test.MyFramework" + } + } + $0.describe("Config") { $0.it("generates config defaults") {