mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
@@ -87,6 +87,10 @@ Note that target names can also be changed by adding a `name` property to a targ
|
||||
- [ ] **disabledValidations**: **[String]** - A list of validations that can be disabled if they're too strict for your use case. By default this is set to an empty array. Currently these are the available options:
|
||||
- `missingConfigs`: Disable errors for configurations in yaml files that don't exist in the project itself. This can be useful if you include the same yaml file in different projects
|
||||
- [ ] **defaultConfig**: **String** - The default configuration for command line builds from Xcode. If the configuration provided here doesn't match one in your [configs](#configs) key, XcodeGen will fail. If you don't set this, the first configuration alphabetically will be chosen.
|
||||
- [ ] **groupSortPosition**: **String** - Where groups are sorted in relation to other files. Either:
|
||||
- `top` - at the top, before files
|
||||
- `bottom` - at the bottom, after other files
|
||||
- `none` - sorted alphabetically with all the other files
|
||||
- [ ] **transitivelyLinkDependencies**: **Bool** - If this is `true` then targets will link to the dependencies of their target dependencies. If a target should embed its dependencies, such as application and test bundles, it will embed these transitive dependencies as well. Some complex setups might want to set this to `false` and explicitly specify dependencies at every level. Targets can override this with [Target](#target).transitivelyLinkDependencies. Defaults to `false`.
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -18,6 +18,7 @@ public struct SpecOptions: Equatable {
|
||||
public var deploymentTarget: DeploymentTarget
|
||||
public var defaultConfig: String?
|
||||
public var transitivelyLinkDependencies: Bool
|
||||
public var groupSortPosition: GroupSortPosition
|
||||
|
||||
public enum ValidationType: String {
|
||||
case missingConfigs
|
||||
@@ -44,6 +45,16 @@ public struct SpecOptions: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where groups are sorted in relation to other files
|
||||
public enum GroupSortPosition: String {
|
||||
/// groups are at the top
|
||||
case top
|
||||
/// groups are at the bottom
|
||||
case bottom
|
||||
/// groups are sorted with the rest of the files
|
||||
case none
|
||||
}
|
||||
|
||||
public init(
|
||||
carthageBuildPath: String? = nil,
|
||||
carthageExecutablePath: String? = nil,
|
||||
@@ -58,7 +69,8 @@ public struct SpecOptions: Equatable {
|
||||
deploymentTarget: DeploymentTarget = .init(),
|
||||
disabledValidations: [ValidationType] = [],
|
||||
defaultConfig: String? = nil,
|
||||
transitivelyLinkDependencies: Bool = false
|
||||
transitivelyLinkDependencies: Bool = false,
|
||||
groupSortPosition: GroupSortPosition = .bottom
|
||||
) {
|
||||
self.carthageBuildPath = carthageBuildPath
|
||||
self.carthageExecutablePath = carthageExecutablePath
|
||||
@@ -74,6 +86,7 @@ public struct SpecOptions: Equatable {
|
||||
self.disabledValidations = disabledValidations
|
||||
self.defaultConfig = defaultConfig
|
||||
self.transitivelyLinkDependencies = transitivelyLinkDependencies
|
||||
self.groupSortPosition = groupSortPosition
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,5 +107,6 @@ extension SpecOptions: JSONObjectConvertible {
|
||||
disabledValidations = jsonDictionary.json(atKeyPath: "disabledValidations") ?? []
|
||||
defaultConfig = jsonDictionary.json(atKeyPath: "defaultConfig")
|
||||
transitivelyLinkDependencies = jsonDictionary.json(atKeyPath: "transitivelyLinkDependencies") ?? false
|
||||
groupSortPosition = jsonDictionary.json(atKeyPath: "groupSortPosition") ?? .bottom
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class PBXProjGenerator {
|
||||
var targetAggregateObjects: [String: ObjectReference<PBXAggregateTarget>] = [:]
|
||||
var targetBuildFiles: [String: ObjectReference<PBXBuildFile>] = [:]
|
||||
var targetFileReferences: [String: String] = [:]
|
||||
var topLevelGroups: Set<String> = []
|
||||
|
||||
var carthageFrameworksByPlatform: [String: Set<String>] = [:]
|
||||
var frameworkFiles: [String] = []
|
||||
|
||||
@@ -80,6 +80,8 @@ public class PBXProjGenerator {
|
||||
)
|
||||
)
|
||||
|
||||
var derivedGroups: [ObjectReference<PBXGroup>] = []
|
||||
|
||||
let mainGroup = createObject(
|
||||
id: "Project",
|
||||
PBXGroup(
|
||||
@@ -161,7 +163,7 @@ public class PBXProjGenerator {
|
||||
name: "Products"
|
||||
)
|
||||
)
|
||||
topLevelGroups.insert(productGroup.reference)
|
||||
derivedGroups.append(productGroup)
|
||||
|
||||
if !carthageFrameworksByPlatform.isEmpty {
|
||||
var platforms: [PBXGroup] = []
|
||||
@@ -199,15 +201,16 @@ public class PBXProjGenerator {
|
||||
name: "Frameworks"
|
||||
)
|
||||
)
|
||||
topLevelGroups.insert(group.reference)
|
||||
derivedGroups.append(group)
|
||||
}
|
||||
|
||||
for rootGroup in sourceGenerator.rootGroups {
|
||||
topLevelGroups.insert(rootGroup)
|
||||
}
|
||||
|
||||
mainGroup.object.children = Array(topLevelGroups)
|
||||
mainGroup.object.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 }
|
||||
|
||||
let projectAttributes: [String: Any] = ["LastUpgradeCheck": project.xcodeVersion]
|
||||
.merged(project.attributes)
|
||||
@@ -392,10 +395,13 @@ public class PBXProjGenerator {
|
||||
return ObjectReference(reference: reference, object: fileElement)
|
||||
}
|
||||
.sorted { child1, child2 in
|
||||
if child1.object.sortOrder == child2.object.sortOrder {
|
||||
let sortOrder1 = child1.object.getSortOrder(groupSortPosition: project.options.groupSortPosition)
|
||||
let sortOrder2 = child2.object.getSortOrder(groupSortPosition: project.options.groupSortPosition)
|
||||
|
||||
if sortOrder1 == sortOrder2 {
|
||||
return child1.object.nameOrPath.localizedStandardCompare(child2.object.nameOrPath) == .orderedAscending
|
||||
} else {
|
||||
return child1.object.sortOrder < child2.object.sortOrder
|
||||
return sortOrder1 < sortOrder2
|
||||
}
|
||||
}
|
||||
group.object.children = children.map { $0.reference }.filter { $0 != group.reference }
|
||||
@@ -891,3 +897,18 @@ extension Target {
|
||||
return type.isApp || type.isTest
|
||||
}
|
||||
}
|
||||
|
||||
extension PBXFileElement {
|
||||
|
||||
public func getSortOrder(groupSortPosition: SpecOptions.GroupSortPosition) -> Int {
|
||||
if type(of: self).isa == "PBXGroup" {
|
||||
switch groupSortPosition {
|
||||
case .top: return -1
|
||||
case .bottom: return 1
|
||||
case .none: return 0
|
||||
}
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,6 @@ extension PBXFileElement {
|
||||
public var nameOrPath: String {
|
||||
return name ?? path ?? ""
|
||||
}
|
||||
|
||||
public var sortOrder: Int {
|
||||
if type(of: self).isa == "PBXGroup" {
|
||||
return 0
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PBXProj {
|
||||
|
||||
@@ -559,10 +559,8 @@
|
||||
G_8340618952527 /* Configs */,
|
||||
G_3234630030493 /* FileGroup */,
|
||||
G_4661500274312 /* Framework */,
|
||||
G_1952740716080 /* Frameworks */,
|
||||
G_8268950006174 /* iMessage */,
|
||||
G_1646573205915 /* iMessage MessagesExtension */,
|
||||
G_8620238527590 /* Products */,
|
||||
G_7189434949822 /* Resources */,
|
||||
G_6651250437419 /* StandaloneFiles */,
|
||||
G_3997550084026 /* StaticLibrary_ObjC */,
|
||||
@@ -571,6 +569,8 @@
|
||||
FR_232605427418 /* Mintfile */,
|
||||
FR_257073931060 /* ResourceFolder */,
|
||||
FR_775316160345 /* SomeFile */,
|
||||
G_1952740716080 /* Frameworks */,
|
||||
G_8620238527590 /* Products */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -8,6 +8,7 @@ options:
|
||||
transitivelyLinkDependencies: true
|
||||
deploymentTarget:
|
||||
watchOS: 4.0
|
||||
groupSortPosition: top
|
||||
fileGroups:
|
||||
- Configs
|
||||
- FileGroup
|
||||
|
||||
@@ -459,6 +459,57 @@ class SourceGeneratorTests: XCTestCase {
|
||||
|
||||
try expect(sourcesBuildPhase.files.count) == 1
|
||||
}
|
||||
|
||||
$0.it("derived directories are sorted last") {
|
||||
let directories = """
|
||||
A:
|
||||
- file.swift
|
||||
P:
|
||||
- file.swift
|
||||
S:
|
||||
- file.swift
|
||||
"""
|
||||
try createDirectories(directories)
|
||||
|
||||
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["A", "P", "S"], dependencies: [Dependency(type: .carthage, reference: "Alamofire")])
|
||||
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 }
|
||||
try expect(groups) == ["A", "P", "S", "Frameworks", "Products"]
|
||||
}
|
||||
|
||||
$0.it("sorts files") {
|
||||
let directories = """
|
||||
Sources:
|
||||
- file3.swift
|
||||
- file.swift
|
||||
- 10file.a
|
||||
- 1file.a
|
||||
- file2.swift
|
||||
- group2:
|
||||
- file.swift
|
||||
- group:
|
||||
- file.swift
|
||||
"""
|
||||
try createDirectories(directories)
|
||||
|
||||
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Sources"], dependencies: [Dependency(type: .carthage, reference: "Alamofire")])
|
||||
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 }
|
||||
try expect(names) == [
|
||||
"1file.a",
|
||||
"10file.a",
|
||||
"file.swift",
|
||||
"file2.swift",
|
||||
"file3.swift",
|
||||
"group",
|
||||
"group2",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user