Skip to content
Open
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
20 changes: 11 additions & 9 deletions Xcodes/Backend/AppState+Install.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
Expand Down Expand Up @@ -203,9 +203,9 @@ extension AppState {
}
.flatMap { installedXcode -> AnyPublisher<InstalledXcode, Error> 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))
Expand All @@ -217,7 +217,7 @@ extension AppState {
}
}
.flatMap { installedXcode -> AnyPublisher<InstalledXcode, Error> in
self.setInstallationStep(of: availableXcode.version, to: .finishing)
self.setInstallationStep(of: availableXcode, to: .finishing)

return self.performPostInstallSteps(for: installedXcode)
.map { installedXcode }
Expand Down Expand Up @@ -249,7 +249,7 @@ extension AppState {
}

func unarchiveAndMoveXIP(availableXcode: AvailableXcode, at source: URL, to destination: URL) -> AnyPublisher<URL, Swift.Error> {
self.setInstallationStep(of: availableXcode.version, to: .unarchiving)
self.setInstallationStep(of: availableXcode, to: .unarchiving)

return unxipOrUnxipExperiment(source)
.catch { error -> AnyPublisher<ProcessOutput, Swift.Error> in
Expand All @@ -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")
Expand Down Expand Up @@ -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)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Xcodes/Backend/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions Xcodes/Backend/Xcode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions XcodesTests/AppStateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down