warning if users download silicon runtime without xcode 26 selected

This commit is contained in:
Matt Kiazyk 2025-08-25 22:26:41 -05:00
parent 0bc8e42a9b
commit 2e2b16e759
9 changed files with 64 additions and 49 deletions

View file

@ -139,7 +139,6 @@
E8DA461125FAF7FB002E85EF /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8DA461025FAF7FB002E85EF /* NotificationsView.swift */; };
E8E98A9025D8631800EC89A0 /* InstallationStepRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBC3FF259AC17F00E2A3D8 /* InstallationStepRowView.swift */; };
E8E98A9625D863D700EC89A0 /* InstallationStepDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */; };
E8EE58C02E1CC2A50003FA9F /* RuntimeArchitecture.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8EE58BF2E1CC2A50003FA9F /* RuntimeArchitecture.swift */; };
E8F44A1E296B4CD7002D6592 /* Path in Frameworks */ = {isa = PBXBuildFile; productRef = E8F44A1D296B4CD7002D6592 /* Path */; };
E8FA00542B5B109800769CE0 /* com.xcodesorg.xcodesapp.Helper in Copy Helper */ = {isa = PBXBuildFile; fileRef = CA9FF8AE2595967A00E47BAF /* com.xcodesorg.xcodesapp.Helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
E8FD5727291EE4AC001E004C /* AsyncNetworkService in Frameworks */ = {isa = PBXBuildFile; productRef = E8FD5726291EE4AC001E004C /* AsyncNetworkService */; };
@ -342,7 +341,6 @@
E8D655BF288DD04700A139C2 /* SelectedActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedActionType.swift; sourceTree = "<group>"; };
E8DA461025FAF7FB002E85EF /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationStepDetailView.swift; sourceTree = "<group>"; };
E8EE58BF2E1CC2A50003FA9F /* RuntimeArchitecture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeArchitecture.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -660,7 +658,6 @@
E8E98A9425D863B100EC89A0 /* InfoPane */ = {
isa = PBXGroup;
children = (
E8EE58BF2E1CC2A50003FA9F /* RuntimeArchitecture.swift */,
B0403CEF2AD92D7B00137C09 /* ReleaseNotesView.swift */,
B0403CF32AD9381D00137C09 /* SDKsView.swift */,
B0403CF52AD9849E00137C09 /* CompilersView.swift */,
@ -938,7 +935,6 @@
53CBAB2C263DCC9100410495 /* XcodesAlert.swift in Sources */,
332807412CA5EA820036F691 /* SignInSecurityKeyTouchView.swift in Sources */,
CA61A6E0259835580008926E /* Xcode.swift in Sources */,
E8EE58C02E1CC2A50003FA9F /* RuntimeArchitecture.swift in Sources */,
CAE4247F259A666100B8B246 /* MainWindow.swift in Sources */,
CA452BB0259FD9770072DFA4 /* ProgressIndicator.swift in Sources */,
B0403CF02AD92D7B00137C09 /* ReleaseNotesView.swift in Sources */,

View file

@ -61,7 +61,22 @@ extension AppState {
// only selected xcodes > 16.1 beta 3 can download runtimes via a xcodebuild -downloadPlatform version
// only Runtimes coming from cryptexDiskImage can be downloaded via xcodebuild
if selectedXcode.version > Version(major: 16, minor: 0, patch: 0) {
downloadRuntimeViaXcodeBuild(runtime: runtime)
if runtime.architectures?.isAppleSilicon ?? false {
if selectedXcode.version > Version(major: 26, minor: 0, patch: 0) {
downloadRuntimeViaXcodeBuild(runtime: runtime)
} else {
// not supported
Logger.appState.error("Trying to download a runtime we can't download")
DispatchQueue.main.async {
self.presentedAlert = .generic(title: localizeString("Alert.Install.Error.Title"), message: localizeString("Alert.Install.Error.Need.Xcode26"))
}
return
}
} else {
downloadRuntimeViaXcodeBuild(runtime: runtime)
}
} else {
// not supported
Logger.appState.error("Trying to download a runtime we can't download")
@ -77,7 +92,8 @@ extension AppState {
func downloadRuntimeViaXcodeBuild(runtime: DownloadableRuntime) {
let downloadRuntimeTask = Current.shell.downloadRuntime(runtime.platform.shortName, runtime.simulatorVersion.buildUpdate)
let downloadRuntimeTask = Current.shell.downloadRuntime(runtime.platform.shortName, runtime.simulatorVersion.buildUpdate, runtime.architectures?.isAppleSilicon ?? false ? Architecture.arm64.rawValue : nil)
runtimePublishers[runtime.identifier] = Task { [weak self] in
guard let self = self else { return }
do {
@ -258,7 +274,10 @@ extension AppState {
}
func coreSimulatorInfo(runtime: DownloadableRuntime) -> CoreSimulatorImage? {
return installedRuntimes.filter({ $0.runtimeInfo.build == runtime.simulatorVersion.buildUpdate }).first
return installedRuntimes.filter({
$0.runtimeInfo.build == runtime.simulatorVersion.buildUpdate &&
((runtime.architectures ?? []).isEmpty ? true :
$0.runtimeInfo.supportedArchitectures == runtime.architectures )}).first
}
func deleteRuntime(runtime: DownloadableRuntime) async throws {

View file

@ -196,7 +196,7 @@ public struct Shell {
return Process.run(unxipPath.url, workingDirectory: url.deletingLastPathComponent(), ["\(url.path)"])
}
public var downloadRuntime: (String, String) -> AsyncThrowingStream<Progress, Error> = { platform, version in
public var downloadRuntime: (String, String, String?) -> AsyncThrowingStream<Progress, Error> = { platform, version, architecture in
return AsyncThrowingStream<Progress, Error> { continuation in
Task {
// Assume progress will not have data races, so we manually opt-out isolation checks.
@ -204,7 +204,7 @@ public struct Shell {
progress.kind = .file
progress.fileOperationKind = .downloading
let process = Process()
var process = Process()
let xcodeBuildPath = Path.root.usr.bin.join("xcodebuild").url
process.executableURL = xcodeBuildPath
@ -215,6 +215,13 @@ public struct Shell {
"\(version)"
]
if let architecture {
process.arguments?.append(contentsOf: [
"-architectureVariant",
"\(architecture)"
])
}
let stdOutPipe = Pipe()
process.standardOutput = stdOutPipe
let stdErrPipe = Pipe()

View file

@ -11,7 +11,7 @@ import XcodesKit
struct PlatformsView: View {
@EnvironmentObject var appState: AppState
@AppStorage("selectedRuntimeArchitecture") private var selectedRuntimeArchitecture: RuntimeArchitecture = .arm64
@AppStorage("selectedRuntimeArchitecture") private var selectedRuntimeArchitecture: Architecture = .arm64
let xcode: Xcode
@ -22,7 +22,7 @@ struct PlatformsView: View {
appState.downloadableRuntimes.filter {
$0.sdkBuildUpdate?.contains(sdkBuild) ?? false &&
($0.architectures?.isEmpty ?? true ||
$0.architectures?.contains(selectedRuntimeArchitecture.rawValue) ?? false)
$0.architectures?.contains(selectedRuntimeArchitecture) ?? false)
}
}
@ -43,10 +43,10 @@ struct PlatformsView: View {
} label: {
switch selectedRuntimeArchitecture {
case .arm64:
Label(selectedRuntimeArchitecture.displayValue, systemImage: "m4.button.horizontal")
Label(selectedRuntimeArchitecture.rawValue, systemImage: "m4.button.horizontal")
.labelStyle(.trailingIcon)
case .x86_64:
Label(selectedRuntimeArchitecture.displayValue, systemImage: "cpu.fill")
Label(selectedRuntimeArchitecture.rawValue, systemImage: "cpu.fill")
.labelStyle(.trailingIcon)
}
}
@ -74,21 +74,21 @@ struct PlatformsView: View {
Text("\(runtime.visibleIdentifier)")
.font(.headline)
ForEach(runtime.architectures ?? [], id: \.self) { architecture in
TagView(text: architecture)
TagView(text: architecture.rawValue)
}
pathIfAvailable(xcode: xcode, runtime: runtime)
if runtime.installState == .notInstalled {
// TODO: Update the downloadableRuntimes with the appropriate installState so we don't have to check path awkwardly
if appState.runtimeInstallPath(xcode: xcode, runtime: runtime) != nil {
EmptyView()
} else {
HStack {
Spacer()
DownloadRuntimeButton(runtime: runtime)
}
}
}
if runtime.installState == .notInstalled {
// TODO: Update the downloadableRuntimes with the appropriate installState so we don't have to check path awkwardly
if appState.runtimeInstallPath(xcode: xcode, runtime: runtime) != nil {
EmptyView()
} else {
HStack {
Spacer()
DownloadRuntimeButton(runtime: runtime)
}
}
}
Spacer()
Text(runtime.downloadFileSizeString)

View file

@ -1,17 +0,0 @@
//
// RuntimeArchitecture.swift
// Xcodes
//
// Created by Matt Kiazyk on 2025-07-07.
//
enum RuntimeArchitecture: String, CaseIterable, Identifiable {
case arm64
case x86_64
var id: Self { self }
var displayValue: String {
return rawValue
}
}

View file

@ -2083,6 +2083,17 @@
}
}
},
"Alert.Install.Error.Need.Xcode26" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Apple supports downloading Apple Silicon runtimes only when Xcode 26+ is selected. Please Select and try downloading again or download the universal build."
}
}
}
},
"Alert.Install.Error.Title" : {
"comment" : "Install",
"extractionState" : "manual",

View file

@ -37,8 +37,10 @@ public struct CoreSimulatorImage: Decodable, Identifiable, Equatable {
public struct CoreSimulatorRuntimeInfo: Decodable {
public let build: String
public let supportedArchitectures: [Architecture]?
public init(build: String) {
public init(build: String, supportedArchitectures: [Architecture]? = nil) {
self.build = build
self.supportedArchitectures = supportedArchitectures
}
}

View file

@ -12,7 +12,7 @@ public struct DownloadableRuntime: Codable, Identifiable, Hashable {
public let category: Category
public let simulatorVersion: SimulatorVersion
public let source: String?
public let architectures: [String]?
public let architectures: [Architecture]?
public let dictionaryVersion: Int
public let contentType: ContentType
public let platform: Platform
@ -170,6 +170,7 @@ public struct InstalledRuntime: Decodable {
let state: String
let version: String
let sizeBytes: Int?
let supportedArchitectures: [Architecture]?
}
extension InstalledRuntime {

View file

@ -15,10 +15,6 @@ public enum Architecture: String, Codable, Equatable, Hashable, Identifiable {
case arm64 = "arm64"
/// The X86\_64 architecture (64-bit Intel)
case x86_64 = "x86_64"
/// The i386 architecture (32-bit Intel)
case i386 = "i386"
/// The PowerPC architecture (Motorola)
case powerPC = "ppc"
}
extension Array where Element == Architecture {