diff --git a/Sources/XcodesKit/Models+Runtimes.swift b/Sources/XcodesKit/Models+Runtimes.swift index 6463569..9817133 100644 --- a/Sources/XcodesKit/Models+Runtimes.swift +++ b/Sources/XcodesKit/Models+Runtimes.swift @@ -11,7 +11,7 @@ struct DownloadableRuntimesResponse: Decodable { public struct DownloadableRuntime: Decodable { let category: Category let simulatorVersion: SimulatorVersion - let source: String + let source: String? let dictionaryVersion: Int let contentType: ContentType let platform: Platform @@ -36,6 +36,17 @@ public struct DownloadableRuntime: Decodable { var visibleIdentifier: String { return platform.shortName + " " + completeVersion } + + var sourceURL: URL { + source.flatMap(URL.init) ?? makeRuntimeURL(runtimeName: name) + } +} + +let xcodeRuntimesFallbackURL = URL(string: "https://download.developer.apple.com/Developer_Tools/")! + +func makeRuntimeURL(runtimeName: String) -> URL { + let baseName = runtimeName.replacingOccurrences(of: ".0 ", with: " ").replacingOccurrences(of: " ", with: "_") + return xcodeRuntimesFallbackURL.appendingPathComponent("\(baseName)/\(baseName).dmg") } func makeVersion(for osVersion: String, betaNumber: Int?) -> String { @@ -79,6 +90,7 @@ extension DownloadableRuntime { enum ContentType: String, Decodable { case diskImage = "diskImage" case package = "package" + case cryptexDiskImage = "cryptexDiskImage" } enum Platform: String, Decodable { diff --git a/Sources/XcodesKit/RuntimeInstaller.swift b/Sources/XcodesKit/RuntimeInstaller.swift index cf0821c..dc00420 100644 --- a/Sources/XcodesKit/RuntimeInstaller.swift +++ b/Sources/XcodesKit/RuntimeInstaller.swift @@ -110,7 +110,7 @@ public class RuntimeInstaller { switch matchedRuntime.contentType { case .package: try await installFromPackage(dmgUrl: dmgUrl, runtime: matchedRuntime) - case .diskImage: + case .diskImage, .cryptexDiskImage: try await installFromImage(dmgUrl: dmgUrl) } if shouldDelete { @@ -183,7 +183,7 @@ public class RuntimeInstaller { @MainActor public func downloadOrUseExistingArchive(runtime: DownloadableRuntime, to destinationDirectory: Path, downloader: Downloader) async throws -> URL { - let url = URL(string: runtime.source)! + let url = runtime.sourceURL let destination = destinationDirectory/url.lastPathComponent let aria2DownloadMetadataPath = destination.parent/(destination.basename() + ".aria2") var aria2DownloadIsIncomplete = false @@ -202,9 +202,7 @@ public class RuntimeInstaller { Current.logging.log("Found existing Runtime that will be used, at \(destination).") return destination.url } - if runtime.authentication == .virtual { - try await sessionService.validateADCSession(path: url.path).async() - } + try await sessionService.validateADCSession(path: url.path).async() let formatter = NumberFormatter(numberStyle: .percent) var observation: NSKeyValueObservation? let result = try await downloader.download(url: url, to: destination, progressChanged: { progress in diff --git a/Tests/XcodesKitTests/RuntimeTests.swift b/Tests/XcodesKitTests/RuntimeTests.swift index 314761a..fe6f135 100644 --- a/Tests/XcodesKitTests/RuntimeTests.swift +++ b/Tests/XcodesKitTests/RuntimeTests.swift @@ -171,7 +171,7 @@ final class RuntimeTests: XCTestCase { } let url = try await runtimeInstaller.downloadOrUseExistingArchive(runtime: runtime, to: .xcodesCaches, downloader: .urlSession) - let fileName = URL(string: runtime.source)!.lastPathComponent + let fileName = runtime.sourceURL.lastPathComponent XCTAssertEqual(url, Path.xcodesCaches.join(fileName).url) XCTAssertNil(xcodeDownloadURL) } @@ -185,10 +185,10 @@ final class RuntimeTests: XCTestCase { return (Progress(), Promise.value((destination, HTTPURLResponse(url: url.pmkRequest.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!))) } let runtime = try await runtimeList.downloadableRuntimes().downloadables.first { $0.visibleIdentifier == "iOS 15.5" }! - let fileName = URL(string: runtime.source)!.lastPathComponent + let fileName = runtime.sourceURL.lastPathComponent let url = try await runtimeInstaller.downloadOrUseExistingArchive(runtime: runtime, to: .xcodesCaches, downloader: .urlSession) XCTAssertEqual(url, Path.xcodesCaches.join(fileName).url) - XCTAssertEqual(xcodeDownloadURL, URL(string: runtime.source)!) + XCTAssertEqual(xcodeDownloadURL, runtime.sourceURL) } func test_installStepsForPackage() async throws {