2017-07-23 21:58:03 +03:00
|
|
|
//
|
|
|
|
// PBXProjGenerator.swift
|
|
|
|
// XcodeGen
|
|
|
|
//
|
|
|
|
// Created by Yonas Kolb on 23/7/17.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import Foundation
|
|
|
|
import PathKit
|
|
|
|
import xcodeproj
|
|
|
|
import JSONUtilities
|
|
|
|
import Yams
|
2017-07-28 17:31:53 +03:00
|
|
|
import ProjectSpec
|
2017-07-23 21:58:03 +03:00
|
|
|
|
|
|
|
public class PBXProjGenerator {
|
|
|
|
|
2017-07-28 17:31:53 +03:00
|
|
|
let spec: ProjectSpec
|
2017-07-26 00:09:51 +03:00
|
|
|
let basePath: Path
|
2017-07-23 21:58:03 +03:00
|
|
|
|
|
|
|
var objects: [PBXObject] = []
|
2017-07-24 00:12:14 +03:00
|
|
|
var fileReferencesByPath: [Path: String] = [:]
|
2017-07-25 00:58:29 +03:00
|
|
|
var groupsByPath: [Path: PBXGroup] = [:]
|
2017-07-23 21:58:03 +03:00
|
|
|
|
|
|
|
var targetNativeReferences: [String: String] = [:]
|
|
|
|
var targetBuildFileReferences: [String: String] = [:]
|
|
|
|
var targetFileReferences: [String: String] = [:]
|
|
|
|
var topLevelGroups: [PBXGroup] = []
|
2017-07-25 01:32:36 +03:00
|
|
|
var carthageFrameworksByPlatform: [String: [String]] = [:]
|
2017-07-25 02:02:54 +03:00
|
|
|
var frameworkFiles: [String] = []
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-07-31 13:29:56 +03:00
|
|
|
var uuids: Set<String> = []
|
2017-07-23 21:58:03 +03:00
|
|
|
var projectReference: String
|
|
|
|
|
2017-07-28 17:31:53 +03:00
|
|
|
public init(spec: ProjectSpec, path: Path) {
|
2017-07-23 21:58:03 +03:00
|
|
|
self.spec = spec
|
2017-07-31 13:29:56 +03:00
|
|
|
basePath = path
|
2017-07-28 17:31:53 +03:00
|
|
|
|
2017-07-23 21:58:03 +03:00
|
|
|
projectReference = ""
|
2017-07-28 01:18:39 +03:00
|
|
|
projectReference = generateUUID(PBXProject.self, spec.name)
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
public func generateUUID<T: ProjectElement>(_ element: T.Type, _ id: String) -> String {
|
|
|
|
var uuid: String = ""
|
|
|
|
var counter: UInt = 0
|
|
|
|
let className: String = String(describing: T.self).replacingOccurrences(of: "PBX", with: "")
|
|
|
|
let classAcronym = String(className.characters.filter { String($0).lowercased() != String($0) })
|
|
|
|
let stringID = String(abs(id.hashValue).description.characters.prefix(10 - classAcronym.characters.count))
|
|
|
|
repeat {
|
|
|
|
counter += 1
|
|
|
|
uuid = "\(classAcronym)\(stringID)\(String(format: "%02d", counter))"
|
2017-07-31 13:29:56 +03:00
|
|
|
} while (uuids.contains(uuid))
|
2017-08-02 14:29:45 +03:00
|
|
|
uuids.insert(uuid)
|
2017-07-28 01:18:39 +03:00
|
|
|
return uuid
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
public func generate() throws -> PBXProj {
|
2017-07-28 01:18:39 +03:00
|
|
|
uuids = []
|
2017-07-27 00:06:34 +03:00
|
|
|
let buildConfigs: [XCBuildConfiguration] = spec.configs.map { config in
|
|
|
|
let buildSettings = spec.getProjectBuildSettings(config: config)
|
2017-07-28 01:18:39 +03:00
|
|
|
return XCBuildConfiguration(reference: generateUUID(XCBuildConfiguration.self, config.name), name: config.name, baseConfigurationReference: nil, buildSettings: buildSettings)
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
2017-07-26 13:51:55 +03:00
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let buildConfigList = XCConfigurationList(reference: generateUUID(XCConfigurationList.self, spec.name), buildConfigurations: buildConfigs.referenceSet, defaultConfigurationName: buildConfigs.first?.name ?? "", defaultConfigurationIsVisible: 0)
|
2017-07-23 21:58:03 +03:00
|
|
|
|
|
|
|
objects += buildConfigs.map { .xcBuildConfiguration($0) }
|
|
|
|
objects.append(.xcConfigurationList(buildConfigList))
|
|
|
|
|
|
|
|
for target in spec.targets {
|
2017-07-28 01:18:39 +03:00
|
|
|
targetNativeReferences[target.name] = generateUUID(PBXNativeTarget.self, target.name)
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let fileReference = PBXFileReference(reference: generateUUID(PBXFileReference.self, target.name), sourceTree: .buildProductsDir, explicitFileType: target.type.fileExtension, path: target.filename, includeInIndex: 0)
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxFileReference(fileReference))
|
|
|
|
targetFileReferences[target.name] = fileReference.reference
|
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference.reference), fileRef: fileReference.reference)
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxBuildFile(buildFile))
|
|
|
|
targetBuildFileReferences[target.name] = buildFile.reference
|
|
|
|
}
|
|
|
|
|
2017-07-24 14:35:21 +03:00
|
|
|
let targets = try spec.targets.map(generateTarget)
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let productGroup = PBXGroup(reference: generateUUID(PBXGroup.self, "Products"), children: Array(targetFileReferences.values), sourceTree: .group, name: "Products")
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxGroup(productGroup))
|
|
|
|
topLevelGroups.append(productGroup)
|
|
|
|
|
2017-07-25 01:32:36 +03:00
|
|
|
if !carthageFrameworksByPlatform.isEmpty {
|
|
|
|
var platforms: [PBXGroup] = []
|
|
|
|
for (platform, fileReferences) in carthageFrameworksByPlatform {
|
2017-07-28 01:18:39 +03:00
|
|
|
let platformGroup = PBXGroup(reference: generateUUID(PBXGroup.self, platform), children: fileReferences, sourceTree: .group, name: platform, path: platform)
|
2017-07-25 01:32:36 +03:00
|
|
|
objects.append(.pbxGroup(platformGroup))
|
|
|
|
platforms.append(platformGroup)
|
|
|
|
}
|
2017-07-28 01:18:39 +03:00
|
|
|
let carthageGroup = PBXGroup(reference: generateUUID(PBXGroup.self, "Carthage"), children: platforms.referenceList, sourceTree: .group, name: "Carthage", path: "Carthage/Build")
|
2017-07-25 01:32:36 +03:00
|
|
|
objects.append(.pbxGroup(carthageGroup))
|
|
|
|
topLevelGroups.append(carthageGroup)
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:02:54 +03:00
|
|
|
if !frameworkFiles.isEmpty {
|
2017-07-28 01:18:39 +03:00
|
|
|
let group = PBXGroup(reference: generateUUID(PBXGroup.self, "Frameworks"), children: frameworkFiles, sourceTree: .group, name: "Frameworks")
|
2017-07-25 02:02:54 +03:00
|
|
|
objects.append(.pbxGroup(group))
|
|
|
|
topLevelGroups.append(group)
|
|
|
|
}
|
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let mainGroup = PBXGroup(reference: generateUUID(PBXGroup.self, "Project"), children: topLevelGroups.referenceList, sourceTree: .group)
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxGroup(mainGroup))
|
|
|
|
|
2017-07-23 23:39:18 +03:00
|
|
|
let knownRegions: [String] = ["en", "Base"]
|
2017-07-24 14:35:21 +03:00
|
|
|
let pbxProjectRoot = PBXProject(reference: projectReference, buildConfigurationList: buildConfigList.reference, compatibilityVersion: "Xcode 3.2", mainGroup: mainGroup.reference, developmentRegion: "English", knownRegions: knownRegions, targets: targets.referenceList)
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxProject(pbxProjectRoot))
|
|
|
|
|
|
|
|
return PBXProj(archiveVersion: 1, objectVersion: 46, rootObject: projectReference, objects: objects)
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SourceFile {
|
|
|
|
let path: Path
|
2017-07-24 00:12:14 +03:00
|
|
|
let fileReference: String
|
2017-07-23 21:58:03 +03:00
|
|
|
let buildFile: PBXBuildFile
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateSourceFile(path: Path) -> SourceFile {
|
|
|
|
let fileReference = fileReferencesByPath[path]!
|
2017-08-03 21:20:30 +03:00
|
|
|
var settings: [String: Any]?
|
2017-07-23 21:58:03 +03:00
|
|
|
if getBuildPhaseForPath(path) == .headers {
|
2017-08-03 21:20:30 +03:00
|
|
|
settings = ["ATTRIBUTES": ["Public"]]
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
2017-07-28 01:18:39 +03:00
|
|
|
let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference), fileRef: fileReference, settings: settings)
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxBuildFile(buildFile))
|
|
|
|
return SourceFile(path: path, fileReference: fileReference, buildFile: buildFile)
|
|
|
|
}
|
|
|
|
|
2017-07-31 13:29:56 +03:00
|
|
|
func generateTarget(_ target: Target) throws -> PBXNativeTarget {
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-08-02 13:54:07 +03:00
|
|
|
let sourcePaths = target.sources.map { basePath + $0 }
|
2017-07-26 13:40:25 +03:00
|
|
|
var sourceFilePaths: [Path] = []
|
|
|
|
|
|
|
|
for source in sourcePaths {
|
2017-07-28 01:18:39 +03:00
|
|
|
let sourceGroups = try getGroups(path: source)
|
2017-07-26 13:40:25 +03:00
|
|
|
sourceFilePaths += sourceGroups.filePaths
|
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-07-27 00:06:34 +03:00
|
|
|
let configs: [XCBuildConfiguration] = spec.configs.map { config in
|
|
|
|
let buildSettings = spec.getTargetBuildSettings(target: target, config: config)
|
2017-07-24 19:03:41 +03:00
|
|
|
var baseConfigurationReference: String?
|
2017-07-27 00:06:34 +03:00
|
|
|
|
2017-07-27 15:41:18 +03:00
|
|
|
if let configPath = target.configFiles[config.name] {
|
2017-08-02 13:54:07 +03:00
|
|
|
let path = basePath + configPath
|
2017-07-24 19:03:41 +03:00
|
|
|
baseConfigurationReference = fileReferencesByPath[path]
|
|
|
|
}
|
2017-08-02 22:25:50 +03:00
|
|
|
return XCBuildConfiguration(reference: generateUUID(XCBuildConfiguration.self, config.name + target.name), name: config.name, baseConfigurationReference: baseConfigurationReference, buildSettings: buildSettings)
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
objects += configs.map { .xcBuildConfiguration($0) }
|
2017-07-28 01:18:39 +03:00
|
|
|
let buildConfigList = XCConfigurationList(reference: generateUUID(XCConfigurationList.self, target.name), buildConfigurations: configs.referenceSet, defaultConfigurationName: "")
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.xcConfigurationList(buildConfigList))
|
|
|
|
|
|
|
|
var dependancies: [String] = []
|
2017-07-25 02:02:54 +03:00
|
|
|
var targetFrameworkBuildFiles: [String] = []
|
2017-07-23 21:58:03 +03:00
|
|
|
var copyFiles: [String] = []
|
2017-08-03 21:03:56 +03:00
|
|
|
var extensions: [String] = []
|
|
|
|
|
2017-07-23 21:58:03 +03:00
|
|
|
for dependancy in target.dependencies {
|
2017-07-24 13:46:01 +03:00
|
|
|
switch dependancy {
|
2017-08-03 21:03:56 +03:00
|
|
|
case let .target(dependencyTargetName):
|
|
|
|
guard let dependencyTarget = spec.getTarget(dependencyTargetName) else { continue }
|
|
|
|
let dependencyFileReference = targetFileReferences[dependencyTargetName]!
|
|
|
|
|
|
|
|
let targetProxy = PBXContainerItemProxy(reference: generateUUID(PBXContainerItemProxy.self, target.name), containerPortal: projectReference, remoteGlobalIDString: targetNativeReferences[dependencyTargetName]!, proxyType: .nativeTarget, remoteInfo: dependencyTargetName)
|
|
|
|
let targetDependancy = PBXTargetDependency(reference: generateUUID(PBXTargetDependency.self, dependencyTargetName + target.name), target: targetNativeReferences[dependencyTargetName]!, targetProxy: targetProxy.reference)
|
2017-07-23 21:58:03 +03:00
|
|
|
|
|
|
|
objects.append(.pbxContainerItemProxy(targetProxy))
|
|
|
|
objects.append(.pbxTargetDependency(targetDependancy))
|
|
|
|
dependancies.append(targetDependancy.reference)
|
|
|
|
|
2017-08-03 21:03:56 +03:00
|
|
|
let dependencyBuildFile = targetBuildFileReferences[dependencyTargetName]!
|
2017-07-31 13:29:56 +03:00
|
|
|
// link
|
2017-07-25 02:02:54 +03:00
|
|
|
targetFrameworkBuildFiles.append(dependencyBuildFile)
|
2017-07-24 00:35:28 +03:00
|
|
|
|
2017-08-03 21:03:56 +03:00
|
|
|
if target.type.isApp {
|
|
|
|
if dependencyTarget.type.isExtension {
|
|
|
|
// embed app extensions
|
|
|
|
let embedSettings: [String: Any] = ["ATTRIBUTES": ["RemoveHeadersOnCopy"]]
|
|
|
|
let embedFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, dependencyFileReference + target.name), fileRef: dependencyFileReference, settings: embedSettings)
|
|
|
|
objects.append(.pbxBuildFile(embedFile))
|
|
|
|
extensions.append(embedFile.reference)
|
|
|
|
} else {
|
|
|
|
// embed frameworks
|
|
|
|
let embedSettings: [String: Any] = ["ATTRIBUTES": ["CodeSignOnCopy", "RemoveHeadersOnCopy"]]
|
|
|
|
let embedFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, dependencyFileReference + target.name), fileRef: dependencyFileReference, settings: embedSettings)
|
|
|
|
objects.append(.pbxBuildFile(embedFile))
|
|
|
|
copyFiles.append(embedFile.reference)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:02:54 +03:00
|
|
|
case let .framework(framework):
|
2017-07-26 00:09:51 +03:00
|
|
|
let fileReference = getFileReference(path: Path(framework), inPath: basePath)
|
2017-08-02 22:25:50 +03:00
|
|
|
let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference)
|
2017-07-25 02:02:54 +03:00
|
|
|
objects.append(.pbxBuildFile(buildFile))
|
|
|
|
targetFrameworkBuildFiles.append(buildFile.reference)
|
|
|
|
if !frameworkFiles.contains(fileReference) {
|
|
|
|
frameworkFiles.append(fileReference)
|
|
|
|
}
|
2017-07-25 01:32:36 +03:00
|
|
|
case let .carthage(carthage):
|
|
|
|
if carthageFrameworksByPlatform[target.platform.rawValue] == nil {
|
|
|
|
carthageFrameworksByPlatform[target.platform.rawValue] = []
|
|
|
|
}
|
|
|
|
let carthagePath: Path = "Carthage/Build"
|
2017-07-28 01:18:39 +03:00
|
|
|
var platformName = target.platform.rawValue
|
|
|
|
if target.platform == .macOS {
|
|
|
|
platformName = "Mac"
|
|
|
|
}
|
|
|
|
var platformPath = carthagePath + platformName
|
2017-07-25 02:02:54 +03:00
|
|
|
var frameworkPath = platformPath + carthage
|
|
|
|
if frameworkPath.extension == nil {
|
|
|
|
frameworkPath = Path(frameworkPath.string + ".framework")
|
|
|
|
}
|
|
|
|
let fileReference = getFileReference(path: frameworkPath, inPath: platformPath)
|
2017-07-25 01:32:36 +03:00
|
|
|
|
2017-08-02 22:25:50 +03:00
|
|
|
let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference)
|
2017-07-25 01:32:36 +03:00
|
|
|
objects.append(.pbxBuildFile(buildFile))
|
|
|
|
carthageFrameworksByPlatform[target.platform.rawValue]?.append(fileReference)
|
|
|
|
|
2017-07-25 02:02:54 +03:00
|
|
|
targetFrameworkBuildFiles.append(buildFile.reference)
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let fileReference = targetFileReferences[target.name]!
|
|
|
|
var buildPhases: [String] = []
|
|
|
|
|
|
|
|
func getBuildFilesForPhase(_ buildPhase: BuildPhase) -> Set<String> {
|
2017-07-26 13:40:25 +03:00
|
|
|
let files = sourceFilePaths.filter { getBuildPhaseForPath($0) == buildPhase }.map(generateSourceFile)
|
2017-07-23 21:58:03 +03:00
|
|
|
return Set(files.map { $0.buildFile.reference })
|
|
|
|
}
|
|
|
|
|
2017-08-01 19:40:40 +03:00
|
|
|
func getRunScript(runScript: RunScript) throws -> PBXShellScriptBuildPhase {
|
|
|
|
|
|
|
|
let shellScript: String
|
|
|
|
switch runScript.script {
|
|
|
|
case let .path(path):
|
2017-08-02 13:54:07 +03:00
|
|
|
shellScript = try (basePath + path).read()
|
2017-08-01 19:40:40 +03:00
|
|
|
case let .script(script):
|
|
|
|
shellScript = script
|
|
|
|
}
|
|
|
|
let escapedScript = shellScript.replacingOccurrences(of: "\"", with: "\\\"").replacingOccurrences(of: "\n", with: "\\n")
|
2017-08-24 18:02:27 +03:00
|
|
|
var shellScriptPhase = PBXShellScriptBuildPhase(
|
2017-08-02 22:25:50 +03:00
|
|
|
reference: generateUUID(PBXShellScriptBuildPhase.self, String(describing: runScript.name) + shellScript + target.name),
|
2017-08-01 19:40:40 +03:00
|
|
|
files: [],
|
|
|
|
name: runScript.name ?? "Run Script",
|
|
|
|
inputPaths: Set(runScript.inputFiles),
|
|
|
|
outputPaths: Set(runScript.outputFiles),
|
|
|
|
shellPath: runScript.shell ?? "/bin/sh",
|
|
|
|
shellScript: escapedScript)
|
2017-08-24 18:02:27 +03:00
|
|
|
shellScriptPhase.runOnlyForDeploymentPostprocessing = runScript.runOnlyWhenInstalling ? 1 : 0
|
2017-08-01 19:40:40 +03:00
|
|
|
objects.append(.pbxShellScriptBuildPhase(shellScriptPhase))
|
|
|
|
buildPhases.append(shellScriptPhase.reference)
|
|
|
|
return shellScriptPhase
|
|
|
|
}
|
|
|
|
|
|
|
|
_ = try target.prebuildScripts.map(getRunScript)
|
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let sourcesBuildPhase = PBXSourcesBuildPhase(reference: generateUUID(PBXSourcesBuildPhase.self, target.name), files: getBuildFilesForPhase(.sources))
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxSourcesBuildPhase(sourcesBuildPhase))
|
|
|
|
buildPhases.append(sourcesBuildPhase.reference)
|
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let resourcesBuildPhase = PBXResourcesBuildPhase(reference: generateUUID(PBXResourcesBuildPhase.self, target.name), files: getBuildFilesForPhase(.resources))
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxResourcesBuildPhase(resourcesBuildPhase))
|
|
|
|
buildPhases.append(resourcesBuildPhase.reference)
|
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let headersBuildPhase = PBXHeadersBuildPhase(reference: generateUUID(PBXHeadersBuildPhase.self, target.name), files: getBuildFilesForPhase(.headers))
|
2017-07-23 21:58:03 +03:00
|
|
|
objects.append(.pbxHeadersBuildPhase(headersBuildPhase))
|
|
|
|
buildPhases.append(headersBuildPhase.reference)
|
|
|
|
|
2017-08-03 21:06:21 +03:00
|
|
|
if !targetFrameworkBuildFiles.isEmpty {
|
|
|
|
|
|
|
|
let frameworkBuildPhase = PBXFrameworksBuildPhase(
|
|
|
|
reference: generateUUID(PBXFrameworksBuildPhase.self, target.name),
|
|
|
|
files: Set(targetFrameworkBuildFiles),
|
|
|
|
runOnlyForDeploymentPostprocessing: 0)
|
|
|
|
|
|
|
|
objects.append(.pbxFrameworksBuildPhase(frameworkBuildPhase))
|
|
|
|
buildPhases.append(frameworkBuildPhase.reference)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !extensions.isEmpty {
|
|
|
|
|
|
|
|
let copyFilesPhase = PBXCopyFilesBuildPhase(
|
|
|
|
reference: generateUUID(PBXCopyFilesBuildPhase.self, "embed app extensions" + target.name),
|
|
|
|
dstPath: "",
|
|
|
|
dstSubfolderSpec: .plugins,
|
|
|
|
files: Set(extensions))
|
|
|
|
|
|
|
|
objects.append(.pbxCopyFilesBuildPhase(copyFilesPhase))
|
|
|
|
buildPhases.append(copyFilesPhase.reference)
|
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-08-03 21:06:21 +03:00
|
|
|
if !copyFiles.isEmpty {
|
|
|
|
|
|
|
|
let copyFilesPhase = PBXCopyFilesBuildPhase(
|
|
|
|
reference: generateUUID(PBXCopyFilesBuildPhase.self, "embed frameworks" + target.name),
|
|
|
|
dstPath: "",
|
|
|
|
dstSubfolderSpec: .frameworks,
|
|
|
|
files: Set(copyFiles))
|
|
|
|
|
|
|
|
objects.append(.pbxCopyFilesBuildPhase(copyFilesPhase))
|
|
|
|
buildPhases.append(copyFilesPhase.reference)
|
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-08-03 21:05:22 +03:00
|
|
|
if target.type.isApp {
|
2017-07-25 02:24:14 +03:00
|
|
|
func getCarthageFrameworks(target: Target) -> [String] {
|
|
|
|
var frameworks: [String] = []
|
|
|
|
for dependency in target.dependencies {
|
|
|
|
switch dependency {
|
2017-07-31 13:29:56 +03:00
|
|
|
case let .carthage(framework): frameworks.append(framework)
|
|
|
|
case let .target(targetName):
|
|
|
|
if let target = spec.targets.first(where: { $0.name == targetName }) {
|
2017-07-25 02:24:14 +03:00
|
|
|
frameworks += getCarthageFrameworks(target: target)
|
|
|
|
}
|
|
|
|
default: break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return frameworks
|
|
|
|
}
|
|
|
|
|
|
|
|
let carthageFrameworks = Set(getCarthageFrameworks(target: target))
|
|
|
|
if !carthageFrameworks.isEmpty {
|
|
|
|
let inputPaths = carthageFrameworks.map { "$(SRCROOT)/Carthage/Build/\(target.platform)/\($0)\($0.contains(".") ? "" : ".framework")" }
|
2017-08-02 22:25:50 +03:00
|
|
|
let carthageScript = PBXShellScriptBuildPhase(reference: generateUUID(PBXShellScriptBuildPhase.self, "Carthage" + target.name), files: [], name: "Carthage", inputPaths: Set(inputPaths), outputPaths: [], shellPath: "/bin/sh", shellScript: "/usr/local/bin/carthage copy-frameworks\n")
|
2017-07-25 02:24:14 +03:00
|
|
|
objects.append(.pbxShellScriptBuildPhase(carthageScript))
|
|
|
|
buildPhases.append(carthageScript.reference)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-01 19:40:40 +03:00
|
|
|
_ = try target.postbuildScripts.map(getRunScript)
|
|
|
|
|
2017-07-23 21:58:03 +03:00
|
|
|
let nativeTarget = PBXNativeTarget(
|
|
|
|
reference: targetNativeReferences[target.name]!,
|
|
|
|
buildConfigurationList: buildConfigList.reference,
|
|
|
|
buildPhases: buildPhases,
|
|
|
|
buildRules: [],
|
|
|
|
dependencies: dependancies,
|
|
|
|
name: target.name,
|
|
|
|
productReference: fileReference,
|
|
|
|
productType: target.type)
|
|
|
|
objects.append(.pbxNativeTarget(nativeTarget))
|
2017-07-24 14:35:21 +03:00
|
|
|
return nativeTarget
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func getBuildPhaseForPath(_ path: Path) -> BuildPhase? {
|
2017-07-24 15:02:11 +03:00
|
|
|
if path.lastComponent == "Info.plist" {
|
|
|
|
return nil
|
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
if let fileExtension = path.extension {
|
|
|
|
switch fileExtension {
|
2017-07-23 22:25:02 +03:00
|
|
|
case "swift", "m": return .sources
|
2017-07-23 21:58:03 +03:00
|
|
|
case "h", "hh", "hpp", "ipp", "tpp", "hxx", "def": return .headers
|
2017-07-24 15:02:11 +03:00
|
|
|
case "xcconfig": return nil
|
2017-07-23 21:58:03 +03:00
|
|
|
default: return .resources
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:02:54 +03:00
|
|
|
func getFileReference(path: Path, inPath: Path) -> String {
|
2017-07-25 01:32:36 +03:00
|
|
|
if let fileReference = fileReferencesByPath[path] {
|
|
|
|
return fileReference
|
|
|
|
} else {
|
2017-07-28 01:18:39 +03:00
|
|
|
let fileReference = PBXFileReference(reference: generateUUID(PBXFileReference.self, path.lastComponent), sourceTree: .group, path: path.byRemovingBase(path: inPath).string)
|
2017-07-25 01:32:36 +03:00
|
|
|
objects.append(.pbxFileReference(fileReference))
|
|
|
|
fileReferencesByPath[path] = fileReference.reference
|
|
|
|
return fileReference.reference
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
func getGroups(path: Path, depth: Int = 0) throws -> (filePaths: [Path], groups: [PBXGroup]) {
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let excludedFiles: [String] = [".DS_Store"]
|
2017-07-24 00:12:14 +03:00
|
|
|
let directories = try path.children().filter { $0.isDirectory && $0.extension == nil && $0.extension != "lproj" }
|
2017-07-28 01:18:39 +03:00
|
|
|
var filePaths = try path.children().filter { $0.isFile || $0.extension != nil && $0.extension != "lproj" }.filter { !excludedFiles.contains($0.lastComponent) }
|
2017-07-24 00:12:14 +03:00
|
|
|
let localisedDirectories = try path.children().filter { $0.extension == "lproj" }
|
2017-07-23 21:58:03 +03:00
|
|
|
var groupChildren: [String] = []
|
2017-07-24 14:50:59 +03:00
|
|
|
var allFilePaths: [Path] = filePaths
|
2017-07-25 00:26:45 +03:00
|
|
|
var groups: [PBXGroup] = []
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
for path in directories {
|
|
|
|
let subGroups = try getGroups(path: path, depth: depth + 1)
|
2017-07-25 00:26:45 +03:00
|
|
|
allFilePaths += subGroups.filePaths
|
|
|
|
groupChildren.append(subGroups.groups.first!.reference)
|
|
|
|
groups += subGroups.groups
|
2017-07-24 14:26:58 +03:00
|
|
|
}
|
|
|
|
|
2017-07-25 02:02:54 +03:00
|
|
|
for filePath in filePaths {
|
|
|
|
let fileReference = getFileReference(path: filePath, inPath: path)
|
2017-07-25 01:32:36 +03:00
|
|
|
groupChildren.append(fileReference)
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
|
2017-07-24 00:12:14 +03:00
|
|
|
for localisedDirectory in localisedDirectories {
|
|
|
|
for path in try localisedDirectory.children() {
|
|
|
|
let filePath = "\(localisedDirectory.lastComponent)/\(path.lastComponent)"
|
2017-07-28 01:18:39 +03:00
|
|
|
let fileReference = PBXFileReference(reference: generateUUID(PBXFileReference.self, localisedDirectory.lastComponent), sourceTree: .group, name: localisedDirectory.lastComponentWithoutExtension, path: filePath)
|
2017-07-24 00:12:14 +03:00
|
|
|
objects.append(.pbxFileReference(fileReference))
|
|
|
|
|
2017-07-28 01:18:39 +03:00
|
|
|
let variantGroup = PBXVariantGroup(reference: generateUUID(PBXVariantGroup.self, path.lastComponent), children: Set([fileReference.reference]), name: path.lastComponent, sourceTree: .group)
|
2017-07-24 00:12:14 +03:00
|
|
|
objects.append(.pbxVariantGroup(variantGroup))
|
|
|
|
|
|
|
|
fileReferencesByPath[path] = variantGroup.reference
|
|
|
|
groupChildren.append(variantGroup.reference)
|
|
|
|
filePaths.append(path)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-24 19:03:41 +03:00
|
|
|
let groupPath: String = depth == 0 ? path.byRemovingBase(path: basePath).string : path.lastComponent
|
2017-07-25 00:26:45 +03:00
|
|
|
let group: PBXGroup
|
2017-07-25 00:58:29 +03:00
|
|
|
if let cachedGroup = groupsByPath[path] {
|
2017-07-25 00:26:45 +03:00
|
|
|
group = cachedGroup
|
|
|
|
} else {
|
2017-07-28 01:18:39 +03:00
|
|
|
group = PBXGroup(reference: generateUUID(PBXGroup.self, path.lastComponent), children: groupChildren, sourceTree: .group, name: path.lastComponent, path: groupPath)
|
2017-07-25 00:26:45 +03:00
|
|
|
objects.append(.pbxGroup(group))
|
|
|
|
if depth == 0 {
|
|
|
|
topLevelGroups.append(group)
|
|
|
|
}
|
2017-07-25 00:58:29 +03:00
|
|
|
groupsByPath[path] = group
|
2017-07-25 00:26:45 +03:00
|
|
|
}
|
|
|
|
groups.insert(group, at: 0)
|
|
|
|
return (allFilePaths, groups)
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
}
|