mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
Merge branch 'master' into copy-files-ordering
This commit is contained in:
@@ -1,45 +1,41 @@
|
||||
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
|
||||
let pbxProj: PBXProj
|
||||
|
||||
var targetSourceExcludePaths: Set<Path> = []
|
||||
var defaultExcludedFiles = [
|
||||
".DS_Store",
|
||||
]
|
||||
|
||||
var targetName: String = ""
|
||||
|
||||
private(set) var knownRegions: Set<String> = []
|
||||
|
||||
init(project: Project, addObjectClosure: @escaping (String, PBXObject) -> String) {
|
||||
init(project: Project, pbxProj: PBXProj) {
|
||||
self.project = project
|
||||
self.addObjectClosure = addObjectClosure
|
||||
self.pbxProj = pbxProj
|
||||
}
|
||||
|
||||
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, context: String? = nil) -> T {
|
||||
pbxProj.add(object: object)
|
||||
object.context = context
|
||||
return object
|
||||
}
|
||||
|
||||
func getAllSourceFiles(targetType: PBXProductType, sources: [TargetSource]) throws -> [SourceFile] {
|
||||
@@ -91,7 +87,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,
|
||||
@@ -100,7 +96,7 @@ class SourceGenerator {
|
||||
)
|
||||
}
|
||||
|
||||
func getContainedFileReference(path: Path) -> String {
|
||||
func getContainedFileReference(path: Path) -> PBXFileElement {
|
||||
let createIntermediateGroups = project.options.createIntermediateGroups
|
||||
|
||||
let parentPath = path.parent()
|
||||
@@ -113,12 +109,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
|
||||
@@ -128,7 +124,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()) ?? []
|
||||
@@ -138,10 +134,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",
|
||||
@@ -152,23 +147,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,
|
||||
@@ -176,8 +170,8 @@ class SourceGenerator {
|
||||
path: fileReferencePath.string
|
||||
)
|
||||
)
|
||||
fileReferencesByPath[fileReferenceKey] = fileReference.reference
|
||||
return fileReference.reference
|
||||
fileReferencesByPath[fileReferenceKey] = fileReference
|
||||
return fileReference
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,12 +203,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 {
|
||||
|
||||
@@ -237,28 +235,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
|
||||
@@ -307,27 +304,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)
|
||||
@@ -338,11 +332,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
|
||||
}
|
||||
|
||||
@@ -365,13 +359,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)
|
||||
@@ -409,7 +403,7 @@ class SourceGenerator {
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: fileReference,
|
||||
buildFile: PBXBuildFile(fileRef: fileReference),
|
||||
buildFile: PBXBuildFile(file: fileReference),
|
||||
buildPhase: .resources
|
||||
)
|
||||
allSourceFiles.append(sourceFile)
|
||||
@@ -425,7 +419,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)
|
||||
@@ -442,7 +436,7 @@ class SourceGenerator {
|
||||
let createIntermediateGroups = project.options.createIntermediateGroups
|
||||
|
||||
var sourceFiles: [SourceFile] = []
|
||||
let sourceReference: String
|
||||
let sourceReference: PBXFileElement
|
||||
var sourcePath = path
|
||||
switch type {
|
||||
case .folder:
|
||||
@@ -483,7 +477,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)
|
||||
|
||||
@@ -491,11 +485,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 {
|
||||
@@ -506,7 +500,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 {
|
||||
@@ -515,10 +509,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user