diff --git a/Xcodes/Backend/AppState+Install.swift b/Xcodes/Backend/AppState+Install.swift index 5e2a0742..32eeb24d 100644 --- a/Xcodes/Backend/AppState+Install.swift +++ b/Xcodes/Backend/AppState+Install.swift @@ -104,7 +104,7 @@ extension AppState { private func downloadXcode(availableXcode: AvailableXcode, downloader: Downloader) -> AnyPublisher<(AvailableXcode, URL), Error> { self.downloadOrUseExistingArchive(for: availableXcode, downloader: downloader, progressChanged: { [unowned self] progress in DispatchQueue.main.async { - self.setInstallationStep(of: availableXcode.version, to: .downloading(progress: progress)) + self.setInstallationStep(of: availableXcode, to: .downloading(progress: progress)) self.overallProgress.addChild(progress, withPendingUnitCount: AppState.totalProgressUnits - AppState.unxipProgressWeight) } }) @@ -203,9 +203,9 @@ extension AppState { } .flatMap { installedXcode -> AnyPublisher in do { - self.setInstallationStep(of: availableXcode.version, to: .trashingArchive) + self.setInstallationStep(of: availableXcode, to: .trashingArchive) try Current.files.trashItem(at: archiveURL) - self.setInstallationStep(of: availableXcode.version, to: .checkingSecurity) + self.setInstallationStep(of: availableXcode, to: .checkingSecurity) return self.verifySecurityAssessment(of: installedXcode) .combineLatest(self.verifySigningCertificate(of: installedXcode.path.url)) @@ -217,7 +217,7 @@ extension AppState { } } .flatMap { installedXcode -> AnyPublisher in - self.setInstallationStep(of: availableXcode.version, to: .finishing) + self.setInstallationStep(of: availableXcode, to: .finishing) return self.performPostInstallSteps(for: installedXcode) .map { installedXcode } @@ -249,7 +249,7 @@ extension AppState { } func unarchiveAndMoveXIP(availableXcode: AvailableXcode, at source: URL, to destination: URL) -> AnyPublisher { - self.setInstallationStep(of: availableXcode.version, to: .unarchiving) + self.setInstallationStep(of: availableXcode, to: .unarchiving) return unxipOrUnxipExperiment(source) .catch { error -> AnyPublisher in @@ -267,7 +267,7 @@ extension AppState { .eraseToAnyPublisher() } .tryMap { output -> URL in - self.setInstallationStep(of: availableXcode.version, to: .moving(destination: destination.path)) + self.setInstallationStep(of: availableXcode, to: .moving(destination: destination.path)) let xcodeURL = source.deletingLastPathComponent().appendingPathComponent("Xcode.app") let xcodeBetaURL = source.deletingLastPathComponent().appendingPathComponent("Xcode-beta.app") @@ -495,13 +495,15 @@ extension AppState { } // MARK: - - - func setInstallationStep(of version: Version, to step: XcodeInstallationStep) { + + func setInstallationStep(of xcode: AvailableXcode, to step: XcodeInstallationStep) { DispatchQueue.main.async { - guard let index = self.allXcodes.firstIndex(where: { $0.version.isEquivalent(to: version) }) else { return } + guard let index = self.allXcodes.firstIndex(where: { $0.id == xcode.xcodeID }) else { return } + self.allXcodes[index].installState = .installing(step) let xcode = self.allXcodes[index] + Current.notificationManager.scheduleNotification(title: xcode.version.major.description + "." + xcode.version.appleDescription, body: step.description, category: .normal) } } diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift index 1f6419dc..9bd12198 100644 --- a/Xcodes/Backend/AppState.swift +++ b/Xcodes/Backend/AppState.swift @@ -557,7 +557,7 @@ class AppState: ObservableObject { installationPublishers[id] = signInIfNeeded() .handleEvents( receiveSubscription: { [unowned self] _ in - self.setInstallationStep(of: availableXcode.version, to: .authenticating) + self.setInstallationStep(of: availableXcode, to: .authenticating) } ) .flatMap { [unowned self] in diff --git a/Xcodes/Backend/Xcode.swift b/Xcodes/Backend/Xcode.swift index b1721499..eac61d07 100644 --- a/Xcodes/Backend/Xcode.swift +++ b/Xcodes/Backend/Xcode.swift @@ -17,6 +17,11 @@ public struct XcodeID: Codable, Hashable, Identifiable { self.version = version self.architectures = architectures } + + public static func == (lhs: Self, rhs: Self) -> Bool { + // First compare versions (using only semVer components) then compare architectures + lhs.version.isEquivalent(to: rhs.version) && lhs.architectures == rhs.architectures + } } struct Xcode: Identifiable, CustomStringConvertible { diff --git a/XcodesTests/AppStateTests.swift b/XcodesTests/AppStateTests.swift index 4be9ca32..022ae76e 100644 --- a/XcodesTests/AppStateTests.swift +++ b/XcodesTests/AppStateTests.swift @@ -183,9 +183,9 @@ class AppStateTests: XCTestCase { func test_Install_FullHappyPath_XcodeReleases() throws { // Available xcode has build identifier subject.allXcodes = [ - .init(version: Version("0.0.0+ABC123")!, installState: .notInstalled, selected: false, icon: nil), - .init(version: Version("0.0.0-Beta.1+DEF456")!, installState: .notInstalled, selected: false, icon: nil), - .init(version: Version("0.0.0-Beta.2+GHI789")!, installState: .notInstalled, selected: false, icon: nil) + Xcode(version: Version("0.0.0+ABC123")!, installState: .notInstalled, selected: false, icon: nil, architectures: [.arm64]), + Xcode(version: Version("0.0.0-Beta.1+DEF456")!, installState: .notInstalled, selected: false, icon: nil, architectures: [.arm64]), + Xcode(version: Version("0.0.0-Beta.2+GHI789")!, installState: .notInstalled, selected: false, icon: nil, architectures: [.arm64]) ] // It hasn't been downloaded @@ -269,7 +269,7 @@ class AppStateTests: XCTestCase { let allXcodesRecorder = subject.$allXcodes.record() let installRecorder = subject.install( - .version(AvailableXcode(version: Version("0.0.0")!, url: URL(string: "https://apple.com/xcode.xip")!, filename: "mock.xip", releaseDate: nil)), + .version(AvailableXcode(version: Version("0.0.0")!, url: URL(string: "https://apple.com/xcode.xip")!, filename: "mock.xip", releaseDate: nil, architectures: [.arm64])), downloader: .urlSession ).record() try wait(for: installRecorder.finished, timeout: 1, description: "Finished")