Skip to content

Commit 4b9d86b

Browse files
committed
Support showing multiple architectures
1 parent a434d26 commit 4b9d86b

31 files changed

Lines changed: 459 additions & 85 deletions

Xcodes.xcodeproj/project.pbxproj

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
CA9FF84E2595079F00E47BAF /* ScrollingTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9FF84D2595079F00E47BAF /* ScrollingTextView.swift */; };
4949
CA9FF8522595080100E47BAF /* AcknowledgementsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9FF8512595080100E47BAF /* AcknowledgementsView.swift */; };
5050
CA9FF8662595130600E47BAF /* View+IsHidden.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9FF8652595130600E47BAF /* View+IsHidden.swift */; };
51-
CA9FF86D25951C6E00E47BAF /* XCModel in Frameworks */ = {isa = PBXBuildFile; productRef = CA9FF86C25951C6E00E47BAF /* XCModel */; };
5251
CA9FF877259528CC00E47BAF /* Version+XcodeReleases.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9FF876259528CC00E47BAF /* Version+XcodeReleases.swift */; };
5352
CA9FF87B2595293E00E47BAF /* DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9FF87A2595293E00E47BAF /* DataSource.swift */; };
5453
CA9FF88125955C7000E47BAF /* AvailableXcode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9FF88025955C7000E47BAF /* AvailableXcode.swift */; };
@@ -363,7 +362,6 @@
363362
CABFA9E42592F08E00380FEE /* Version in Frameworks */,
364363
CABFA9FD2592F13300380FEE /* LegibleError in Frameworks */,
365364
E689540325BE8C64000EBCEA /* DockProgress in Frameworks */,
366-
CA9FF86D25951C6E00E47BAF /* XCModel in Frameworks */,
367365
CABFA9F82592F0F900380FEE /* KeychainAccess in Frameworks */,
368366
E83FDC442CBB649100679C6B /* Sparkle in Frameworks */,
369367
E862D43B2CC8B26F00BAA376 /* SRP in Frameworks */,
@@ -726,7 +724,6 @@
726724
CABFA9ED2592F0CC00380FEE /* SwiftSoup */,
727725
CABFA9F72592F0F900380FEE /* KeychainAccess */,
728726
CABFA9FC2592F13300380FEE /* LegibleError */,
729-
CA9FF86C25951C6E00E47BAF /* XCModel */,
730727
CAA858CC25A3D8BC00ACF8C0 /* ErrorHandling */,
731728
E689540225BE8C64000EBCEA /* DockProgress */,
732729
E8FD5726291EE4AC001E004C /* AsyncNetworkService */,
@@ -816,7 +813,6 @@
816813
CABFA9EC2592F0CC00380FEE /* XCRemoteSwiftPackageReference "SwiftSoup" */,
817814
CABFA9F62592F0F900380FEE /* XCRemoteSwiftPackageReference "KeychainAccess" */,
818815
CABFA9FB2592F13300380FEE /* XCRemoteSwiftPackageReference "LegibleError" */,
819-
CA9FF86B25951C6E00E47BAF /* XCRemoteSwiftPackageReference "data" */,
820816
CAA858CB25A3D8BC00ACF8C0 /* XCRemoteSwiftPackageReference "ErrorHandling" */,
821817
CAC28186259EE27200B8AB0B /* XCRemoteSwiftPackageReference "CombineExpectations" */,
822818
E689540125BE8C64000EBCEA /* XCRemoteSwiftPackageReference "DockProgress" */,
@@ -1504,14 +1500,6 @@
15041500
minimumVersion = 0.1.4;
15051501
};
15061502
};
1507-
CA9FF86B25951C6E00E47BAF /* XCRemoteSwiftPackageReference "data" */ = {
1508-
isa = XCRemoteSwiftPackageReference;
1509-
repositoryURL = "https://github.com/xcodereleases/data";
1510-
requirement = {
1511-
branch = main;
1512-
kind = branch;
1513-
};
1514-
};
15151503
CAA858CB25A3D8BC00ACF8C0 /* XCRemoteSwiftPackageReference "ErrorHandling" */ = {
15161504
isa = XCRemoteSwiftPackageReference;
15171505
repositoryURL = "https://github.com/RobotsAndPencils/ErrorHandling";
@@ -1607,11 +1595,6 @@
16071595
isa = XCSwiftPackageProductDependency;
16081596
productName = LibFido2Swift;
16091597
};
1610-
CA9FF86C25951C6E00E47BAF /* XCModel */ = {
1611-
isa = XCSwiftPackageProductDependency;
1612-
package = CA9FF86B25951C6E00E47BAF /* XCRemoteSwiftPackageReference "data" */;
1613-
productName = XCModel;
1614-
};
16151598
CAA1CB2C255A5262003FD669 /* AppleAPI */ = {
16161599
isa = XCSwiftPackageProductDependency;
16171600
productName = AppleAPI;

Xcodes.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Xcodes/Backend/AppState+Install.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ extension AppState {
502502
self.allXcodes[index].installState = .installing(step)
503503

504504
let xcode = self.allXcodes[index]
505-
Current.notificationManager.scheduleNotification(title: xcode.id.appleDescription, body: step.description, category: .normal)
505+
Current.notificationManager.scheduleNotification(title: xcode.version.major.description + "." + xcode.version.appleDescription, body: step.description, category: .normal)
506506
}
507507
}
508508

Xcodes/Backend/AppState+Update.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import Foundation
33
import Path
44
import Version
55
import SwiftSoup
6-
import struct XCModel.Xcode
76
import AppleAPI
87
import XcodesKit
98

@@ -211,8 +210,8 @@ extension AppState {
211210
private func xcodeReleases() -> AnyPublisher<[AvailableXcode], Error> {
212211
Current.network.dataTask(with: URLRequest(url: URL(string: "https://xcodereleases.com/data.json")!))
213212
.map(\.data)
214-
.decode(type: [XCModel.Xcode].self, decoder: JSONDecoder())
215-
.map { xcReleasesXcodes in
213+
.decode(type: [XcodeRelease].self, decoder: JSONDecoder())
214+
.map { xcReleasesXcodes in
216215
let xcodes = xcReleasesXcodes.compactMap { xcReleasesXcode -> AvailableXcode? in
217216
guard
218217
let downloadURL = xcReleasesXcode.links?.download?.url,
@@ -233,7 +232,8 @@ extension AppState {
233232
requiredMacOSVersion: xcReleasesXcode.requires,
234233
releaseNotesURL: xcReleasesXcode.links?.notes?.url,
235234
sdks: xcReleasesXcode.sdks,
236-
compilers: xcReleasesXcode.compilers
235+
compilers: xcReleasesXcode.compilers,
236+
architectures: xcReleasesXcode.architectures
237237
)
238238
}
239239
return xcodes

Xcodes/Backend/AppState.swift

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ enum PreferenceKey: String {
2626
case xcodeListCategory
2727
case allowedMajorVersions
2828
case hideSupportXcodes
29+
case xcodeListArchitectures
2930

3031
func isManaged() -> Bool { UserDefaults.standard.objectIsForced(forKey: self.rawValue) }
3132
}
@@ -146,7 +147,7 @@ class AppState: ObservableObject {
146147
// MARK: - Publisher Cancellables
147148

148149
var cancellables = Set<AnyCancellable>()
149-
private var installationPublishers: [Version: AnyCancellable] = [:]
150+
private var installationPublishers: [XcodeID: AnyCancellable] = [:]
150151
internal var runtimePublishers: [String: Task<(), any Error>] = [:]
151152
private var selectPublisher: AnyCancellable?
152153
private var uninstallPublisher: AnyCancellable?
@@ -523,8 +524,8 @@ class AppState: ObservableObject {
523524

524525
// MARK: - Install
525526

526-
func checkMinVersionAndInstall(id: Xcode.ID) {
527-
guard let availableXcode = availableXcodes.first(where: { $0.version == id }) else { return }
527+
func checkMinVersionAndInstall(id: XcodeID) {
528+
guard let availableXcode = availableXcodes.first(where: { $0.version == id.version }) else { return }
528529

529530
// Check to see if users macOS is supported
530531
if let requiredMacOSVersion = availableXcode.requiredMacOSVersion {
@@ -550,8 +551,8 @@ class AppState: ObservableObject {
550551
return !ProcessInfo.processInfo.isOperatingSystemAtLeast(xcodeMinimumMacOSVersion)
551552
}
552553

553-
func install(id: Xcode.ID) {
554-
guard let availableXcode = availableXcodes.first(where: { $0.version == id }) else { return }
554+
func install(id: XcodeID) {
555+
guard let availableXcode = availableXcodes.first(where: { $0.version == id.version }) else { return }
555556

556557
installationPublishers[id] = signInIfNeeded()
557558
.handleEvents(
@@ -626,7 +627,7 @@ class AppState: ObservableObject {
626627
/// Skips using the username/password to log in to Apple, and simply gets a Auth Cookie used in downloading
627628
/// As of Nov 2022 this was returning a 403 forbidden
628629
func installWithoutLogin(id: Xcode.ID) {
629-
guard let availableXcode = availableXcodes.first(where: { $0.version == id }) else { return }
630+
guard let availableXcode = availableXcodes.first(where: { $0.version == id.version }) else { return }
630631

631632
installationPublishers[id] = self.install(.version(availableXcode), downloader: Downloader(rawValue: Current.defaults.string(forKey: "downloader") ?? "aria2") ?? .aria2)
632633
.receive(on: DispatchQueue.main)
@@ -649,7 +650,7 @@ class AppState: ObservableObject {
649650
}
650651

651652
func cancelInstall(id: Xcode.ID) {
652-
guard let availableXcode = availableXcodes.first(where: { $0.version == id }) else { return }
653+
guard let availableXcode = availableXcodes.first(where: { $0.version == id.version }) else { return }
653654

654655
// Cancel the publisher
655656
installationPublishers[id] = nil
@@ -767,7 +768,7 @@ class AppState: ObservableObject {
767768
config.allowsRunningApplicationSubstitution = false
768769
NSWorkspace.shared.openApplication(at: path.url, configuration: config)
769770
default:
770-
Logger.appState.error("\(xcode.id) is not installed")
771+
Logger.appState.error("\(xcode.id.version) is not installed")
771772
return
772773
}
773774
}
@@ -863,15 +864,15 @@ class AppState: ObservableObject {
863864
// If build metadata matches exactly, replace the available version with the installed version.
864865
// This should handle Apple versions from /downloads/more which don't have build metadata identifiers.
865866
if let index = adjustedAvailableXcodes.map(\.version).firstIndex(where: { $0.buildMetadataIdentifiers == installedXcode.version.buildMetadataIdentifiers }) {
866-
adjustedAvailableXcodes[index].version = installedXcode.version
867+
adjustedAvailableXcodes[index].xcodeID = installedXcode.xcodeID
867868
}
868869
// If an installed version is the same as one that's listed online which doesn't have build metadata, replace it with the installed version
869870
// Not all prerelease Apple versions available online include build metadata
870871
else if let index = adjustedAvailableXcodes.firstIndex(where: { availableXcode in
871872
availableXcode.version.isEquivalent(to: installedXcode.version) &&
872873
availableXcode.version.buildMetadataIdentifiers.isEmpty
873874
}) {
874-
adjustedAvailableXcodes[index].version = installedXcode.version
875+
adjustedAvailableXcodes[index].xcodeID = installedXcode.xcodeID
875876
}
876877
}
877878
}
@@ -888,14 +889,15 @@ class AppState: ObservableObject {
888889
// Include this version if there's only one with this build identifier
889890
return availableXcodesWithIdenticalBuildIdentifiers.count == 1 ||
890891
// Or if there's more than one with this build identifier and this is the release version
891-
availableXcodesWithIdenticalBuildIdentifiers.count > 1 && availableXcode.version.prereleaseIdentifiers.isEmpty
892-
}
892+
893+
availableXcodesWithIdenticalBuildIdentifiers.count > 1 && (availableXcode.version.prereleaseIdentifiers.isEmpty || availableXcode.architectures?.count ?? 0 != 0)
894+
}
893895
.map { availableXcode -> Xcode in
894896
let installedXcode = installedXcodes.first(where: { installedXcode in
895897
availableXcode.version.isEquivalent(to: installedXcode.version)
896898
})
897899

898-
let identicalBuilds: [Version]
900+
let identicalBuilds: [XcodeID]
899901
let prereleaseAvailableXcodesWithIdenticalBuildIdentifiers = availableXcodes
900902
.filter {
901903
return $0.version.buildMetadataIdentifiers == availableXcode.version.buildMetadataIdentifiers &&
@@ -905,7 +907,7 @@ class AppState: ObservableObject {
905907
}
906908
// If this is the release version, add the identical builds to it
907909
if !prereleaseAvailableXcodesWithIdenticalBuildIdentifiers.isEmpty, availableXcode.version.prereleaseIdentifiers.isEmpty {
908-
identicalBuilds = [availableXcode.version] + prereleaseAvailableXcodesWithIdenticalBuildIdentifiers.map(\.version)
910+
identicalBuilds = [availableXcode.xcodeID] + prereleaseAvailableXcodesWithIdenticalBuildIdentifiers.map(\.xcodeID)
909911
} else {
910912
identicalBuilds = []
911913
}
@@ -926,7 +928,8 @@ class AppState: ObservableObject {
926928
releaseDate: availableXcode.releaseDate,
927929
sdks: availableXcode.sdks,
928930
compilers: availableXcode.compilers,
929-
downloadFileSize: availableXcode.fileSize
931+
downloadFileSize: availableXcode.fileSize,
932+
architectures: availableXcode.architectures
930933
)
931934
}
932935

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import Foundation
22
import Version
3-
import struct XCModel.SDKs
4-
import struct XCModel.Compilers
3+
import XcodesKit
54

65
/// A version of Xcode that's available for installation
76
public struct AvailableXcode: Codable {
8-
public var version: Version
7+
public var version: Version {
8+
return xcodeID.version
9+
}
910
public let url: URL
1011
public let filename: String
1112
public let releaseDate: Date?
@@ -14,9 +15,11 @@ public struct AvailableXcode: Codable {
1415
public let sdks: SDKs?
1516
public let compilers: Compilers?
1617
public let fileSize: Int64?
18+
public let architectures: [Architecture]?
1719
public var downloadPath: String {
1820
return url.path
1921
}
22+
public var xcodeID: XcodeID
2023

2124
public init(
2225
version: Version,
@@ -27,9 +30,9 @@ public struct AvailableXcode: Codable {
2730
releaseNotesURL: URL? = nil,
2831
sdks: SDKs? = nil,
2932
compilers: Compilers? = nil,
30-
fileSize: Int64? = nil
33+
fileSize: Int64? = nil,
34+
architectures: [Architecture]? = nil
3135
) {
32-
self.version = version
3336
self.url = url
3437
self.filename = filename
3538
self.releaseDate = releaseDate
@@ -38,5 +41,7 @@ public struct AvailableXcode: Codable {
3841
self.sdks = sdks
3942
self.compilers = compilers
4043
self.fileSize = fileSize
44+
self.architectures = architectures
45+
self.xcodeID = XcodeID(version: version, architectures: architectures)
4146
}
4247
}

Xcodes/Backend/InstalledXcode.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ import Path
55
/// A version of Xcode that's already installed
66
public struct InstalledXcode: Equatable {
77
public let path: Path
8+
public let xcodeID: XcodeID
9+
810
/// Composed of the bundle short version from Info.plist and the product build version from version.plist
9-
public let version: Version
11+
public var version: Version {
12+
return xcodeID.version
13+
}
1014

1115
public init?(path: Path) {
1216
self.path = path
@@ -32,11 +36,13 @@ public struct InstalledXcode: Equatable {
3236
prereleaseIdentifiers = ["beta"]
3337
}
3438

35-
self.version = Version(major: bundleVersion.major,
39+
let version = Version(major: bundleVersion.major,
3640
minor: bundleVersion.minor,
3741
patch: bundleVersion.patch,
3842
prereleaseIdentifiers: prereleaseIdentifiers,
3943
buildMetadataIdentifiers: [versionPlist.productBuildVersion].compactMap { $0 })
44+
45+
self.xcodeID = XcodeID(version: version, architectures: nil)
4046
}
4147
}
4248

Xcodes/Backend/SDKs+Xcode.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
//
88

99
import Foundation
10-
import struct XCModel.SDKs
1110
import XcodesKit
1211
import SwiftUI
1312

Xcodes/Backend/Version+XcodeReleases.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import Version
2-
import struct XCModel.Xcode
2+
import XcodesKit
33

44
extension Version {
55
/// Initialize a Version from an XcodeReleases' XCModel.Xcode
66
///
77
/// This is kinda quick-and-dirty, and it would probably be better for us to adopt something closer to XCModel.Xcode under the hood and map the scraped data to it instead.
8-
init?(xcReleasesXcode: XCModel.Xcode) {
8+
init?(xcReleasesXcode: XcodeRelease) {
99
var versionString = xcReleasesXcode.version.number ?? ""
1010

1111
// Append trailing ".0" in order to get a fully-specified version string

0 commit comments

Comments
 (0)