mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2024-09-19 08:37:53 +03:00
Add support for nested templates
It would be convenient if templates could be nested, which means a template can be based on another template. This change implements support for nested templates. It avoids cycles by just ignoring templates that have already been visited when collecting the set of templates to use.
This commit is contained in:
parent
f32673af70
commit
0c2554db2b
@ -6,6 +6,7 @@
|
||||
- Added `missingConfigFiles` to `options.disabledValidations` to optionally skip checking for the existence of config files.
|
||||
- Added ability to automatically include Carthage related dependencies via `includeRelated: true` [#506](https://github.com/yonaskolb/XcodeGen/pull/506) @rpassis
|
||||
- Added ability to define a per-platform `deploymentTarget` for Multi-Platform targets. [#510](https://github.com/yonaskolb/XcodeGen/pull/510) @ainopara
|
||||
- Added support for nested target templates [#534](https://github.com/yonaskolb/XcodeGen/pull/534) @tomquist
|
||||
|
||||
#### Fixed
|
||||
- Sources outside a project spec's directory will be correctly referenced as relative paths in the project file. [#524](https://github.com/yonaskolb/XcodeGen/pull/524)
|
||||
|
@ -139,9 +139,28 @@ extension Target {
|
||||
|
||||
let targetTemplatesDictionary: [String: JSONDictionary] = jsonDictionary["targetTemplates"] as? [String: JSONDictionary] ?? [:]
|
||||
|
||||
for (targetName, var target) in targetsDictionary {
|
||||
// Recursively collects all nested template names of a given dictionary.
|
||||
func collectTemplates(of jsonDictionary: JSONDictionary,
|
||||
into allTemplates: inout [String],
|
||||
insertAt insertionIndex: inout Int) {
|
||||
guard let templates = jsonDictionary["templates"] as? [String] else {
|
||||
return
|
||||
}
|
||||
for template in templates where !allTemplates.contains(template) {
|
||||
guard let templateDictionary = targetTemplatesDictionary[template] else {
|
||||
continue
|
||||
}
|
||||
allTemplates.insert(template, at: insertionIndex)
|
||||
collectTemplates(of: templateDictionary, into: &allTemplates, insertAt: &insertionIndex)
|
||||
insertionIndex += 1
|
||||
}
|
||||
}
|
||||
|
||||
if let templates = target["templates"] as? [String] {
|
||||
for (targetName, var target) in targetsDictionary {
|
||||
var templates: [String] = []
|
||||
var index: Int = 0
|
||||
collectTemplates(of: target, into: &templates, insertAt: &index)
|
||||
if !templates.isEmpty {
|
||||
var mergedDictionary: JSONDictionary = [:]
|
||||
for template in templates {
|
||||
if let templateDictionary = targetTemplatesDictionary[template] {
|
||||
|
@ -363,6 +363,127 @@ class SpecLoadingTests: XCTestCase {
|
||||
try expect(target.configFiles["debug"]) == "Configs/Framework/debug.xcconfig" // replaces $target_name
|
||||
}
|
||||
|
||||
$0.it("parses nested target templates") {
|
||||
|
||||
let targetDictionary: [String: Any] = [
|
||||
"deploymentTarget": "1.2.0",
|
||||
"sources": ["targetSource"],
|
||||
"templates": ["temp2"],
|
||||
]
|
||||
|
||||
let project = try getProjectSpec([
|
||||
"targets": ["Framework": targetDictionary],
|
||||
"targetTemplates": [
|
||||
"temp": [
|
||||
"type": "framework",
|
||||
"platform": "iOS",
|
||||
"sources": ["nestedTemplateSource1"],
|
||||
],
|
||||
"temp1": [
|
||||
"type": "application",
|
||||
"sources": ["nestedTemplateSource2"],
|
||||
],
|
||||
"temp2": [
|
||||
"platform": "tvOS",
|
||||
"deploymentTarget": "1.1.0",
|
||||
"configFiles": ["debug": "Configs/$target_name/debug.xcconfig"],
|
||||
"templates": ["temp", "temp1"],
|
||||
"sources": ["templateSource"],
|
||||
]
|
||||
],
|
||||
])
|
||||
|
||||
let target = project.targets.first!
|
||||
try expect(target.type) == .application // uses value of last nested template
|
||||
try expect(target.platform) == .tvOS // uses latest value
|
||||
try expect(target.deploymentTarget) == Version("1.2.0") // keeps value
|
||||
try expect(target.sources) == ["nestedTemplateSource1", "nestedTemplateSource2", "templateSource", "targetSource"] // merges array in order
|
||||
try expect(target.configFiles["debug"]) == "Configs/Framework/debug.xcconfig" // replaces $target_name
|
||||
}
|
||||
|
||||
$0.it("parses complex nested target templates") {
|
||||
|
||||
let targetDictionary: [String: Any] = [
|
||||
"type": "framework",
|
||||
"platform": "iOS",
|
||||
"templates": ["temp"],
|
||||
"sources": ["target"],
|
||||
]
|
||||
|
||||
let project = try getProjectSpec([
|
||||
"targets": ["Framework": targetDictionary],
|
||||
"targetTemplates": [
|
||||
"temp": [
|
||||
"templates": ["a", "d"],
|
||||
"sources": ["temp"],
|
||||
],
|
||||
"a": [
|
||||
"templates": ["b", "c"],
|
||||
"sources": ["a"],
|
||||
],
|
||||
"b": [
|
||||
"sources": ["b"],
|
||||
],
|
||||
"c": [
|
||||
"sources": ["c"],
|
||||
],
|
||||
"d": [
|
||||
"sources": ["d"],
|
||||
"templates": ["e"],
|
||||
],
|
||||
"e": [
|
||||
"sources": ["e"],
|
||||
],
|
||||
|
||||
],
|
||||
])
|
||||
|
||||
let target = project.targets.first!
|
||||
try expect(target.type) == .framework // uses value of last nested template
|
||||
try expect(target.platform) == .iOS // uses latest value
|
||||
try expect(target.sources) == ["b", "c", "a", "e", "d", "temp", "target"] // merges array in order
|
||||
}
|
||||
|
||||
$0.it("parses nested target templates with cycle") {
|
||||
|
||||
let targetDictionary: [String: Any] = [
|
||||
"deploymentTarget": "1.2.0",
|
||||
"sources": ["targetSource"],
|
||||
"templates": ["temp2"],
|
||||
]
|
||||
|
||||
let project = try getProjectSpec([
|
||||
"targets": ["Framework": targetDictionary],
|
||||
"targetTemplates": [
|
||||
"temp": [
|
||||
"type": "framework",
|
||||
"platform": "iOS",
|
||||
"templates": ["temp1"],
|
||||
"sources": ["nestedTemplateSource1"],
|
||||
],
|
||||
"temp1": [
|
||||
"platform": "macOS",
|
||||
"templates": ["temp2"],
|
||||
"sources": ["nestedTemplateSource2"],
|
||||
],
|
||||
"temp2": [
|
||||
"platform": "tvOS",
|
||||
"deploymentTarget": "1.1.0",
|
||||
"configFiles": ["debug": "Configs/$target_name/debug.xcconfig"],
|
||||
"templates": ["temp", "temp1"],
|
||||
"sources": ["templateSource"],
|
||||
]
|
||||
],
|
||||
])
|
||||
|
||||
let target = project.targets.first!
|
||||
try expect(target.type) == .framework // uses value
|
||||
try expect(target.platform) == .tvOS // uses latest value
|
||||
try expect(target.deploymentTarget) == Version("1.2.0") // keeps value
|
||||
try expect(target.sources) == ["nestedTemplateSource2", "nestedTemplateSource1", "templateSource", "targetSource"] // merges array in order
|
||||
try expect(target.configFiles["debug"]) == "Configs/Framework/debug.xcconfig" // replaces $target_name
|
||||
}
|
||||
|
||||
$0.it("parses aggregate targets") {
|
||||
let dictionary: [String: Any] = [
|
||||
"targets": ["target_1", "target_2"],
|
||||
|
Loading…
Reference in New Issue
Block a user