Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Sources/XcodesKit/Models.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public struct Xcode: Codable, Equatable {
public let filename: String
public let releaseDate: Date?

public var downloadPath: String {
return url.path
}

public init(version: Version, url: URL, filename: String, releaseDate: Date?) {
self.version = version
self.url = url
Expand Down
11 changes: 11 additions & 0 deletions Sources/XcodesKit/URLRequest+Apple.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ extension URL {
static let download = URL(string: "https://developer.apple.com/download")!
static let downloads = URL(string: "https://developer.apple.com/services-account/QH65B2/downloadws/listDownloads.action")!
static let downloadXcode = URL(string: "https://developer.apple.com/devcenter/download.action")!
static let downloadADCAuth = URL(string: "https://developerservices2.apple.com/services/download")!
}

extension URLRequest {
Expand All @@ -25,4 +26,14 @@ extension URLRequest {
request.allHTTPHeaderFields?["Accept"] = "*/*"
return request
}

// default to a known download path if none passed in
static func downloadADCAuth(path: String? = "/Developer_Tools/Xcode_14/Xcode_14.xip") -> URLRequest {
var components = URLComponents(url: .downloadADCAuth, resolvingAgainstBaseURL: false)!
components.queryItems = [URLQueryItem(name: "path", value: path)]
var request = URLRequest(url: components.url!)
request.allHTTPHeaderFields = request.allHTTPHeaderFields ?? [:]
request.allHTTPHeaderFields?["Accept"] = "*/*"
return request
}
}
38 changes: 23 additions & 15 deletions Sources/XcodesKit/XcodeInstaller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,15 @@ public final class XcodeInstaller {

private func downloadXcode(version: Version, dataSource: DataSource, downloader: Downloader, willInstall: Bool) -> Promise<(Xcode, URL)> {
return firstly { () -> Promise<Version> in
loginIfNeeded().map { version }
if dataSource == .apple {
return loginIfNeeded().map { version }
} else {
guard let xcode = self.xcodeList.availableXcodes.first(withVersion: version) else {
throw Error.unavailableVersion(version)
}

return validateADCSession(path: xcode.downloadPath).map { version }
}
}
.then { version -> Promise<Version> in
if self.xcodeList.shouldUpdate {
Expand All @@ -297,14 +305,6 @@ public final class XcodeInstaller {
return Promise.value(version)
}
}
.then { version -> Promise<Version> in
// This request would've already been made if the Apple data source were being used.
// That's not the case for the Xcode Releases data source.
// We need the cookies from its response in order to download Xcodes though,
// so perform it here first just to be sure.
Current.network.dataTask(with: URLRequest.downloads)
.map { _ in version }
}
.then { version -> Promise<(Xcode, URL)> in
guard let xcode = self.xcodeList.availableXcodes.first(withVersion: version) else {
throw Error.unavailableVersion(version)
Expand Down Expand Up @@ -334,7 +334,11 @@ public final class XcodeInstaller {
.map { return (xcode, $0) }
}
}


func validateADCSession(path: String) -> Promise<Void> {
return Current.network.dataTask(with: URLRequest.downloadADCAuth(path: path)).asVoid()
}

func loginIfNeeded(withUsername providedUsername: String? = nil, shouldPromptForPassword: Bool = false) -> Promise<Void> {
return firstly { () -> Promise<Void> in
return Current.network.validateSession()
Expand Down Expand Up @@ -626,11 +630,15 @@ public final class XcodeInstaller {
}

func update(dataSource: DataSource) -> Promise<[Xcode]> {
return firstly { () -> Promise<Void> in
loginIfNeeded()
}
.then { () -> Promise<[Xcode]> in
self.xcodeList.update(dataSource: dataSource)
if dataSource == .apple {
return firstly { () -> Promise<Void> in
loginIfNeeded()
}
.then { () -> Promise<[Xcode]> in
self.xcodeList.update(dataSource: dataSource)
}
} else {
return self.xcodeList.update(dataSource: dataSource)
}
}

Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.