mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2024-11-10 06:14:38 +03:00
add target templates
This commit is contained in:
parent
a43a96075a
commit
c50d1dd157
@ -38,6 +38,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
|
- [ ] **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.
|
- [ ] **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)
|
- [ ] **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`.
|
||||||
|
|
||||||
### Include
|
### Include
|
||||||
|
|
||||||
@ -163,6 +164,7 @@ Settings are merged in the following order: groups, base, configs.
|
|||||||
- `INFOPLIST_FILE`: If it doesn't exist your sources will be searched for `Info.plist` files and the first one found will be used for this setting
|
- `INFOPLIST_FILE`: If it doesn't exist your sources will be searched for `Info.plist` files and the first one found will be used for this setting
|
||||||
- `FRAMEWORK_SEARCH_PATHS`: If carthage dependencies are used, the platform build path will be added to this setting
|
- `FRAMEWORK_SEARCH_PATHS`: If carthage dependencies are used, the platform build path will be added to this setting
|
||||||
- [ ] **dependencies**: **[[Dependency](#dependency)]** - Dependencies for the target
|
- [ ] **dependencies**: **[[Dependency](#dependency)]** - Dependencies for the target
|
||||||
|
- [ ] **templates**: **[String]** - A list of target templates that will be merged in order
|
||||||
- [ ] **transitivelyLinkDependencies**: **Bool** - If this is not specified the value from the project set in [Options](#options)`.transitivelyLinkDependencies` will be used.
|
- [ ] **transitivelyLinkDependencies**: **Bool** - If this is not specified the value from the project set in [Options](#options)`.transitivelyLinkDependencies` will be used.
|
||||||
- [ ] **prebuildScripts**: **[[Build Script](#build-script)]** - Build scripts that run *before* any other build phases
|
- [ ] **prebuildScripts**: **[[Build Script](#build-script)]** - Build scripts that run *before* any other build phases
|
||||||
- [ ] **postbuildScripts**: **[[Build Script](#build-script)]** - Build scripts that run *after* any other build phases
|
- [ ] **postbuildScripts**: **[[Build Script](#build-script)]** - Build scripts that run *after* any other build phases
|
||||||
|
@ -128,6 +128,6 @@ extension Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func filterJSON(jsonDictionary: JSONDictionary) throws -> JSONDictionary {
|
static func filterJSON(jsonDictionary: JSONDictionary) throws -> JSONDictionary {
|
||||||
return try Target.generateCrossPlaformTargets(jsonDictionary: jsonDictionary)
|
return try Target.resolveTargets(jsonDictionary: jsonDictionary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,24 @@ extension Dictionary where Key == String, Value: Any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func merge(dictionary: JSONDictionary, onto base: JSONDictionary) -> JSONDictionary {
|
||||||
|
var merged = base
|
||||||
|
|
||||||
|
for (key, value) in dictionary {
|
||||||
|
if key.hasSuffix(":REPLACE") {
|
||||||
|
let newKey = key.replacingOccurrences(of: ":REPLACE", with: "")
|
||||||
|
merged[newKey] = value
|
||||||
|
} else if let dictionary = value as? JSONDictionary, let base = merged[key] as? JSONDictionary {
|
||||||
|
merged[key] = merge(dictionary: dictionary, onto: base)
|
||||||
|
} else if let array = value as? [Any], let base = merged[key] as? [Any] {
|
||||||
|
merged[key] = base + array
|
||||||
|
} else {
|
||||||
|
merged[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
public func += (lhs: inout BuildSettings, rhs: BuildSettings?) {
|
public func += (lhs: inout BuildSettings, rhs: BuildSettings?) {
|
||||||
guard let rhs = rhs else { return }
|
guard let rhs = rhs else { return }
|
||||||
lhs.merge(rhs)
|
lhs.merge(rhs)
|
||||||
|
@ -45,22 +45,4 @@ extension Project {
|
|||||||
}
|
}
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func merge(dictionary: JSONDictionary, onto base: JSONDictionary) -> JSONDictionary {
|
|
||||||
var merged = base
|
|
||||||
|
|
||||||
for (key, value) in dictionary {
|
|
||||||
if key.hasSuffix(":REPLACE") {
|
|
||||||
let newKey = key.replacingOccurrences(of: ":REPLACE", with: "")
|
|
||||||
merged[newKey] = value
|
|
||||||
} else if let dictionary = value as? JSONDictionary, let base = merged[key] as? JSONDictionary {
|
|
||||||
merged[key] = merge(dictionary: dictionary, onto: base)
|
|
||||||
} else if let array = value as? [Any], let base = merged[key] as? [Any] {
|
|
||||||
merged[key] = base + array
|
|
||||||
} else {
|
|
||||||
merged[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return merged
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -95,11 +95,27 @@ extension Target: CustomStringConvertible {
|
|||||||
|
|
||||||
extension Target {
|
extension Target {
|
||||||
|
|
||||||
static func generateCrossPlaformTargets(jsonDictionary: JSONDictionary) throws -> JSONDictionary {
|
static func resolveTargets(jsonDictionary: JSONDictionary) throws -> JSONDictionary {
|
||||||
guard let targetsDictionary: [String: JSONDictionary] = jsonDictionary["targets"] as? [String: JSONDictionary] else {
|
guard var targetsDictionary: [String: JSONDictionary] = jsonDictionary["targets"] as? [String: JSONDictionary] else {
|
||||||
return jsonDictionary
|
return jsonDictionary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let targetTemplatesDictionary: [String: JSONDictionary] = jsonDictionary["targetTemplates"] as? [String: JSONDictionary] ?? [:]
|
||||||
|
|
||||||
|
for (targetName, var target) in targetsDictionary {
|
||||||
|
|
||||||
|
if let templates = target["templates"] as? [String] {
|
||||||
|
var mergedDictionary: JSONDictionary = [:]
|
||||||
|
for template in templates {
|
||||||
|
if let templateDictionary = targetTemplatesDictionary[template] {
|
||||||
|
mergedDictionary = merge(dictionary: templateDictionary, onto: mergedDictionary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target = merge(dictionary: mergedDictionary, onto: target)
|
||||||
|
}
|
||||||
|
targetsDictionary[targetName] = target
|
||||||
|
}
|
||||||
|
|
||||||
let platformReplacement = "$platform"
|
let platformReplacement = "$platform"
|
||||||
var crossPlatformTargets: [String: JSONDictionary] = [:]
|
var crossPlatformTargets: [String: JSONDictionary] = [:]
|
||||||
|
|
||||||
@ -156,6 +172,7 @@ extension Target {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var merged = jsonDictionary
|
var merged = jsonDictionary
|
||||||
|
|
||||||
merged["targets"] = crossPlatformTargets
|
merged["targets"] = crossPlatformTargets
|
||||||
return merged
|
return merged
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "0930"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "NT_324671077936"
|
||||||
|
BuildableName = "App_watchOS.app"
|
||||||
|
BlueprintName = "App_watchOS"
|
||||||
|
ReferencedContainer = "container:Project.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Production Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "NT_324671077936"
|
||||||
|
BuildableName = "App_watchOS.app"
|
||||||
|
BlueprintName = "App_watchOS"
|
||||||
|
ReferencedContainer = "container:Project.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Production Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "NT_324671077936"
|
||||||
|
BuildableName = "App_watchOS.app"
|
||||||
|
BlueprintName = "App_watchOS"
|
||||||
|
ReferencedContainer = "container:Project.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Production Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "NT_324671077936"
|
||||||
|
BuildableName = "App_watchOS.app"
|
||||||
|
BlueprintName = "App_watchOS"
|
||||||
|
ReferencedContainer = "container:Project.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Production Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Production Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
@ -80,6 +80,7 @@ targets:
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER: com.project.app.watch
|
PRODUCT_BUNDLE_IDENTIFIER: com.project.app.watch
|
||||||
dependencies:
|
dependencies:
|
||||||
- target: App_watchOS Extension
|
- target: App_watchOS Extension
|
||||||
|
templates: [MyTemplate]
|
||||||
|
|
||||||
App_watchOS Extension:
|
App_watchOS Extension:
|
||||||
type: watchkit2-extension
|
type: watchkit2-extension
|
||||||
@ -148,3 +149,6 @@ schemes:
|
|||||||
commandLineArguments:
|
commandLineArguments:
|
||||||
argument: YES
|
argument: YES
|
||||||
argument.with.dot: YES
|
argument.with.dot: YES
|
||||||
|
targetTemplates:
|
||||||
|
MyTemplate:
|
||||||
|
scheme: {}
|
||||||
|
@ -12,6 +12,9 @@ targets:
|
|||||||
NewTarget:
|
NewTarget:
|
||||||
type: application
|
type: application
|
||||||
platform: iOS
|
platform: iOS
|
||||||
|
templates: [IncludedTemplate]
|
||||||
|
sources:
|
||||||
|
- folder1
|
||||||
IncludedTarget:
|
IncludedTarget:
|
||||||
name: IncludedTargetNew
|
name: IncludedTargetNew
|
||||||
platform: tvOS
|
platform: tvOS
|
||||||
|
@ -11,3 +11,7 @@ targets:
|
|||||||
platform: iOS
|
platform: iOS
|
||||||
sources:
|
sources:
|
||||||
- Target
|
- Target
|
||||||
|
targetTemplates:
|
||||||
|
IncludedTemplate:
|
||||||
|
sources:
|
||||||
|
- folder2
|
||||||
|
@ -22,7 +22,7 @@ class SpecLoadingTests: XCTestCase {
|
|||||||
]
|
]
|
||||||
try expect(project.targets) == [
|
try expect(project.targets) == [
|
||||||
Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"]),
|
Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"]),
|
||||||
Target(name: "NewTarget", type: .application, platform: .iOS),
|
Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["folder1", "folder2"]),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +176,26 @@ class SpecLoadingTests: XCTestCase {
|
|||||||
try expect(project.targets) == [target_iOS, target_tvOS]
|
try expect(project.targets) == [target_iOS, target_tvOS]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$0.it("parses target templates") {
|
||||||
|
|
||||||
|
let targetDictionary: [String: Any] = [
|
||||||
|
"type": "framework",
|
||||||
|
"templates": ["temp2", "temp"]
|
||||||
|
]
|
||||||
|
|
||||||
|
let project = try getProjectSpec([
|
||||||
|
"targets": ["Framework": targetDictionary],
|
||||||
|
"targetTemplates": [
|
||||||
|
"temp": ["platform": "iOS"],
|
||||||
|
"temp2": ["platform": "tvOS"],
|
||||||
|
]
|
||||||
|
])
|
||||||
|
|
||||||
|
let target = Target(name: "Framework", type: .framework, platform: .iOS)
|
||||||
|
|
||||||
|
try expect(project.targets.first) == target
|
||||||
|
}
|
||||||
|
|
||||||
$0.it("parses target schemes") {
|
$0.it("parses target schemes") {
|
||||||
var targetDictionary = validTarget
|
var targetDictionary = validTarget
|
||||||
targetDictionary["scheme"] = [
|
targetDictionary["scheme"] = [
|
||||||
|
Loading…
Reference in New Issue
Block a user