Skip to content

Commit 5bff140

Browse files
committed
add hidingOlderIdenticalBuilds helper
1 parent a62f612 commit 5bff140

2 files changed

Lines changed: 70 additions & 2 deletions

File tree

Sources/XcodesKit/Models/Xcodes/XcodeListGrouping.swift

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,9 @@ public extension Array {
167167

168168
/// Groups arbitrary elements by the major version of a derived Xcode list item.
169169
func groupedByMajorVersion(item: (Element) -> XcodeListItem) -> [XcodeListElementMajorVersionGroup<Element>] {
170-
Dictionary(grouping: self, by: { item($0).version.major })
170+
let visibleElements = hidingOlderIdenticalBuilds(item: item)
171+
172+
return Dictionary(grouping: visibleElements, by: { item($0).version.major })
171173
.map { majorVersion, elements in
172174
let minorVersionGroups = Dictionary(grouping: elements, by: { item($0).version.minor })
173175
.map { minorVersion, minorElements in
@@ -223,7 +225,9 @@ public extension Array where Element == XcodeListItem {
223225

224226
/// Groups Xcode list items by major version, then minor version.
225227
func groupedByMajorVersion() -> [XcodeMajorVersionGroup] {
226-
Dictionary(grouping: self, by: { $0.version.major })
228+
let visibleItems = hidingOlderIdenticalBuilds(item: { $0 })
229+
230+
return Dictionary(grouping: visibleItems, by: { $0.version.major })
227231
.map { majorVersion, xcodes in
228232
let minorVersionGroups = Dictionary(grouping: xcodes, by: { $0.version.minor })
229233
.map { minorVersion, minorXcodes in
@@ -275,6 +279,30 @@ private struct XcodeListFilteredElement<Element> {
275279
let item: XcodeListItem
276280
}
277281

282+
private extension Array {
283+
func hidingOlderIdenticalBuilds(item: (Element) -> XcodeListItem) -> [Element] {
284+
let items = map(item)
285+
let visibleIDs = Set(items.map(\.id))
286+
let identicalBuildGroups = items
287+
.map(\.identicalBuilds)
288+
.filter { $0.isEmpty == false }
289+
290+
return filter { element in
291+
let currentID = item(element).id
292+
293+
return identicalBuildGroups.contains { identicalBuilds in
294+
guard identicalBuilds.contains(currentID) else { return false }
295+
296+
return identicalBuilds.contains { identicalID in
297+
identicalID.architectures == currentID.architectures &&
298+
identicalID.version > currentID.version &&
299+
visibleIDs.contains(identicalID)
300+
}
301+
} == false
302+
}
303+
}
304+
}
305+
278306
private extension Array {
279307
func applying(_ filters: XcodeListFilters) -> [Element] where Element: XcodeListFilterable {
280308
var elements = self

Tests/XcodesKitTests/XcodeListGroupingTests.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,44 @@ final class XcodeListGroupingTests: XCTestCase {
5757
XCTAssertTrue(minorGroup.hasInstalling)
5858
}
5959

60+
func testGroupedVersionsHideOlderIdenticalBuildsWhenNewerBuildIsVisible() throws {
61+
let releaseID = XcodeID(version: try XCTUnwrap(Version("26.5.0+17F76")))
62+
let releaseCandidateID = XcodeID(version: try XCTUnwrap(Version("26.5.0-Release.Candidate+17F76")))
63+
let items = try [
64+
item("26.5.0+17F76", identicalBuilds: [releaseID, releaseCandidateID]),
65+
item("26.5.0-Release.Candidate+17F76")
66+
]
67+
68+
let versions = try XCTUnwrap(items.groupedByMajorVersion().first?.versions.map(\.version))
69+
70+
XCTAssertEqual(versions, [try XCTUnwrap(Version("26.5.0+17F76"))])
71+
}
72+
73+
func testGroupedVersionsKeepOlderIdenticalBuildsWhenNewerBuildIsFilteredOut() throws {
74+
let releaseID = XcodeID(version: try XCTUnwrap(Version("26.5.0+17F76")))
75+
let releaseCandidateID = XcodeID(version: try XCTUnwrap(Version("26.5.0-Release.Candidate+17F76")))
76+
let items = try [
77+
item("26.5.0-Release.Candidate+17F76", identicalBuilds: [releaseID, releaseCandidateID])
78+
]
79+
80+
let versions = try XCTUnwrap(items.groupedByMajorVersion().first?.versions.map(\.version))
81+
82+
XCTAssertEqual(versions, [try XCTUnwrap(Version("26.5.0-Release.Candidate+17F76"))])
83+
}
84+
85+
func testGenericGroupedVersionsHideOlderIdenticalBuildsWhenNewerBuildIsVisible() throws {
86+
let releaseID = XcodeID(version: try XCTUnwrap(Version("26.5.0+17F76")))
87+
let releaseCandidateID = XcodeID(version: try XCTUnwrap(Version("26.5.0-Release.Candidate+17F76")))
88+
let items = try [
89+
PositionedXcodeListItem(position: 0, item: item("26.5.0+17F76", identicalBuilds: [releaseID, releaseCandidateID])),
90+
PositionedXcodeListItem(position: 1, item: item("26.5.0-Release.Candidate+17F76"))
91+
]
92+
93+
let groups = items.groupedByMajorVersion(item: \.item)
94+
95+
XCTAssertEqual(groups.first?.versions.map(\.position), [0])
96+
}
97+
6098
func testAppliesVersionArchitectureSearchAndInstalledFilters() throws {
6199
let installedPath = try XCTUnwrap(Path("/Applications/Xcode-16.0.app"))
62100
let items = try [
@@ -109,12 +147,14 @@ final class XcodeListGroupingTests: XCTestCase {
109147

110148
private func item(
111149
_ version: String,
150+
identicalBuilds: [XcodeID] = [],
112151
installState: XcodeInstallState = .notInstalled,
113152
selected: Bool = false,
114153
architectures: [Architecture]? = nil
115154
) throws -> XcodeListItem {
116155
XcodeListItem(
117156
version: try XCTUnwrap(Version(version)),
157+
identicalBuilds: identicalBuilds,
118158
installState: installState,
119159
selected: selected,
120160
architectures: architectures

0 commit comments

Comments
 (0)