show installed xcodes specific with architectures

This commit is contained in:
Matt Kiazyk 2025-08-23 20:11:57 -06:00
parent debc41f688
commit ceae881d9a
5 changed files with 25 additions and 20 deletions

View file

@ -894,7 +894,11 @@ class AppState: ObservableObject {
}
.map { availableXcode -> Xcode in
let installedXcode = installedXcodes.first(where: { installedXcode in
availableXcode.version.isEquivalent(to: installedXcode.version)
if availableXcode.architectures == nil {
return availableXcode.version.isEquivalent(to: installedXcode.version)
} else {
return availableXcode.xcodeID == installedXcode.xcodeID
}
})
let identicalBuilds: [XcodeID]
@ -913,7 +917,7 @@ class AppState: ObservableObject {
}
// If the existing install state is "installing", keep it
let existingXcodeInstallState = allXcodes.first { $0.version == availableXcode.version && $0.installState.installing }?.installState
let existingXcodeInstallState = allXcodes.first { $0.id == availableXcode.xcodeID && $0.installState.installing }?.installState
// Otherwise, determine it from whether there's an installed Xcode
let defaultXcodeInstallState: XcodeInstallState = installedXcode.map { .installed($0.path) } ?? .notInstalled

View file

@ -1,6 +1,7 @@
import Foundation
import Version
import Path
import XcodesKit
/// A version of Xcode that's already installed
public struct InstalledXcode: Equatable {
@ -36,8 +37,12 @@ public struct InstalledXcode: Equatable {
prereleaseIdentifiers = ["beta"]
}
// need:
// lipo -archs /Applications/Xcode-26.0.0-Beta.3.app/Contents/MacOS/Xcode
let archsString = try? XcodesKit.Current.shell.archs(path.url.appending(path: "Contents/MacOS/Xcode")).out
let architectures = archsString?
.trimmingCharacters(in: .whitespacesAndNewlines)
.split(separator: " ")
.compactMap { Architecture(rawValue: String($0)) }
let version = Version(major: bundleVersion.major,
minor: bundleVersion.minor,
@ -45,7 +50,7 @@ public struct InstalledXcode: Equatable {
prereleaseIdentifiers: prereleaseIdentifiers,
buildMetadataIdentifiers: [versionPlist.productBuildVersion].compactMap { $0 })
self.xcodeID = XcodeID(version: version, architectures: nil)
self.xcodeID = XcodeID(version: version, architectures: architectures)
}
}

View file

@ -17,18 +17,6 @@ public struct XcodeID: Codable, Hashable, Identifiable {
self.version = version
self.architectures = architectures
}
public var architectureString: String {
switch architectures {
case .some(let architectures):
if architectures.isAppleSilicon {
return "Apple Silicon"
} else {
return "Universal"
}
default: return "Universal"
}
}
}
struct Xcode: Identifiable, CustomStringConvertible {

View file

@ -6,10 +6,14 @@ public typealias ProcessOutput = (status: Int32, out: String, err: String)
extension Process {
static func run(_ executable: Path, workingDirectory: URL? = nil, input: String? = nil, _ arguments: String...) async throws -> ProcessOutput {
return try await run(executable.url, workingDirectory: workingDirectory, input: input, arguments)
return try run(executable.url, workingDirectory: workingDirectory, input: input, arguments)
}
static func run(_ executable: URL, workingDirectory: URL? = nil, input: String? = nil, _ arguments: [String]) async throws -> ProcessOutput {
static func run(_ executable: Path, workingDirectory: URL? = nil, input: String? = nil, _ arguments: String...) throws -> ProcessOutput {
return try run(executable.url, workingDirectory: workingDirectory, input: input, arguments)
}
static func run(_ executable: URL, workingDirectory: URL? = nil, input: String? = nil, _ arguments: [String]) throws -> ProcessOutput {
let process = Process()
process.currentDirectoryURL = workingDirectory ?? executable.deletingLastPathComponent()

View file

@ -26,4 +26,8 @@ public struct XcodesShell {
public var deleteRuntime: (String) async throws -> ProcessOutput = {
try await Process.run(Path.root.usr.bin.join("xcrun"), "simctl", "runtime", "delete", $0)
}
public var archs: (URL) throws -> ProcessOutput = {
try Process.run(Path.root.usr.bin.join("lipo"), "-archs", $0.path)
}
}