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
1 change: 1 addition & 0 deletions Xcodes/Backend/AppState+Install.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extension AppState {
let (xcode, url) = try await getXcodeArchiveAsync(installationType, downloader: downloader)
try Task.checkCancellation()
let installedXcode = try await installArchivedXcodeAsync(xcode, at: url)
recordInstalledXcode(installedXcode)

guard let index = allXcodes.firstIndex(where: { $0.version.isEquivalent(to: installedXcode.version) }) else {
return installedXcode
Expand Down
11 changes: 11 additions & 0 deletions Xcodes/Backend/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class AppState: ObservableObject {
}
}
private var installedXcodes: [InstalledXcode] = []
private var installedXcodesRevision = UUID()
@Published var updateTask: Task<Void, Never>?
var updateTaskID: UUID?
var isUpdating: Bool { updateTask != nil }
Expand Down Expand Up @@ -934,14 +935,24 @@ class AppState: ObservableObject {
}
}

func recordInstalledXcode(_ xcode: InstalledXcode) {
// Invalidate scans started before this installation completed.
installedXcodesRevision = UUID()
installedXcodes.removeAll { $0.path == xcode.path }
installedXcodes.append(xcode)
}

@discardableResult
func updateInstalledXcodesAsync(recomposeAllXcodes: Bool = true) async -> [InstalledXcode] {
let revision = UUID()
installedXcodesRevision = revision
let installDirectory = Path.installDirectory
let files = Current.files
let installedXcodes = await Task.detached(priority: .userInitiated) {
files.installedXcodes(installDirectory)
}.value

guard installedXcodesRevision == revision else { return self.installedXcodes }
self.installedXcodes = installedXcodes
if recomposeAllXcodes {
updateAllXcodes(
Expand Down
13 changes: 13 additions & 0 deletions XcodesTests/AppStateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,18 @@ class AppStateTests: XCTestCase {
[.installed(Path("/Applications/Xcode-0.0.0.app")!), .notInstalled, .notInstalled]
]
)
assertInstalledStateSurvivesRecomposition()
}

private func assertInstalledStateSurvivesRecomposition() {
subject.availableXcodes = [
AvailableXcode(version: Version("0.0.0")!, url: URL(string: "https://apple.com/xcode.xip")!, filename: "mock.xip", releaseDate: nil)
]
let path = Path("/Applications/Xcode-0.0.0.app")!
XCTAssertEqual(subject.allXcodes.first?.installState, .installed(path))
subject.selectedXcodePath = path.string + "/Contents/Developer"
XCTAssertEqual(subject.allXcodes.first?.installState, .installed(path))
XCTAssertEqual(subject.allXcodes.first?.selected, true)
}

private static func downloadableRuntime() throws -> DownloadableRuntime {
Expand Down Expand Up @@ -971,6 +983,7 @@ class AppStateTests: XCTestCase {
[.installed(Path("/Applications/Xcode-0.0.0.app")!), .notInstalled, .notInstalled]
]
)
assertInstalledStateSurvivesRecomposition()
}

func test_Install_NotEnoughFreeSpace() async throws {
Expand Down