Merge pull request #54 from yonaskolb/target_map

Change targets from list to map
This commit is contained in:
Yonas Kolb
2017-09-18 21:51:12 +02:00
committed by GitHub
10 changed files with 71 additions and 64 deletions
@@ -83,7 +83,7 @@
isa = PBXGroup;
children = (
FR7078510801 /* FrameworkFile.swift */,
FR1345298502 /* Info.plist */,
FR1345298501 /* Info.plist */,
FR7740960501 /* MyFramework.h */,
);
name = MyFramework;
@@ -95,7 +95,7 @@
children = (
FR1332263601 /* AppDelegate.swift */,
FR5980633301 /* Assets.xcassets */,
FR1345298501 /* Info.plist */,
FR1345298502 /* Info.plist */,
FR6218091901 /* ViewController.swift */,
VG6405436301 /* LaunchScreen.storyboard */,
VG1473702401 /* Main.storyboard */,
@@ -107,8 +107,8 @@
G84487712001 = {
isa = PBXGroup;
children = (
G65232631501 /* TestProject */,
G29934978701 /* MyFramework */,
G65232631501 /* TestProject */,
G26536595301 /* TestProjectTests */,
G86202385201 /* Products */,
);
@@ -223,8 +223,8 @@
);
mainGroup = G84487712001;
targets = (
NT6523263101 /* TestProject */,
NT2993497801 /* MyFramework */,
NT6523263101 /* TestProject */,
NT2653659501 /* TestProjectTests */,
);
};
+3 -3
View File
@@ -1,6 +1,6 @@
name: GeneratedProject
targets:
- name: TestProject
TestProject:
type: application
platform: iOS
sources: TestProject
@@ -23,7 +23,7 @@ targets:
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
- name: MyFramework
MyFramework:
type: framework
platform: iOS
sources: MyFramework
@@ -32,7 +32,7 @@ targets:
postbuildScripts:
- name: Swiftlint
path: scripts/swiftlint.sh
- name: TestProjectTests
TestProjectTests:
type: bundle.unit-test
platform: iOS
sources: TestProjectTests
+5 -1
View File
@@ -7,6 +7,10 @@ settingGroups:
new:
MY_SETTING: VALUE
targets:
- name: NewTarget
NewTarget:
type: application
platform: iOS
IncludedTarget:
name: IncludedTargetNew
platform: tvOS
sources: Target
+1 -1
View File
@@ -4,6 +4,6 @@ settingGroups:
MY_SETTING1: VALUE1
MY_SETTING2: VALUE2
targets:
- name: IncludedTarget
IncludedTarget:
type: application
platform: iOS
+1 -1
View File
@@ -68,7 +68,7 @@ configs:
config1: debug
config2: release
targets:
- name: Target
Target:
type: application
platform: iOS
settings:
+2 -2
View File
@@ -38,7 +38,7 @@ Given a very simple project spec file like this:
```yaml
name: My Project
targets:
- name: MyApp
MyApp:
type: application
platform: iOS
sources: MyApp
@@ -46,7 +46,7 @@ targets:
PRODUCT_BUNDLE_IDENTIFIER: com.myapp
dependencies:
- target: MyFramework
- name: MyFramework
MyFramework:
type: framework
platform: iOS
sources: MyFramework
+6 -1
View File
@@ -74,12 +74,13 @@ extension ProjectSpec.Options: Equatable {
extension ProjectSpec: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
let jsonDictionary = try ProjectSpec.filterJSON(jsonDictionary: jsonDictionary)
name = try jsonDictionary.json(atKeyPath: "name")
settings = jsonDictionary.json(atKeyPath: "settings") ?? .empty
settingGroups = jsonDictionary.json(atKeyPath: "settingGroups") ?? jsonDictionary.json(atKeyPath: "settingPresets") ?? [:]
let configs: [String: String] = jsonDictionary.json(atKeyPath: "configs") ?? [:]
self.configs = configs.map { Config(name: $0, type: ConfigType(rawValue: $1)) }
targets = try Target.decodeTargets(jsonDictionary: jsonDictionary)
targets = try jsonDictionary.json(atKeyPath: "targets").sorted { $0.name < $1.name }
schemes = try jsonDictionary.json(atKeyPath: "schemes")
attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [:]
if jsonDictionary["options"] != nil {
@@ -88,6 +89,10 @@ extension ProjectSpec: JSONObjectConvertible {
options = Options()
}
}
static func filterJSON(jsonDictionary: JSONDictionary) throws -> JSONDictionary {
return try Target.generateCrossPlaformTargets(jsonDictionary: jsonDictionary)
}
}
extension ProjectSpec.Options: JSONObjectConvertible {
+18 -21
View File
@@ -48,22 +48,20 @@ public struct Target {
extension Target {
static func decodeTargets(jsonDictionary: JSONDictionary) throws -> [Target] {
guard jsonDictionary["targets"] != nil else {
return []
static func generateCrossPlaformTargets(jsonDictionary: JSONDictionary) throws -> JSONDictionary {
guard let targetsDictionary: [String: JSONDictionary] = jsonDictionary["targets"] as? [String: JSONDictionary] else {
return jsonDictionary
}
let array: [JSONDictionary] = try jsonDictionary.json(atKeyPath: "targets", invalidItemBehaviour: .fail)
var targets: [JSONDictionary] = []
let platformReplacement = "$platform"
var crossPlatformTargets: [String: JSONDictionary] = [:]
for json in array {
for (targetName, target) in targetsDictionary {
if let platforms = json["platform"] as? [String] {
if let platforms = target["platform"] as? [String] {
for platform in platforms {
var platformTarget = json
var platformTarget = target
func replacePlatform(_ dictionary: JSONDictionary) -> JSONDictionary {
var replaced = dictionary
@@ -88,31 +86,30 @@ extension Target {
platformTarget["platform"] = platform
let platformSuffix = platformTarget["platformSuffix"] as? String ?? "_\(platform)"
let platformPrefix = platformTarget["platformPrefix"] as? String ?? ""
let name = platformTarget["name"] as? String ?? ""
platformTarget["name"] = platformPrefix + name + platformSuffix
let newTargetName = platformPrefix + targetName + platformSuffix
var settings = platformTarget["settings"] as? JSONDictionary ?? [:]
if settings["configs"] != nil || settings["groups"] != nil || settings["base"] != nil {
var base = settings["base"] as? JSONDictionary ?? [:]
if base["PRODUCT_NAME"] == nil {
base["PRODUCT_NAME"] = name
base["PRODUCT_NAME"] = targetName
}
settings["base"] = base
} else {
if settings["PRODUCT_NAME"] == nil {
settings["PRODUCT_NAME"] = name
settings["PRODUCT_NAME"] = targetName
}
}
platformTarget["settings"] = settings
targets.append(platformTarget)
crossPlatformTargets[newTargetName] = platformTarget
}
} else {
targets.append(json)
crossPlatformTargets[targetName] = target
}
}
return try targets.map { try Target(jsonDictionary: $0) }
var merged = jsonDictionary
merged["targets"] = crossPlatformTargets
return merged
}
}
@@ -159,10 +156,10 @@ extension TargetScheme: JSONObjectConvertible {
}
}
extension Target: JSONObjectConvertible {
extension Target: NamedJSONDictionaryConvertible {
public init(jsonDictionary: JSONDictionary) throws {
name = try jsonDictionary.json(atKeyPath: "name")
public init(name: String, jsonDictionary: JSONDictionary) throws {
self.name = jsonDictionary.json(atKeyPath: "name") ?? name
let typeString: String = try jsonDictionary.json(atKeyPath: "type")
if let type = PBXProductType(string: typeString) {
self.type = type
@@ -23,11 +23,11 @@ func specLoadingTests() {
func expectTargetError(_ target: [String: Any], _ expectedError: ProjectSpecError) throws {
try expectError(expectedError) {
_ = try Target(jsonDictionary: target)
_ = try Target(name: "test", jsonDictionary: target)
}
}
let validTarget: [String: Any] = ["name": "test", "type": "application", "platform": "iOS"]
let validTarget: [String: Any] = ["type": "application", "platform": "iOS"]
let invalid = "invalid"
describe("Spec Loader") {
@@ -41,7 +41,7 @@ func specLoadingTests() {
"new": Settings(dictionary: ["MY_SETTING": "VALUE"]),
]
try expect(spec.targets) == [
Target(name: "IncludedTarget", type: .application, platform: .iOS),
Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["Target"]),
Target(name: "NewTarget", type: .application, platform: .iOS),
]
}
@@ -74,7 +74,7 @@ func specLoadingTests() {
["carthage": "name"],
["framework": "path"],
]
let target = try Target(jsonDictionary: targetDictionary)
let target = try Target(name: "test", jsonDictionary: targetDictionary)
try expect(target.dependencies.count) == 3
try expect(target.dependencies[0]) == Dependency(type: .target, reference: "name", embed: false)
try expect(target.dependencies[1]) == Dependency(type: .carthage, reference: "name")
@@ -83,14 +83,13 @@ func specLoadingTests() {
$0.it("parsed cross platform targets") {
let targetDictionary: [String: Any] = [
"name": "Framework",
"platform": ["iOS", "tvOS"],
"type": "framework",
"sources": ["Framework", "Framework $platform"],
"settings": ["SETTING": "value_$platform"],
]
let spec = try getProjectSpec(["targets": [targetDictionary]])
let spec = try getProjectSpec(["targets": ["Framework": targetDictionary]])
var target_iOS = Target(name: "Framework_iOS", type: .framework, platform: .iOS)
var target_tvOS = Target(name: "Framework_tvOS", type: .framework, platform: .tvOS)
@@ -167,7 +166,7 @@ func specLoadingTests() {
BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: true),
]
let parsedTarget = try Target(jsonDictionary: target)
let parsedTarget = try Target(name: "test", jsonDictionary: target)
try expect(parsedTarget.prebuildScripts) == expectedScripts
try expect(parsedTarget.postbuildScripts) == expectedScripts
}
+25 -23
View File
@@ -25,13 +25,13 @@ Required properties are marked 🔵 and optional properties with ⚪️.
## Project
- 🔵 **name**: `String` - Name of the generated project
- ⚪️ **include**: `[String]` - The paths to other specs. They will be merged in order and then the current spec will be merged on top
- ⚪️ **include**: `[String]` - The paths to other specs. They will be merged in order and then the current spec will be merged on top. Target names can be changed by adding a `name` property
- ⚪️ **options**: [Options](#options) - Various options to override default behaviour
- ⚪️ **attributes**: `map` - The PBXProject attributes. This is for advanced use. Defaults to ``{"LastUpgradeCheck": "0830"}``
- ⚪️ **configs**: [Configs](#configs) - Project build configurations. Defaults to `Debug` and `Release` configs
- ⚪️ **settings**: [Settings](#settings) - Project specific settings. Default base and config type settings will be applied first before any settings defined here
- ⚪️ **settingGroups**: [Setting Groups](#setting-groups) - Setting groups mapped by name
- ⚪️ **targets**: [[Target](#target)] - The list of targets in the project
- ⚪️ **targets**: [String: [Target](#target)] - The list of targets in the project mapped by name
### Options
- ⚪️ **carthageBuildPath**: `String` - The path to the carthage build directory. Defaults to `Carthage/Build`. This is used when specifying target carthage dependencies
@@ -94,7 +94,6 @@ Settings are merged in the following order: groups, base, configs.
## Target
- 🔵 **name**: `String` - Name of the target
- 🔵 **type**: [Product Type](#product-type) - Product type of the target
- 🔵 **platform**: [Platform](#platform) - Platform of the target
- ⚪️ **sources**: [Sources](#sources) - Source directories of the target
@@ -146,18 +145,19 @@ The generated targets by default will have a suffix of `_$platform` applied, you
If no `PRODUCT_NAME` build setting is specified for a target, this will be set to the target name, so that this target can be imported under a single name.
```
name: MyFramework
sources: MyFramework
platform: [iOS, tvOS]
type: framework
settings:
base:
INFOPLIST_FILE: MyApp/Info.plist
PRODUCT_BUNDLE_IDENTIFIER: com.myapp
MY_SETTING: platform $platform
groups:
- $platform
```yaml
targets:
MyFramework:
sources: MyFramework
platform: [iOS, tvOS]
type: framework
settings:
base:
INFOPLIST_FILE: MyApp/Info.plist
PRODUCT_BUNDLE_IDENTIFIER: com.myapp
MY_SETTING: platform $platform
groups:
- $platform
```
The above will generate 2 targets named `MyFramework_iOS` and `MyFramework_tvOS`, with all the relevant platform build settings. They will both have a `PRODUCT_NAME` of `MyFramework`
@@ -166,9 +166,9 @@ Specifies the source directories for a target. This can either be a single path
```yaml
targets:
- name: MyTarget
MyTarget
sources: MyTargetSource
- name: MyOtherTarget
MyOtherTarget
sources:
- MyOtherTargetSource1
- MyOtherTargetSource2
@@ -201,12 +201,13 @@ If any applications contain carthage dependencies within itself or any dependent
```yaml
targets:
- name: MyTarget
MyTarget:
dependencies:
- target: MyFramework
- framework: path/to/framework.framework
- carthage: Result
- name: MyFramework
MyFramework:
type: framework
```
### Config Files
@@ -214,7 +215,7 @@ Specifies `.xcconfig` files for each configuration.
```yaml
targets:
- name: MyTarget
MyTarget:
configFiles:
Debug: config_files/debug.xcconfig
Release: config_files/release.xcconfig
@@ -237,7 +238,7 @@ A multiline script can be written using the various YAML multiline methods, for
```yaml
targets:
- name: MyTarget
MyTarget:
prebuildScripts:
- path: myscripts/my_script.sh
name: My Script
@@ -279,7 +280,7 @@ configs:
Staging Release: release
Production Release: release
targets
- name: MyApp
MyApp:
scheme:
testTargets:
- MyUnitTests
@@ -287,5 +288,6 @@ targets
- Test
- Staging
- Production
- name: MyUnitTests
MyUnitTests:
sources: Tests
```