mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
Fix a bug when an installed version was appended
We were appending a version without appending a corresponding AvailableXcode, and these two arrays were being zipped later so they wouldn't line up. This change simplifies this method a bit by working on only a single array, and then also moves that appending to the end after the array of Xcodes is created.
This commit is contained in:
parent
26da7969a1
commit
62237bf4a8
3 changed files with 53 additions and 24 deletions
|
|
@ -357,48 +357,40 @@ class AppState: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAllXcodes(availableXcodes: [AvailableXcode], installedXcodes: [InstalledXcode], selectedXcodePath: String?) {
|
func updateAllXcodes(availableXcodes: [AvailableXcode], installedXcodes: [InstalledXcode], selectedXcodePath: String?) {
|
||||||
// First, adjust all of the available Xcode versions so that available and installed versions line up and the second part of this function works properly.
|
var adjustedAvailableXcodes = availableXcodes
|
||||||
var allAvailableXcodeVersions = availableXcodes.map { $0.version }
|
|
||||||
|
// First, adjust all of the available Xcodes so that available and installed versions line up and the second part of this function works properly.
|
||||||
for installedXcode in installedXcodes {
|
for installedXcode in installedXcodes {
|
||||||
// We can trust that build metadata identifiers are unique for each version of Xcode, so if we have it then it's all we need.
|
// We can trust that build metadata identifiers are unique for each version of Xcode, so if we have it then it's all we need.
|
||||||
// If build metadata matches exactly, replace the available version with the installed version.
|
// If build metadata matches exactly, replace the available version with the installed version.
|
||||||
// This should handle both Xcode Releases versions which can have different prerelease identifiers and Apple versions which rarely have build metadata identifiers.
|
// This should handle both Xcode Releases versions which can have different prerelease identifiers and Apple versions which rarely have build metadata identifiers.
|
||||||
if let index = allAvailableXcodeVersions.firstIndex(where: { $0.buildMetadataIdentifiers == installedXcode.version.buildMetadataIdentifiers }) {
|
if let index = adjustedAvailableXcodes.map(\.version).firstIndex(where: { $0.buildMetadataIdentifiers == installedXcode.version.buildMetadataIdentifiers }) {
|
||||||
allAvailableXcodeVersions[index] = installedXcode.version
|
adjustedAvailableXcodes[index].version = installedXcode.version
|
||||||
}
|
|
||||||
// If an installed version isn't listed online, add the installed version
|
|
||||||
// Xcode Releases should have all versions
|
|
||||||
// Apple didn't used to keep all prerelease versions around but has started to recently
|
|
||||||
else if !allAvailableXcodeVersions.contains(where: { version in
|
|
||||||
version.isEquivalent(to: installedXcode.version)
|
|
||||||
}) {
|
|
||||||
allAvailableXcodeVersions.append(installedXcode.version)
|
|
||||||
}
|
}
|
||||||
// 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
|
// 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
|
||||||
// This was originally added for Apple versions
|
// Not all prerelease Apple versions available online include build metadata
|
||||||
else if let index = allAvailableXcodeVersions.firstIndex(where: { version in
|
else if let index = adjustedAvailableXcodes.firstIndex(where: { availableXcode in
|
||||||
version.isEquivalent(to: installedXcode.version) &&
|
availableXcode.version.isEquivalent(to: installedXcode.version) &&
|
||||||
version.buildMetadataIdentifiers.isEmpty
|
availableXcode.version.buildMetadataIdentifiers.isEmpty
|
||||||
}) {
|
}) {
|
||||||
allAvailableXcodeVersions[index] = installedXcode.version
|
adjustedAvailableXcodes[index].version = installedXcode.version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map all of the available versions into Xcode values that join available and installed Xcode data for display.
|
// Map all of the available versions into Xcode values that join available and installed Xcode data for display.
|
||||||
allXcodes = zip(allAvailableXcodeVersions, availableXcodes)
|
var newAllXcodes = adjustedAvailableXcodes
|
||||||
.sorted(by: { $0.0 > $1.0 })
|
.map { availableXcode -> Xcode in
|
||||||
.map { availableXcodeVersion, availableXcode in
|
|
||||||
let installedXcode = installedXcodes.first(where: { installedXcode in
|
let installedXcode = installedXcodes.first(where: { installedXcode in
|
||||||
availableXcodeVersion.isEquivalent(to: installedXcode.version)
|
availableXcode.version.isEquivalent(to: installedXcode.version)
|
||||||
})
|
})
|
||||||
|
|
||||||
// If the existing install state is "installing", keep it
|
// If the existing install state is "installing", keep it
|
||||||
let existingXcodeInstallState = allXcodes.first { $0.version == availableXcodeVersion && $0.installing }?.installState
|
let existingXcodeInstallState = allXcodes.first { $0.version == availableXcode.version && $0.installing }?.installState
|
||||||
// Otherwise, determine it from whether there's an installed Xcode
|
// Otherwise, determine it from whether there's an installed Xcode
|
||||||
let defaultXcodeInstallState: XcodeInstallState = installedXcode != nil ? .installed : .notInstalled
|
let defaultXcodeInstallState: XcodeInstallState = installedXcode != nil ? .installed : .notInstalled
|
||||||
|
|
||||||
return Xcode(
|
return Xcode(
|
||||||
version: availableXcodeVersion,
|
version: availableXcode.version,
|
||||||
installState: existingXcodeInstallState ?? defaultXcodeInstallState,
|
installState: existingXcodeInstallState ?? defaultXcodeInstallState,
|
||||||
selected: installedXcode != nil && selectedXcodePath?.hasPrefix(installedXcode!.path.string) == true,
|
selected: installedXcode != nil && selectedXcodePath?.hasPrefix(installedXcode!.path.string) == true,
|
||||||
path: installedXcode?.path.string,
|
path: installedXcode?.path.string,
|
||||||
|
|
@ -409,6 +401,25 @@ class AppState: ObservableObject {
|
||||||
compilers: availableXcode.compilers
|
compilers: availableXcode.compilers
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If an installed version isn't listed in the available versions, add the installed version
|
||||||
|
// Xcode Releases should have all versions
|
||||||
|
// Apple didn't used to keep all prerelease versions around but has started to recently
|
||||||
|
for installedXcode in installedXcodes {
|
||||||
|
if !newAllXcodes.contains(where: { xcode in xcode.version.isEquivalent(to: installedXcode.version) }) {
|
||||||
|
newAllXcodes.append(
|
||||||
|
Xcode(
|
||||||
|
version: installedXcode.version,
|
||||||
|
installState: .installed,
|
||||||
|
selected: selectedXcodePath?.hasPrefix(installedXcode.path.string) == true,
|
||||||
|
path: installedXcode.path.string,
|
||||||
|
icon: NSWorkspace.shared.icon(forFile: installedXcode.path.string)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.allXcodes = newAllXcodes.sorted { $0.version > $1.version }
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import struct XCModel.Compilers
|
||||||
|
|
||||||
/// A version of Xcode that's available for installation
|
/// A version of Xcode that's available for installation
|
||||||
public struct AvailableXcode: Codable {
|
public struct AvailableXcode: Codable {
|
||||||
public let version: Version
|
public var version: Version
|
||||||
public let url: URL
|
public let url: URL
|
||||||
public let filename: String
|
public let filename: String
|
||||||
public let releaseDate: Date?
|
public let releaseDate: Date?
|
||||||
|
|
|
||||||
|
|
@ -88,4 +88,22 @@ class AppStateUpdateTests: XCTestCase {
|
||||||
// XCModel types aren't equatable, so just check for non-nil for now
|
// XCModel types aren't equatable, so just check for non-nil for now
|
||||||
XCTAssertNotNil(subject.allXcodes[0].sdks)
|
XCTAssertNotNil(subject.allXcodes[0].sdks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAppendingInstalledVersionThatIsNotAvailable() {
|
||||||
|
subject.allXcodes = [
|
||||||
|
]
|
||||||
|
|
||||||
|
subject.updateAllXcodes(
|
||||||
|
availableXcodes: [
|
||||||
|
AvailableXcode(version: Version("1.2.3")!, url: URL(string: "https://apple.com/xcode.xip")!, filename: "mock.xip", releaseDate: nil, sdks: .init(iOS: .init("14.3")))
|
||||||
|
],
|
||||||
|
installedXcodes: [
|
||||||
|
// There's a version installed which for some reason isn't listed online
|
||||||
|
InstalledXcode(path: Path("/Applications/Xcode-0.0.0.app")!)!
|
||||||
|
],
|
||||||
|
selectedXcodePath: nil
|
||||||
|
)
|
||||||
|
|
||||||
|
XCTAssertEqual(subject.allXcodes.map(\.version), [Version("1.2.3")!, Version("0.0.0+ABC123")!])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue