Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to set an order of groups #613

Merged
merged 11 commits into from
Apr 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Improve speed of metadata parsing and dependency resolution. [#803](https://github.com/yonaskolb/XcodeGen/pull/803) @michaeleisel
- Improve support for iOS sticker packs and add support for `launchAutomaticallySubstyle` to run schemes. [#824](https://github.com/yonaskolb/XcodeGen/pull/824) @scelis
- Add --project-root option to generate command. [#828](https://github.com/yonaskolb/XcodeGen/pull/828) @ileitch
- Add an ability to set an order of groups with `options.groupOrdering` [#480](https://github.com/yonaskolb/XcodeGen/pull/613) @Beniamiiin

#### Fixed
- Fixed issue when linking and embeding static frameworks: they should be linked and NOT embed. [#820](https://github.com/yonaskolb/XcodeGen/pull/820) @acecilia
Expand Down
18 changes: 18 additions & 0 deletions Docs/ProjectSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Note that target names can also be changed by adding a `name` property to a targ
- `none` - sorted alphabetically with all the other files
- `top` - at the top, before files
- `bottom` (default) - at the bottom, after other files
- [ ] **groupOrdering**: **[[GroupOrdering]](#groupOrdering)** - An order of groups.
- [ ] **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`.
- [ ] **generateEmptyDirectories**: **Bool** - If this is `true` then empty directories will be added to project too else will be missed. Defaults to `false`.
- [ ] **findCarthageFrameworks**: **Bool** - When this is set to `true`, all the invididual frameworks for Carthage dependencies will automatically be found. This property can be overriden individually for each carthage dependency - for more details see See **findFrameworks** in the [Dependency](#dependency) section. Defaults to `false`.
Expand All @@ -133,6 +134,23 @@ options:
postGenCommand: pod install
```

### GroupOrdering

Describe an order of groups. Available parameters:

- [ ] **pattern**: **String** - A group name pattern. Can be just a single string and also can be a regex pattern. Optional option, if you don't set it, it will pattern for the main group, i.e. the project.
- [ ] **order**: **[String]** - An order of groups.

```yaml
options:
groupOrdering:
- order: [Sources, Resources, Tests, Support files, Configurations]
- pattern: '^.*Screen$'
order: [View, Presenter, Interactor, Entities, Assembly]
```

In this example, we set up the order of two groups. First one is the main group, i.e. the project, note that in this case, we shouldn't set `pattern` option and the second group order is for groups whose names ends with `Screen`.

### Configs

Each config maps to a build type of either `debug` or `release` which will then apply default build settings to the project. Any value other than `debug` or `release` (for example `none`), will mean no default build settings will be applied to the project.
Expand Down
32 changes: 32 additions & 0 deletions Sources/ProjectSpec/GroupOrdering.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Foundation
import JSONUtilities

/// Describes an order of groups.
public struct GroupOrdering: Equatable {

/// A group name pattern.
public var pattern: String

/// A group name regex.
public var regex: NSRegularExpression?

/// Subgroups orders.
public var order: [String]

public init(pattern: String = "", order: [String] = []) {
self.pattern = pattern
self.regex = try? NSRegularExpression(pattern: pattern)
self.order = order
}

}

extension GroupOrdering: JSONObjectConvertible {

public init(jsonDictionary: JSONDictionary) throws {
pattern = jsonDictionary.json(atKeyPath: "pattern") ?? ""
regex = try? NSRegularExpression(pattern: pattern)
order = jsonDictionary.json(atKeyPath: "order") ?? []
}

}
10 changes: 10 additions & 0 deletions Sources/ProjectSpec/NSRegularExpressionExtensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Foundation

public extension NSRegularExpression {

func isMatch(to string: String) -> Bool {
let range = NSRange(location: 0, length: string.utf16.count)
return self.firstMatch(in: string, options: [], range: range) != nil
}

}
4 changes: 4 additions & 0 deletions Sources/ProjectSpec/SpecOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public struct SpecOptions: Equatable {
public var defaultConfig: String?
public var transitivelyLinkDependencies: Bool
public var groupSortPosition: GroupSortPosition
public var groupOrdering: [GroupOrdering]
public var generateEmptyDirectories: Bool
public var findCarthageFrameworks: Bool
public var localPackagesGroup: String?
Expand Down Expand Up @@ -85,6 +86,7 @@ public struct SpecOptions: Equatable {
defaultConfig: String? = nil,
transitivelyLinkDependencies: Bool = transitivelyLinkDependenciesDefault,
groupSortPosition: GroupSortPosition = groupSortPositionDefault,
groupOrdering: [GroupOrdering] = [],
generateEmptyDirectories: Bool = generateEmptyDirectoriesDefault,
findCarthageFrameworks: Bool = findCarthageFrameworksDefault,
localPackagesGroup: String? = nil,
Expand All @@ -107,6 +109,7 @@ public struct SpecOptions: Equatable {
self.defaultConfig = defaultConfig
self.transitivelyLinkDependencies = transitivelyLinkDependencies
self.groupSortPosition = groupSortPosition
self.groupOrdering = groupOrdering
self.generateEmptyDirectories = generateEmptyDirectories
self.findCarthageFrameworks = findCarthageFrameworks
self.localPackagesGroup = localPackagesGroup
Expand Down Expand Up @@ -137,6 +140,7 @@ extension SpecOptions: JSONObjectConvertible {
defaultConfig = jsonDictionary.json(atKeyPath: "defaultConfig")
transitivelyLinkDependencies = jsonDictionary.json(atKeyPath: "transitivelyLinkDependencies") ?? SpecOptions.transitivelyLinkDependenciesDefault
groupSortPosition = jsonDictionary.json(atKeyPath: "groupSortPosition") ?? SpecOptions.groupSortPositionDefault
groupOrdering = jsonDictionary.json(atKeyPath: "groupOrdering") ?? []
generateEmptyDirectories = jsonDictionary.json(atKeyPath: "generateEmptyDirectories") ?? SpecOptions.generateEmptyDirectoriesDefault
findCarthageFrameworks = jsonDictionary.json(atKeyPath: "findCarthageFrameworks") ?? SpecOptions.findCarthageFrameworksDefault
localPackagesGroup = jsonDictionary.json(atKeyPath: "localPackagesGroup")
Expand Down
48 changes: 48 additions & 0 deletions Sources/XcodeGenKit/PBXProjGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ public class PBXProjGenerator {

mainGroup.children = Array(sourceGenerator.rootGroups)
sortGroups(group: mainGroup)
setupGroupOrdering(group: mainGroup)
// add derived groups at the end
derivedGroups.forEach(sortGroups)
mainGroup.children += derivedGroups
Expand Down Expand Up @@ -573,6 +574,53 @@ public class PBXProjGenerator {
let childGroups = group.children.compactMap { $0 as? PBXGroup }
childGroups.forEach(sortGroups)
}

public func setupGroupOrdering(group: PBXGroup) {
let groupOrdering = project.options.groupOrdering.first { groupOrdering in
let groupName = group.nameOrPath

if groupName == groupOrdering.pattern {
return true
}

if let regex = groupOrdering.regex {
return regex.isMatch(to: groupName)
}

return false
}

if let order = groupOrdering?.order {
let files = group.children.filter { $0 is PBXFileReference }
Beniamiiin marked this conversation as resolved.
Show resolved Hide resolved
var groups = group.children.filter { $0 is PBXGroup }

var filteredGroups = [PBXFileElement]()

for groupName in order {
guard let group = groups.first(where: { $0.nameOrPath == groupName }) else {
Beniamiiin marked this conversation as resolved.
Show resolved Hide resolved
continue
}

filteredGroups.append(group)
groups.removeAll { $0 == group }
}

filteredGroups += groups

switch project.options.groupSortPosition {
case .top:
group.children = filteredGroups + files
case .bottom:
group.children = files + filteredGroups
default:
break
}
}

// sort sub groups
let childGroups = group.children.compactMap { $0 as? PBXGroup }
childGroups.forEach(setupGroupOrdering)
}

func getPBXProj(from reference: ProjectReference) throws -> PBXProj {
if let cachedProject = projects[reference] {
Expand Down
Loading