From a587d53798c20c851a2cbfb2e518994bac1085df Mon Sep 17 00:00:00 2001 From: Matt Kiazyk Date: Mon, 10 Jun 2024 16:18:36 -0500 Subject: [PATCH] don't fail downloading old runtime images --- Xcodes/Backend/AppState+Runtimes.swift | 36 +++++++++++++++---- .../XcodesKit/Models/Runtimes/Runtimes.swift | 14 +++++--- .../XcodesKit/Services/RuntimeService.swift | 11 ++++-- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Xcodes/Backend/AppState+Runtimes.swift b/Xcodes/Backend/AppState+Runtimes.swift index 838f1856..54be1114 100644 --- a/Xcodes/Backend/AppState+Runtimes.swift +++ b/Xcodes/Backend/AppState+Runtimes.swift @@ -57,6 +57,9 @@ extension AppState { self.setInstallationStep(of: runtime, to: .installing) } switch runtime.contentType { + case .cryptexDiskImage: + // not supported yet (do we need to for old packages?) + throw "Installing via cryptexDiskImage not support - please install manually from \(downloadedURL.description)" case .package: // not supported yet (do we need to for old packages?) throw "Installing via package not support - please install manually from \(downloadedURL.description)" @@ -80,19 +83,31 @@ extension AppState { Logger.appState.error("Error downloading runtime: \(error.localizedDescription)") DispatchQueue.main.async { self.error = error - self.presentedAlert = .generic(title: localizeString("Alert.Install.Error.Title"), message: error.legibleLocalizedDescription) + if let error = error as? String { + self.presentedAlert = .generic(title: localizeString("Alert.Install.Error.Title"), message: error) + } else { + self.presentedAlert = .generic(title: localizeString("Alert.Install.Error.Title"), message: error.legibleLocalizedDescription) + } } } } } func downloadRunTimeFull(runtime: DownloadableRuntime) async throws -> URL { + guard let source = runtime.source else { + throw "Invalid runtime source" + } + + guard let downloadPath = runtime.downloadPath else { + throw "Invalid runtime downloadPath" + } + // sets a proper cookie for runtimes - try await validateADCSession(path: runtime.downloadPath) + try await validateADCSession(path: downloadPath) let downloader = Downloader(rawValue: UserDefaults.standard.string(forKey: "downloader") ?? "aria2") ?? .aria2 - let url = URL(string: runtime.source)! + let url = URL(string: source)! let expectedRuntimePath = Path.xcodesApplicationSupport/"\(url.lastPathComponent)" // aria2 downloads directly to the destination (instead of into /tmp first) so we need to make sure that the download isn't incomplete let aria2DownloadMetadataPath = expectedRuntimePath.parent/(expectedRuntimePath.basename() + ".aria2") @@ -123,9 +138,15 @@ extension AppState { } public func downloadRuntimeWithAria2(_ runtime: DownloadableRuntime, to destination: Path, aria2Path: Path) -> AsyncThrowingStream { - let cookies = AppleAPI.Current.network.session.configuration.httpCookieStorage?.cookies(for: runtime.url) ?? [] + guard let url = runtime.url else { + return AsyncThrowingStream { continuation in + continuation.finish(throwing: "Invalid or non existant runtime url") + } + } + + let cookies = AppleAPI.Current.network.session.configuration.httpCookieStorage?.cookies(for: url) ?? [] - return Current.shell.downloadWithAria2Async(aria2Path, runtime.url, destination, cookies) + return Current.shell.downloadWithAria2Async(aria2Path, url, destination, cookies) } @@ -140,7 +161,10 @@ extension AppState { runtimePublishers[runtime.identifier] = nil // If the download is cancelled by the user, clean up the download files that aria2 creates. - let url = URL(string: runtime.source)! + guard let source = runtime.source else { + return + } + let url = URL(string: source)! let expectedRuntimePath = Path.xcodesApplicationSupport/"\(url.lastPathComponent)" let aria2DownloadMetadataPath = expectedRuntimePath.parent/(expectedRuntimePath.basename() + ".aria2") diff --git a/Xcodes/XcodesKit/Sources/XcodesKit/Models/Runtimes/Runtimes.swift b/Xcodes/XcodesKit/Sources/XcodesKit/Models/Runtimes/Runtimes.swift index 23cfb332..e068165f 100644 --- a/Xcodes/XcodesKit/Sources/XcodesKit/Models/Runtimes/Runtimes.swift +++ b/Xcodes/XcodesKit/Sources/XcodesKit/Models/Runtimes/Runtimes.swift @@ -11,7 +11,7 @@ public struct DownloadableRuntimesResponse: Codable { public struct DownloadableRuntime: Codable, Identifiable, Hashable { public let category: Category public let simulatorVersion: SimulatorVersion - public let source: String + public let source: String? public let dictionaryVersion: Int public let contentType: ContentType public let platform: Platform @@ -21,11 +21,14 @@ public struct DownloadableRuntime: Codable, Identifiable, Hashable { public let hostRequirements: HostRequirements? public let name: String public let authentication: Authentication? - public var url: URL { - return URL(string: source)! + public var url: URL? { + if let source { + return URL(string: source)! + } + return nil } - public var downloadPath: String { - url.path + public var downloadPath: String? { + url?.path } // dynamically updated - not decoded @@ -117,6 +120,7 @@ extension DownloadableRuntime { public enum ContentType: String, Codable { case diskImage = "diskImage" case package = "package" + case cryptexDiskImage = "cryptexDiskImage" } public enum Platform: String, Codable { diff --git a/Xcodes/XcodesKit/Sources/XcodesKit/Services/RuntimeService.swift b/Xcodes/XcodesKit/Sources/XcodesKit/Services/RuntimeService.swift index 32508019..1efbc2e2 100644 --- a/Xcodes/XcodesKit/Sources/XcodesKit/Services/RuntimeService.swift +++ b/Xcodes/XcodesKit/Sources/XcodesKit/Services/RuntimeService.swift @@ -22,9 +22,14 @@ public struct RuntimeService { // Apple gives a plist for download let (data, _) = try await networkService.requestData(urlRequest, validators: []) - let decodedResponse = try PropertyListDecoder().decode(DownloadableRuntimesResponse.self, from: data) - - return decodedResponse + do { + let decodedResponse = try PropertyListDecoder().decode(DownloadableRuntimesResponse.self, from: data) + return decodedResponse + } catch { + print("error: \(error)") + throw error + } + } public func installedRuntimes() async throws -> [InstalledRuntime] {