From 6f4c7d79acd7a0ab1557211da9fbeac78fd57251 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Mon, 28 Jan 2019 15:54:56 +1100 Subject: [PATCH 1/2] replace $target_name in target templates --- Docs/ProjectSpec.md | 26 +++++++++++++++++-- Sources/ProjectSpec/Project.swift | 2 +- Sources/ProjectSpec/Spec.swift | 18 +++++++++++++ Sources/ProjectSpec/Target.swift | 22 ++-------------- Tests/XcodeGenKitTests/SpecLoadingTests.swift | 2 ++ 5 files changed, 47 insertions(+), 23 deletions(-) diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index 594f06aef..3dbfbf4b6 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -24,6 +24,7 @@ Required properties are marked with checkbox. Some of the YAML examples don't sh - [Target Scheme](#target-scheme) - [Legacy Target](#legacy-target) - [Aggregate Target](#aggregate-target) +- [Target Template](#target-template) - [Scheme](#scheme) ## Project @@ -39,7 +40,7 @@ Required properties are marked with checkbox. Some of the YAML examples don't sh - [ ] **targets**: **[String: [Target](#target)]** - The list of targets in the project mapped by name - [ ] **fileGroups**: **[String]** - A list of paths to add to the root of the project. These aren't files that will be included in your targets, but that you'd like to include in the project hierachy anyway. For example a folder of xcconfig files that aren't already added by any target sources, or a Readme file. - [ ] **schemes**: **[Scheme](#scheme)** - A list of schemes by name. This allows more control over what is found in [Target Scheme](#target-scheme) -- [ ] **targetTemplates**: **[String: [Target](#target)]** - a list of targets that can be used as templates for actual targets which reference them via a `template` property. They can be used to extract common target settings. Works great in combination with `include`. +- [ ] **targetTemplates**: **[String: [Target Template](#target-template)]** - a list of targets that can be used as templates for actual targets which reference them via a `template` property. They can be used to extract common target settings. Works great in combination with `include`. ### Include @@ -200,7 +201,7 @@ Settings are merged in the following order: groups, base, configs. - `CFBundleVersion` - `CFBundlePackageType` - [ ] **entitlements**: **[Plist](#plist)** - If defined this will generate and write a `.entitlements` file, and use it by setting `CODE_SIGN_ENTITLEMENTS` build setting for every configuration. All properties must be provided -- [ ] **templates**: **[String]** - A list of target templates that will be merged in order +- [ ] **templates**: **[String]** - A list of [Target Templates](#target-template) referenced by name that will be merged with the target in order. Any instances of `$target_name` within these templates will be replaced with the target name. - [ ] **transitivelyLinkDependencies**: **Bool** - If this is not specified the value from the project set in [Options](#options)`.transitivelyLinkDependencies` will be used. - [ ] **directlyEmbedCarthageDependencies**: **Bool** - If this is `true` Carthage dependencies will be embedded using an `Embed Frameworks` build phase instead of the `copy-frameworks` script. Defaults to `true` for all targets except iOS/tvOS/watchOS Applications. - [ ] **requiresObjCLinking**: **Bool** - If this is `true` any targets that link to this target will have `-ObjC` added to their `OTHER_LDFLAGS`. This is required if a static library has any catagories or extensions on Objective-C code. See [this guide](https://pewpewthespells.com/blog/objc_linker_flags.html#objc) for more details. Defaults to `true` if `type` is `library.static`. If you are 100% sure you don't have catagories or extensions on Objective-C code (pure Swift with no use of Foundation/UIKit) you can set this to `false`, otherwise it's best to leave it alone. @@ -554,6 +555,27 @@ This is used to override settings or run build scripts in specific targets - [ ] **scheme**: **[Target Scheme](#target-scheme)** - Generated scheme - [ ] **attributes**: **[String: Any]** - This sets values in the project `TargetAttributes`. It is merged with `attributes` from the project and anything automatically added by XcodeGen, with any duplicate values being override by values specified here +## Target Template + +This is a template that can be referenced from a normal target using the `templates` property. The properties of this template are the same as a [Target](#target)]. +Any instances of `$target_name` within each template will be replaced by the final target name which references the template. + + +```yaml +targets: + MyFramework: + templates: + - Framework + sources: + - SomeSources +targetTemplates: + Framework: + platform: iOS + type: framework + sources: + - $target_name/Sources +``` + ## Scheme Schemes allows for more control than the convenience [Target Scheme](#target-scheme) on [Target](#target) diff --git a/Sources/ProjectSpec/Project.swift b/Sources/ProjectSpec/Project.swift index c2c11b0f0..ca23a9130 100644 --- a/Sources/ProjectSpec/Project.swift +++ b/Sources/ProjectSpec/Project.swift @@ -168,8 +168,8 @@ extension Project { static func resolveProject(jsonDictionary: JSONDictionary) throws -> JSONDictionary { var jsonDictionary = jsonDictionary - jsonDictionary = try Target.resolveTargetTemplates(jsonDictionary: jsonDictionary) jsonDictionary = try Target.resolveMultiplatformTargets(jsonDictionary: jsonDictionary) + jsonDictionary = try Target.resolveTargetTemplates(jsonDictionary: jsonDictionary) return jsonDictionary } } diff --git a/Sources/ProjectSpec/Spec.swift b/Sources/ProjectSpec/Spec.swift index 10f2c4156..dd53ad026 100644 --- a/Sources/ProjectSpec/Spec.swift +++ b/Sources/ProjectSpec/Spec.swift @@ -108,4 +108,22 @@ extension Dictionary where Key == String, Value: Any { } return merged } + + func replaceString(_ template: String, with replacement: String) -> JSONDictionary { + var replaced: JSONDictionary = self + for (key, value) in self { + switch value { + case let dictionary as JSONDictionary: + replaced[key] = dictionary.replaceString(template, with: replacement) + case let string as String: + replaced[key] = string.replacingOccurrences(of: template, with: replacement) + case let array as [JSONDictionary]: + replaced[key] = array.map { $0.replaceString(template, with: replacement) } + case let array as [String]: + replaced[key] = array.map { $0.replacingOccurrences(of: template, with: replacement) } + default: break + } + } + return replaced + } } diff --git a/Sources/ProjectSpec/Target.swift b/Sources/ProjectSpec/Target.swift index 0a9b748f6..c9f4d5726 100644 --- a/Sources/ProjectSpec/Target.swift +++ b/Sources/ProjectSpec/Target.swift @@ -149,6 +149,7 @@ extension Target { } } target = target.merged(onto: mergedDictionary) + target = target.replaceString("$target_name", with: targetName) } targetsDictionary[targetName] = target } @@ -163,7 +164,6 @@ extension Target { return jsonDictionary } - let platformReplacement = "$platform" var crossPlatformTargets: [String: JSONDictionary] = [:] for (targetName, target) in targetsDictionary { @@ -173,25 +173,7 @@ extension Target { for platform in platforms { var platformTarget = target - func replacePlatform(_ dictionary: JSONDictionary) -> JSONDictionary { - var replaced = dictionary - for (key, value) in dictionary { - switch value { - case let dictionary as JSONDictionary: - replaced[key] = replacePlatform(dictionary) - case let string as String: - replaced[key] = string.replacingOccurrences(of: platformReplacement, with: platform) - case let array as [JSONDictionary]: - replaced[key] = array.map(replacePlatform) - case let array as [String]: - replaced[key] = array.map { $0.replacingOccurrences(of: platformReplacement, with: platform) } - default: break - } - } - return replaced - } - - platformTarget = replacePlatform(platformTarget) + platformTarget = platformTarget.replaceString("$platform", with: platform) platformTarget["platform"] = platform let platformSuffix = platformTarget["platformSuffix"] as? String ?? "_\(platform)" diff --git a/Tests/XcodeGenKitTests/SpecLoadingTests.swift b/Tests/XcodeGenKitTests/SpecLoadingTests.swift index 3401adab5..f0ddd865d 100644 --- a/Tests/XcodeGenKitTests/SpecLoadingTests.swift +++ b/Tests/XcodeGenKitTests/SpecLoadingTests.swift @@ -347,6 +347,7 @@ class SpecLoadingTests: XCTestCase { "type": "framework", "platform": "tvOS", "deploymentTarget": "1.1.0", + "configFiles": ["debug": "Configs/$target_name/debug.xcconfig"] ], ], ]) @@ -356,6 +357,7 @@ class SpecLoadingTests: XCTestCase { try expect(target.platform) == .iOS // uses latest value try expect(target.deploymentTarget) == Version("1.2.0") // keeps value try expect(target.sources) == ["templateSource", "targetSource"] // merges array in order + try expect(target.configFiles["debug"]) == "Configs/Framework/debug.xcconfig" // replaces $target_name } $0.it("parses aggregate targets") { From a8c12a7f08b5773b3e2aa4c06da4101bf679d6af Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Mon, 28 Jan 2019 15:58:45 +1100 Subject: [PATCH 2/2] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cacd434f5..9c79ebbe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Added ability to generate empty directories via `options.generateEmptyDirectories` [#480](https://github.com/yonaskolb/XcodeGen/pull/480) @Beniamiiin - Added support for the `instrumentsPackage` product type [#482](https://github.com/yonaskolb/XcodeGen/pull/482) @ksulliva - Added support for `inputFileLists` and `outputFileLists` within project build scripts [#500](https://github.com/yonaskolb/XcodeGen/pull/500) @lukewakeford +- Added support for a `$target_name` replacement string within target templates [#504](https://github.com/yonaskolb/XcodeGen/pull/504) @yonaskolb #### Changed - **BREAKING**: All the paths within `include` files are now relative to that file and not the root spec. This can be disabled with a `relativePaths: false` on the include. See the [documentation](https://github.com/yonaskolb/XcodeGen/blob/master/Docs/ProjectSpec.md#include) for more details [#489](https://github.com/yonaskolb/XcodeGen/pull/489) @ellneal