mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
+6
-6
@@ -42,8 +42,8 @@
|
||||
"repositoryURL": "https://github.com/onevcat/Rainbow.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f407235c7e473c3cb2d2907bb6822616d22a0b78",
|
||||
"version": "3.0.3"
|
||||
"revision": "f69961599ad524251d677fbec9e4bac57385d6fc",
|
||||
"version": "3.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -51,8 +51,8 @@
|
||||
"repositoryURL": "https://github.com/JohnSundell/ShellOut.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "479a89d9bfa7585496bd4a3e4faffac5b01af37f",
|
||||
"version": "2.0.0"
|
||||
"revision": "f1c253a34a40df4bfd268b09fdb101b059f6d52d",
|
||||
"version": "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -78,8 +78,8 @@
|
||||
"repositoryURL": "https://github.com/xcodeswift/xcproj.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "1b0864a4417efc35c21fdc7d98d3c9bb0152eaf9",
|
||||
"version": "1.8.0"
|
||||
"revision": "5f68ad74627a537cdd3d022644edd0fa7a80d4a7",
|
||||
"version": "4.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ let package = Package(
|
||||
.package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "3.3.0"),
|
||||
.package(url: "https://github.com/kylef/Spectre.git", from: "0.8.0"),
|
||||
.package(url: "https://github.com/onevcat/Rainbow.git", from: "3.0.0"),
|
||||
.package(url: "https://github.com/xcodeswift/xcproj.git", from: "1.7.0")
|
||||
.package(url: "https://github.com/xcodeswift/xcproj.git", from: "4.0.0")
|
||||
],
|
||||
targets: [
|
||||
.target(name: "XcodeGen", dependencies: [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct Config: Equatable {
|
||||
public var name: String
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct Dependency: Equatable {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct DeploymentTarget: Equatable {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import xcproj
|
||||
import Yams
|
||||
|
||||
public struct ProjectSpec {
|
||||
@@ -27,8 +27,8 @@ public struct ProjectSpec {
|
||||
public var disabledValidations: [ValidationType]
|
||||
public var developmentLanguage: String?
|
||||
public var usesTabs: Bool?
|
||||
public var tabWidth: Int?
|
||||
public var indentWidth: Int?
|
||||
public var tabWidth: UInt?
|
||||
public var indentWidth: UInt?
|
||||
public var xcodeVersion: String?
|
||||
public var deploymentTarget: DeploymentTarget
|
||||
|
||||
@@ -59,8 +59,8 @@ public struct ProjectSpec {
|
||||
bundleIdPrefix: String? = nil,
|
||||
settingPresets: SettingPresets = .all,
|
||||
developmentLanguage: String? = nil,
|
||||
indentWidth: Int? = nil,
|
||||
tabWidth: Int? = nil,
|
||||
indentWidth: UInt? = nil,
|
||||
tabWidth: UInt? = nil,
|
||||
usesTabs: Bool? = nil,
|
||||
xcodeVersion: String? = nil,
|
||||
deploymentTarget: DeploymentTarget = .init(),
|
||||
@@ -208,8 +208,8 @@ extension ProjectSpec.Options: JSONObjectConvertible {
|
||||
createIntermediateGroups = jsonDictionary.json(atKeyPath: "createIntermediateGroups") ?? false
|
||||
developmentLanguage = jsonDictionary.json(atKeyPath: "developmentLanguage")
|
||||
usesTabs = jsonDictionary.json(atKeyPath: "usesTabs")
|
||||
indentWidth = jsonDictionary.json(atKeyPath: "indentWidth")
|
||||
tabWidth = jsonDictionary.json(atKeyPath: "tabWidth")
|
||||
indentWidth = (jsonDictionary.json(atKeyPath: "indentWidth") as Int?).flatMap(UInt.init)
|
||||
tabWidth = (jsonDictionary.json(atKeyPath: "tabWidth") as Int?).flatMap(UInt.init)
|
||||
deploymentTarget = jsonDictionary.json(atKeyPath: "deploymentTarget") ?? DeploymentTarget()
|
||||
disabledValidations = jsonDictionary.json(atKeyPath: "disabledValidations") ?? []
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public typealias BuildType = XCScheme.BuildAction.Entry.BuildFor
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
import PathKit
|
||||
import xcproj
|
||||
|
||||
public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertible {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import Yams
|
||||
import JSONUtilities
|
||||
|
||||
extension ProjectSpec {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct LegacyTarget {
|
||||
public var toolPath: String
|
||||
@@ -37,7 +37,6 @@ public struct Target {
|
||||
return legacy != nil
|
||||
}
|
||||
|
||||
|
||||
public var filename: String {
|
||||
var filename = productName ?? name
|
||||
if let fileExtension = type.fileExtension {
|
||||
@@ -219,7 +218,7 @@ extension Target: NamedJSONDictionaryConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = jsonDictionary.json(atKeyPath: "name") ?? name
|
||||
self.productName = jsonDictionary.json(atKeyPath: "productName")
|
||||
productName = jsonDictionary.json(atKeyPath: "productName")
|
||||
let typeString: String = try jsonDictionary.json(atKeyPath: "type")
|
||||
if let type = PBXProductType(string: typeString) {
|
||||
self.type = type
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import PathKit
|
||||
import xcproj
|
||||
|
||||
extension PBXProductType {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import Yams
|
||||
import PathKit
|
||||
import Yams
|
||||
|
||||
public func loadYamlDictionary(path: Path) throws -> [String: Any] {
|
||||
let string: String = try path.read()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import Commander
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import ProjectSpec
|
||||
import JSONUtilities
|
||||
|
||||
let version = "1.5.0"
|
||||
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import xcproj
|
||||
import JSONUtilities
|
||||
import Yams
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import Yams
|
||||
|
||||
public class PBXProjGenerator {
|
||||
|
||||
let spec: ProjectSpec
|
||||
|
||||
let proj: PBXProj
|
||||
let sourceGenerator: SourceGenerator
|
||||
let referenceGenerator = ReferenceGenerator()
|
||||
var sourceGenerator: SourceGenerator!
|
||||
|
||||
var targetNativeReferences: [String: String] = [:]
|
||||
var targetBuildFiles: [String: PBXBuildFile] = [:]
|
||||
var targetObjects: [String: ObjectReference<PBXTarget>] = [:]
|
||||
var targetBuildFiles: [String: ObjectReference<PBXBuildFile>] = [:]
|
||||
var targetFileReferences: [String: String] = [:]
|
||||
var topLevelGroups: Set<String> = []
|
||||
var carthageFrameworksByPlatform: [String: Set<String>] = [:]
|
||||
@@ -28,15 +27,21 @@ public class PBXProjGenerator {
|
||||
|
||||
public init(spec: ProjectSpec) {
|
||||
self.spec = spec
|
||||
proj = PBXProj(objectVersion: 46, rootObject: referenceGenerator.generate(PBXProject.self, spec.name))
|
||||
sourceGenerator = SourceGenerator(spec: spec, referenceGenerator: referenceGenerator) { _ in }
|
||||
sourceGenerator.addObject = { [weak self] object in
|
||||
self?.addObject(object)
|
||||
proj = PBXProj(rootObject: "", objectVersion: 46)
|
||||
sourceGenerator = SourceGenerator(spec: spec) { [unowned self] id, object in
|
||||
self.addObject(id: id, object)
|
||||
}
|
||||
}
|
||||
|
||||
func addObject(_ object: PBXObject) {
|
||||
proj.objects.addObject(object)
|
||||
func addObject(id: String, _ object: PBXObject) -> String {
|
||||
let reference = proj.objects.generateReference(object, id)
|
||||
proj.objects.addObject(object, reference: reference)
|
||||
return reference
|
||||
}
|
||||
|
||||
func createObject<T>(id: String, _ object: T) -> ObjectReference<T> {
|
||||
let reference = addObject(id: id, object)
|
||||
return ObjectReference(reference: reference, object: object)
|
||||
}
|
||||
|
||||
public func generate() throws -> PBXProj {
|
||||
@@ -44,109 +49,151 @@ public class PBXProjGenerator {
|
||||
fatalError("Cannot use PBXProjGenerator to generate more than once")
|
||||
}
|
||||
generated = true
|
||||
|
||||
for group in spec.fileGroups {
|
||||
try sourceGenerator.getFileGroups(path: group)
|
||||
}
|
||||
|
||||
let buildConfigs: [XCBuildConfiguration] = spec.configs.map { config in
|
||||
let buildConfigs: [ObjectReference<XCBuildConfiguration>] = spec.configs.map { config in
|
||||
let buildSettings = spec.getProjectBuildSettings(config: config)
|
||||
var baseConfigurationReference: String?
|
||||
if let configPath = spec.configFiles[config.name] {
|
||||
baseConfigurationReference = sourceGenerator.getContainedFileReference(path: spec.basePath + configPath)
|
||||
}
|
||||
return XCBuildConfiguration(
|
||||
reference: referenceGenerator.generate(XCBuildConfiguration.self, config.name),
|
||||
name: config.name,
|
||||
baseConfigurationReference: baseConfigurationReference,
|
||||
buildSettings: buildSettings
|
||||
return createObject(
|
||||
id: config.name,
|
||||
XCBuildConfiguration(
|
||||
name: config.name,
|
||||
baseConfigurationReference: baseConfigurationReference,
|
||||
buildSettings: buildSettings
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let buildConfigList = XCConfigurationList(
|
||||
reference: referenceGenerator.generate(XCConfigurationList.self, spec.name),
|
||||
buildConfigurations: buildConfigs.references,
|
||||
defaultConfigurationName: buildConfigs.first?.name ?? "",
|
||||
defaultConfigurationIsVisible: 0
|
||||
let buildConfigList = createObject(
|
||||
id: spec.name,
|
||||
XCConfigurationList(
|
||||
buildConfigurations: buildConfigs.map { $0.reference },
|
||||
defaultConfigurationName: buildConfigs.first?.object.name ?? ""
|
||||
)
|
||||
)
|
||||
|
||||
buildConfigs.forEach(addObject)
|
||||
addObject(buildConfigList)
|
||||
let mainGroup = createObject(
|
||||
id: "Project",
|
||||
PBXGroup(
|
||||
children: [],
|
||||
sourceTree: .group,
|
||||
usesTabs: spec.options.usesTabs,
|
||||
indentWidth: spec.options.indentWidth,
|
||||
tabWidth: spec.options.tabWidth
|
||||
)
|
||||
)
|
||||
|
||||
let project = createObject(
|
||||
id: spec.name,
|
||||
PBXProject(
|
||||
name: spec.name,
|
||||
buildConfigurationList: buildConfigList.reference,
|
||||
compatibilityVersion: "Xcode 3.2",
|
||||
mainGroup: mainGroup.reference,
|
||||
developmentRegion: spec.options.developmentLanguage ?? "en"
|
||||
)
|
||||
)
|
||||
|
||||
proj.rootObject = project.reference
|
||||
|
||||
for target in spec.targets {
|
||||
targetNativeReferences[target.name] = target.isLegacy ?
|
||||
referenceGenerator.generate(PBXLegacyTarget.self, target.name) :
|
||||
referenceGenerator.generate(PBXNativeTarget.self, target.name)
|
||||
let targetObject: PBXTarget
|
||||
|
||||
if target.isLegacy {
|
||||
targetObject = PBXLegacyTarget(
|
||||
name: target.name,
|
||||
buildToolPath: target.legacy?.toolPath,
|
||||
buildArgumentsString: target.legacy?.arguments,
|
||||
passBuildSettingsInEnvironment: target.legacy?.passSettings ?? false,
|
||||
buildWorkingDirectory: target.legacy?.workingDirectory
|
||||
)
|
||||
} else {
|
||||
targetObject = PBXNativeTarget(name: target.name)
|
||||
}
|
||||
|
||||
targetObjects[target.name] = createObject(id: target.name, targetObject)
|
||||
|
||||
var explicitFileType: String?
|
||||
var lastKnownFileType: String?
|
||||
let fileType = PBXFileReference.fileType(path: Path(target.filename))
|
||||
if (target.platform == .macOS || target.type == .framework) {
|
||||
if target.platform == .macOS || target.type == .framework {
|
||||
explicitFileType = fileType
|
||||
} else {
|
||||
lastKnownFileType = fileType
|
||||
}
|
||||
|
||||
let fileReference = PBXFileReference(
|
||||
reference: referenceGenerator.generate(PBXFileReference.self, target.name),
|
||||
sourceTree: .buildProductsDir,
|
||||
explicitFileType: explicitFileType,
|
||||
lastKnownFileType: lastKnownFileType,
|
||||
path: target.filename,
|
||||
includeInIndex: 0
|
||||
let fileReference = createObject(
|
||||
id: target.name,
|
||||
PBXFileReference(
|
||||
sourceTree: .buildProductsDir,
|
||||
explicitFileType: explicitFileType,
|
||||
lastKnownFileType: lastKnownFileType,
|
||||
path: target.filename,
|
||||
includeInIndex: false
|
||||
)
|
||||
)
|
||||
addObject(fileReference)
|
||||
targetFileReferences[target.name] = fileReference.reference
|
||||
|
||||
let buildFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference.reference),
|
||||
fileRef: fileReference.reference
|
||||
targetFileReferences[target.name] = fileReference.reference
|
||||
targetBuildFiles[target.name] = createObject(
|
||||
id: fileReference.reference,
|
||||
PBXBuildFile(fileRef: fileReference.reference)
|
||||
)
|
||||
addObject(buildFile)
|
||||
targetBuildFiles[target.name] = buildFile
|
||||
}
|
||||
|
||||
let targets = try spec.targets.map(generateTarget)
|
||||
try spec.targets.forEach(generateTarget)
|
||||
|
||||
let productGroup = PBXGroup(
|
||||
reference: referenceGenerator.generate(PBXGroup.self, "Products"),
|
||||
children: Array(targetFileReferences.values),
|
||||
sourceTree: .group,
|
||||
name: "Products"
|
||||
let productGroup = createObject(
|
||||
id: "Products",
|
||||
PBXGroup(
|
||||
children: Array(targetFileReferences.values),
|
||||
sourceTree: .group,
|
||||
name: "Products"
|
||||
)
|
||||
)
|
||||
addObject(productGroup)
|
||||
topLevelGroups.insert(productGroup.reference)
|
||||
|
||||
if !carthageFrameworksByPlatform.isEmpty {
|
||||
var platforms: [PBXGroup] = []
|
||||
var platformReferences: [String] = []
|
||||
for (platform, fileReferences) in carthageFrameworksByPlatform {
|
||||
let platformGroup = PBXGroup(
|
||||
reference: referenceGenerator.generate(PBXGroup.self, "Carthage" + platform),
|
||||
children: fileReferences.sorted(),
|
||||
sourceTree: .group,
|
||||
path: platform
|
||||
let platformGroup: ObjectReference<PBXGroup> = createObject(
|
||||
id: "Carthage" + platform,
|
||||
PBXGroup(
|
||||
children: fileReferences.sorted(),
|
||||
sourceTree: .group,
|
||||
path: platform
|
||||
)
|
||||
)
|
||||
addObject(platformGroup)
|
||||
platforms.append(platformGroup)
|
||||
platformReferences.append(platformGroup.reference)
|
||||
platforms.append(platformGroup.object)
|
||||
}
|
||||
let carthageGroup = PBXGroup(
|
||||
reference: referenceGenerator.generate(PBXGroup.self, "Carthage"),
|
||||
children: platforms.references.sorted(),
|
||||
sourceTree: .group,
|
||||
name: "Carthage",
|
||||
path: carthageBuildPath
|
||||
let carthageGroup = createObject(
|
||||
id: "Carthage",
|
||||
PBXGroup(
|
||||
children: platformReferences.sorted(),
|
||||
sourceTree: .group,
|
||||
name: "Carthage",
|
||||
path: carthageBuildPath
|
||||
)
|
||||
)
|
||||
addObject(carthageGroup)
|
||||
frameworkFiles.append(carthageGroup.reference)
|
||||
}
|
||||
|
||||
if !frameworkFiles.isEmpty {
|
||||
let group = PBXGroup(
|
||||
reference: referenceGenerator.generate(PBXGroup.self, "Frameworks"),
|
||||
children: frameworkFiles,
|
||||
sourceTree: .group,
|
||||
name: "Frameworks"
|
||||
let group = createObject(
|
||||
id: "Frameworks",
|
||||
PBXGroup(
|
||||
children: frameworkFiles,
|
||||
sourceTree: .group,
|
||||
name: "Frameworks"
|
||||
)
|
||||
)
|
||||
addObject(group)
|
||||
topLevelGroups.insert(group.reference)
|
||||
}
|
||||
|
||||
@@ -154,93 +201,81 @@ public class PBXProjGenerator {
|
||||
topLevelGroups.insert(rootGroup)
|
||||
}
|
||||
|
||||
let mainGroup = PBXGroup(
|
||||
reference: referenceGenerator.generate(PBXGroup.self, "Project"),
|
||||
children: Array(topLevelGroups),
|
||||
sourceTree: .group,
|
||||
usesTabs: spec.options.usesTabs.map { $0 ? 1 : 0 },
|
||||
indentWidth: spec.options.indentWidth,
|
||||
tabWidth: spec.options.tabWidth
|
||||
)
|
||||
addObject(mainGroup)
|
||||
|
||||
mainGroup.object.children = Array(topLevelGroups)
|
||||
sortGroups(group: mainGroup)
|
||||
|
||||
let projectAttributes: [String: Any] = ["LastUpgradeCheck": spec.xcodeVersion]
|
||||
.merged(spec.attributes)
|
||||
.merged(self.generateTargetAttributes() ?? [:])
|
||||
|
||||
let root = PBXProject(
|
||||
name: spec.name,
|
||||
reference: proj.rootObject,
|
||||
buildConfigurationList: buildConfigList.reference,
|
||||
compatibilityVersion: "Xcode 3.2",
|
||||
mainGroup: mainGroup.reference,
|
||||
developmentRegion: spec.options.developmentLanguage ?? "en",
|
||||
knownRegions: sourceGenerator.knownRegions.sorted(),
|
||||
targets: targets.references,
|
||||
attributes: projectAttributes
|
||||
)
|
||||
proj.objects.projects.append(root)
|
||||
.merged(generateTargetAttributes() ?? [:])
|
||||
|
||||
project.object.knownRegions = sourceGenerator.knownRegions.sorted()
|
||||
project.object.targets = targetObjects.values.sorted { $0.object.name < $1.object.name }.map { $0.reference }
|
||||
project.object.attributes = projectAttributes
|
||||
|
||||
return proj
|
||||
}
|
||||
|
||||
|
||||
func generateTargetAttributes() -> [String: Any]? {
|
||||
|
||||
|
||||
|
||||
var targetAttributes: [String: Any] = [:]
|
||||
|
||||
|
||||
// look up TEST_TARGET_NAME build setting
|
||||
func testTargetName(_ target: PBXTarget) -> String? {
|
||||
guard let configurationList = target.buildConfigurationList else { return nil }
|
||||
guard let buildConfigurationReferences = self.proj.objects.configurationLists[configurationList]?.buildConfigurations else { return nil }
|
||||
|
||||
|
||||
let configs = buildConfigurationReferences
|
||||
.flatMap { ref in self.proj.objects.buildConfigurations[ref] }
|
||||
|
||||
|
||||
return configs
|
||||
.flatMap { $0.buildSettings["TEST_TARGET_NAME"] as? String }
|
||||
.first
|
||||
}
|
||||
|
||||
let uiTestTargets = self.proj.objects.nativeTargets.values
|
||||
.filter { $0.productType == .uiTestBundle }
|
||||
|
||||
|
||||
let uiTestTargets = proj.objects.nativeTargets.objectReferences.filter { $0.object.productType == .uiTestBundle }
|
||||
|
||||
for uiTestTarget in uiTestTargets {
|
||||
guard let name = testTargetName(uiTestTarget) else { continue }
|
||||
guard let name = testTargetName(uiTestTarget.object) else { continue }
|
||||
guard let target = self.proj.objects.targets(named: name).first else { continue }
|
||||
|
||||
targetAttributes[uiTestTarget.reference] = [ "TestTargetID": target.reference]
|
||||
|
||||
targetAttributes[uiTestTarget.reference] = ["TestTargetID": target.reference]
|
||||
}
|
||||
|
||||
|
||||
guard !targetAttributes.isEmpty else { return nil }
|
||||
|
||||
return [
|
||||
"TargetAttributes": targetAttributes
|
||||
"TargetAttributes": targetAttributes,
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
func sortGroups(group: PBXGroup) {
|
||||
func sortGroups(group: ObjectReference<PBXGroup>) {
|
||||
// sort children
|
||||
let children = group.children
|
||||
.flatMap { proj.objects.getFileElement(reference: $0) }
|
||||
let children = group.object.children
|
||||
.flatMap { reference -> ObjectReference<PBXFileElement>? in
|
||||
guard let fileElement = proj.objects.getFileElement(reference: reference) else {
|
||||
return nil
|
||||
}
|
||||
return ObjectReference(reference: reference, object: fileElement)
|
||||
}
|
||||
.sorted { child1, child2 in
|
||||
if child1.sortOrder == child2.sortOrder {
|
||||
return child1.nameOrPath < child2.nameOrPath
|
||||
if child1.object.sortOrder == child2.object.sortOrder {
|
||||
return child1.object.nameOrPath < child2.object.nameOrPath
|
||||
} else {
|
||||
return child1.sortOrder < child2.sortOrder
|
||||
return child1.object.sortOrder < child2.object.sortOrder
|
||||
}
|
||||
}
|
||||
group.children = children.map { $0.reference }.filter { $0 != group.reference }
|
||||
group.object.children = children.map { $0.reference }.filter { $0 != group.reference }
|
||||
|
||||
// sort sub groups
|
||||
let childGroups = group.children.flatMap { proj.objects.groups[$0] }
|
||||
let childGroups = group.object.children.flatMap { reference -> ObjectReference<PBXGroup>? in
|
||||
guard let group = proj.objects.groups[reference] else {
|
||||
return nil
|
||||
}
|
||||
return ObjectReference(reference: reference, object: group) }
|
||||
childGroups.forEach(sortGroups)
|
||||
}
|
||||
|
||||
func generateTarget(_ target: Target) throws -> PBXTarget {
|
||||
func generateTarget(_ target: Target) throws {
|
||||
|
||||
sourceGenerator.targetName = target.name
|
||||
let carthageDependencies = getAllCarthageDependencies(target: target)
|
||||
@@ -250,7 +285,7 @@ public class PBXProjGenerator {
|
||||
var plistPath: Path?
|
||||
var searchForPlist = true
|
||||
|
||||
let configs: [XCBuildConfiguration] = spec.configs.map { config in
|
||||
let configs: [ObjectReference<XCBuildConfiguration>] = spec.configs.map { config in
|
||||
var buildSettings = spec.getTargetBuildSettings(target: target, config: config)
|
||||
|
||||
// automatically set INFOPLIST_FILE path
|
||||
@@ -307,20 +342,18 @@ public class PBXProjGenerator {
|
||||
if let configPath = target.configFiles[config.name] {
|
||||
baseConfigurationReference = sourceGenerator.getContainedFileReference(path: spec.basePath + configPath)
|
||||
}
|
||||
return XCBuildConfiguration(
|
||||
reference: referenceGenerator.generate(XCBuildConfiguration.self, config.name + target.name),
|
||||
let buildConfig = XCBuildConfiguration(
|
||||
name: config.name,
|
||||
baseConfigurationReference: baseConfigurationReference,
|
||||
buildSettings: buildSettings
|
||||
)
|
||||
return createObject(id: config.name + target.name, buildConfig)
|
||||
}
|
||||
configs.forEach(addObject)
|
||||
let buildConfigList = XCConfigurationList(
|
||||
reference: referenceGenerator.generate(XCConfigurationList.self, target.name),
|
||||
buildConfigurations: configs.references,
|
||||
|
||||
let buildConfigList = createObject(id: target.name, XCConfigurationList(
|
||||
buildConfigurations: configs.map { $0.reference },
|
||||
defaultConfigurationName: ""
|
||||
)
|
||||
addObject(buildConfigList)
|
||||
))
|
||||
|
||||
var dependencies: [String] = []
|
||||
var targetFrameworkBuildFiles: [String] = []
|
||||
@@ -338,42 +371,44 @@ public class PBXProjGenerator {
|
||||
guard let dependencyTarget = spec.getTarget(dependencyTargetName) else { continue }
|
||||
let dependencyFileReference = targetFileReferences[dependencyTargetName]!
|
||||
|
||||
let targetProxy = PBXContainerItemProxy(
|
||||
reference: referenceGenerator.generate(PBXContainerItemProxy.self, target.name),
|
||||
containerPortal: proj.rootObject,
|
||||
remoteGlobalIDString: targetNativeReferences[dependencyTargetName]!,
|
||||
proxyType: .nativeTarget,
|
||||
remoteInfo: dependencyTargetName
|
||||
let targetProxy = createObject(
|
||||
id: target.name,
|
||||
PBXContainerItemProxy(
|
||||
containerPortal: proj.rootObject,
|
||||
remoteGlobalIDString: targetObjects[dependencyTargetName]!.reference,
|
||||
proxyType: .nativeTarget,
|
||||
remoteInfo: dependencyTargetName
|
||||
)
|
||||
)
|
||||
let targetDependency = PBXTargetDependency(
|
||||
reference: referenceGenerator.generate(PBXTargetDependency.self, dependencyTargetName + target.name),
|
||||
target: targetNativeReferences[dependencyTargetName]!,
|
||||
targetProxy: targetProxy.reference
|
||||
|
||||
let targetDependency = createObject(
|
||||
id: dependencyTargetName + target.name,
|
||||
PBXTargetDependency(
|
||||
target: targetObjects[dependencyTargetName]!.reference,
|
||||
targetProxy: targetProxy.reference
|
||||
)
|
||||
)
|
||||
|
||||
addObject(targetProxy)
|
||||
addObject(targetDependency)
|
||||
dependencies.append(targetDependency.reference)
|
||||
|
||||
if (dependencyTarget.type.isLibrary || dependencyTarget.type.isFramework) && dependency.link {
|
||||
let dependencyBuildFile = targetBuildFiles[dependencyTargetName]!
|
||||
let buildFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, dependencyBuildFile.reference + target.name),
|
||||
fileRef: dependencyBuildFile.fileRef!
|
||||
let buildFile = createObject(
|
||||
id: dependencyBuildFile.reference + target.name,
|
||||
PBXBuildFile(fileRef: dependencyBuildFile.object.fileRef!)
|
||||
)
|
||||
addObject(buildFile)
|
||||
targetFrameworkBuildFiles.append(buildFile.reference)
|
||||
}
|
||||
|
||||
if embed && !dependencyTarget.type.isLibrary {
|
||||
|
||||
let embedSettings = dependency.buildSettings
|
||||
let embedFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, dependencyFileReference + target.name),
|
||||
fileRef: dependencyFileReference,
|
||||
settings: embedSettings
|
||||
let embedFile = createObject(
|
||||
id: dependencyFileReference + target.name,
|
||||
PBXBuildFile(
|
||||
fileRef: dependencyFileReference,
|
||||
settings: dependency.buildSettings
|
||||
)
|
||||
)
|
||||
addObject(embedFile)
|
||||
|
||||
if dependencyTarget.type.isExtension {
|
||||
// embed app extension
|
||||
@@ -402,11 +437,10 @@ public class PBXProjGenerator {
|
||||
)
|
||||
}
|
||||
|
||||
let buildFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name),
|
||||
fileRef: fileReference
|
||||
let buildFile = createObject(
|
||||
id: fileReference + target.name,
|
||||
PBXBuildFile(fileRef: fileReference)
|
||||
)
|
||||
addObject(buildFile)
|
||||
|
||||
targetFrameworkBuildFiles.append(buildFile.reference)
|
||||
if !frameworkFiles.contains(fileReference) {
|
||||
@@ -414,12 +448,10 @@ public class PBXProjGenerator {
|
||||
}
|
||||
|
||||
if embed {
|
||||
let embedFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name),
|
||||
fileRef: fileReference,
|
||||
settings: dependency.buildSettings
|
||||
let embedFile = createObject(
|
||||
id: fileReference + target.name,
|
||||
PBXBuildFile(fileRef: fileReference, settings: dependency.buildSettings)
|
||||
)
|
||||
addObject(embedFile)
|
||||
copyFrameworksReferences.append(embedFile.reference)
|
||||
}
|
||||
case .carthage:
|
||||
@@ -430,21 +462,19 @@ public class PBXProjGenerator {
|
||||
}
|
||||
let fileReference = sourceGenerator.getFileReference(path: frameworkPath, inPath: platformPath)
|
||||
|
||||
let buildFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name),
|
||||
fileRef: fileReference
|
||||
let buildFile = createObject(
|
||||
id: fileReference + target.name,
|
||||
PBXBuildFile(fileRef: fileReference)
|
||||
)
|
||||
addObject(buildFile)
|
||||
|
||||
carthageFrameworksByPlatform[target.platform.carthageDirectoryName, default: []].insert(fileReference)
|
||||
|
||||
targetFrameworkBuildFiles.append(buildFile.reference)
|
||||
if target.platform == .macOS && target.type.isApp {
|
||||
let embedFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name),
|
||||
fileRef: fileReference,
|
||||
settings: dependency.buildSettings
|
||||
let embedFile = createObject(
|
||||
id: fileReference + target.name,
|
||||
PBXBuildFile(fileRef: fileReference, settings: dependency.buildSettings)
|
||||
)
|
||||
addObject(embedFile)
|
||||
copyFrameworksReferences.append(embedFile.reference)
|
||||
}
|
||||
}
|
||||
@@ -456,17 +486,17 @@ public class PBXProjGenerator {
|
||||
func getBuildFilesForPhase(_ buildPhase: BuildPhase) -> [String] {
|
||||
let files = sourceFiles
|
||||
.filter { $0.buildPhase == buildPhase }
|
||||
.reduce(into: [SourceFile]()) { (output, sourceFile) in
|
||||
if !output.contains(where: { $0.fileReference == sourceFile.fileReference }) {
|
||||
output.append(sourceFile)
|
||||
}
|
||||
.reduce(into: [SourceFile]()) { output, sourceFile in
|
||||
if !output.contains(where: { $0.fileReference == sourceFile.fileReference }) {
|
||||
output.append(sourceFile)
|
||||
}
|
||||
}
|
||||
.sorted { $0.path.lastComponent < $1.path.lastComponent }
|
||||
files.forEach { addObject($0.buildFile) }
|
||||
return files.map { $0.buildFile.reference }
|
||||
return files.map { createObject(id: $0.fileReference + target.name, $0.buildFile) }
|
||||
.map { $0.reference }
|
||||
}
|
||||
|
||||
func getBuildScript(buildScript: BuildScript) throws -> PBXShellScriptBuildPhase {
|
||||
func generateBuildScript(buildScript: BuildScript) throws {
|
||||
|
||||
let shellScript: String
|
||||
switch buildScript.script {
|
||||
@@ -477,7 +507,6 @@ public class PBXProjGenerator {
|
||||
}
|
||||
|
||||
let shellScriptPhase = PBXShellScriptBuildPhase(
|
||||
reference: referenceGenerator.generate(PBXShellScriptBuildPhase.self, String(describing: buildScript.name) + shellScript + target.name),
|
||||
files: [],
|
||||
name: buildScript.name ?? "Run Script",
|
||||
inputPaths: buildScript.inputFiles,
|
||||
@@ -485,83 +514,79 @@ public class PBXProjGenerator {
|
||||
shellPath: buildScript.shell ?? "/bin/sh",
|
||||
shellScript: shellScript
|
||||
)
|
||||
shellScriptPhase.runOnlyForDeploymentPostprocessing = buildScript.runOnlyWhenInstalling ? 1 : 0
|
||||
addObject(shellScriptPhase)
|
||||
buildPhases.append(shellScriptPhase.reference)
|
||||
return shellScriptPhase
|
||||
shellScriptPhase.runOnlyForDeploymentPostprocessing = buildScript.runOnlyWhenInstalling
|
||||
let shellScriptPhaseReference = createObject(id: String(describing: buildScript.name) + shellScript + target.name, shellScriptPhase)
|
||||
buildPhases.append(shellScriptPhaseReference.reference)
|
||||
}
|
||||
|
||||
_ = try target.prebuildScripts.map(getBuildScript)
|
||||
try target.prebuildScripts.forEach(generateBuildScript)
|
||||
|
||||
let sourcesBuildPhaseFiles = getBuildFilesForPhase(.sources)
|
||||
if !sourcesBuildPhaseFiles.isEmpty {
|
||||
let sourcesBuildPhase = PBXSourcesBuildPhase(reference: referenceGenerator.generate(PBXSourcesBuildPhase.self, target.name), files: sourcesBuildPhaseFiles)
|
||||
addObject(sourcesBuildPhase)
|
||||
let sourcesBuildPhase = createObject(id: target.name, PBXSourcesBuildPhase(files: sourcesBuildPhaseFiles))
|
||||
buildPhases.append(sourcesBuildPhase.reference)
|
||||
}
|
||||
|
||||
let resourcesBuildPhaseFiles = getBuildFilesForPhase(.resources) + copyResourcesReferences
|
||||
if !resourcesBuildPhaseFiles.isEmpty {
|
||||
let resourcesBuildPhase = PBXResourcesBuildPhase(reference: referenceGenerator.generate(PBXResourcesBuildPhase.self, target.name), files: resourcesBuildPhaseFiles)
|
||||
addObject(resourcesBuildPhase)
|
||||
let resourcesBuildPhase = createObject(id: target.name, PBXResourcesBuildPhase(files: resourcesBuildPhaseFiles))
|
||||
buildPhases.append(resourcesBuildPhase.reference)
|
||||
}
|
||||
|
||||
let headersBuildPhaseFiles = getBuildFilesForPhase(.headers)
|
||||
if !headersBuildPhaseFiles.isEmpty && (target.type == .framework || target.type == .dynamicLibrary) {
|
||||
let headersBuildPhase = PBXHeadersBuildPhase(reference: referenceGenerator.generate(PBXHeadersBuildPhase.self, target.name), files: headersBuildPhaseFiles)
|
||||
addObject(headersBuildPhase)
|
||||
let headersBuildPhase = createObject(id: target.name, PBXHeadersBuildPhase(files: headersBuildPhaseFiles))
|
||||
buildPhases.append(headersBuildPhase.reference)
|
||||
}
|
||||
|
||||
if !targetFrameworkBuildFiles.isEmpty {
|
||||
|
||||
let frameworkBuildPhase = PBXFrameworksBuildPhase(
|
||||
reference: referenceGenerator.generate(PBXFrameworksBuildPhase.self, target.name),
|
||||
files: targetFrameworkBuildFiles,
|
||||
runOnlyForDeploymentPostprocessing: 0
|
||||
let frameworkBuildPhase = createObject(
|
||||
id: target.name,
|
||||
PBXFrameworksBuildPhase(files: targetFrameworkBuildFiles)
|
||||
)
|
||||
|
||||
addObject(frameworkBuildPhase)
|
||||
buildPhases.append(frameworkBuildPhase.reference)
|
||||
}
|
||||
|
||||
if !extensions.isEmpty {
|
||||
|
||||
let copyFilesPhase = PBXCopyFilesBuildPhase(
|
||||
reference: referenceGenerator.generate(PBXCopyFilesBuildPhase.self, "embed app extensions" + target.name),
|
||||
dstPath: "",
|
||||
dstSubfolderSpec: .plugins,
|
||||
files: extensions
|
||||
let copyFilesPhase = createObject(
|
||||
id: "embed app extensions" + target.name,
|
||||
PBXCopyFilesBuildPhase(
|
||||
dstPath: "",
|
||||
dstSubfolderSpec: .plugins,
|
||||
files: extensions
|
||||
)
|
||||
)
|
||||
|
||||
addObject(copyFilesPhase)
|
||||
buildPhases.append(copyFilesPhase.reference)
|
||||
}
|
||||
|
||||
if !copyFrameworksReferences.isEmpty {
|
||||
|
||||
let copyFilesPhase = PBXCopyFilesBuildPhase(
|
||||
reference: referenceGenerator.generate(PBXCopyFilesBuildPhase.self, "embed frameworks" + target.name),
|
||||
dstPath: "",
|
||||
dstSubfolderSpec: .frameworks,
|
||||
files: copyFrameworksReferences
|
||||
let copyFilesPhase = createObject(
|
||||
id: "embed frameworks" + target.name,
|
||||
PBXCopyFilesBuildPhase(
|
||||
dstPath: "",
|
||||
dstSubfolderSpec: .frameworks,
|
||||
files: copyFrameworksReferences
|
||||
)
|
||||
)
|
||||
|
||||
addObject(copyFilesPhase)
|
||||
buildPhases.append(copyFilesPhase.reference)
|
||||
}
|
||||
|
||||
if !copyWatchReferences.isEmpty {
|
||||
|
||||
let copyFilesPhase = PBXCopyFilesBuildPhase(
|
||||
reference: referenceGenerator.generate(PBXCopyFilesBuildPhase.self, "embed watch content" + target.name),
|
||||
dstPath: "$(CONTENTS_FOLDER_PATH)/Watch",
|
||||
dstSubfolderSpec: .productsDirectory,
|
||||
files: copyWatchReferences
|
||||
let copyFilesPhase = createObject(
|
||||
id: "embed watch content" + target.name,
|
||||
PBXCopyFilesBuildPhase(
|
||||
dstPath: "$(CONTENTS_FOLDER_PATH)/Watch",
|
||||
dstSubfolderSpec: .productsDirectory,
|
||||
files: copyWatchReferences
|
||||
)
|
||||
)
|
||||
|
||||
addObject(copyFilesPhase)
|
||||
buildPhases.append(copyFilesPhase.reference)
|
||||
}
|
||||
|
||||
@@ -579,54 +604,34 @@ public class PBXProjGenerator {
|
||||
.map { "$(SRCROOT)/\(carthageBuildPath)/\(target.platform)/\($0)\($0.contains(".") ? "" : ".framework")" }
|
||||
let outputPaths = carthageFrameworksToEmbed
|
||||
.map { "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/\($0)\($0.contains(".") ? "" : ".framework")" }
|
||||
let carthageScript = PBXShellScriptBuildPhase(
|
||||
reference: referenceGenerator.generate(PBXShellScriptBuildPhase.self, "Carthage" + target.name),
|
||||
files: [],
|
||||
name: "Carthage",
|
||||
inputPaths: inputPaths,
|
||||
outputPaths: outputPaths,
|
||||
shellPath: "/bin/sh",
|
||||
shellScript: "/usr/local/bin/carthage copy-frameworks\n"
|
||||
let carthageScript = createObject(
|
||||
id: "Carthage" + target.name,
|
||||
PBXShellScriptBuildPhase(
|
||||
files: [],
|
||||
name: "Carthage",
|
||||
inputPaths: inputPaths,
|
||||
outputPaths: outputPaths,
|
||||
shellPath: "/bin/sh",
|
||||
shellScript: "/usr/local/bin/carthage copy-frameworks\n"
|
||||
)
|
||||
)
|
||||
addObject(carthageScript)
|
||||
buildPhases.append(carthageScript.reference)
|
||||
}
|
||||
}
|
||||
|
||||
_ = try target.postbuildScripts.map(getBuildScript)
|
||||
try target.postbuildScripts.forEach(generateBuildScript)
|
||||
|
||||
let pbxtarget: PBXTarget
|
||||
if target.isLegacy {
|
||||
pbxtarget = PBXLegacyTarget(
|
||||
reference: targetNativeReferences[target.name]!,
|
||||
name: target.name,
|
||||
buildToolPath: target.legacy?.toolPath,
|
||||
buildArgumentsString: target.legacy?.arguments,
|
||||
passBuildSettingsInEnvironment: target.legacy?.passSettings ?? false,
|
||||
buildWorkingDirectory: target.legacy?.workingDirectory,
|
||||
buildConfigurationList: buildConfigList.reference,
|
||||
buildPhases: buildPhases,
|
||||
buildRules: [],
|
||||
dependencies: dependencies,
|
||||
productName: target.name,
|
||||
productReference: fileReference,
|
||||
productType: nil
|
||||
)
|
||||
} else {
|
||||
pbxtarget = PBXNativeTarget(
|
||||
reference: targetNativeReferences[target.name]!,
|
||||
name: target.name,
|
||||
buildConfigurationList: buildConfigList.reference,
|
||||
buildPhases: buildPhases,
|
||||
buildRules: [],
|
||||
dependencies: dependencies,
|
||||
productName: target.name,
|
||||
productReference: fileReference,
|
||||
productType: target.type
|
||||
)
|
||||
let targetObject = targetObjects[target.name]!.object
|
||||
|
||||
targetObject.name = target.name
|
||||
targetObject.buildConfigurationList = buildConfigList.reference
|
||||
targetObject.buildPhases = buildPhases
|
||||
targetObject.dependencies = dependencies
|
||||
targetObject.productName = target.name
|
||||
targetObject.productReference = fileReference
|
||||
if !target.isLegacy {
|
||||
targetObject.productType = target.type
|
||||
}
|
||||
addObject(pbxtarget)
|
||||
return pbxtarget
|
||||
}
|
||||
|
||||
func getInfoPlist(_ sources: [TargetSource]) -> Path? {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import xcproj
|
||||
import JSONUtilities
|
||||
import Yams
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import Yams
|
||||
|
||||
public class ProjectGenerator {
|
||||
|
||||
@@ -31,8 +31,8 @@ public class ProjectGenerator {
|
||||
}
|
||||
|
||||
func generateWorkspace() throws -> XCWorkspace {
|
||||
let workspaceReferences: [XCWorkspace.Data.FileRef] = [XCWorkspace.Data.FileRef.project(path: Path(""))]
|
||||
let workspaceData = XCWorkspace.Data(references: workspaceReferences)
|
||||
let dataElement: XCWorkspaceDataElement = .file(XCWorkspaceDataFileRef(location: .`self`("")))
|
||||
let workspaceData = XCWorkspaceData(children: [dataElement])
|
||||
return XCWorkspace(data: workspaceData)
|
||||
}
|
||||
|
||||
@@ -40,15 +40,12 @@ public class ProjectGenerator {
|
||||
|
||||
func getBuildEntry(_ buildTarget: Scheme.BuildTarget) -> XCScheme.BuildAction.Entry {
|
||||
|
||||
let predicate: (PBXTarget) -> Bool = { $0.name == buildTarget.target }
|
||||
let targetReference =
|
||||
pbxProject.objects.nativeTargets.referenceValues.first { predicate($0 as PBXTarget) } ??
|
||||
pbxProject.objects.legacyTargets.referenceValues.first { predicate($0 as PBXTarget) }!
|
||||
let targetReference = pbxProject.objects.targets(named: buildTarget.target).first!
|
||||
|
||||
let buildableReference = XCScheme.BuildableReference(
|
||||
referencedContainer: "container:\(spec.name).xcodeproj",
|
||||
blueprintIdentifier: targetReference.reference,
|
||||
buildableName: buildTarget.target + (targetReference.productType?.fileExtension.map { ".\($0)" } ?? ""),
|
||||
buildableName: buildTarget.target + (targetReference.object.productType?.fileExtension.map { ".\($0)" } ?? ""),
|
||||
blueprintName: scheme.name
|
||||
)
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
|
||||
public class ReferenceGenerator {
|
||||
|
||||
private var references: Set<String> = []
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
public func generate<T: PBXObject>(_ element: T.Type, _ id: String) -> String {
|
||||
var uuid: String = ""
|
||||
var counter: UInt = 0
|
||||
let characterCount = 16
|
||||
let className: String = String(describing: T.self)
|
||||
.replacingOccurrences(of: "PBX", with: "")
|
||||
.replacingOccurrences(of: "XC", with: "")
|
||||
let classAcronym = String(className.filter { String($0).lowercased() != String($0) })
|
||||
let stringID = String(abs(id.hashValue).description.prefix(characterCount - classAcronym.count - 2))
|
||||
repeat {
|
||||
uuid = "\(classAcronym)_\(stringID)\(counter > 0 ? "-\(counter)" : "")"
|
||||
counter += 1
|
||||
} while (references.contains(uuid))
|
||||
references.insert(uuid)
|
||||
return uuid
|
||||
}
|
||||
|
||||
public func clear() {
|
||||
references.removeAll()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
|
||||
public enum SettingsPresetFile {
|
||||
case config(ConfigType)
|
||||
|
||||
@@ -14,21 +14,28 @@ class SourceGenerator {
|
||||
|
||||
var rootGroups: Set<String> = []
|
||||
private var fileReferencesByPath: [String: String] = [:]
|
||||
private var groupsByPath: [Path: PBXGroup] = [:]
|
||||
private var variantGroupsByPath: [Path: PBXVariantGroup] = [:]
|
||||
private var groupsByPath: [Path: ObjectReference<PBXGroup>] = [:]
|
||||
private var variantGroupsByPath: [Path: ObjectReference<PBXVariantGroup>] = [:]
|
||||
|
||||
private let spec: ProjectSpec
|
||||
private let referenceGenerator: ReferenceGenerator
|
||||
var addObject: (PBXObject) -> Void
|
||||
var addObjectClosure: (String, PBXObject) -> String
|
||||
|
||||
var targetName: String = ""
|
||||
|
||||
private(set) var knownRegions: Set<String> = []
|
||||
|
||||
init(spec: ProjectSpec, referenceGenerator: ReferenceGenerator, addObject: @escaping (PBXObject) -> Void) {
|
||||
init(spec: ProjectSpec, addObjectClosure: @escaping (String, PBXObject) -> String) {
|
||||
self.spec = spec
|
||||
self.referenceGenerator = referenceGenerator
|
||||
self.addObject = addObject
|
||||
self.addObjectClosure = addObjectClosure
|
||||
}
|
||||
|
||||
func addObject(id: String, _ object: PBXObject) -> String {
|
||||
return addObjectClosure(id, object)
|
||||
}
|
||||
|
||||
func createObject<T: PBXObject>(id: String, _ object: T) -> ObjectReference<T> {
|
||||
let reference = addObject(id: id, object)
|
||||
return ObjectReference(reference: reference, object: object)
|
||||
}
|
||||
|
||||
func getAllSourceFiles(sources: [TargetSource]) throws -> [SourceFile] {
|
||||
@@ -61,11 +68,7 @@ class SourceGenerator {
|
||||
settings["COMPILER_FLAGS"] = targetSource.compilerFlags.joined(separator: " ")
|
||||
}
|
||||
|
||||
let buildFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + targetName),
|
||||
fileRef: fileReference,
|
||||
settings: settings.isEmpty ? nil : settings
|
||||
)
|
||||
let buildFile = PBXBuildFile(fileRef: fileReference, settings: settings.isEmpty ? nil : settings)
|
||||
return SourceFile(
|
||||
path: path,
|
||||
fileReference: fileReference,
|
||||
@@ -102,14 +105,15 @@ class SourceGenerator {
|
||||
fileReferenceName = nil
|
||||
}
|
||||
let lastKnownFileType = PBXFileReference.fileType(path: path)
|
||||
let fileReference = PBXFileReference(
|
||||
reference: referenceGenerator.generate(PBXFileReference.self, path.byRemovingBase(path: spec.basePath).string),
|
||||
sourceTree: sourceTree,
|
||||
name: fileReferenceName,
|
||||
lastKnownFileType: lastKnownFileType,
|
||||
path: fileReferencePath.string
|
||||
let fileReference = createObject(
|
||||
id: path.byRemovingBase(path: spec.basePath).string,
|
||||
PBXFileReference(
|
||||
sourceTree: sourceTree,
|
||||
name: fileReferenceName,
|
||||
lastKnownFileType: lastKnownFileType,
|
||||
path: fileReferencePath.string
|
||||
)
|
||||
)
|
||||
addObject(fileReference)
|
||||
fileReferencesByPath[path.string.lowercased()] = fileReference.reference
|
||||
return fileReference.reference
|
||||
}
|
||||
@@ -130,13 +134,13 @@ class SourceGenerator {
|
||||
return nil
|
||||
}
|
||||
|
||||
private func getGroup(path: Path, name: String? = nil, mergingChildren children: [String], createIntermediateGroups: Bool, isBaseGroup: Bool) -> PBXGroup {
|
||||
let group: PBXGroup
|
||||
private func getGroup(path: Path, name: String? = nil, mergingChildren children: [String], createIntermediateGroups: Bool, isBaseGroup: Bool) -> ObjectReference<PBXGroup> {
|
||||
let groupReference: ObjectReference<PBXGroup>
|
||||
|
||||
if let cachedGroup = groupsByPath[path] {
|
||||
// only add the children that aren't already in the cachedGroup
|
||||
cachedGroup.children = Array(Set(cachedGroup.children + children))
|
||||
group = cachedGroup
|
||||
cachedGroup.object.children = Array(Set(cachedGroup.object.children + children))
|
||||
groupReference = cachedGroup
|
||||
} else {
|
||||
|
||||
// lives outside the spec base path
|
||||
@@ -152,35 +156,33 @@ class SourceGenerator {
|
||||
let groupPath = isTopLevelGroup ?
|
||||
path.byRemovingBase(path: spec.basePath).string :
|
||||
path.lastComponent
|
||||
group = PBXGroup(
|
||||
reference: referenceGenerator.generate(PBXGroup.self, path.byRemovingBase(path: spec.basePath).string),
|
||||
let group = PBXGroup(
|
||||
children: children,
|
||||
sourceTree: .group,
|
||||
name: groupName != groupPath ? groupName : nil,
|
||||
path: groupPath
|
||||
)
|
||||
addObject(group)
|
||||
groupsByPath[path] = group
|
||||
groupReference = createObject(id: path.byRemovingBase(path: spec.basePath).string, group)
|
||||
groupsByPath[path] = groupReference
|
||||
|
||||
if isTopLevelGroup {
|
||||
rootGroups.insert(group.reference)
|
||||
rootGroups.insert(groupReference.reference)
|
||||
}
|
||||
}
|
||||
return group
|
||||
return groupReference
|
||||
}
|
||||
|
||||
private func getVariantGroup(path: Path, inPath: Path) -> PBXVariantGroup {
|
||||
let variantGroup: PBXVariantGroup
|
||||
private func getVariantGroup(path: Path, inPath: Path) -> ObjectReference<PBXVariantGroup> {
|
||||
let variantGroup: ObjectReference<PBXVariantGroup>
|
||||
if let cachedGroup = variantGroupsByPath[path] {
|
||||
variantGroup = cachedGroup
|
||||
} else {
|
||||
variantGroup = PBXVariantGroup(
|
||||
reference: referenceGenerator.generate(PBXVariantGroup.self, path.byRemovingBase(path: spec.basePath).string),
|
||||
let group = PBXVariantGroup(
|
||||
children: [],
|
||||
name: path.lastComponent,
|
||||
sourceTree: .group
|
||||
)
|
||||
addObject(variantGroup)
|
||||
variantGroup = createObject(id: path.byRemovingBase(path: spec.basePath).string, group)
|
||||
variantGroupsByPath[path] = variantGroup
|
||||
}
|
||||
return variantGroup
|
||||
@@ -236,7 +238,7 @@ class SourceGenerator {
|
||||
}
|
||||
|
||||
private func getGroupSources(targetSource: TargetSource, path: Path, isBaseGroup: Bool)
|
||||
throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) {
|
||||
throws -> (sourceFiles: [SourceFile], groups: [ObjectReference<PBXGroup>]) {
|
||||
|
||||
let children = try getSourceChildren(targetSource: targetSource, dirPath: path)
|
||||
|
||||
@@ -256,7 +258,7 @@ class SourceGenerator {
|
||||
var allSourceFiles: [SourceFile] = filePaths.map {
|
||||
generateSourceFile(targetSource: targetSource, path: $0)
|
||||
}
|
||||
var groups: [PBXGroup] = []
|
||||
var groups: [ObjectReference<PBXGroup>] = []
|
||||
|
||||
for path in directories {
|
||||
let subGroups = try getGroupSources(targetSource: targetSource, path: path, isBaseGroup: false)
|
||||
@@ -293,17 +295,12 @@ class SourceGenerator {
|
||||
for filePath in try baseLocalisedDirectory.children().sorted() {
|
||||
let variantGroup = getVariantGroup(path: filePath, inPath: path)
|
||||
groupChildren.append(variantGroup.reference)
|
||||
baseLocalisationVariantGroups.append(variantGroup)
|
||||
baseLocalisationVariantGroups.append(variantGroup.object)
|
||||
|
||||
let buildFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, variantGroup.reference + targetName),
|
||||
fileRef: variantGroup.reference,
|
||||
settings: nil
|
||||
)
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: variantGroup.reference,
|
||||
buildFile: buildFile,
|
||||
buildFile: PBXBuildFile(fileRef: variantGroup.reference),
|
||||
buildPhase: .resources
|
||||
)
|
||||
allSourceFiles.append(sourceFile)
|
||||
@@ -336,17 +333,13 @@ class SourceGenerator {
|
||||
}
|
||||
} else {
|
||||
// add SourceFile to group if there is no Base.lproj directory
|
||||
let buildFile = PBXBuildFile(
|
||||
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + targetName),
|
||||
fileRef: fileReference,
|
||||
settings: nil
|
||||
)
|
||||
allSourceFiles.append(SourceFile(
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: fileReference,
|
||||
buildFile: buildFile,
|
||||
buildFile: PBXBuildFile(fileRef: fileReference),
|
||||
buildPhase: .resources
|
||||
))
|
||||
)
|
||||
allSourceFiles.append(sourceFile)
|
||||
groupChildren.append(fileReference)
|
||||
}
|
||||
}
|
||||
@@ -402,7 +395,7 @@ class SourceGenerator {
|
||||
let (groupSourceFiles, groups) = try getGroupSources(targetSource: targetSource, path: path, isBaseGroup: true)
|
||||
let group = groups.first!
|
||||
if let name = targetSource.name {
|
||||
group.name = name
|
||||
group.object.name = name
|
||||
}
|
||||
|
||||
sourceFiles += groupSourceFiles
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import UIKit
|
||||
import Framework
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
FR_481575785861 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
FR_500792082643 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/LocalizedStoryboard.strings; sourceTree = "<group>"; };
|
||||
FR_525119120469 /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FR_602633703434 /* en */ = {isa = PBXFileReference; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
FR_602633703434 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
FR_609193904586 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
FR_635802719871 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
|
||||
FR_643034527839 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@@ -124,7 +124,7 @@
|
||||
FR_675266829517 /* Standalone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Standalone.swift; sourceTree = "<group>"; };
|
||||
FR_722239415598 /* TestProjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProjectTests.swift; sourceTree = "<group>"; };
|
||||
FR_725187762757 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
FR_746876637628 /* Base */ = {isa = PBXFileReference; name = Base; path = Base.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
FR_746876637628 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
FR_752394658615 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Alamofire.framework; sourceTree = "<group>"; };
|
||||
FR_771029596306 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
FR_783122899910 /* App_iOS_Tests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = App_iOS_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -395,8 +395,6 @@
|
||||
buildConfigurationList = CL_479264660374 /* Build configuration list for PBXLegacyTarget "Legacy" */;
|
||||
buildPhases = (
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
buildToolPath = /usr/bin/true;
|
||||
dependencies = (
|
||||
);
|
||||
@@ -606,6 +604,7 @@
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"You ran a script\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
SSBP_3886691194 /* MyScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -620,6 +619,7 @@
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"You ran a script\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
SSBP_5106020372 /* Strip Unused Architectures from Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -634,6 +634,7 @@
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "################################################################################\n#\n# Copyright 2015 Realm Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n################################################################################\n\n# This script strips all non-valid architectures from dynamic libraries in\n# the application's `Frameworks` directory.\n#\n# The following environment variables are required:\n#\n# BUILT_PRODUCTS_DIR\n# FRAMEWORKS_FOLDER_PATH\n# VALID_ARCHS\n# EXPANDED_CODE_SIGN_IDENTITY\n\n\n# Signs a framework with the provided identity\ncode_sign() {\n # Use the current code_sign_identitiy\n echo \"Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}\"\n echo \"/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements $1\"\n /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"\n}\n\n# Set working directory to product’s embedded frameworks\ncd \"${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\n\nif [ \"$ACTION\" = \"install\" ]; then\n echo \"Copy .bcsymbolmap files to .xcarchive\"\n find . -name '*.bcsymbolmap' -type f -exec mv {} \"${CONFIGURATION_BUILD_DIR}\" \\;\nelse\n # Delete *.bcsymbolmap files from framework bundle unless archiving\n find . -name '*.bcsymbolmap' -type f -exec rm -rf \"{}\" +\\;\nfi\n\necho \"Stripping frameworks\"\n\nfor file in $(find . -type f -perm +111); do\n # Skip non-dynamic libraries\n if ! [[ \"$(file \"$file\")\" == *\"dynamically linked shared library\"* ]]; then\n continue\n fi\n # Get architectures for current file\n archs=\"$(lipo -info \"${file}\" | rev | cut -d ':' -f1 | rev)\"\n stripped=\"\"\n for arch in $archs; do\n if ! [[ \"${VALID_ARCHS}\" == *\"$arch\"* ]]; then\n # Strip non-valid architectures in-place\n lipo -remove \"$arch\" -output \"$file\" \"$file\" || exit 1\n stripped=\"$stripped $arch\"\n fi\n done\n if [[ \"$stripped\" != \"\" ]]; then\n echo \"Stripped $file of architectures:$stripped\"\n if [ \"${CODE_SIGNING_REQUIRED}\" == \"YES\" ]; then\n code_sign \"${file}\"\n fi\n fi\ndone\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
SSBP_6331376344 /* MyScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -648,6 +649,7 @@
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"You ran a script\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
SSBP_8106229290 /* Carthage */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -664,6 +666,7 @@
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/usr/local/bin/carthage copy-frameworks\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
SSBP_8255377629 /* MyScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -678,6 +681,7 @@
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"You ran a script\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
SSBP_8706434794 /* MyScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -692,6 +696,7 @@
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"You ran a script!\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
@@ -2188,7 +2193,7 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = "";
|
||||
};
|
||||
CL_479264660374 = {
|
||||
CL_479264660374 /* Build configuration list for PBXLegacyTarget "Legacy" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
BC_805283956103 /* Production Debug */,
|
||||
|
||||
+7
-4
@@ -1,4 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Workspace version="1.0">
|
||||
<FileRef location="self:" />
|
||||
</Workspace>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
+143
-47
@@ -1,47 +1,143 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Scheme LastUpgradeVersion="0920" version="1.3">
|
||||
<AnalyzeAction buildConfiguration="Production Debug" />
|
||||
<ArchiveAction buildConfiguration="Production Release" revealArchiveInOrganizer="YES" />
|
||||
<TestAction selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" codeCoverageEnabled="YES" shouldUseLaunchSchemeArgsEnv="NO" buildConfiguration="Production Debug">
|
||||
<Testables>
|
||||
<TestableReference skipped="NO">
|
||||
<BuildableReference BlueprintIdentifier="NT_783122899910" ReferencedContainer="container:Project.xcodeproj" BuildableName="App_iOS_Tests.xctest" BlueprintName="App_iOS" BuildableIdentifier="primary" />
|
||||
</TestableReference>
|
||||
<TestableReference skipped="NO">
|
||||
<BuildableReference BlueprintIdentifier="NT_123503999387" ReferencedContainer="container:Project.xcodeproj" BuildableName="App_iOS_UITests.xctest" BlueprintName="App_iOS" BuildableIdentifier="primary" />
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference BlueprintIdentifier="NT_825232110500" ReferencedContainer="container:Project.xcodeproj" BuildableName="App_iOS.app" BlueprintName="App_iOS" BuildableIdentifier="primary" />
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument argument="MyEnabledArgument" isEnabled="YES" />
|
||||
<CommandLineArgument argument="MyDisabledArgument" isEnabled="NO" />
|
||||
</CommandLineArguments>
|
||||
</TestAction>
|
||||
<ProfileAction savedToolIdentifier="" useCustomWorkingDirectory="NO" shouldUseLaunchSchemeArgsEnv="NO" buildConfiguration="Production Release" debugDocumentVersioning="YES">
|
||||
<BuildableProductRunnable runnableDebuggingMode="0">
|
||||
<BuildableReference BlueprintIdentifier="NT_825232110500" ReferencedContainer="container:Project.xcodeproj" BuildableName="App_iOS.app" BlueprintName="App_iOS" BuildableIdentifier="primary" />
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument argument="MyEnabledArgument" isEnabled="YES" />
|
||||
<CommandLineArgument argument="MyDisabledArgument" isEnabled="NO" />
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<BuildAction parallelizeBuildables="YES" buildImplicitDependencies="YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry buildForArchiving="YES" buildForTesting="YES" buildForRunning="YES" buildForProfiling="YES" buildForAnalyzing="YES">
|
||||
<BuildableReference BlueprintIdentifier="NT_825232110500" ReferencedContainer="container:Project.xcodeproj" BuildableName="App_iOS.app" BlueprintName="App_iOS" BuildableIdentifier="primary" />
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<LaunchAction selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle="0" buildConfiguration="Production Debug" debugServiceExtension="internal" ignoresPersistentStateOnLaunch="NO" useCustomWorkingDirectory="NO" allowLocationSimulation="YES" debugDocumentVersioning="YES">
|
||||
<BuildableProductRunnable runnableDebuggingMode="0">
|
||||
<BuildableReference BlueprintIdentifier="NT_825232110500" ReferencedContainer="container:Project.xcodeproj" BuildableName="App_iOS.app" BlueprintName="App_iOS" BuildableIdentifier="primary" />
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument argument="MyEnabledArgument" isEnabled="YES" />
|
||||
<CommandLineArgument argument="MyDisabledArgument" isEnabled="NO" />
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
</Scheme>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
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_825232110500"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Production Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "NO"
|
||||
codeCoverageEnabled = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_783122899910"
|
||||
BuildableName = "App_iOS_Tests.xctest"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_123503999387"
|
||||
BuildableName = "App_iOS_UITests.xctest"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Production Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Production Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "NO"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Production Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Production Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import XCTest
|
||||
@testable import XcodeGenKitTests
|
||||
import XCTest
|
||||
|
||||
XCTMain([
|
||||
testCase(GeneratorTests.allTests),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Spectre
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import ProjectSpec
|
||||
|
||||
let fixturePath = Path(#file).parent().parent() + "Fixtures"
|
||||
|
||||
@@ -33,8 +33,8 @@ func fixtureTests() {
|
||||
$0.it("generates variant group") {
|
||||
guard let project = project else { return }
|
||||
|
||||
func getFileReferences(_ path: String) -> [PBXFileReference] {
|
||||
return project.pbxproj.objects.fileReferences.referenceValues.filter { $0.path == path }
|
||||
func getFileReferences(_ path: String) -> [ObjectReference<PBXFileReference>] {
|
||||
return project.pbxproj.objects.fileReferences.objectReferences.filter { $0.object.path == path }
|
||||
}
|
||||
|
||||
func getVariableGroups(_ name: String?) -> [PBXVariantGroup] {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import Yams
|
||||
|
||||
func projectGeneratorTests() {
|
||||
@@ -34,7 +34,7 @@ func projectGeneratorTests() {
|
||||
platform: .iOS,
|
||||
settings: Settings(buildSettings: ["SETTING_2": "VALUE"])
|
||||
)
|
||||
|
||||
|
||||
let uiTest = Target(
|
||||
name: "MyAppUITests",
|
||||
type: .uiTestBundle,
|
||||
@@ -192,23 +192,23 @@ func projectGeneratorTests() {
|
||||
try expect(nativeTargets.contains { $0.name == framework.name }).beTrue()
|
||||
try expect(nativeTargets.contains { $0.name == uiTest.name }).beTrue()
|
||||
}
|
||||
|
||||
|
||||
$0.it("generates target attributes") {
|
||||
|
||||
let pbxProject = try getPbxProj(spec)
|
||||
|
||||
|
||||
guard let targetAttributes = pbxProject.objects.projects.referenceValues.first?.attributes["TargetAttributes"] as? [String: [String: Any]] else {
|
||||
throw failure("Couldn't find Project TargetAttributes")
|
||||
}
|
||||
|
||||
|
||||
guard let appTarget = pbxProject.objects.targets(named: application.name).first else {
|
||||
throw failure("Couldn't find App Target")
|
||||
}
|
||||
|
||||
|
||||
guard let uiTestTarget = pbxProject.objects.targets(named: uiTest.name).first else {
|
||||
throw failure("Couldn't find UITest Target")
|
||||
}
|
||||
|
||||
|
||||
try expect(targetAttributes[uiTestTarget.reference]?["TestTargetID"] as? String) == appTarget.reference
|
||||
}
|
||||
|
||||
@@ -243,12 +243,12 @@ func projectGeneratorTests() {
|
||||
|
||||
$0.it("generates dependencies") {
|
||||
let pbxProject = try getPbxProj(spec)
|
||||
|
||||
let nativeTargets = pbxProject.objects.nativeTargets.referenceValues
|
||||
let dependencies = pbxProject.objects.targetDependencies.referenceValues
|
||||
|
||||
let nativeTargets = pbxProject.objects.nativeTargets.objectReferences
|
||||
let dependencies = pbxProject.objects.targetDependencies.objectReferences
|
||||
try expect(dependencies.count) == 2
|
||||
try expect(dependencies[0].target) == nativeTargets.first { $0.name == framework.name }!.reference
|
||||
try expect(dependencies[1].target) == nativeTargets.first { $0.name == application.name }!.reference
|
||||
try expect(dependencies[0].object.target) == nativeTargets.first { $0.object.name == framework.name }!.reference
|
||||
try expect(dependencies[1].object.target) == nativeTargets.first { $0.object.name == application.name }!.reference
|
||||
}
|
||||
|
||||
$0.it("generates run scripts") {
|
||||
@@ -263,15 +263,15 @@ func projectGeneratorTests() {
|
||||
}
|
||||
let buildPhases = nativeTarget.buildPhases
|
||||
|
||||
let scripts = pbxProject.objects.shellScriptBuildPhases.referenceValues
|
||||
let scripts = pbxProject.objects.shellScriptBuildPhases.objectReferences
|
||||
let script1 = scripts[0]
|
||||
let script2 = scripts[1]
|
||||
try expect(scripts.count) == 2
|
||||
try expect(buildPhases.first) == script1.reference
|
||||
try expect(buildPhases.last) == script2.reference
|
||||
|
||||
try expect(script1.shellScript) == "script1"
|
||||
try expect(script2.shellScript) == "script2"
|
||||
try expect(script1.object.shellScript) == "script1"
|
||||
try expect(script2.object.shellScript) == "script2"
|
||||
}
|
||||
|
||||
$0.it("generates targets with cylical dependencies") {
|
||||
@@ -312,8 +312,8 @@ func projectGeneratorTests() {
|
||||
schemes: [scheme]
|
||||
)
|
||||
let project = try getProject(spec)
|
||||
guard let target = project.pbxproj.objects.nativeTargets.referenceValues
|
||||
.first(where: { $0.name == application.name }) else {
|
||||
guard let target = project.pbxproj.objects.nativeTargets.objectReferences
|
||||
.first(where: { $0.object.name == application.name }) else {
|
||||
throw failure("Target not found")
|
||||
}
|
||||
guard let xcscheme = project.sharedData?.schemes.first else {
|
||||
@@ -327,15 +327,15 @@ func projectGeneratorTests() {
|
||||
|
||||
let buildableReferences: [XCScheme.BuildableReference] = [
|
||||
buildActionEntry.buildableReference,
|
||||
xcscheme.launchAction?.buildableProductRunnable.buildableReference,
|
||||
xcscheme.profileAction?.buildableProductRunnable.buildableReference,
|
||||
xcscheme.launchAction?.buildableProductRunnable?.buildableReference,
|
||||
xcscheme.profileAction?.buildableProductRunnable?.buildableReference,
|
||||
xcscheme.testAction?.macroExpansion,
|
||||
].flatMap { $0 }
|
||||
|
||||
for buildableReference in buildableReferences {
|
||||
try expect(buildableReference.blueprintIdentifier) == target.reference
|
||||
try expect(buildableReference.blueprintName) == scheme.name
|
||||
try expect(buildableReference.buildableName) == "\(target.name).\(target.productType!.fileExtension!)"
|
||||
try expect(buildableReference.buildableName) == "\(target.object.name).\(target.object.productType!.fileExtension!)"
|
||||
}
|
||||
|
||||
try expect(xcscheme.launchAction?.buildConfiguration) == "Debug"
|
||||
@@ -361,8 +361,8 @@ func projectGeneratorTests() {
|
||||
|
||||
try expect(project.sharedData?.schemes.count) == 2
|
||||
|
||||
guard let nativeTarget = project.pbxproj.objects.nativeTargets.referenceValues
|
||||
.first(where: { $0.name == application.name }) else {
|
||||
guard let nativeTarget = project.pbxproj.objects.nativeTargets.objectReferences
|
||||
.first(where: { $0.object.name == application.name }) else {
|
||||
throw failure("Target not found")
|
||||
}
|
||||
guard let xcscheme = project.sharedData?.schemes
|
||||
@@ -382,33 +382,6 @@ func projectGeneratorTests() {
|
||||
}
|
||||
}
|
||||
|
||||
$0.describe("Reference Generator") {
|
||||
|
||||
let referenceGenerator = ReferenceGenerator()
|
||||
$0.before {
|
||||
referenceGenerator.clear()
|
||||
}
|
||||
|
||||
$0.it("generates prefixes") {
|
||||
let references = [
|
||||
referenceGenerator.generate(PBXGroup.self, "a"),
|
||||
referenceGenerator.generate(PBXFileReference.self, "a"),
|
||||
referenceGenerator.generate(XCConfigurationList.self, "a"),
|
||||
]
|
||||
try expect(references[0].hasPrefix("G")).to.beTrue()
|
||||
try expect(references[1].hasPrefix("FR")).to.beTrue()
|
||||
try expect(references[2].hasPrefix("CL")).to.beTrue()
|
||||
}
|
||||
|
||||
$0.it("handles duplicates") {
|
||||
let first = referenceGenerator.generate(PBXGroup.self, "a")
|
||||
let second = referenceGenerator.generate(PBXGroup.self, "a")
|
||||
|
||||
try expect(first) != second
|
||||
try expect(second.hasSuffix("-1")).to.beTrue()
|
||||
}
|
||||
}
|
||||
|
||||
$0.describe("Sources") {
|
||||
|
||||
let directoryPath = Path("TestDirectory")
|
||||
@@ -775,13 +748,12 @@ func projectGeneratorTests() {
|
||||
try project.expectFile(paths: ["C", "Info.plist"], buildPhase: .none)
|
||||
}
|
||||
|
||||
|
||||
$0.it("duplicate TargetSource is included once in sources build phase") {
|
||||
let directories = """
|
||||
Sources:
|
||||
A:
|
||||
- a.swift
|
||||
"""
|
||||
Sources:
|
||||
A:
|
||||
- a.swift
|
||||
"""
|
||||
try createDirectories(directories)
|
||||
|
||||
let target = Target(name: "Test", type: .application, platform: .iOS, sources: [
|
||||
@@ -838,8 +810,8 @@ extension PBXProj {
|
||||
}
|
||||
|
||||
if let buildPhase = buildPhase {
|
||||
let buildFile = objects.buildFiles.referenceValues
|
||||
.first(where: { $0.fileRef == fileReference.reference })
|
||||
let buildFile = objects.buildFiles.objectReferences
|
||||
.first(where: { $0.object.fileRef == fileReference.reference })
|
||||
let actualBuildPhase = buildFile
|
||||
.flatMap { buildFile in objects.buildPhases.referenceValues.first { $0.files.contains(buildFile.reference) } }?.buildPhase
|
||||
|
||||
@@ -869,7 +841,7 @@ extension PBXProj {
|
||||
}
|
||||
}
|
||||
|
||||
func getFileReference(paths: [String], names: [String]) -> PBXFileReference? {
|
||||
func getFileReference(paths: [String], names: [String]) -> ObjectReference<PBXFileReference>? {
|
||||
guard let project = objects.projects.first?.value else { return nil }
|
||||
guard let mainGroup = objects.groups.getReference(project.mainGroup) else { return nil }
|
||||
|
||||
@@ -886,7 +858,7 @@ extension PBXProj {
|
||||
return mainGroup
|
||||
}
|
||||
|
||||
private func getFileReference(group: PBXGroup, paths: [String], names: [String]) -> PBXFileReference? {
|
||||
private func getFileReference(group: PBXGroup, paths: [String], names: [String]) -> ObjectReference<PBXFileReference>? {
|
||||
|
||||
guard !paths.isEmpty else { return nil }
|
||||
let path = paths.first!
|
||||
@@ -894,8 +866,14 @@ extension PBXProj {
|
||||
let restOfPath = Array(paths.dropFirst())
|
||||
let restOfName = Array(names.dropFirst())
|
||||
if restOfPath.isEmpty {
|
||||
let fileReferences = group.children.flatMap { self.objects.fileReferences.getReference($0) }
|
||||
return fileReferences.first { $0.path == path && $0.nameOrPath == name }
|
||||
let fileReferences: [ObjectReference<PBXFileReference>] = group.children.flatMap { reference in
|
||||
if let fileReference = self.objects.fileReferences.getReference(reference) {
|
||||
return ObjectReference(reference: reference, object: fileReference)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fileReferences.first { $0.object.path == path && $0.object.nameOrPath == name }
|
||||
} else {
|
||||
let groups = group.children.flatMap { self.objects.groups.getReference($0) }
|
||||
guard let group = groups.first(where: { $0.path == path && $0.nameOrPath == name }) else { return nil }
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
|
||||
func projectSpecTests() {
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Spectre
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import ProjectSpec
|
||||
|
||||
func specLoadingTests() {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import xcproj
|
||||
import ProjectSpec
|
||||
|
||||
func expectError<T: Error>(_ expectedError: T, _ closure: () throws -> Void) throws where T: CustomStringConvertible {
|
||||
do {
|
||||
|
||||
Reference in New Issue
Block a user