Skip to content

Commit fadab3c

Browse files
committed
Add ability to download Xcode without logging in using XcodeRelease
2 parents c979aa4 + 42d8544 commit fadab3c

File tree

3 files changed

+38
-15
lines changed

3 files changed

+38
-15
lines changed

Sources/XcodesKit/Models.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ public struct Xcode: Codable, Equatable {
5050
public let filename: String
5151
public let releaseDate: Date?
5252

53+
public var downloadPath: String {
54+
return url.path
55+
}
56+
5357
public init(version: Version, url: URL, filename: String, releaseDate: Date?) {
5458
self.version = version
5559
self.url = url

Sources/XcodesKit/URLRequest+Apple.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extension URL {
44
static let download = URL(string: "https://developer.apple.com/download")!
55
static let downloads = URL(string: "https://developer.apple.com/services-account/QH65B2/downloadws/listDownloads.action")!
66
static let downloadXcode = URL(string: "https://developer.apple.com/devcenter/download.action")!
7+
static let downloadADCAuth = URL(string: "https://developerservices2.apple.com/services/download")!
78
}
89

910
extension URLRequest {
@@ -25,4 +26,14 @@ extension URLRequest {
2526
request.allHTTPHeaderFields?["Accept"] = "*/*"
2627
return request
2728
}
29+
30+
// default to a known download path if none passed in
31+
static func downloadADCAuth(path: String? = "/Developer_Tools/Xcode_14/Xcode_14.xip") -> URLRequest {
32+
var components = URLComponents(url: .downloadADCAuth, resolvingAgainstBaseURL: false)!
33+
components.queryItems = [URLQueryItem(name: "path", value: path)]
34+
var request = URLRequest(url: components.url!)
35+
request.allHTTPHeaderFields = request.allHTTPHeaderFields ?? [:]
36+
request.allHTTPHeaderFields?["Accept"] = "*/*"
37+
return request
38+
}
2839
}

Sources/XcodesKit/XcodeInstaller.swift

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,15 @@ public final class XcodeInstaller {
287287

288288
private func downloadXcode(version: Version, dataSource: DataSource, downloader: Downloader, willInstall: Bool) -> Promise<(Xcode, URL)> {
289289
return firstly { () -> Promise<Version> in
290-
loginIfNeeded().map { version }
290+
if dataSource == .apple {
291+
return loginIfNeeded().map { version }
292+
} else {
293+
guard let xcode = self.xcodeList.availableXcodes.first(withVersion: version) else {
294+
throw Error.unavailableVersion(version)
295+
}
296+
297+
return validateADCSession(path: xcode.downloadPath).map { version }
298+
}
291299
}
292300
.then { version -> Promise<Version> in
293301
if self.xcodeList.shouldUpdate {
@@ -297,14 +305,6 @@ public final class XcodeInstaller {
297305
return Promise.value(version)
298306
}
299307
}
300-
.then { version -> Promise<Version> in
301-
// This request would've already been made if the Apple data source were being used.
302-
// That's not the case for the Xcode Releases data source.
303-
// We need the cookies from its response in order to download Xcodes though,
304-
// so perform it here first just to be sure.
305-
Current.network.dataTask(with: URLRequest.downloads)
306-
.map { _ in version }
307-
}
308308
.then { version -> Promise<(Xcode, URL)> in
309309
guard let xcode = self.xcodeList.availableXcodes.first(withVersion: version) else {
310310
throw Error.unavailableVersion(version)
@@ -334,7 +334,11 @@ public final class XcodeInstaller {
334334
.map { return (xcode, $0) }
335335
}
336336
}
337-
337+
338+
func validateADCSession(path: String) -> Promise<Void> {
339+
return Current.network.dataTask(with: URLRequest.downloadADCAuth(path: path)).asVoid()
340+
}
341+
338342
func loginIfNeeded(withUsername providedUsername: String? = nil, shouldPromptForPassword: Bool = false) -> Promise<Void> {
339343
return firstly { () -> Promise<Void> in
340344
return Current.network.validateSession()
@@ -626,11 +630,15 @@ public final class XcodeInstaller {
626630
}
627631

628632
func update(dataSource: DataSource) -> Promise<[Xcode]> {
629-
return firstly { () -> Promise<Void> in
630-
loginIfNeeded()
631-
}
632-
.then { () -> Promise<[Xcode]> in
633-
self.xcodeList.update(dataSource: dataSource)
633+
if dataSource == .apple {
634+
return firstly { () -> Promise<Void> in
635+
loginIfNeeded()
636+
}
637+
.then { () -> Promise<[Xcode]> in
638+
self.xcodeList.update(dataSource: dataSource)
639+
}
640+
} else {
641+
return self.xcodeList.update(dataSource: dataSource)
634642
}
635643
}
636644

0 commit comments

Comments
 (0)