mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
Merge pull request #388 from yonaskolb/xcodeproj_5
Upgrade to xcodeproj 6
This commit is contained in:
+9
-22
@@ -2,7 +2,15 @@ version: 2
|
||||
jobs:
|
||||
macOS_swift_4.1:
|
||||
macos:
|
||||
xcode: "9.3.0"
|
||||
xcode: "9.4.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Build Test Project
|
||||
command: ./build-fixtures.sh
|
||||
macOS_swift_4.2:
|
||||
macos:
|
||||
xcode: "10.0.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@@ -20,27 +28,6 @@ jobs:
|
||||
- run:
|
||||
name: Build release
|
||||
command: make build
|
||||
macOS_swift_4.2:
|
||||
macos:
|
||||
xcode: "10.0.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Build
|
||||
command: swift build
|
||||
- run:
|
||||
name: Test
|
||||
command: swift test 2>&1 | xcpretty
|
||||
# disabled till UUID's are stable
|
||||
# - run:
|
||||
# name: Check Project Diff
|
||||
# command: ./diff-fixtures.sh
|
||||
- run:
|
||||
name: Build Test Project
|
||||
command: ./build-fixtures.sh
|
||||
- run:
|
||||
name: Build release
|
||||
command: make build
|
||||
workflows:
|
||||
version: 2
|
||||
workflow:
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#### Added
|
||||
- Added `weak` Weak linking setting for dependencies [411](https://github.com/yonaskolb/XcodeGen/pull/411) @alvarhansen
|
||||
|
||||
#### Changed
|
||||
- Performance improvements for large projects [388](https://github.com/yonaskolb/XcodeGen/pull/388) @yonaskolb
|
||||
- Upgraded to xcodeproj 6 [388](https://github.com/yonaskolb/XcodeGen/pull/388) @yonaskolb
|
||||
- Upgraded to Swift 4.2 [388](https://github.com/yonaskolb/XcodeGen/pull/388) @yonaskolb
|
||||
|
||||
## 1.11.2
|
||||
|
||||
|
||||
+17
-17
@@ -3,11 +3,11 @@
|
||||
"pins": [
|
||||
{
|
||||
"package": "AEXML",
|
||||
"repositoryURL": "https://github.com/tadija/AEXML.git",
|
||||
"repositoryURL": "https://github.com/tadija/AEXML",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "6eea665515d079c338690147082a8084a36484b0",
|
||||
"version": "4.3.0"
|
||||
"revision": "54bb8ea6fb693dd3f92a89e5fcc19e199fdeedd0",
|
||||
"version": "4.3.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -24,8 +24,8 @@
|
||||
"repositoryURL": "https://github.com/yonaskolb/JSONUtilities.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "d9f957b1b2a078c93f96c723040d4cbffcb7d3f9",
|
||||
"version": "4.0.2"
|
||||
"revision": "db238f4858ac2ac3fff228b5b71ce90488a6a9b3",
|
||||
"version": "4.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -46,15 +46,6 @@
|
||||
"version": "3.1.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "ShellOut",
|
||||
"repositoryURL": "https://github.com/JohnSundell/ShellOut.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f1c253a34a40df4bfd268b09fdb101b059f6d52d",
|
||||
"version": "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Spectre",
|
||||
"repositoryURL": "https://github.com/kylef/Spectre.git",
|
||||
@@ -65,12 +56,21 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "xcproj",
|
||||
"package": "SwiftShell",
|
||||
"repositoryURL": "https://github.com/kareman/SwiftShell",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "beebe43c986d89ea5359ac3adcb42dac94e5e08a",
|
||||
"version": "4.1.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "xcodeproj",
|
||||
"repositoryURL": "https://github.com/tuist/xcodeproj.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "5253c22f208558264e3a64a3a29f11537ca1b41a",
|
||||
"version": "4.3.1"
|
||||
"revision": "869ae3f417b0fb545e454ead36e2e13f157265a2",
|
||||
"version": "6.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
// swift-tools-version:4.0
|
||||
// swift-tools-version:4.2
|
||||
|
||||
import PackageDescription
|
||||
|
||||
@@ -13,10 +13,10 @@ let package = Package(
|
||||
.package(url: "https://github.com/kylef/PathKit.git", from: "0.9.0"),
|
||||
.package(url: "https://github.com/kylef/Commander.git", from: "0.8.0"),
|
||||
.package(url: "https://github.com/jpsim/Yams.git", from: "1.0.0"),
|
||||
.package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.0.0"),
|
||||
.package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.1.0"),
|
||||
.package(url: "https://github.com/kylef/Spectre.git", from: "0.9.0"),
|
||||
.package(url: "https://github.com/onevcat/Rainbow.git", from: "3.0.0"),
|
||||
.package(url: "https://github.com/tuist/xcodeproj.git", from: "4.3.1"),
|
||||
.package(url: "https://github.com/tuist/xcodeproj.git", from: "6.2.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "XcodeGen", dependencies: [
|
||||
@@ -27,12 +27,12 @@ let package = Package(
|
||||
.target(name: "XcodeGenKit", dependencies: [
|
||||
"ProjectSpec",
|
||||
"JSONUtilities",
|
||||
"xcproj",
|
||||
"xcodeproj",
|
||||
"PathKit",
|
||||
]),
|
||||
.target(name: "ProjectSpec", dependencies: [
|
||||
"JSONUtilities",
|
||||
"xcproj",
|
||||
"xcodeproj",
|
||||
"Yams",
|
||||
]),
|
||||
.testTarget(name: "XcodeGenKitTests", dependencies: [
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct Config: Equatable {
|
||||
public var name: String
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct Dependency: Equatable {
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct DeploymentTarget: Equatable {
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import xcproj
|
||||
import Yams
|
||||
|
||||
public struct Project: BuildSettingsContainer {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public typealias BuildType = XCScheme.BuildAction.Entry.BuildFor
|
||||
|
||||
@@ -311,7 +311,7 @@ extension BuildType: JSONPrimitiveConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
extension XCScheme.EnvironmentVariable: JSONObjectConvertible, Equatable {
|
||||
extension XCScheme.EnvironmentVariable: JSONObjectConvertible {
|
||||
|
||||
private static func parseValue(_ value: Any) -> String {
|
||||
if let bool = value as? Bool {
|
||||
@@ -346,10 +346,4 @@ extension XCScheme.EnvironmentVariable: JSONObjectConvertible, Equatable {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
public static func == (lhs: XCScheme.EnvironmentVariable, rhs: XCScheme.EnvironmentVariable) -> Bool {
|
||||
return lhs.variable == rhs.variable &&
|
||||
lhs.value == rhs.value &&
|
||||
lhs.enabled == rhs.enabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertible {
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct SpecOptions: Equatable {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public struct LegacyTarget: Equatable {
|
||||
public var toolPath: String
|
||||
@@ -39,14 +39,14 @@ public struct Target: ProjectTarget {
|
||||
public var legacy: LegacyTarget?
|
||||
public var deploymentTarget: Version?
|
||||
public var attributes: [String: Any]
|
||||
internal var productName: String?
|
||||
public var productName: String
|
||||
|
||||
public var isLegacy: Bool {
|
||||
return legacy != nil
|
||||
}
|
||||
|
||||
public var filename: String {
|
||||
var filename = productName ?? name
|
||||
var filename = productName
|
||||
if let fileExtension = type.fileExtension {
|
||||
filename += ".\(fileExtension)"
|
||||
}
|
||||
@@ -57,6 +57,7 @@ public struct Target: ProjectTarget {
|
||||
name: String,
|
||||
type: PBXProductType,
|
||||
platform: Platform,
|
||||
productName: String? = nil,
|
||||
deploymentTarget: Version? = nil,
|
||||
settings: Settings = .empty,
|
||||
configFiles: [String: String] = [:],
|
||||
@@ -76,6 +77,7 @@ public struct Target: ProjectTarget {
|
||||
self.type = type
|
||||
self.platform = platform
|
||||
self.deploymentTarget = deploymentTarget
|
||||
self.productName = productName ?? name
|
||||
self.settings = settings
|
||||
self.configFiles = configFiles
|
||||
self.sources = sources
|
||||
@@ -230,8 +232,9 @@ extension LegacyTarget: JSONObjectConvertible {
|
||||
extension Target: NamedJSONDictionaryConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = jsonDictionary.json(atKeyPath: "name") ?? name
|
||||
productName = jsonDictionary.json(atKeyPath: "productName")
|
||||
let resolvedName: String = jsonDictionary.json(atKeyPath: "name") ?? name
|
||||
self.name = resolvedName
|
||||
self.productName = jsonDictionary.json(atKeyPath: "productName") ?? resolvedName
|
||||
let typeString: String = try jsonDictionary.json(atKeyPath: "type")
|
||||
if let type = PBXProductType(string: typeString) {
|
||||
self.type = type
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public struct TargetScheme: Equatable {
|
||||
public var testTargets: [String]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public struct TargetSource: Equatable {
|
||||
|
||||
@@ -57,7 +57,7 @@ public struct TargetSource: Equatable {
|
||||
case sharedSupport
|
||||
case plugins
|
||||
|
||||
public var destination: xcproj.PBXCopyFilesBuildPhase.SubFolder? {
|
||||
public var destination: xcodeproj.PBXCopyFilesBuildPhase.SubFolder? {
|
||||
switch self {
|
||||
case .absolutePath: return .absolutePath
|
||||
case .productsDirectory: return .productsDirectory
|
||||
@@ -82,7 +82,7 @@ public struct TargetSource: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public var buildPhase: xcproj.BuildPhase? {
|
||||
public var buildPhase: xcodeproj.BuildPhase? {
|
||||
switch self {
|
||||
case .sources: return .sources
|
||||
case .headers: return .headers
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
extension PBXProductType {
|
||||
|
||||
@@ -60,7 +60,7 @@ extension XCScheme.CommandLineArguments {
|
||||
public convenience init(_ dict: [String: Bool]) {
|
||||
let args = dict.map { tuple in
|
||||
XCScheme.CommandLineArguments.CommandLineArgument(name: tuple.key, enabled: tuple.value)
|
||||
}
|
||||
}.sorted { $0.name < $1.name }
|
||||
self.init(arguments: args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
let version = try Version("1.11.2")
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import Yams
|
||||
|
||||
public class PBXProjGenerator {
|
||||
@@ -12,13 +11,12 @@ public class PBXProjGenerator {
|
||||
let pbxProj: PBXProj
|
||||
var sourceGenerator: SourceGenerator!
|
||||
|
||||
var targetObjects: [String: ObjectReference<PBXTarget>] = [:]
|
||||
var targetAggregateObjects: [String: ObjectReference<PBXAggregateTarget>] = [:]
|
||||
var targetBuildFiles: [String: ObjectReference<PBXBuildFile>] = [:]
|
||||
var targetFileReferences: [String: String] = [:]
|
||||
var targetObjects: [String: PBXTarget] = [:]
|
||||
var targetAggregateObjects: [String: PBXAggregateTarget] = [:]
|
||||
var targetFileReferences: [String: PBXFileReference] = [:]
|
||||
|
||||
var carthageFrameworksByPlatform: [String: Set<String>] = [:]
|
||||
var frameworkFiles: [String] = []
|
||||
var carthageFrameworksByPlatform: [String: Set<PBXFileElement>] = [:]
|
||||
var frameworkFiles: [PBXFileElement] = []
|
||||
|
||||
var generated = false
|
||||
|
||||
@@ -28,21 +26,15 @@ public class PBXProjGenerator {
|
||||
|
||||
public init(project: Project) {
|
||||
self.project = project
|
||||
pbxProj = PBXProj(rootObject: "", objectVersion: 46)
|
||||
sourceGenerator = SourceGenerator(project: project) { [unowned self] id, object in
|
||||
self.addObject(id: id, object)
|
||||
pbxProj = PBXProj(rootObject: nil, objectVersion: 46)
|
||||
sourceGenerator = SourceGenerator(project: project) { [unowned self] object in
|
||||
_ = self.addObject(object)
|
||||
}
|
||||
}
|
||||
|
||||
func addObject(id: String, _ object: PBXObject) -> String {
|
||||
let reference = pbxProj.objects.generateReference(object, id)
|
||||
pbxProj.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)
|
||||
func addObject<T: PBXObject>(_ object: T) -> T {
|
||||
pbxProj.add(object: object)
|
||||
return object
|
||||
}
|
||||
|
||||
public func generate() throws -> PBXProj {
|
||||
@@ -55,35 +47,34 @@ public class PBXProjGenerator {
|
||||
try sourceGenerator.getFileGroups(path: group)
|
||||
}
|
||||
|
||||
let buildConfigs: [ObjectReference<XCBuildConfiguration>] = project.configs.map { config in
|
||||
let buildConfigs: [XCBuildConfiguration] = project.configs.map { config in
|
||||
let buildSettings = project.getProjectBuildSettings(config: config)
|
||||
var baseConfigurationReference: String?
|
||||
if let configPath = project.configFiles[config.name] {
|
||||
baseConfigurationReference = sourceGenerator.getContainedFileReference(path: project.basePath + configPath)
|
||||
var baseConfiguration: PBXFileReference?
|
||||
if let configPath = project.configFiles[config.name],
|
||||
let fileReference = sourceGenerator.getContainedFileReference(path: project.basePath + configPath) as? PBXFileReference {
|
||||
baseConfiguration = fileReference
|
||||
}
|
||||
return createObject(
|
||||
id: config.name,
|
||||
let buildConfig = addObject(
|
||||
XCBuildConfiguration(
|
||||
name: config.name,
|
||||
baseConfigurationReference: baseConfigurationReference,
|
||||
buildSettings: buildSettings
|
||||
)
|
||||
)
|
||||
buildConfig.baseConfiguration = baseConfiguration
|
||||
return buildConfig
|
||||
}
|
||||
|
||||
let configName = project.options.defaultConfig ?? buildConfigs.first?.object.name ?? ""
|
||||
let buildConfigList = createObject(
|
||||
id: project.name,
|
||||
let configName = project.options.defaultConfig ?? buildConfigs.first?.name ?? ""
|
||||
let buildConfigList = addObject(
|
||||
XCConfigurationList(
|
||||
buildConfigurations: buildConfigs.map { $0.reference },
|
||||
buildConfigurations: buildConfigs,
|
||||
defaultConfigurationName: configName
|
||||
)
|
||||
)
|
||||
|
||||
var derivedGroups: [ObjectReference<PBXGroup>] = []
|
||||
var derivedGroups: [PBXGroup] = []
|
||||
|
||||
let mainGroup = createObject(
|
||||
id: "Project",
|
||||
let mainGroup = addObject(
|
||||
PBXGroup(
|
||||
children: [],
|
||||
sourceTree: .group,
|
||||
@@ -93,18 +84,17 @@ public class PBXProjGenerator {
|
||||
)
|
||||
)
|
||||
|
||||
let pbxProject = createObject(
|
||||
id: project.name,
|
||||
let pbxProject = addObject(
|
||||
PBXProject(
|
||||
name: project.name,
|
||||
buildConfigurationList: buildConfigList.reference,
|
||||
buildConfigurationList: buildConfigList,
|
||||
compatibilityVersion: "Xcode 3.2",
|
||||
mainGroup: mainGroup.reference,
|
||||
mainGroup: mainGroup,
|
||||
developmentRegion: project.options.developmentLanguage ?? "en"
|
||||
)
|
||||
)
|
||||
|
||||
pbxProj.rootObject = pbxProject.reference
|
||||
pbxProj.rootObject = pbxProject
|
||||
|
||||
for target in project.targets {
|
||||
let targetObject: PBXTarget
|
||||
@@ -115,26 +105,26 @@ public class PBXProjGenerator {
|
||||
buildToolPath: target.legacy?.toolPath,
|
||||
buildArgumentsString: target.legacy?.arguments,
|
||||
passBuildSettingsInEnvironment: target.legacy?.passSettings ?? false,
|
||||
buildWorkingDirectory: target.legacy?.workingDirectory
|
||||
buildWorkingDirectory: target.legacy?.workingDirectory,
|
||||
buildPhases: []
|
||||
)
|
||||
} else {
|
||||
targetObject = PBXNativeTarget(name: target.name)
|
||||
targetObject = PBXNativeTarget(name: target.name, buildPhases: [])
|
||||
}
|
||||
|
||||
targetObjects[target.name] = createObject(id: target.name, targetObject)
|
||||
targetObjects[target.name] = addObject(targetObject)
|
||||
|
||||
var explicitFileType: String?
|
||||
var lastKnownFileType: String?
|
||||
let fileType = PBXFileReference.fileType(path: Path(target.filename))
|
||||
let fileType = Xcode.fileType(path: Path(target.filename))
|
||||
if target.platform == .macOS || target.platform == .watchOS || target.type == .framework {
|
||||
explicitFileType = fileType
|
||||
} else {
|
||||
lastKnownFileType = fileType
|
||||
}
|
||||
|
||||
if !target.isLegacy {
|
||||
let fileReference = createObject(
|
||||
id: target.name,
|
||||
if !target.isLegacy && targetFileReferences[target.productName] == nil {
|
||||
let fileReference = addObject(
|
||||
PBXFileReference(
|
||||
sourceTree: .buildProductsDir,
|
||||
explicitFileType: explicitFileType,
|
||||
@@ -144,18 +134,13 @@ public class PBXProjGenerator {
|
||||
)
|
||||
)
|
||||
|
||||
targetFileReferences[target.name] = fileReference.reference
|
||||
targetBuildFiles[target.name] = createObject(
|
||||
id: fileReference.reference,
|
||||
PBXBuildFile(fileRef: fileReference.reference)
|
||||
)
|
||||
targetFileReferences[target.productName] = fileReference
|
||||
}
|
||||
}
|
||||
|
||||
for target in project.aggregateTargets {
|
||||
|
||||
let aggregateTarget = createObject(
|
||||
id: target.name,
|
||||
let aggregateTarget = addObject(
|
||||
PBXAggregateTarget(
|
||||
name: target.name,
|
||||
productName: target.name
|
||||
@@ -167,10 +152,9 @@ public class PBXProjGenerator {
|
||||
try project.targets.forEach(generateTarget)
|
||||
try project.aggregateTargets.forEach(generateAggregateTarget)
|
||||
|
||||
let productGroup = createObject(
|
||||
id: "Products",
|
||||
let productGroup = addObject(
|
||||
PBXGroup(
|
||||
children: Array(targetFileReferences.values),
|
||||
children: targetFileReferences.valueArray,
|
||||
sourceTree: .group,
|
||||
name: "Products"
|
||||
)
|
||||
@@ -179,34 +163,29 @@ public class PBXProjGenerator {
|
||||
|
||||
if !carthageFrameworksByPlatform.isEmpty {
|
||||
var platforms: [PBXGroup] = []
|
||||
var platformReferences: [String] = []
|
||||
for (platform, fileReferences) in carthageFrameworksByPlatform {
|
||||
let platformGroup: ObjectReference<PBXGroup> = createObject(
|
||||
id: "Carthage" + platform,
|
||||
for (platform, files) in carthageFrameworksByPlatform {
|
||||
let platformGroup: PBXGroup = addObject(
|
||||
PBXGroup(
|
||||
children: fileReferences.sorted(),
|
||||
children: files.sorted { $0.nameOrPath < $1.nameOrPath },
|
||||
sourceTree: .group,
|
||||
path: platform
|
||||
)
|
||||
)
|
||||
platformReferences.append(platformGroup.reference)
|
||||
platforms.append(platformGroup.object)
|
||||
platforms.append(platformGroup)
|
||||
}
|
||||
let carthageGroup = createObject(
|
||||
id: "Carthage",
|
||||
let carthageGroup = addObject(
|
||||
PBXGroup(
|
||||
children: platformReferences.sorted(),
|
||||
children: platforms,
|
||||
sourceTree: .group,
|
||||
name: "Carthage",
|
||||
path: carthageBuildPath
|
||||
)
|
||||
)
|
||||
frameworkFiles.append(carthageGroup.reference)
|
||||
frameworkFiles.append(carthageGroup)
|
||||
}
|
||||
|
||||
if !frameworkFiles.isEmpty {
|
||||
let group = createObject(
|
||||
id: "Frameworks",
|
||||
let group = addObject(
|
||||
PBXGroup(
|
||||
children: frameworkFiles,
|
||||
sourceTree: .group,
|
||||
@@ -216,90 +195,86 @@ public class PBXProjGenerator {
|
||||
derivedGroups.append(group)
|
||||
}
|
||||
|
||||
mainGroup.object.children = Array(sourceGenerator.rootGroups)
|
||||
mainGroup.children = Array(sourceGenerator.rootGroups)
|
||||
sortGroups(group: mainGroup)
|
||||
// add derived groups at the end
|
||||
derivedGroups.forEach(sortGroups)
|
||||
mainGroup.object.children += derivedGroups
|
||||
.sorted { $0.object.nameOrPath.localizedStandardCompare($1.object.nameOrPath) == .orderedAscending }
|
||||
.map { $0.reference }
|
||||
mainGroup.children += derivedGroups
|
||||
.sorted { $0.nameOrPath.localizedStandardCompare($1.nameOrPath) == .orderedAscending }
|
||||
.map { $0 }
|
||||
|
||||
let projectAttributes: [String: Any] = ["LastUpgradeCheck": project.xcodeVersion]
|
||||
.merged(project.attributes)
|
||||
.merged(generateTargetAttributes() ?? [:])
|
||||
|
||||
let knownRegions = sourceGenerator.knownRegions.sorted()
|
||||
pbxProject.object.knownRegions = knownRegions.isEmpty ? ["en"] : knownRegions
|
||||
|
||||
let allTargets: [ObjectReference<PBXTarget>] = Array(targetObjects.values) + Array(targetAggregateObjects.values.map { ObjectReference(reference: $0.reference, object: $0.object) })
|
||||
pbxProject.object.targets = allTargets
|
||||
.sorted { $0.object.name < $1.object.name }
|
||||
.map { $0.reference }
|
||||
pbxProject.object.attributes = projectAttributes
|
||||
pbxProject.knownRegions = knownRegions.isEmpty ? ["en"] : knownRegions
|
||||
|
||||
let allTargets: [PBXTarget] = Array(targetObjects.values) + Array(targetAggregateObjects.values)
|
||||
pbxProject.targets = allTargets
|
||||
.sorted { $0.name < $1.name }
|
||||
pbxProject.attributes = projectAttributes
|
||||
pbxProject.targetAttributes = generateTargetAttributes()
|
||||
return pbxProj
|
||||
}
|
||||
|
||||
func generateAggregateTarget(_ target: AggregateTarget) throws {
|
||||
|
||||
let aggregateTarget = targetAggregateObjects[target.name]!.object
|
||||
let aggregateTarget = targetAggregateObjects[target.name]!
|
||||
|
||||
let configs: [ObjectReference<XCBuildConfiguration>] = project.configs.map { config in
|
||||
let configs: [XCBuildConfiguration] = project.configs.map { config in
|
||||
|
||||
let buildSettings = project.getBuildSettings(settings: target.settings, config: config)
|
||||
|
||||
var baseConfigurationReference: String?
|
||||
var baseConfiguration: PBXFileReference?
|
||||
if let configPath = target.configFiles[config.name] {
|
||||
baseConfigurationReference = sourceGenerator.getContainedFileReference(path: project.basePath + configPath)
|
||||
baseConfiguration = sourceGenerator.getContainedFileReference(path: project.basePath + configPath) as? PBXFileReference
|
||||
}
|
||||
let buildConfig = XCBuildConfiguration(
|
||||
name: config.name,
|
||||
baseConfigurationReference: baseConfigurationReference,
|
||||
baseConfiguration: baseConfiguration,
|
||||
buildSettings: buildSettings
|
||||
)
|
||||
return createObject(id: config.name + target.name, buildConfig)
|
||||
return addObject(buildConfig)
|
||||
}
|
||||
|
||||
let dependencies: [String] = target.targets.map { generateTargetDependency(from: target.name, to: $0).reference }
|
||||
let dependencies = target.targets.map { generateTargetDependency(from: target.name, to: $0) }
|
||||
|
||||
let buildConfigList = createObject(id: target.name, XCConfigurationList(
|
||||
buildConfigurations: configs.map { $0.reference },
|
||||
let buildConfigList = addObject(XCConfigurationList(
|
||||
buildConfigurations: configs,
|
||||
defaultConfigurationName: ""
|
||||
))
|
||||
|
||||
var buildPhases: [String] = []
|
||||
var buildPhases: [PBXBuildPhase] = []
|
||||
buildPhases += try target.buildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) }
|
||||
|
||||
aggregateTarget.buildPhases = buildPhases
|
||||
aggregateTarget.buildConfigurationList = buildConfigList.reference
|
||||
aggregateTarget.buildConfigurationList = buildConfigList
|
||||
aggregateTarget.dependencies = dependencies
|
||||
}
|
||||
|
||||
func generateTargetDependency(from: String, to target: String) -> ObjectReference<PBXTargetDependency> {
|
||||
guard let targetReference = targetObjects[target]?.reference ?? targetAggregateObjects[target]?.reference else {
|
||||
func generateTargetDependency(from: String, to target: String) -> PBXTargetDependency {
|
||||
guard let targetObject = targetObjects[target] ?? targetAggregateObjects[target] else {
|
||||
fatalError("target not found")
|
||||
}
|
||||
let targetProxy = createObject(
|
||||
id: "\(from)-\(target)",
|
||||
let targetProxy = addObject(
|
||||
PBXContainerItemProxy(
|
||||
containerPortal: pbxProj.rootObject,
|
||||
remoteGlobalIDString: targetReference,
|
||||
containerPortal: pbxProj.rootObject!,
|
||||
remoteGlobalID: targetObject,
|
||||
proxyType: .nativeTarget,
|
||||
remoteInfo: target
|
||||
)
|
||||
)
|
||||
|
||||
let targetDependency = createObject(
|
||||
id: "\(from)-\(target)",
|
||||
let targetDependency = addObject(
|
||||
PBXTargetDependency(
|
||||
target: targetReference,
|
||||
targetProxy: targetProxy.reference
|
||||
target: targetObject,
|
||||
targetProxy: targetProxy
|
||||
)
|
||||
)
|
||||
return targetDependency
|
||||
}
|
||||
|
||||
func generateBuildScript(targetName: String, buildScript: BuildScript) throws -> String {
|
||||
func generateBuildScript(targetName: String, buildScript: BuildScript) throws -> PBXShellScriptBuildPhase {
|
||||
|
||||
let shellScript: String
|
||||
switch buildScript.script {
|
||||
@@ -310,47 +285,43 @@ public class PBXProjGenerator {
|
||||
}
|
||||
|
||||
let shellScriptPhase = PBXShellScriptBuildPhase(
|
||||
files: [],
|
||||
name: buildScript.name ?? "Run Script",
|
||||
inputPaths: buildScript.inputFiles,
|
||||
outputPaths: buildScript.outputFiles,
|
||||
shellPath: buildScript.shell ?? "/bin/sh",
|
||||
shellScript: shellScript
|
||||
shellScript: shellScript,
|
||||
runOnlyForDeploymentPostprocessing: buildScript.runOnlyWhenInstalling,
|
||||
showEnvVarsInLog: buildScript.showEnvVars
|
||||
)
|
||||
shellScriptPhase.runOnlyForDeploymentPostprocessing = buildScript.runOnlyWhenInstalling
|
||||
shellScriptPhase.showEnvVarsInLog = buildScript.showEnvVars
|
||||
return createObject(id: String(describing: buildScript.name) + shellScript + targetName, shellScriptPhase).reference
|
||||
return addObject(shellScriptPhase)
|
||||
}
|
||||
|
||||
func generateTargetAttributes() -> [String: Any]? {
|
||||
func generateTargetAttributes() -> [PBXTarget: [String: Any]] {
|
||||
|
||||
var targetAttributes: [String: [String: Any]] = [:]
|
||||
var targetAttributes: [PBXTarget: [String: Any]] = [:]
|
||||
|
||||
let uiTestTargets = pbxProj.objects.nativeTargets.objectReferences.filter { $0.object.productType == .uiTestBundle }
|
||||
let uiTestTargets = pbxProj.nativeTargets.filter { $0.productType == .uiTestBundle }
|
||||
for uiTestTarget in uiTestTargets {
|
||||
|
||||
// look up TEST_TARGET_NAME build setting
|
||||
func testTargetName(_ target: PBXTarget) -> String? {
|
||||
guard let configurationList = target.buildConfigurationList else { return nil }
|
||||
guard let buildConfigurationReferences = self.pbxProj.objects.configurationLists[configurationList]?.buildConfigurations else { return nil }
|
||||
guard let buildConfigurations = target.buildConfigurationList?.buildConfigurations else { return nil }
|
||||
|
||||
let configs = buildConfigurationReferences
|
||||
.compactMap { ref in self.pbxProj.objects.buildConfigurations[ref] }
|
||||
|
||||
return configs
|
||||
return buildConfigurations
|
||||
.compactMap { $0.buildSettings["TEST_TARGET_NAME"] as? String }
|
||||
.first
|
||||
}
|
||||
|
||||
guard let name = testTargetName(uiTestTarget.object) else { continue }
|
||||
guard let target = self.pbxProj.objects.targets(named: name).first else { continue }
|
||||
guard let name = testTargetName(uiTestTarget) else { continue }
|
||||
guard let target = self.pbxProj.targets(named: name).first else { continue }
|
||||
|
||||
targetAttributes[uiTestTarget.reference, default: [:]].merge(["TestTargetID": target.reference])
|
||||
// FIX: Can't set in xcproj 5.0+
|
||||
targetAttributes[uiTestTarget, default: [:]].merge(["TestTargetID": target])
|
||||
}
|
||||
|
||||
func generateTargetAttributes(_ target: ProjectTarget, targetReference: String) {
|
||||
func generateTargetAttributes(_ target: ProjectTarget, pbxTarget: PBXTarget) {
|
||||
if !target.attributes.isEmpty {
|
||||
targetAttributes[targetReference, default: [:]].merge(target.attributes)
|
||||
targetAttributes[pbxTarget, default: [:]].merge(target.attributes)
|
||||
}
|
||||
|
||||
func getSingleBuildSetting(_ setting: String) -> String? {
|
||||
@@ -367,7 +338,7 @@ public class PBXProjGenerator {
|
||||
|
||||
func setTargetAttribute(attribute: String, buildSetting: String) {
|
||||
if let setting = getSingleBuildSetting(buildSetting) {
|
||||
targetAttributes[targetReference, default: [:]].merge([attribute: setting])
|
||||
targetAttributes[pbxTarget, default: [:]].merge([attribute: setting])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,49 +347,39 @@ public class PBXProjGenerator {
|
||||
}
|
||||
|
||||
for target in project.aggregateTargets {
|
||||
guard let targetReference = targetAggregateObjects[target.name]?.reference else {
|
||||
guard let pbxTarget = targetAggregateObjects[target.name] else {
|
||||
continue
|
||||
}
|
||||
generateTargetAttributes(target, targetReference: targetReference)
|
||||
generateTargetAttributes(target, pbxTarget: pbxTarget)
|
||||
}
|
||||
|
||||
for target in project.targets {
|
||||
guard let targetReference = targetObjects[target.name]?.reference else {
|
||||
guard let pbxTarget = targetObjects[target.name] else {
|
||||
continue
|
||||
}
|
||||
generateTargetAttributes(target, targetReference: targetReference)
|
||||
generateTargetAttributes(target, pbxTarget: pbxTarget)
|
||||
}
|
||||
|
||||
return targetAttributes.isEmpty ? nil : ["TargetAttributes": targetAttributes]
|
||||
return targetAttributes
|
||||
}
|
||||
|
||||
func sortGroups(group: ObjectReference<PBXGroup>) {
|
||||
func sortGroups(group: PBXGroup) {
|
||||
// sort children
|
||||
let children = group.object.children
|
||||
.compactMap { reference -> ObjectReference<PBXFileElement>? in
|
||||
guard let fileElement = pbxProj.objects.getFileElement(reference: reference) else {
|
||||
return nil
|
||||
}
|
||||
return ObjectReference(reference: reference, object: fileElement)
|
||||
}
|
||||
let children = group.children
|
||||
.sorted { child1, child2 in
|
||||
let sortOrder1 = child1.object.getSortOrder(groupSortPosition: project.options.groupSortPosition)
|
||||
let sortOrder2 = child2.object.getSortOrder(groupSortPosition: project.options.groupSortPosition)
|
||||
let sortOrder1 = child1.getSortOrder(groupSortPosition: project.options.groupSortPosition)
|
||||
let sortOrder2 = child2.getSortOrder(groupSortPosition: project.options.groupSortPosition)
|
||||
|
||||
if sortOrder1 == sortOrder2 {
|
||||
return child1.object.nameOrPath.localizedStandardCompare(child2.object.nameOrPath) == .orderedAscending
|
||||
return child1.nameOrPath.localizedStandardCompare(child2.nameOrPath) == .orderedAscending
|
||||
} else {
|
||||
return sortOrder1 < sortOrder2
|
||||
}
|
||||
}
|
||||
group.object.children = children.map { $0.reference }.filter { $0 != group.reference }
|
||||
group.children = children.filter { $0 != group }
|
||||
|
||||
// sort sub groups
|
||||
let childGroups = group.object.children.compactMap { reference -> ObjectReference<PBXGroup>? in
|
||||
guard let group = pbxProj.objects.groups[reference] else {
|
||||
return nil
|
||||
}
|
||||
return ObjectReference(reference: reference, object: group) }
|
||||
let childGroups = group.children.compactMap { $0 as? PBXGroup }
|
||||
childGroups.forEach(sortGroups)
|
||||
}
|
||||
|
||||
@@ -428,19 +389,20 @@ public class PBXProjGenerator {
|
||||
let carthageDependencies = getAllCarthageDependencies(target: target)
|
||||
|
||||
let sourceFiles = try sourceGenerator.getAllSourceFiles(targetType: target.type, sources: target.sources)
|
||||
.sorted { $0.path.lastComponent < $1.path.lastComponent }
|
||||
|
||||
var plistPath: Path?
|
||||
var searchForPlist = true
|
||||
var anyDependencyRequiresObjCLinking = false
|
||||
|
||||
var dependencies: [String] = []
|
||||
var targetFrameworkBuildFiles: [String] = []
|
||||
var dependencies: [PBXTargetDependency] = []
|
||||
var targetFrameworkBuildFiles: [PBXBuildFile] = []
|
||||
var frameworkBuildPaths = Set<String>()
|
||||
var copyFilesBuildPhasesFiles: [TargetSource.BuildPhase.CopyFilesSettings: [String]] = [:]
|
||||
var copyFrameworksReferences: [String] = []
|
||||
var copyResourcesReferences: [String] = []
|
||||
var copyWatchReferences: [String] = []
|
||||
var extensions: [String] = []
|
||||
var copyFilesBuildPhasesFiles: [TargetSource.BuildPhase.CopyFilesSettings: [PBXBuildFile]] = [:]
|
||||
var copyFrameworksReferences: [PBXBuildFile] = []
|
||||
var copyResourcesReferences: [PBXBuildFile] = []
|
||||
var copyWatchReferences: [PBXBuildFile] = []
|
||||
var extensions: [PBXBuildFile] = []
|
||||
var carthageFrameworksToEmbed: [String] = []
|
||||
|
||||
let targetDependencies = (target.transitivelyLinkDependencies ?? project.options.transitivelyLinkDependencies) ?
|
||||
@@ -475,11 +437,11 @@ public class PBXProjGenerator {
|
||||
case .target:
|
||||
let dependencyTargetName = dependency.reference
|
||||
let targetDependency = generateTargetDependency(from: target.name, to: dependencyTargetName)
|
||||
dependencies.append(targetDependency.reference)
|
||||
dependencies.append(targetDependency)
|
||||
|
||||
guard let dependencyTarget = project.getTarget(dependencyTargetName) else { continue }
|
||||
|
||||
let dependencyFileReference = targetFileReferences[dependencyTargetName]!
|
||||
let dependencyFileReference = targetFileReferences[dependencyTarget.productName]!
|
||||
|
||||
let dependecyLinkage = dependencyTarget.defaultLinkage
|
||||
let link = dependency.link ?? (
|
||||
@@ -487,15 +449,11 @@ public class PBXProjGenerator {
|
||||
|| (dependecyLinkage == .static && target.type.isExecutable)
|
||||
)
|
||||
if link {
|
||||
let dependencyBuildFile = targetBuildFiles[dependencyTargetName]!
|
||||
let buildFile = createObject(
|
||||
id: dependencyBuildFile.reference + target.name,
|
||||
PBXBuildFile(
|
||||
fileRef: dependencyBuildFile.object.fileRef!,
|
||||
settings: getDependencyFrameworkSettings(dependency: dependency)
|
||||
)
|
||||
let dependencyFile = targetFileReferences[dependencyTarget.productName]!
|
||||
let buildFile = addObject(
|
||||
PBXBuildFile(file: dependencyFile, settings: getDependencyFrameworkSettings(dependency: dependency))
|
||||
)
|
||||
targetFrameworkBuildFiles.append(buildFile.reference)
|
||||
targetFrameworkBuildFiles.append(buildFile)
|
||||
|
||||
if !anyDependencyRequiresObjCLinking
|
||||
&& dependencyTarget.requiresObjCLinking ?? (dependencyTarget.type == .staticLibrary) {
|
||||
@@ -508,32 +466,31 @@ public class PBXProjGenerator {
|
||||
|| (target.type.isTest && (dependencyTarget.type.isFramework || dependencyTarget.type == .bundle))
|
||||
))
|
||||
if embed {
|
||||
let embedFile = createObject(
|
||||
id: dependencyFileReference + target.name,
|
||||
let embedFile = addObject(
|
||||
PBXBuildFile(
|
||||
fileRef: dependencyFileReference,
|
||||
file: dependencyFileReference,
|
||||
settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? !dependencyTarget.type.isExecutable)
|
||||
)
|
||||
)
|
||||
|
||||
if dependencyTarget.type.isExtension {
|
||||
// embed app extension
|
||||
extensions.append(embedFile.reference)
|
||||
extensions.append(embedFile)
|
||||
} else if dependencyTarget.type.isFramework {
|
||||
copyFrameworksReferences.append(embedFile.reference)
|
||||
copyFrameworksReferences.append(embedFile)
|
||||
} else if dependencyTarget.type.isApp && dependencyTarget.platform == .watchOS {
|
||||
copyWatchReferences.append(embedFile.reference)
|
||||
copyWatchReferences.append(embedFile)
|
||||
} else if dependencyTarget.type == .xpcService {
|
||||
copyFilesBuildPhasesFiles[.xpcServices, default: []].append(embedFile.reference)
|
||||
copyFilesBuildPhasesFiles[.xpcServices, default: []].append(embedFile)
|
||||
} else {
|
||||
copyResourcesReferences.append(embedFile.reference)
|
||||
copyResourcesReferences.append(embedFile)
|
||||
}
|
||||
}
|
||||
|
||||
case .framework:
|
||||
guard target.type != .staticLibrary else { break }
|
||||
|
||||
let fileReference: String
|
||||
let fileReference: PBXFileElement
|
||||
if dependency.implicit {
|
||||
fileReference = sourceGenerator.getFileReference(
|
||||
path: Path(dependency.reference),
|
||||
@@ -547,25 +504,20 @@ public class PBXProjGenerator {
|
||||
)
|
||||
}
|
||||
|
||||
let buildFile = createObject(
|
||||
id: "framework" + fileReference + target.name,
|
||||
PBXBuildFile(
|
||||
fileRef: fileReference,
|
||||
settings: getDependencyFrameworkSettings(dependency: dependency)
|
||||
)
|
||||
let buildFile = addObject(
|
||||
PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency))
|
||||
)
|
||||
|
||||
targetFrameworkBuildFiles.append(buildFile.reference)
|
||||
targetFrameworkBuildFiles.append(buildFile)
|
||||
if !frameworkFiles.contains(fileReference) {
|
||||
frameworkFiles.append(fileReference)
|
||||
}
|
||||
|
||||
if embed {
|
||||
let embedFile = createObject(
|
||||
id: "framework embed" + fileReference + target.name,
|
||||
PBXBuildFile(fileRef: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true))
|
||||
let embedFile = addObject(
|
||||
PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true))
|
||||
)
|
||||
copyFrameworksReferences.append(embedFile.reference)
|
||||
copyFrameworksReferences.append(embedFile)
|
||||
}
|
||||
|
||||
let buildPath = Path(dependency.reference).parent().string.quoted
|
||||
@@ -581,17 +533,13 @@ public class PBXProjGenerator {
|
||||
}
|
||||
let fileReference = sourceGenerator.getFileReference(path: frameworkPath, inPath: platformPath)
|
||||
|
||||
let buildFile = createObject(
|
||||
id: "carthage" + fileReference + target.name,
|
||||
PBXBuildFile(
|
||||
fileRef: fileReference,
|
||||
settings: getDependencyFrameworkSettings(dependency: dependency)
|
||||
)
|
||||
let buildFile = addObject(
|
||||
PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency))
|
||||
)
|
||||
|
||||
carthageFrameworksByPlatform[target.platform.carthageDirectoryName, default: []].insert(fileReference)
|
||||
|
||||
targetFrameworkBuildFiles.append(buildFile.reference)
|
||||
targetFrameworkBuildFiles.append(buildFile)
|
||||
|
||||
// Embedding handled by iterating over `carthageDependencies` below
|
||||
}
|
||||
@@ -611,39 +559,36 @@ public class PBXProjGenerator {
|
||||
|
||||
if embed {
|
||||
if directlyEmbedCarthage {
|
||||
let embedFile = createObject(
|
||||
id: "carthage embed" + fileReference + target.name,
|
||||
PBXBuildFile(fileRef: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true))
|
||||
let embedFile = addObject(
|
||||
PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true))
|
||||
)
|
||||
copyFrameworksReferences.append(embedFile.reference)
|
||||
copyFrameworksReferences.append(embedFile)
|
||||
} else {
|
||||
carthageFrameworksToEmbed.append(dependency.reference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fileReference = targetFileReferences[target.name]
|
||||
var buildPhases: [String] = []
|
||||
let fileReference = targetFileReferences[target.productName]
|
||||
var buildPhases: [PBXBuildPhase] = []
|
||||
|
||||
func getBuildFilesForSourceFiles(_ sourceFiles: [SourceFile]) -> [String] {
|
||||
let files = sourceFiles
|
||||
func getBuildFilesForSourceFiles(_ sourceFiles: [SourceFile]) -> [PBXBuildFile] {
|
||||
return sourceFiles
|
||||
.reduce(into: [SourceFile]()) { output, sourceFile in
|
||||
if !output.contains(where: { $0.fileReference == sourceFile.fileReference }) {
|
||||
if !output.contains(where: { $0.fileReference === sourceFile.fileReference }) {
|
||||
output.append(sourceFile)
|
||||
}
|
||||
}
|
||||
.sorted { $0.path.lastComponent < $1.path.lastComponent }
|
||||
return files.map { createObject(id: $0.fileReference + target.name, $0.buildFile) }
|
||||
.map { $0.reference }
|
||||
.map { addObject($0.buildFile) }
|
||||
}
|
||||
|
||||
func getBuildFilesForPhase(_ buildPhase: BuildPhase) -> [String] {
|
||||
func getBuildFilesForPhase(_ buildPhase: BuildPhase) -> [PBXBuildFile] {
|
||||
let filteredSourceFiles = sourceFiles
|
||||
.filter { $0.buildPhase?.buildPhase == buildPhase }
|
||||
return getBuildFilesForSourceFiles(filteredSourceFiles)
|
||||
}
|
||||
|
||||
func getBuildFilesForCopyFilesPhases() -> [TargetSource.BuildPhase.CopyFilesSettings: [String]] {
|
||||
func getBuildFilesForCopyFilesPhases() -> [TargetSource.BuildPhase.CopyFilesSettings: [PBXBuildFile]] {
|
||||
var sourceFilesByCopyFiles: [TargetSource.BuildPhase.CopyFilesSettings: [SourceFile]] = [:]
|
||||
for sourceFile in sourceFiles {
|
||||
guard case let .copyFiles(copyFilesSettings)? = sourceFile.buildPhase else { continue }
|
||||
@@ -655,19 +600,23 @@ public class PBXProjGenerator {
|
||||
buildPhases += try target.prebuildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) }
|
||||
|
||||
let headersBuildPhaseFiles = getBuildFilesForPhase(.headers)
|
||||
if !headersBuildPhaseFiles.isEmpty && (target.type == .framework || target.type == .dynamicLibrary) {
|
||||
let headersBuildPhase = createObject(id: target.name, PBXHeadersBuildPhase(files: headersBuildPhaseFiles))
|
||||
buildPhases.append(headersBuildPhase.reference)
|
||||
if !headersBuildPhaseFiles.isEmpty {
|
||||
if (target.type == .framework || target.type == .dynamicLibrary) {
|
||||
let headersBuildPhase = addObject(PBXHeadersBuildPhase(files: headersBuildPhaseFiles))
|
||||
buildPhases.append(headersBuildPhase)
|
||||
} else {
|
||||
headersBuildPhaseFiles.forEach { pbxProj.delete(object: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
let sourcesBuildPhaseFiles = getBuildFilesForPhase(.sources)
|
||||
let sourcesBuildPhase = createObject(id: target.name, PBXSourcesBuildPhase(files: sourcesBuildPhaseFiles))
|
||||
buildPhases.append(sourcesBuildPhase.reference)
|
||||
let sourcesBuildPhase = addObject(PBXSourcesBuildPhase(files: sourcesBuildPhaseFiles))
|
||||
buildPhases.append(sourcesBuildPhase)
|
||||
|
||||
let resourcesBuildPhaseFiles = getBuildFilesForPhase(.resources) + copyResourcesReferences
|
||||
if !resourcesBuildPhaseFiles.isEmpty {
|
||||
let resourcesBuildPhase = createObject(id: target.name, PBXResourcesBuildPhase(files: resourcesBuildPhaseFiles))
|
||||
buildPhases.append(resourcesBuildPhase.reference)
|
||||
let resourcesBuildPhase = addObject(PBXResourcesBuildPhase(files: resourcesBuildPhaseFiles))
|
||||
buildPhases.append(resourcesBuildPhase)
|
||||
}
|
||||
|
||||
let swiftObjCInterfaceHeader = project.getCombinedBuildSetting("SWIFT_OBJC_INTERFACE_HEADER_NAME", target: target, config: project.configs[0]) as? String
|
||||
@@ -678,10 +627,8 @@ public class PBXProjGenerator {
|
||||
|
||||
let inputPaths = ["$(DERIVED_SOURCES_DIR)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME)"]
|
||||
let outputPaths = ["$(BUILT_PRODUCTS_DIR)/include/$(PRODUCT_MODULE_NAME)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME)"]
|
||||
let script = createObject(
|
||||
id: "Swift.h" + target.name,
|
||||
let script = addObject(
|
||||
PBXShellScriptBuildPhase(
|
||||
files: [],
|
||||
name: "Copy Swift Objective-C Interface Header",
|
||||
inputPaths: inputPaths,
|
||||
outputPaths: outputPaths,
|
||||
@@ -689,14 +636,13 @@ public class PBXProjGenerator {
|
||||
shellScript: "ditto \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n"
|
||||
)
|
||||
)
|
||||
buildPhases.append(script.reference)
|
||||
buildPhases.append(script)
|
||||
}
|
||||
|
||||
copyFilesBuildPhasesFiles.merge(getBuildFilesForCopyFilesPhases()) { $0 + $1 }
|
||||
if !copyFilesBuildPhasesFiles.isEmpty {
|
||||
for (copyFiles, buildPhaseFiles) in copyFilesBuildPhasesFiles {
|
||||
let copyFilesBuildPhase = createObject(
|
||||
id: "copy files" + copyFiles.destination.rawValue + copyFiles.subpath + target.name,
|
||||
let copyFilesBuildPhase = addObject(
|
||||
PBXCopyFilesBuildPhase(
|
||||
dstPath: copyFiles.subpath,
|
||||
dstSubfolderSpec: copyFiles.destination.destination,
|
||||
@@ -704,23 +650,21 @@ public class PBXProjGenerator {
|
||||
)
|
||||
)
|
||||
|
||||
buildPhases.append(copyFilesBuildPhase.reference)
|
||||
buildPhases.append(copyFilesBuildPhase)
|
||||
}
|
||||
}
|
||||
|
||||
if !targetFrameworkBuildFiles.isEmpty {
|
||||
|
||||
let frameworkBuildPhase = createObject(
|
||||
id: target.name,
|
||||
let frameworkBuildPhase = addObject(
|
||||
PBXFrameworksBuildPhase(files: targetFrameworkBuildFiles)
|
||||
)
|
||||
buildPhases.append(frameworkBuildPhase.reference)
|
||||
buildPhases.append(frameworkBuildPhase)
|
||||
}
|
||||
|
||||
if !extensions.isEmpty {
|
||||
|
||||
let copyFilesPhase = createObject(
|
||||
id: "embed app extensions" + target.name,
|
||||
let copyFilesPhase = addObject(
|
||||
PBXCopyFilesBuildPhase(
|
||||
dstPath: "",
|
||||
dstSubfolderSpec: .plugins,
|
||||
@@ -729,14 +673,13 @@ public class PBXProjGenerator {
|
||||
)
|
||||
)
|
||||
|
||||
buildPhases.append(copyFilesPhase.reference)
|
||||
buildPhases.append(copyFilesPhase)
|
||||
}
|
||||
|
||||
copyFrameworksReferences += getBuildFilesForPhase(.frameworks)
|
||||
if !copyFrameworksReferences.isEmpty {
|
||||
|
||||
let copyFilesPhase = createObject(
|
||||
id: "embed frameworks" + target.name,
|
||||
let copyFilesPhase = addObject(
|
||||
PBXCopyFilesBuildPhase(
|
||||
dstPath: "",
|
||||
dstSubfolderSpec: .frameworks,
|
||||
@@ -745,13 +688,12 @@ public class PBXProjGenerator {
|
||||
)
|
||||
)
|
||||
|
||||
buildPhases.append(copyFilesPhase.reference)
|
||||
buildPhases.append(copyFilesPhase)
|
||||
}
|
||||
|
||||
if !copyWatchReferences.isEmpty {
|
||||
|
||||
let copyFilesPhase = createObject(
|
||||
id: "embed watch content" + target.name,
|
||||
let copyFilesPhase = addObject(
|
||||
PBXCopyFilesBuildPhase(
|
||||
dstPath: "$(CONTENTS_FOLDER_PATH)/Watch",
|
||||
dstSubfolderSpec: .productsDirectory,
|
||||
@@ -760,7 +702,7 @@ public class PBXProjGenerator {
|
||||
)
|
||||
)
|
||||
|
||||
buildPhases.append(copyFilesPhase.reference)
|
||||
buildPhases.append(copyFilesPhase)
|
||||
}
|
||||
|
||||
if !carthageFrameworksToEmbed.isEmpty {
|
||||
@@ -770,10 +712,8 @@ public class PBXProjGenerator {
|
||||
let outputPaths = carthageFrameworksToEmbed
|
||||
.map { "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/\($0)\($0.contains(".") ? "" : ".framework")" }
|
||||
let carthageExecutable = project.options.carthageExecutablePath ?? "carthage"
|
||||
let carthageScript = createObject(
|
||||
id: "Carthage" + target.name,
|
||||
let carthageScript = addObject(
|
||||
PBXShellScriptBuildPhase(
|
||||
files: [],
|
||||
name: "Carthage",
|
||||
inputPaths: inputPaths,
|
||||
outputPaths: outputPaths,
|
||||
@@ -781,12 +721,11 @@ public class PBXProjGenerator {
|
||||
shellScript: "\(carthageExecutable) copy-frameworks\n"
|
||||
)
|
||||
)
|
||||
buildPhases.append(carthageScript.reference)
|
||||
buildPhases.append(carthageScript)
|
||||
}
|
||||
|
||||
let buildRules = target.buildRules.map { buildRule in
|
||||
createObject(
|
||||
id: "\(target.name)-\(buildRule.action)-\(buildRule.fileType)",
|
||||
addObject(
|
||||
PBXBuildRule(
|
||||
compilerSpec: buildRule.action.compilerSpec,
|
||||
fileType: buildRule.fileType.fileType,
|
||||
@@ -797,12 +736,12 @@ public class PBXProjGenerator {
|
||||
outputFilesCompilerFlags: buildRule.outputFilesCompilerFlags,
|
||||
script: buildRule.action.script
|
||||
)
|
||||
).reference
|
||||
)
|
||||
}
|
||||
|
||||
buildPhases += try target.postbuildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) }
|
||||
|
||||
let configs: [ObjectReference<XCBuildConfiguration>] = project.configs.map { config in
|
||||
let configs: [XCBuildConfiguration] = project.configs.map { config in
|
||||
var buildSettings = project.getTargetBuildSettings(target: target, config: config)
|
||||
|
||||
// automatically set INFOPLIST_FILE path
|
||||
@@ -876,32 +815,33 @@ public class PBXProjGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
var baseConfigurationReference: String?
|
||||
if let configPath = target.configFiles[config.name] {
|
||||
baseConfigurationReference = sourceGenerator.getContainedFileReference(path: project.basePath + configPath)
|
||||
var baseConfiguration: PBXFileReference?
|
||||
if let configPath = target.configFiles[config.name],
|
||||
let fileReference = sourceGenerator.getContainedFileReference(path: project.basePath + configPath) as? PBXFileReference {
|
||||
baseConfiguration = fileReference
|
||||
}
|
||||
let buildConfig = XCBuildConfiguration(
|
||||
name: config.name,
|
||||
baseConfigurationReference: baseConfigurationReference,
|
||||
buildSettings: buildSettings
|
||||
)
|
||||
return createObject(id: config.name + target.name, buildConfig)
|
||||
buildConfig.baseConfiguration = baseConfiguration
|
||||
return addObject(buildConfig)
|
||||
}
|
||||
|
||||
let buildConfigList = createObject(id: target.name, XCConfigurationList(
|
||||
buildConfigurations: configs.map { $0.reference },
|
||||
let buildConfigList = addObject(XCConfigurationList(
|
||||
buildConfigurations: configs,
|
||||
defaultConfigurationName: ""
|
||||
))
|
||||
|
||||
let targetObject = targetObjects[target.name]!.object
|
||||
let targetObject = targetObjects[target.name]!
|
||||
|
||||
targetObject.name = target.name
|
||||
targetObject.buildConfigurationList = buildConfigList.reference
|
||||
targetObject.buildConfigurationList = buildConfigList
|
||||
targetObject.buildPhases = buildPhases
|
||||
targetObject.dependencies = dependencies
|
||||
targetObject.productName = target.name
|
||||
targetObject.buildRules = buildRules
|
||||
targetObject.productReference = fileReference
|
||||
targetObject.product = fileReference
|
||||
if !target.isLegacy {
|
||||
targetObject.productType = target.type
|
||||
}
|
||||
@@ -943,7 +883,7 @@ public class PBXProjGenerator {
|
||||
if let target = projectTarget as? Target {
|
||||
for dependency in target.dependencies {
|
||||
// don't overwrite frameworks, to allow top level ones to rule
|
||||
if frameworks.contains(reference: dependency.reference) {
|
||||
if frameworks[dependency.reference] != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -987,7 +927,7 @@ public class PBXProjGenerator {
|
||||
|
||||
for dependency in target.dependencies {
|
||||
// don't overwrite dependencies, to allow top level ones to rule
|
||||
if dependencies.contains(reference: dependency.reference) {
|
||||
if dependencies[dependency.reference] != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import Yams
|
||||
|
||||
public class ProjectGenerator {
|
||||
@@ -42,8 +42,8 @@ public class ProjectGenerator {
|
||||
|
||||
func getBuildEntry(_ buildTarget: Scheme.BuildTarget) -> XCScheme.BuildAction.Entry {
|
||||
|
||||
guard let targetReference = pbxProject.objects.targets(named: buildTarget.target).first else {
|
||||
fatalError("Unable to find target named \"\(buildTarget.target)\" in \"PBXProj.objects.targets\"")
|
||||
guard let pbxTarget = pbxProject.targets(named: buildTarget.target).first else {
|
||||
fatalError("Unable to find target named \"\(buildTarget.target)\" in \"PBXProj.targets\"")
|
||||
}
|
||||
|
||||
guard let buildableName =
|
||||
@@ -53,7 +53,7 @@ public class ProjectGenerator {
|
||||
}
|
||||
let buildableReference = XCScheme.BuildableReference(
|
||||
referencedContainer: "container:\(project.name).xcodeproj",
|
||||
blueprintIdentifier: targetReference.reference,
|
||||
blueprint: pbxTarget,
|
||||
buildableName: buildableName,
|
||||
blueprintName: buildTarget.target
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import Yams
|
||||
|
||||
extension Project {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public enum SettingsPresetFile {
|
||||
case config(ConfigType)
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
struct SourceFile {
|
||||
let path: Path
|
||||
let fileReference: String
|
||||
let fileReference: PBXFileElement
|
||||
let buildFile: PBXBuildFile
|
||||
let buildPhase: TargetSource.BuildPhase?
|
||||
}
|
||||
|
||||
class SourceGenerator {
|
||||
|
||||
var rootGroups: Set<String> = []
|
||||
private var fileReferencesByPath: [String: String] = [:]
|
||||
private var groupsByPath: [Path: ObjectReference<PBXGroup>] = [:]
|
||||
private var variantGroupsByPath: [Path: ObjectReference<PBXVariantGroup>] = [:]
|
||||
var rootGroups: Set<PBXFileElement> = []
|
||||
private var fileReferencesByPath: [String: PBXFileElement] = [:]
|
||||
private var groupsByPath: [Path: PBXGroup] = [:]
|
||||
private var variantGroupsByPath: [Path: PBXVariantGroup] = [:]
|
||||
|
||||
private let project: Project
|
||||
var addObjectClosure: (String, PBXObject) -> String
|
||||
var addObjectClosure: (PBXObject) -> Void
|
||||
var targetSourceExcludePaths: Set<Path> = []
|
||||
var defaultExcludedFiles = [
|
||||
".DS_Store",
|
||||
@@ -28,18 +28,14 @@ class SourceGenerator {
|
||||
|
||||
private(set) var knownRegions: Set<String> = []
|
||||
|
||||
init(project: Project, addObjectClosure: @escaping (String, PBXObject) -> String) {
|
||||
init(project: Project, addObjectClosure: @escaping (PBXObject) -> Void) {
|
||||
self.project = project
|
||||
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 addObject<T: PBXObject>(_ object: T) -> T {
|
||||
addObjectClosure(object)
|
||||
return object
|
||||
}
|
||||
|
||||
func getAllSourceFiles(targetType: PBXProductType, sources: [TargetSource]) throws -> [SourceFile] {
|
||||
@@ -90,7 +86,7 @@ class SourceGenerator {
|
||||
settings["COMPILER_FLAGS"] = targetSource.compilerFlags.joined(separator: " ")
|
||||
}
|
||||
|
||||
let buildFile = PBXBuildFile(fileRef: fileReference, settings: settings.isEmpty ? nil : settings)
|
||||
let buildFile = PBXBuildFile(file: fileReference, settings: settings.isEmpty ? nil : settings)
|
||||
return SourceFile(
|
||||
path: path,
|
||||
fileReference: fileReference,
|
||||
@@ -99,7 +95,7 @@ class SourceGenerator {
|
||||
)
|
||||
}
|
||||
|
||||
func getContainedFileReference(path: Path) -> String {
|
||||
func getContainedFileReference(path: Path) -> PBXFileElement {
|
||||
let createIntermediateGroups = project.options.createIntermediateGroups
|
||||
|
||||
let parentPath = path.parent()
|
||||
@@ -112,12 +108,12 @@ class SourceGenerator {
|
||||
)
|
||||
|
||||
if createIntermediateGroups {
|
||||
createIntermediaGroups(for: parentGroup.reference, at: parentPath)
|
||||
createIntermediaGroups(for: parentGroup, at: parentPath)
|
||||
}
|
||||
return fileReference
|
||||
}
|
||||
|
||||
func getFileReference(path: Path, inPath: Path, name: String? = nil, sourceTree: PBXSourceTree = .group, lastKnownFileType: String? = nil) -> String {
|
||||
func getFileReference(path: Path, inPath: Path, name: String? = nil, sourceTree: PBXSourceTree = .group, lastKnownFileType: String? = nil) -> PBXFileElement {
|
||||
let fileReferenceKey = path.string.lowercased()
|
||||
if let fileReference = fileReferencesByPath[fileReferenceKey] {
|
||||
return fileReference
|
||||
@@ -127,7 +123,7 @@ class SourceGenerator {
|
||||
if fileReferencePath.string == fileReferenceName {
|
||||
fileReferenceName = nil
|
||||
}
|
||||
let lastKnownFileType = lastKnownFileType ?? PBXFileReference.fileType(path: path)
|
||||
let lastKnownFileType = lastKnownFileType ?? Xcode.fileType(path: path)
|
||||
|
||||
if path.extension == "xcdatamodeld" {
|
||||
let versionedModels = (try? path.children()) ?? []
|
||||
@@ -137,10 +133,9 @@ class SourceGenerator {
|
||||
.filter { $0.extension == "xcdatamodel" }
|
||||
.sorted { $0.string.localizedStandardCompare($1.string) == .orderedAscending }
|
||||
|
||||
let modelFileReference =
|
||||
let modelFileReferences =
|
||||
sortedPaths.map { path in
|
||||
createObject(
|
||||
id: path.byRemovingBase(path: project.basePath).string,
|
||||
addObject(
|
||||
PBXFileReference(
|
||||
sourceTree: .group,
|
||||
lastKnownFileType: "wrapper.xcdatamodel",
|
||||
@@ -151,23 +146,22 @@ class SourceGenerator {
|
||||
// If no current version path is found we fall back to alphabetical
|
||||
// order by taking the last item in the sortedPaths array
|
||||
let currentVersionPath = findCurrentCoreDataModelVersionPath(using: versionedModels) ?? sortedPaths.last
|
||||
let currentVersion: ObjectReference<PBXFileReference>? = {
|
||||
let currentVersion: PBXFileReference? = {
|
||||
guard let indexOf = sortedPaths.index(where: { $0 == currentVersionPath }) else { return nil }
|
||||
return modelFileReference[indexOf]
|
||||
return modelFileReferences[indexOf]
|
||||
}()
|
||||
let versionGroup = addObject(id: fileReferencePath.string, XCVersionGroup(
|
||||
currentVersion: currentVersion?.reference,
|
||||
let versionGroup = addObject(XCVersionGroup(
|
||||
currentVersion: currentVersion,
|
||||
path: fileReferencePath.string,
|
||||
sourceTree: sourceTree,
|
||||
versionGroupType: "wrapper.xcdatamodel",
|
||||
children: modelFileReference.map { $0.reference }
|
||||
children: modelFileReferences
|
||||
))
|
||||
fileReferencesByPath[fileReferenceKey] = versionGroup
|
||||
return versionGroup
|
||||
} else {
|
||||
// For all extensions other than `xcdatamodeld`
|
||||
let fileReference = createObject(
|
||||
id: path.byRemovingBase(path: project.basePath).string,
|
||||
let fileReference = addObject(
|
||||
PBXFileReference(
|
||||
sourceTree: sourceTree,
|
||||
name: fileReferenceName,
|
||||
@@ -175,8 +169,8 @@ class SourceGenerator {
|
||||
path: fileReferencePath.string
|
||||
)
|
||||
)
|
||||
fileReferencesByPath[fileReferenceKey] = fileReference.reference
|
||||
return fileReference.reference
|
||||
fileReferencesByPath[fileReferenceKey] = fileReference
|
||||
return fileReference
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,12 +201,16 @@ class SourceGenerator {
|
||||
|
||||
/// Create a group or return an existing one at the path.
|
||||
/// Any merged children are added to a new group or merged into an existing one.
|
||||
private func getGroup(path: Path, name: String? = nil, mergingChildren children: [String], createIntermediateGroups: Bool, isBaseGroup: Bool) -> ObjectReference<PBXGroup> {
|
||||
let groupReference: ObjectReference<PBXGroup>
|
||||
private func getGroup(path: Path, name: String? = nil, mergingChildren children: [PBXFileElement], createIntermediateGroups: Bool, isBaseGroup: Bool) -> PBXGroup {
|
||||
let groupReference: PBXGroup
|
||||
|
||||
if let cachedGroup = groupsByPath[path] {
|
||||
// only add the children that aren't already in the cachedGroup
|
||||
cachedGroup.object.children = Array(Set(cachedGroup.object.children + children))
|
||||
for child in children {
|
||||
// only add the children that aren't already in the cachedGroup
|
||||
if !cachedGroup.children.contains(child) {
|
||||
cachedGroup.children.append(child)
|
||||
}
|
||||
}
|
||||
groupReference = cachedGroup
|
||||
} else {
|
||||
|
||||
@@ -235,28 +233,27 @@ class SourceGenerator {
|
||||
name: groupName != groupPath ? groupName : nil,
|
||||
path: groupPath
|
||||
)
|
||||
groupReference = createObject(id: path.byRemovingBase(path: project.basePath).string, group)
|
||||
groupReference = addObject(group)
|
||||
groupsByPath[path] = groupReference
|
||||
|
||||
if isTopLevelGroup {
|
||||
rootGroups.insert(groupReference.reference)
|
||||
rootGroups.insert(groupReference)
|
||||
}
|
||||
}
|
||||
return groupReference
|
||||
}
|
||||
|
||||
/// Creates a variant group or returns an existing one at the path
|
||||
private func getVariantGroup(path: Path, inPath: Path) -> ObjectReference<PBXVariantGroup> {
|
||||
let variantGroup: ObjectReference<PBXVariantGroup>
|
||||
private func getVariantGroup(path: Path, inPath: Path) -> PBXVariantGroup {
|
||||
let variantGroup: PBXVariantGroup
|
||||
if let cachedGroup = variantGroupsByPath[path] {
|
||||
variantGroup = cachedGroup
|
||||
} else {
|
||||
let group = PBXVariantGroup(
|
||||
children: [],
|
||||
sourceTree: .group,
|
||||
name: path.lastComponent
|
||||
)
|
||||
variantGroup = createObject(id: path.byRemovingBase(path: project.basePath).string, group)
|
||||
variantGroup = addObject(group)
|
||||
variantGroupsByPath[path] = variantGroup
|
||||
}
|
||||
return variantGroup
|
||||
@@ -305,27 +302,24 @@ class SourceGenerator {
|
||||
|
||||
/// creates all the source files and groups they belong to for a given targetSource
|
||||
private func getGroupSources(targetType: PBXProductType, targetSource: TargetSource, path: Path, isBaseGroup: Bool)
|
||||
throws -> (sourceFiles: [SourceFile], groups: [ObjectReference<PBXGroup>]) {
|
||||
throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) {
|
||||
|
||||
let children = try getSourceChildren(targetSource: targetSource, dirPath: path)
|
||||
|
||||
let directories = children
|
||||
.filter { $0.isDirectory && $0.extension == nil && $0.extension != "lproj" }
|
||||
.sorted { $0.lastComponent < $1.lastComponent }
|
||||
|
||||
let filePaths = children
|
||||
.filter { $0.isFile || $0.extension != nil && $0.extension != "lproj" }
|
||||
.sorted { $0.lastComponent < $1.lastComponent }
|
||||
|
||||
let localisedDirectories = children
|
||||
.filter { $0.extension == "lproj" }
|
||||
.sorted { $0.lastComponent < $1.lastComponent }
|
||||
|
||||
var groupChildren: [String] = filePaths.map { getFileReference(path: $0, inPath: path) }
|
||||
var groupChildren: [PBXFileElement] = filePaths.map { getFileReference(path: $0, inPath: path) }
|
||||
var allSourceFiles: [SourceFile] = filePaths.map {
|
||||
generateSourceFile(targetType: targetType, targetSource: targetSource, path: $0)
|
||||
}
|
||||
var groups: [ObjectReference<PBXGroup>] = []
|
||||
var groups: [PBXGroup] = []
|
||||
|
||||
for path in directories {
|
||||
let subGroups = try getGroupSources(targetType: targetType, targetSource: targetSource, path: path, isBaseGroup: false)
|
||||
@@ -336,11 +330,11 @@ class SourceGenerator {
|
||||
|
||||
allSourceFiles += subGroups.sourceFiles
|
||||
|
||||
guard let first = subGroups.groups.first else {
|
||||
guard let firstGroup = subGroups.groups.first else {
|
||||
continue
|
||||
}
|
||||
|
||||
groupChildren.append(first.reference)
|
||||
groupChildren.append(firstGroup)
|
||||
groups += subGroups.groups
|
||||
}
|
||||
|
||||
@@ -363,13 +357,13 @@ class SourceGenerator {
|
||||
.filter(isIncludedPath)
|
||||
.sorted() {
|
||||
let variantGroup = getVariantGroup(path: filePath, inPath: path)
|
||||
groupChildren.append(variantGroup.reference)
|
||||
baseLocalisationVariantGroups.append(variantGroup.object)
|
||||
groupChildren.append(variantGroup)
|
||||
baseLocalisationVariantGroups.append(variantGroup)
|
||||
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: variantGroup.reference,
|
||||
buildFile: PBXBuildFile(fileRef: variantGroup.reference),
|
||||
fileReference: variantGroup,
|
||||
buildFile: PBXBuildFile(file: variantGroup),
|
||||
buildPhase: .resources
|
||||
)
|
||||
allSourceFiles.append(sourceFile)
|
||||
@@ -407,7 +401,7 @@ class SourceGenerator {
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: fileReference,
|
||||
buildFile: PBXBuildFile(fileRef: fileReference),
|
||||
buildFile: PBXBuildFile(file: fileReference),
|
||||
buildPhase: .resources
|
||||
)
|
||||
allSourceFiles.append(sourceFile)
|
||||
@@ -423,7 +417,7 @@ class SourceGenerator {
|
||||
isBaseGroup: isBaseGroup
|
||||
)
|
||||
if project.options.createIntermediateGroups {
|
||||
createIntermediaGroups(for: group.reference, at: path)
|
||||
createIntermediaGroups(for: group, at: path)
|
||||
}
|
||||
|
||||
groups.insert(group, at: 0)
|
||||
@@ -440,7 +434,7 @@ class SourceGenerator {
|
||||
let createIntermediateGroups = project.options.createIntermediateGroups
|
||||
|
||||
var sourceFiles: [SourceFile] = []
|
||||
let sourceReference: String
|
||||
let sourceReference: PBXFileElement
|
||||
var sourcePath = path
|
||||
switch type {
|
||||
case .folder:
|
||||
@@ -481,7 +475,7 @@ class SourceGenerator {
|
||||
} else {
|
||||
let parentGroup = getGroup(path: parentPath, mergingChildren: [fileReference], createIntermediateGroups: createIntermediateGroups, isBaseGroup: true)
|
||||
sourcePath = parentPath
|
||||
sourceReference = parentGroup.reference
|
||||
sourceReference = parentGroup
|
||||
}
|
||||
sourceFiles.append(sourceFile)
|
||||
|
||||
@@ -489,11 +483,11 @@ class SourceGenerator {
|
||||
let (groupSourceFiles, groups) = try getGroupSources(targetType: targetType, targetSource: targetSource, path: path, isBaseGroup: true)
|
||||
let group = groups.first!
|
||||
if let name = targetSource.name {
|
||||
group.object.name = name
|
||||
group.name = name
|
||||
}
|
||||
|
||||
sourceFiles += groupSourceFiles
|
||||
sourceReference = group.reference
|
||||
sourceReference = group
|
||||
}
|
||||
|
||||
if createIntermediateGroups {
|
||||
@@ -504,7 +498,7 @@ class SourceGenerator {
|
||||
}
|
||||
|
||||
// Add groups for all parents recursively
|
||||
private func createIntermediaGroups(for groupReference: String, at path: Path) {
|
||||
private func createIntermediaGroups(for fileElement: PBXFileElement, at path: Path) {
|
||||
|
||||
let parentPath = path.parent()
|
||||
guard parentPath != project.basePath && path.string.contains(project.basePath.string) else {
|
||||
@@ -513,10 +507,10 @@ class SourceGenerator {
|
||||
}
|
||||
|
||||
let hasParentGroup = groupsByPath[parentPath] != nil
|
||||
let parentGroup = getGroup(path: parentPath, mergingChildren: [groupReference], createIntermediateGroups: true, isBaseGroup: false)
|
||||
let parentGroup = getGroup(path: parentPath, mergingChildren: [fileElement], createIntermediateGroups: true, isBaseGroup: false)
|
||||
|
||||
if !hasParentGroup {
|
||||
createIntermediaGroups(for: parentGroup.reference, at: parentPath)
|
||||
createIntermediaGroups(for: parentGroup, at: parentPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import PathKit
|
||||
|
||||
extension PBXFileElement {
|
||||
|
||||
@@ -11,8 +12,8 @@ extension PBXFileElement {
|
||||
extension PBXProj {
|
||||
|
||||
public func printGroups() -> String {
|
||||
guard let project = objects.projects.first?.value,
|
||||
let mainGroup = objects.groups.getReference(project.mainGroup) else {
|
||||
guard let project = projects.first,
|
||||
let mainGroup = project.mainGroup else {
|
||||
return ""
|
||||
}
|
||||
return printGroup(group: mainGroup)
|
||||
@@ -20,17 +21,31 @@ extension PBXProj {
|
||||
|
||||
public func printGroup(group: PBXGroup) -> String {
|
||||
var string = group.nameOrPath
|
||||
for reference in group.children {
|
||||
if let group = objects.groups.getReference(reference) {
|
||||
for child in group.children {
|
||||
if let group = child as? PBXGroup {
|
||||
string += "\n 📁 " + printGroup(group: group).replacingOccurrences(of: "\n ", with: "\n ")
|
||||
} else if let fileReference = objects.fileReferences.getReference(reference) {
|
||||
} else if let fileReference = child as? PBXFileReference {
|
||||
string += "\n 📄 " + fileReference.nameOrPath
|
||||
} else if let variantGroup = objects.variantGroups.getReference(reference) {
|
||||
} else if let variantGroup = child as? PBXVariantGroup {
|
||||
string += "\n 🌎 " + variantGroup.nameOrPath
|
||||
} else if let versionGroup = objects.versionGroups.getReference(reference) {
|
||||
} else if let versionGroup = child as? XCVersionGroup {
|
||||
string += "\n 🔢 " + versionGroup.nameOrPath
|
||||
}
|
||||
}
|
||||
return string
|
||||
}
|
||||
}
|
||||
|
||||
extension Dictionary {
|
||||
|
||||
public var valueArray: Array<Value> {
|
||||
return Array(values)
|
||||
}
|
||||
}
|
||||
|
||||
extension Xcode {
|
||||
|
||||
public static func fileType(path: Path) -> String? {
|
||||
return path.extension.flatMap { Xcode.filetype(extension: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+18
-18
@@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -33,7 +33,7 @@
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_783122899910"
|
||||
BlueprintIdentifier = "NT_193BAF154270D1C21E269EDF2A1BD3F6"
|
||||
BuildableName = "App_iOS_Tests.xctest"
|
||||
BlueprintName = "App_iOS_Tests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -43,7 +43,7 @@
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_123503999387"
|
||||
BlueprintIdentifier = "NT_D4BAEEEC88124103C8DFF41FCE206DCE"
|
||||
BuildableName = "App_iOS_UITests.xctest"
|
||||
BlueprintName = "App_iOS_UITests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -53,21 +53,21 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -86,21 +86,21 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -115,21 +115,21 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
|
||||
+18
-18
@@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -33,7 +33,7 @@
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_783122899910"
|
||||
BlueprintIdentifier = "NT_193BAF154270D1C21E269EDF2A1BD3F6"
|
||||
BuildableName = "App_iOS_Tests.xctest"
|
||||
BlueprintName = "App_iOS_Tests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -43,7 +43,7 @@
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_123503999387"
|
||||
BlueprintIdentifier = "NT_D4BAEEEC88124103C8DFF41FCE206DCE"
|
||||
BuildableName = "App_iOS_UITests.xctest"
|
||||
BlueprintName = "App_iOS_UITests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -53,21 +53,21 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -86,21 +86,21 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -115,21 +115,21 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
|
||||
+18
-18
@@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -33,7 +33,7 @@
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_783122899910"
|
||||
BlueprintIdentifier = "NT_193BAF154270D1C21E269EDF2A1BD3F6"
|
||||
BuildableName = "App_iOS_Tests.xctest"
|
||||
BlueprintName = "App_iOS_Tests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -43,7 +43,7 @@
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_123503999387"
|
||||
BlueprintIdentifier = "NT_D4BAEEEC88124103C8DFF41FCE206DCE"
|
||||
BuildableName = "App_iOS_UITests.xctest"
|
||||
BlueprintName = "App_iOS_UITests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -53,21 +53,21 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -86,21 +86,21 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -115,21 +115,21 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
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>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
|
||||
+4
-4
@@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_324671077936"
|
||||
BlueprintIdentifier = "NT_38A9FE87056942A2746E0FF025B52A91"
|
||||
BuildableName = "App_watchOS.app"
|
||||
BlueprintName = "App_watchOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -32,7 +32,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_324671077936"
|
||||
BlueprintIdentifier = "NT_38A9FE87056942A2746E0FF025B52A91"
|
||||
BuildableName = "App_watchOS.app"
|
||||
BlueprintName = "App_watchOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -57,7 +57,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_324671077936"
|
||||
BlueprintIdentifier = "NT_38A9FE87056942A2746E0FF025B52A91"
|
||||
BuildableName = "App_watchOS.app"
|
||||
BlueprintName = "App_watchOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -78,7 +78,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_324671077936"
|
||||
BlueprintIdentifier = "NT_38A9FE87056942A2746E0FF025B52A91"
|
||||
BuildableName = "App_watchOS.app"
|
||||
BlueprintName = "App_watchOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
|
||||
+5
-5
@@ -14,7 +14,7 @@
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -32,7 +32,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -50,7 +50,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -72,7 +72,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -101,7 +101,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
|
||||
+4
-4
@@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_935153865209"
|
||||
BlueprintIdentifier = "NT_6BD068FAAC6AA35C090C48147B94EC6E"
|
||||
BuildableName = "iMessageApp.app"
|
||||
BlueprintName = "iMessageApp"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -32,7 +32,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_935153865209"
|
||||
BlueprintIdentifier = "NT_6BD068FAAC6AA35C090C48147B94EC6E"
|
||||
BuildableName = "iMessageApp.app"
|
||||
BlueprintName = "iMessageApp"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -57,7 +57,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_935153865209"
|
||||
BlueprintIdentifier = "NT_6BD068FAAC6AA35C090C48147B94EC6E"
|
||||
BuildableName = "iMessageApp.app"
|
||||
BlueprintName = "iMessageApp"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -78,7 +78,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_935153865209"
|
||||
BlueprintIdentifier = "NT_6BD068FAAC6AA35C090C48147B94EC6E"
|
||||
BuildableName = "iMessageApp.app"
|
||||
BlueprintName = "iMessageApp"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
import Yams
|
||||
|
||||
@@ -34,10 +34,10 @@ extension PBXProj {
|
||||
func validateGroup(_ group: PBXGroup) throws {
|
||||
let hasDuplicatedChildren = group.children.count != Set(group.children).count
|
||||
if hasDuplicatedChildren {
|
||||
throw failure("Group \"\(group.nameOrPath)\" has duplicated children:\n - \(group.children.sorted().joined(separator: "\n - "))")
|
||||
throw failure("Group \"\(group.nameOrPath)\" has duplicated children:\n - \(group.children.map { String(describing: $0) }.joined(separator: "\n - "))")
|
||||
}
|
||||
for child in group.children {
|
||||
if let group = objects.groups.getReference(child) {
|
||||
if let group = child as? PBXGroup {
|
||||
try validateGroup(group)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import Foundation
|
||||
import XCTest
|
||||
import ProjectSpec
|
||||
@@ -22,6 +22,7 @@ class GeneratedPerformanceTests: XCTestCase {
|
||||
let generator = ProjectGenerator(project: project)
|
||||
let xcodeProject = try generator.generateXcodeProject()
|
||||
self.measure {
|
||||
xcodeProject.pbxproj.invalidateUUIDs()
|
||||
try! xcodeProject.write(path: project.projectPath)
|
||||
}
|
||||
}
|
||||
@@ -50,6 +51,7 @@ class FixturePerformanceTests: XCTestCase {
|
||||
let generator = ProjectGenerator(project: project)
|
||||
let xcodeProject = try generator.generateXcodeProject()
|
||||
self.measure {
|
||||
xcodeProject.pbxproj.invalidateUUIDs()
|
||||
try! xcodeProject.write(path: project.projectPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
class ProjectFixtureTests: XCTestCase {
|
||||
@@ -18,12 +18,12 @@ class ProjectFixtureTests: XCTestCase {
|
||||
$0.it("generates variant group") {
|
||||
guard let xcodeProject = xcodeProject else { return }
|
||||
|
||||
func getFileReferences(_ path: String) -> [ObjectReference<PBXFileReference>] {
|
||||
return xcodeProject.pbxproj.objects.fileReferences.objectReferences.filter { $0.object.path == path }
|
||||
func getFileReferences(_ path: String) -> [PBXFileReference] {
|
||||
return xcodeProject.pbxproj.fileReferences.filter { $0.path == path }
|
||||
}
|
||||
|
||||
func getVariableGroups(_ name: String?) -> [PBXVariantGroup] {
|
||||
return xcodeProject.pbxproj.objects.variantGroups.referenceValues.filter { $0.name == name }
|
||||
return xcodeProject.pbxproj.variantGroups.filter { $0.name == name }
|
||||
}
|
||||
|
||||
let resourceName = "LocalizedStoryboard.storyboard"
|
||||
@@ -35,13 +35,13 @@ class ProjectFixtureTests: XCTestCase {
|
||||
do {
|
||||
let refs = getFileReferences(baseResource)
|
||||
try expect(refs.count) == 1
|
||||
try expect(variableGroup.children.filter { $0 == refs.first?.reference }.count) == 1
|
||||
try expect(variableGroup.children.filter { $0 == refs.first }.count) == 1
|
||||
}
|
||||
|
||||
do {
|
||||
let refs = getFileReferences(localizedResource)
|
||||
try expect(refs.count) == 1
|
||||
try expect(variableGroup.children.filter { $0 == refs.first?.reference }.count) == 1
|
||||
try expect(variableGroup.children.filter { $0 == refs.first }.count) == 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
import Yams
|
||||
|
||||
@@ -47,11 +47,9 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let options = SpecOptions(bundleIdPrefix: "com.test")
|
||||
let project = Project(basePath: "", name: "test", targets: [framework], options: options)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
guard let target = pbxProj.objects.nativeTargets.first?.value,
|
||||
guard let target = pbxProj.nativeTargets.first,
|
||||
let buildConfigList = target.buildConfigurationList,
|
||||
let buildConfigs = pbxProj.objects.configurationLists.getReference(buildConfigList),
|
||||
let buildConfigReference = buildConfigs.buildConfigurations.first,
|
||||
let buildConfig = pbxProj.objects.buildConfigurations.getReference(buildConfigReference) else {
|
||||
let buildConfig = buildConfigList.buildConfigurations.first else {
|
||||
throw failure("Build Config not found")
|
||||
}
|
||||
try expect(buildConfig.buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] as? String) == "com.test.MyFramework"
|
||||
@@ -61,7 +59,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let options = SpecOptions(settingPresets: .none)
|
||||
let project = Project(basePath: "", name: "test", targets: [framework], options: options)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let allSettings = pbxProj.objects.buildConfigurations.referenceValues.reduce([:]) { $0.merged($1.buildSettings) }.keys.sorted()
|
||||
let allSettings = pbxProj.buildConfigurations.reduce([:]) { $0.merged($1.buildSettings) }.keys.sorted()
|
||||
try expect(allSettings) == ["SETTING_2"]
|
||||
}
|
||||
|
||||
@@ -69,7 +67,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let options = SpecOptions(developmentLanguage: "de")
|
||||
let project = Project(basePath: "", name: "test", options: options)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
guard let pbxProject = pbxProj.objects.projects.first?.value else {
|
||||
guard let pbxProject = pbxProj.projects.first else {
|
||||
throw failure("Could't find PBXProject")
|
||||
}
|
||||
try expect(pbxProject.developmentRegion) == "de"
|
||||
@@ -98,8 +96,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: "", name: "test", configs: [Config(name: "Aconfig"), Config(name: "Bconfig")], targets: [framework], options: options)
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
guard let projectConfigListReference = pbxProject.objects.projects.values.first?.buildConfigurationList,
|
||||
let defaultConfigurationName = pbxProject.objects.configurationLists[projectConfigListReference]?.defaultConfigurationName
|
||||
guard let projectConfigList = pbxProject.projects.first?.buildConfigurationList,
|
||||
let defaultConfigurationName = projectConfigList.defaultConfigurationName
|
||||
else {
|
||||
throw failure("Default configuration name not found")
|
||||
}
|
||||
@@ -115,7 +113,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
$0.it("generates config defaults") {
|
||||
let project = Project(basePath: "", name: "test")
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let configs = pbxProj.objects.buildConfigurations.referenceValues
|
||||
let configs = pbxProj.buildConfigurations
|
||||
try expect(configs.count) == 2
|
||||
try expect(configs).contains(name: "Debug")
|
||||
try expect(configs).contains(name: "Release")
|
||||
@@ -128,7 +126,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
configs: [Config(name: "config1"), Config(name: "config2")]
|
||||
)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let configs = pbxProj.objects.buildConfigurations.referenceValues
|
||||
let configs = pbxProj.buildConfigurations
|
||||
try expect(configs.count) == 2
|
||||
try expect(configs).contains(name: "config1")
|
||||
try expect(configs).contains(name: "config2")
|
||||
@@ -141,7 +139,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
configs: [Config(name: "config")]
|
||||
)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
guard let config = pbxProj.objects.buildConfigurations.first?.value else {
|
||||
guard let config = pbxProj.buildConfigurations.first else {
|
||||
throw failure("configuration not found")
|
||||
}
|
||||
try expect(config.buildSettings.isEmpty).to.beTrue()
|
||||
@@ -204,8 +202,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
$0.it("generates aggregate targets") {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
let nativeTargets = pbxProject.objects.nativeTargets.referenceValues
|
||||
let aggregateTargets = pbxProject.objects.aggregateTargets.referenceValues
|
||||
let nativeTargets = pbxProject.nativeTargets.sorted { $0.name < $1.name }
|
||||
let aggregateTargets = pbxProject.aggregateTargets.sorted { $0.name < $1.name }
|
||||
|
||||
try expect(nativeTargets.count) == 4
|
||||
try expect(aggregateTargets.count) == 2
|
||||
@@ -222,8 +220,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let target2 = nativeTargets.first { $0.name == "Other2" }
|
||||
try expect(target2?.dependencies.count) == 2
|
||||
|
||||
let targetDependencies = pbxProject.objects.targetDependencies.referenceValues
|
||||
try expect(targetDependencies.count) == 7
|
||||
try expect(pbxProject.targetDependencies.count) == 7
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,7 +232,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
$0.it("generates targets") {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
let nativeTargets = pbxProject.objects.nativeTargets.referenceValues
|
||||
let nativeTargets = pbxProject.nativeTargets
|
||||
try expect(nativeTargets.count) == 4
|
||||
try expect(nativeTargets.contains { $0.name == app.name }).beTrue()
|
||||
try expect(nativeTargets.contains { $0.name == framework.name }).beTrue()
|
||||
@@ -253,22 +250,22 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: "", name: "test", targets: [appTargetWithAttributes, framework, optionalFramework, testTargetWithAttributes])
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
guard let targetAttributes = pbxProject.objects.projects.referenceValues.first?.attributes["TargetAttributes"] as? [String: [String: Any]] else {
|
||||
guard let targetAttributes = pbxProject.projects.first?.targetAttributes else {
|
||||
throw failure("Couldn't find Project TargetAttributes")
|
||||
}
|
||||
|
||||
guard let appTarget = pbxProject.objects.targets(named: app.name).first else {
|
||||
guard let appTarget = pbxProject.targets(named: app.name).first else {
|
||||
throw failure("Couldn't find App Target")
|
||||
}
|
||||
|
||||
guard let uiTestTarget = pbxProject.objects.targets(named: uiTest.name).first else {
|
||||
guard let uiTestTarget = pbxProject.targets(named: uiTest.name).first else {
|
||||
throw failure("Couldn't find UITest Target")
|
||||
}
|
||||
|
||||
try expect(targetAttributes[uiTestTarget.reference]?["TestTargetID"] as? String) == appTarget.reference
|
||||
try expect(targetAttributes[uiTestTarget.reference]?["ProvisioningStyle"] as? String) == "Manual"
|
||||
try expect(targetAttributes[appTarget.reference]?["ProvisioningStyle"] as? String) == "Automatic"
|
||||
try expect(targetAttributes[appTarget.reference]?["DevelopmentTeam"] as? String) == "123"
|
||||
try expect((targetAttributes[uiTestTarget]?["TestTargetID"] as? PBXNativeTarget)?.name) == app.name
|
||||
try expect(targetAttributes[uiTestTarget]?["ProvisioningStyle"] as? String) == "Manual"
|
||||
try expect(targetAttributes[appTarget]?["ProvisioningStyle"] as? String) == "Automatic"
|
||||
try expect(targetAttributes[appTarget]?["DevelopmentTeam"] as? String) == "123"
|
||||
}
|
||||
|
||||
$0.it("generates platform version") {
|
||||
@@ -277,16 +274,14 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
guard let projectConfigListReference = pbxProject.objects.projects.values.first?.buildConfigurationList,
|
||||
let projectConfigReference = pbxProject.objects.configurationLists[projectConfigListReference]?.buildConfigurations.first,
|
||||
let projectConfig = pbxProject.objects.buildConfigurations[projectConfigReference]
|
||||
guard let projectConfigList = pbxProject.projects.first?.buildConfigurationList,
|
||||
let projectConfig = projectConfigList.buildConfigurations.first
|
||||
else {
|
||||
throw failure("Couldn't find Project config")
|
||||
}
|
||||
|
||||
guard let targetConfigListReference = pbxProject.objects.nativeTargets.referenceValues.first?.buildConfigurationList,
|
||||
let targetConfigReference = pbxProject.objects.configurationLists[targetConfigListReference]?.buildConfigurations.first,
|
||||
let targetConfig = pbxProject.objects.buildConfigurations[targetConfigReference]
|
||||
guard let targetConfigList = pbxProject.nativeTargets.first?.buildConfigurationList,
|
||||
let targetConfig = targetConfigList.buildConfigurations.first
|
||||
else {
|
||||
throw failure("Couldn't find Target config")
|
||||
}
|
||||
@@ -303,14 +298,14 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
$0.it("generates dependencies") {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
let nativeTargets = pbxProject.objects.nativeTargets.objectReferences
|
||||
let dependencies = pbxProject.objects.targetDependencies.objectReferences
|
||||
let nativeTargets = pbxProject.nativeTargets
|
||||
let dependencies = pbxProject.targetDependencies.sorted { $0.target?.name ?? "" < $1.target?.name ?? "" }
|
||||
try expect(dependencies.count) == 2
|
||||
let appTarget = nativeTargets.first { $0.object.name == app.name }
|
||||
let frameworkTarget = nativeTargets.first { $0.object.name == framework.name }
|
||||
let appTarget = nativeTargets.first { $0.name == app.name }
|
||||
let frameworkTarget = nativeTargets.first { $0.name == framework.name }
|
||||
|
||||
try expect(dependencies).contains { $0.object.target == appTarget?.reference }
|
||||
try expect(dependencies).contains { $0.object.target == frameworkTarget?.reference }
|
||||
try expect(dependencies).contains { $0.target == appTarget }
|
||||
try expect(dependencies).contains { $0.target == frameworkTarget }
|
||||
}
|
||||
|
||||
$0.it("generates targets with correct transitive embeds") {
|
||||
@@ -550,20 +545,21 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
for target in targets {
|
||||
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues.first(where: { $0.name == target.name }) else {
|
||||
guard let nativeTarget = pbxProject.nativeTargets.first(where: { $0.name == target.name }) else {
|
||||
throw failure("PBXNativeTarget for \(target) not found")
|
||||
}
|
||||
let buildPhases = nativeTarget.buildPhases
|
||||
let resourcesPhases = pbxProject.objects.resourcesBuildPhases.objectReferences.filter { buildPhases.contains($0.reference) }
|
||||
let frameworkPhases = pbxProject.objects.frameworksBuildPhases.objectReferences.filter { buildPhases.contains($0.reference) }
|
||||
let copyFilesPhases = pbxProject.objects.copyFilesBuildPhases.objectReferences.filter { buildPhases.contains($0.reference) }
|
||||
let resourcesPhases = pbxProject.resourcesBuildPhases.filter { buildPhases.contains($0) }
|
||||
let frameworkPhases = pbxProject.frameworksBuildPhases.filter { buildPhases.contains($0) }
|
||||
let copyFilesPhases = pbxProject.copyFilesBuildPhases.filter { buildPhases.contains($0) }
|
||||
|
||||
// ensure only the right resources are copies, no more, no less
|
||||
let expectedResourceFiles = expectedResourceFiles[target.name]!
|
||||
try expect(resourcesPhases.count) == (expectedResourceFiles.isEmpty ? 0 : 1)
|
||||
if !expectedResourceFiles.isEmpty {
|
||||
let resourceFiles = resourcesPhases[0].object.files
|
||||
.compactMap { pbxProject.objects.buildFiles[$0]?.fileRef.flatMap { pbxProject.objects.fileReferences[$0]?.nameOrPath } }
|
||||
let resourceFiles = resourcesPhases[0].files
|
||||
.compactMap { $0.file }
|
||||
.map { $0.nameOrPath }
|
||||
try expect(Set(resourceFiles)) == expectedResourceFiles
|
||||
}
|
||||
|
||||
@@ -571,8 +567,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let expectedLinkedFiles = expectedLinkedFiles[target.name]!
|
||||
try expect(frameworkPhases.count) == (expectedLinkedFiles.isEmpty ? 0 : 1)
|
||||
if !expectedLinkedFiles.isEmpty {
|
||||
let linkFrameworks = frameworkPhases[0].object.files
|
||||
.compactMap { pbxProject.objects.buildFiles[$0]?.fileRef.flatMap { pbxProject.objects.fileReferences[$0]?.nameOrPath } }
|
||||
let linkFrameworks = frameworkPhases[0].files
|
||||
.compactMap { $0.file?.nameOrPath }
|
||||
try expect(Set(linkFrameworks)) == expectedLinkedFiles
|
||||
}
|
||||
|
||||
@@ -580,8 +576,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let expectedEmbeddedFrameworks = expectedEmbeddedFrameworks[target.name]!
|
||||
try expect(copyFilesPhases.count) == (expectedEmbeddedFrameworks.isEmpty ? 0 : 1)
|
||||
if !expectedEmbeddedFrameworks.isEmpty {
|
||||
let copyFiles = copyFilesPhases[0].object.files
|
||||
.compactMap { pbxProject.objects.buildFiles[$0]?.fileRef.flatMap { pbxProject.objects.fileReferences[$0]?.nameOrPath } }
|
||||
let copyFiles = copyFilesPhases[0].files
|
||||
.compactMap { $0.file?.nameOrPath }
|
||||
try expect(Set(copyFiles)) == expectedEmbeddedFrameworks
|
||||
}
|
||||
}
|
||||
@@ -648,11 +644,9 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
|
||||
func buildSettings(for target: Target) throws -> BuildSettings {
|
||||
guard let nativeTarget = pbxProj.objects.targets(named: target.name).first?.object,
|
||||
guard let nativeTarget = pbxProj.targets(named: target.name).first,
|
||||
let buildConfigList = nativeTarget.buildConfigurationList,
|
||||
let buildConfigs = pbxProj.objects.configurationLists.getReference(buildConfigList),
|
||||
let buildConfigReference = buildConfigs.buildConfigurations.first,
|
||||
let buildConfig = pbxProj.objects.buildConfigurations.getReference(buildConfigReference) else {
|
||||
let buildConfig = buildConfigList.buildConfigurations.first else {
|
||||
throw failure("XCBuildConfiguration not found for Target \(target.name.quoted)")
|
||||
}
|
||||
|
||||
@@ -706,16 +700,15 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
func scriptBuildPhases(target: Target) throws -> [PBXShellScriptBuildPhase] {
|
||||
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues.first(where: { $0.name == target.name }) else {
|
||||
guard let nativeTarget = pbxProject.nativeTargets.first(where: { $0.name == target.name }) else {
|
||||
throw failure("PBXNativeTarget for \(target) not found")
|
||||
}
|
||||
let buildPhases = nativeTarget.buildPhases
|
||||
let scriptPhases = pbxProject.objects.shellScriptBuildPhases.objectReferences.filter({ buildPhases.contains($0.reference) }).map { $0.object }
|
||||
let scriptPhases = buildPhases.compactMap { $0 as? PBXShellScriptBuildPhase }
|
||||
return scriptPhases
|
||||
}
|
||||
|
||||
let expectedScriptPhase = PBXShellScriptBuildPhase(
|
||||
files: [],
|
||||
name: "Copy Swift Objective-C Interface Header",
|
||||
inputPaths: ["$(DERIVED_SOURCES_DIR)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME)"],
|
||||
outputPaths: ["$(BUILT_PRODUCTS_DIR)/include/$(PRODUCT_MODULE_NAME)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME)"],
|
||||
@@ -734,20 +727,18 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
scriptSpec.targets[0].postbuildScripts = [BuildScript(script: .script("script2"))]
|
||||
let pbxProject = try scriptSpec.generatePbxProj()
|
||||
|
||||
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues
|
||||
guard let nativeTarget = pbxProject.nativeTargets
|
||||
.first(where: { $0.buildPhases.count >= 2 }) else {
|
||||
throw failure("Target with build phases not found")
|
||||
}
|
||||
let buildPhases = nativeTarget.buildPhases
|
||||
|
||||
let scripts = pbxProject.objects.shellScriptBuildPhases
|
||||
let script1 = scripts.first { $0.value.shellScript == "script1" }
|
||||
let script2 = scripts.first { $0.value.shellScript == "script2" }
|
||||
|
||||
let scripts = pbxProject.shellScriptBuildPhases
|
||||
let script1 = scripts.first { $0.shellScript == "script1" }
|
||||
let script2 = scripts.first { $0.shellScript == "script2" }
|
||||
try expect(scripts.count) == 2
|
||||
|
||||
try expect(buildPhases.first) == script1?.key
|
||||
try expect(buildPhases.last) == script2?.key
|
||||
try expect(buildPhases.first) == script1
|
||||
try expect(buildPhases.last) == script2
|
||||
}
|
||||
|
||||
$0.it("generates targets with cylical dependencies") {
|
||||
@@ -789,7 +780,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
]
|
||||
let pbxProject = try scriptSpec.generatePbxProj()
|
||||
|
||||
let buildRules = pbxProject.objects.buildRules.referenceValues
|
||||
let buildRules = pbxProject.buildRules
|
||||
try expect(buildRules.count) == 2
|
||||
let first = buildRules.first { $0.name == "My Rule" }!
|
||||
let second = buildRules.first { $0.name != "My Rule" }!
|
||||
@@ -826,13 +817,12 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: "", name: "test", targets: [app, framework, optionalFramework, uiTest])
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues.first(where: { $0.name == app.name }) else {
|
||||
guard let nativeTarget = pbxProject.nativeTargets.first(where: { $0.name == app.name }) else {
|
||||
throw failure("PBXNativeTarget for \(app.name) not found")
|
||||
}
|
||||
let buildPhases = nativeTarget.buildPhases
|
||||
let frameworkPhases = pbxProject.objects.frameworksBuildPhases.objectReferences.filter { buildPhases.contains($0.reference) }
|
||||
let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase }
|
||||
|
||||
let frameworkBuildFiles = frameworkPhases[0].object.files.compactMap { pbxProject.objects.buildFiles[$0] }
|
||||
let frameworkBuildFiles = frameworkPhases[0].files
|
||||
let buildFileSettings = frameworkBuildFiles.map { $0.settings }
|
||||
|
||||
try expect(frameworkBuildFiles.count) == 2
|
||||
@@ -860,8 +850,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
schemes: [scheme]
|
||||
)
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
guard let target = xcodeProject.pbxproj.objects.nativeTargets.objectReferences
|
||||
.first(where: { $0.object.name == app.name }) else {
|
||||
guard let target = xcodeProject.pbxproj.nativeTargets
|
||||
.first(where: { $0.name == app.name }) else {
|
||||
throw failure("Target not found")
|
||||
}
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
@@ -887,9 +877,9 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
].compactMap { $0 }
|
||||
|
||||
for buildableReference in buildableReferences {
|
||||
try expect(buildableReference.blueprintIdentifier) == target.reference
|
||||
try expect(buildableReference.blueprintName) == target.object.name
|
||||
try expect(buildableReference.buildableName) == "\(target.object.name).\(target.object.productType!.fileExtension!)"
|
||||
// FIXME: try expect(buildableReference.blueprintIdentifier) == target.reference
|
||||
try expect(buildableReference.blueprintName) == target.name
|
||||
try expect(buildableReference.buildableName) == "\(target.name).\(target.productType!.fileExtension!)"
|
||||
}
|
||||
|
||||
try expect(xcscheme.launchAction?.buildConfiguration) == "Debug"
|
||||
@@ -925,8 +915,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
}
|
||||
|
||||
try expect(
|
||||
xcodeProject.pbxproj.objects.nativeTargets.objectReferences
|
||||
.contains(where: { $0.object.name == app.name })
|
||||
xcodeProject.pbxproj.nativeTargets
|
||||
.contains(where: { $0.name == app.name })
|
||||
).beTrue()
|
||||
try expect(xcscheme.launchAction?.environmentVariables) == runVariables
|
||||
try expect(xcscheme.testAction?.environmentVariables).to.beNil()
|
||||
@@ -949,10 +939,6 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
try expect(xcodeProject.sharedData?.schemes.count) == 2
|
||||
|
||||
guard let nativeTarget = xcodeProject.pbxproj.objects.nativeTargets.objectReferences
|
||||
.first(where: { $0.object.name == app.name }) else {
|
||||
throw failure("Target not found")
|
||||
}
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes
|
||||
.first(where: { $0.name == "\(target.name) Test" }) else {
|
||||
throw failure("Scheme not found")
|
||||
@@ -960,7 +946,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else {
|
||||
throw failure("Build Action entry not found")
|
||||
}
|
||||
try expect(buildActionEntry.buildableReference.blueprintIdentifier) == nativeTarget.reference
|
||||
|
||||
try expect(buildActionEntry.buildableReference.blueprintIdentifier.count > 0) == true
|
||||
|
||||
try expect(xcscheme.launchAction?.buildConfiguration) == "Test Debug"
|
||||
try expect(xcscheme.testAction?.buildConfiguration) == "Test Debug"
|
||||
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
class ProjectSpecTests: XCTestCase {
|
||||
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
import Yams
|
||||
|
||||
@@ -85,14 +85,16 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
try pbxProj.expectFile(paths: ["Sources", "Bar.swift"], buildPhase: .sources)
|
||||
let buildPhase = pbxProj.objects.copyFilesBuildPhases.referenceValues.first
|
||||
let buildPhase = pbxProj.copyFilesBuildPhases.first
|
||||
try expect(buildPhase?.dstSubfolderSpec) == .frameworks
|
||||
let fileReference = pbxProj.getFileReference(
|
||||
paths: ["Sources", "Foo.framework"],
|
||||
names: ["Sources", "Foo.framework"]
|
||||
)?.reference ?? ""
|
||||
let buildFile = pbxProj.objects.buildFiles.objectReferences
|
||||
.first(where: { $0.object.fileRef == fileReference })?.reference ?? ""
|
||||
)
|
||||
guard let buildFile = pbxProj.buildFiles
|
||||
.first(where: { $0.file == fileReference }) else {
|
||||
throw failure("Cant find build file")
|
||||
}
|
||||
try expect(buildPhase?.files.count) == 1
|
||||
try expect(buildPhase?.files.contains(buildFile)) == true
|
||||
}
|
||||
@@ -112,16 +114,16 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
guard let fileReference = pbxProj.objects.fileReferences.first(where: { $0.value.nameOrPath == "model2.xcdatamodel" }) else {
|
||||
guard let fileReference = pbxProj.fileReferences.first(where: { $0.nameOrPath == "model2.xcdatamodel" }) else {
|
||||
throw failure("Couldn't find model file reference")
|
||||
}
|
||||
guard let versionGroup = pbxProj.objects.versionGroups.values.first else {
|
||||
guard let versionGroup = pbxProj.versionGroups.first else {
|
||||
throw failure("Couldn't find version group")
|
||||
}
|
||||
try expect(versionGroup.currentVersion) == fileReference.key
|
||||
try expect(versionGroup.currentVersion) == fileReference
|
||||
try expect(versionGroup.children.count) == 3
|
||||
try expect(versionGroup.path) == "model.xcdatamodeld"
|
||||
try expect(fileReference.value.path) == "model2.xcdatamodel"
|
||||
try expect(fileReference.path) == "model2.xcdatamodel"
|
||||
}
|
||||
|
||||
$0.it("handles duplicate names") {
|
||||
@@ -458,9 +460,7 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
try pbxProj.expectFile(paths: ["Sources/A", "a.swift"], names: ["A", "a.swift"], buildPhase: .sources)
|
||||
|
||||
let sourcesBuildPhase = pbxProj.objects.buildPhases
|
||||
.first(where: { $0.1.buildPhase == BuildPhase.sources })!
|
||||
.value
|
||||
let sourcesBuildPhase = pbxProj.buildPhases.first(where: { $0.buildPhase == BuildPhase.sources })!
|
||||
|
||||
try expect(sourcesBuildPhase.files.count) == 1
|
||||
}
|
||||
@@ -480,7 +480,7 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let groups = try pbxProj.getMainGroup().children.compactMap { pbxProj.objects.getFileElement(reference: $0)?.nameOrPath }
|
||||
let groups = try pbxProj.getMainGroup().children.map { $0.nameOrPath }
|
||||
try expect(groups) == ["A", "P", "S", "Frameworks", "Products"]
|
||||
}
|
||||
|
||||
@@ -503,8 +503,9 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let group = pbxProj.objects.group(named: "Sources", inGroup: try pbxProj.getMainGroup())!.object
|
||||
let names = group.children.compactMap { pbxProj.objects.getFileElement(reference: $0)?.nameOrPath }
|
||||
let mainGroup = try pbxProj.getMainGroup()
|
||||
let group = mainGroup.children.compactMap { $0 as? PBXGroup }.first { $0.nameOrPath == "Sources" }!
|
||||
let names = group.children.compactMap { $0.nameOrPath }
|
||||
try expect(names) == [
|
||||
"1file.a",
|
||||
"10file.a",
|
||||
@@ -532,10 +533,10 @@ extension PBXProj {
|
||||
}
|
||||
|
||||
if let buildPhase = buildPhase {
|
||||
let buildFile = objects.buildFiles.objectReferences
|
||||
.first(where: { $0.object.fileRef == fileReference.reference })
|
||||
let buildFile = buildFiles
|
||||
.first(where: { $0.file === fileReference })
|
||||
let actualBuildPhase = buildFile
|
||||
.flatMap { buildFile in objects.buildPhases.referenceValues.first { $0.files.contains(buildFile.reference) } }?.buildPhase
|
||||
.flatMap { buildFile in buildPhases.first { $0.files.contains(buildFile) } }?.buildPhase
|
||||
|
||||
var error: String?
|
||||
if let buildPhase = buildPhase.buildPhase {
|
||||
@@ -563,24 +564,20 @@ extension PBXProj {
|
||||
}
|
||||
}
|
||||
|
||||
func getFileReference(paths: [String], names: [String], file: String = #file, line: Int = #line) -> ObjectReference<PBXFileReference>? {
|
||||
guard let project = objects.projects.first?.value else { return nil }
|
||||
guard let mainGroup = objects.groups.getReference(project.mainGroup) else { return nil }
|
||||
func getFileReference(paths: [String], names: [String], file: String = #file, line: Int = #line) -> PBXFileReference? {
|
||||
guard let mainGroup = projects.first?.mainGroup else { return nil }
|
||||
|
||||
return getFileReference(group: mainGroup, paths: paths, names: names)
|
||||
}
|
||||
|
||||
func getMainGroup(function: String = #function, file: String = #file, line: Int = #line) throws -> PBXGroup {
|
||||
guard let project = objects.projects.first?.value else {
|
||||
throw failure("Couldn't find project", file: file, line: line)
|
||||
}
|
||||
guard let mainGroup = objects.groups.getReference(project.mainGroup) else {
|
||||
guard let mainGroup = projects.first?.mainGroup else {
|
||||
throw failure("Couldn't find main group", file: file, line: line)
|
||||
}
|
||||
return mainGroup
|
||||
}
|
||||
|
||||
private func getFileReference(group: PBXGroup, paths: [String], names: [String]) -> ObjectReference<PBXFileReference>? {
|
||||
private func getFileReference(group: PBXGroup, paths: [String], names: [String]) -> PBXFileReference? {
|
||||
|
||||
guard !paths.isEmpty else { return nil }
|
||||
let path = paths.first!
|
||||
@@ -588,16 +585,10 @@ extension PBXProj {
|
||||
let restOfPath = Array(paths.dropFirst())
|
||||
let restOfName = Array(names.dropFirst())
|
||||
if restOfPath.isEmpty {
|
||||
let fileReferences: [ObjectReference<PBXFileReference>] = group.children.compactMap { 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 }
|
||||
let fileReferences: [PBXFileReference] = group.children.compactMap { $0 as? PBXFileReference }
|
||||
return fileReferences.first { $0.path == path && $0.nameOrPath == name }
|
||||
} else {
|
||||
let groups = group.children.compactMap { self.objects.groups.getReference($0) }
|
||||
let groups = group.children.compactMap { $0 as? PBXGroup }
|
||||
guard let group = groups.first(where: { $0.path == path && $0.nameOrPath == name }) else { return nil }
|
||||
return getFileReference(group: group, paths: restOfPath, names: restOfName)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
class SpecLoadingTests: XCTestCase {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Foundation
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
let fixturePath = Path(#file).parent().parent() + "Fixtures"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import ProjectSpec
|
||||
import PathKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
extension Project {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user