diff --git a/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift b/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift
index cb4ec68..c8e2810 100644
--- a/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift
+++ b/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift
@@ -158,9 +158,12 @@ public class Client {
}
.decode(type: AppleSession.self, decoder: JSONDecoder())
.tryMap { session in
- if session.provider == nil {
- throw AuthenticationError.notDeveloperAppleId
- }
+ // A user that is a non-paid Apple Developer will have a provider == nil
+ // Those users can still download Xcode.
+ // Non Apple Developers will get caught in the download as invalid
+// if session.provider == nil {
+// throw AuthenticationError.notDeveloperAppleId
+// }
}
.eraseToAnyPublisher()
}
@@ -197,6 +200,7 @@ public enum AuthenticationError: Swift.Error, LocalizedError, Equatable {
case badStatusCode(statusCode: Int, data: Data, response: HTTPURLResponse)
case notDeveloperAppleId
case notAuthorized
+ case invalidResult(resultString: String?)
public var errorDescription: String? {
switch self {
@@ -227,6 +231,8 @@ public enum AuthenticationError: Swift.Error, LocalizedError, Equatable {
return "You are not registered as an Apple Developer. Please visit Apple Developer Registration. https://developer.apple.com/register/"
case .notAuthorized:
return "You are not authorized. Please Sign in with your Apple ID first."
+ case let .invalidResult(resultString):
+ return resultString ?? "If you continue to have problems, please submit a bug report in the Help menu."
}
}
}
diff --git a/Xcodes/Backend/AppState+Update.swift b/Xcodes/Backend/AppState+Update.swift
index ed998af..58b3626 100644
--- a/Xcodes/Backend/AppState+Update.swift
+++ b/Xcodes/Backend/AppState+Update.swift
@@ -130,15 +130,20 @@ extension AppState {
extension AppState {
// MARK: - Apple
- private func releasedXcodes() -> AnyPublisher<[AvailableXcode], Error> {
+ private func releasedXcodes() -> AnyPublisher<[AvailableXcode], Swift.Error> {
Current.network.dataTask(with: URLRequest.downloads)
.map(\.data)
.decode(type: Downloads.self, decoder: configure(JSONDecoder()) {
$0.dateDecodingStrategy = .formatted(.downloadsDateModified)
})
- .map { downloads -> [AvailableXcode] in
- let xcodes = downloads
- .downloads
+ .tryMap { downloads -> [AvailableXcode] in
+ if downloads.hasError {
+ throw AuthenticationError.invalidResult(resultString: downloads.resultsString)
+ }
+ guard let downloadList = downloads.downloads else {
+ throw AuthenticationError.invalidResult(resultString: "No download information found")
+ }
+ let xcodes = downloadList
.filter { $0.name.range(of: "^Xcode [0-9]", options: .regularExpression) != nil }
.compactMap { download -> AvailableXcode? in
let urlPrefix = URL(string: "https://download.developer.apple.com/")!
diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift
index f6090cb..78755e6 100644
--- a/Xcodes/Backend/AppState.swift
+++ b/Xcodes/Backend/AppState.swift
@@ -337,8 +337,18 @@ class AppState: ObservableObject {
// 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)
- .receive(on: DispatchQueue.main)
- .map { _ in Void() }
+ .map(\.data)
+ .decode(type: Downloads.self, decoder: configure(JSONDecoder()) {
+ $0.dateDecodingStrategy = .formatted(.downloadsDateModified)
+ })
+ .tryMap { downloads -> Void in
+ if downloads.hasError {
+ throw AuthenticationError.invalidResult(resultString: downloads.resultsString)
+ }
+ if downloads.downloads == nil {
+ throw AuthenticationError.invalidResult(resultString: "No download information found")
+ }
+ }
.mapError { $0 as Error }
}
.flatMap { [unowned self] in
diff --git a/Xcodes/Backend/Downloads.swift b/Xcodes/Backend/Downloads.swift
index 55096e4..aab9779 100644
--- a/Xcodes/Backend/Downloads.swift
+++ b/Xcodes/Backend/Downloads.swift
@@ -3,7 +3,13 @@ import Path
import Version
struct Downloads: Codable {
- let downloads: [Download]
+ let resultCode: Int
+ let resultsString: String?
+ let downloads: [Download]?
+
+ var hasError: Bool {
+ return resultCode != 0
+ }
}
// Set to Int64 as ByteCountFormatter uses it.
diff --git a/Xcodes/Resources/Licenses.rtf b/Xcodes/Resources/Licenses.rtf
index 58f4a3d..96bf513 100644
--- a/Xcodes/Resources/Licenses.rtf
+++ b/Xcodes/Resources/Licenses.rtf
@@ -1,4 +1,4 @@
-{\rtf1\ansi\ansicpg1252\cocoartf2578
+{\rtf1\ansi\ansicpg1252\cocoartf2580
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 .SFNS-Regular;}
{\colortbl;\red255\green255\blue255;}
{\*\expandedcolortbl;;}
@@ -363,73 +363,6 @@ SOFTWARE.\
\
\
-\fs34 Sparkle\
-\
-
-\fs26 Copyright (c) 2006-2013 Andy Matuschak.\
-Copyright (c) 2009-2013 Elgato Systems GmbH.\
-Copyright (c) 2011-2014 Kornel Lesi\uc0\u324 ski.\
-Copyright (c) 2015-2017 Mayur Pawashe.\
-Copyright (c) 2014 C.W. Betts.\
-Copyright (c) 2014 Petroules Corporation.\
-Copyright (c) 2014 Big Nerd Ranch.\
-All rights reserved.\
-\
-Permission is hereby granted, free of charge, to any person obtaining a copy of\
-this software and associated documentation files (the "Software"), to deal in\
-the Software without restriction, including without limitation the rights to\
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\
-the Software, and to permit persons to whom the Software is furnished to do so,\
-subject to the following conditions:\
-\
-The above copyright notice and this permission notice shall be included in all\
-copies or substantial portions of the Software.\
-\
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\
-\
-=================\
-EXTERNAL LICENSES\
-=================\
-\
-bspatch.c and bsdiff.c, from bsdiff 4.3 :\
- Copyright (c) 2003-2005 Colin Percival.\
-\
-sais.c and sais.c, from sais-lite (2010/08/07) :\
- Copyright (c) 2008-2010 Yuta Mori.\
-\
-SUDSAVerifier.m:\
- Copyright (c) 2011 Mark Hamlin.\
-\
-All rights reserved.\
-\
-Redistribution and use in source and binary forms, with or without\
-modification, are permitted providing that the following conditions\
-are met:\
-1. Redistributions of source code must retain the above copyright\
- notice, this list of conditions and the following disclaimer.\
-2. Redistributions in binary form must reproduce the above copyright\
- notice, this list of conditions and the following disclaimer in the\
- documentation and/or other materials provided with the distribution.\
-\
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\
-POSSIBILITY OF SUCH DAMAGE.\
-\
-\
-
\fs34 LegibleError\
\
diff --git a/XcodesTests/AppStateTests.swift b/XcodesTests/AppStateTests.swift
index c708d9d..ce38607 100644
--- a/XcodesTests/AppStateTests.swift
+++ b/XcodesTests/AppStateTests.swift
@@ -93,7 +93,7 @@ class AppStateTests: XCTestCase {
}
// It's an available release version
else if urlRequest.url! == URLRequest.downloads.url! {
- let downloads = Downloads(downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip", fileSize: 9484444)], dateModified: Date())])
+ let downloads = Downloads(resultCode: 0, resultsString: nil, downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip", fileSize: 9484444)], dateModified: Date())])
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .formatted(.downloadsDateModified)
let downloadsData = try! encoder.encode(downloads)
@@ -203,7 +203,7 @@ class AppStateTests: XCTestCase {
}
// It's an available release version
else if urlRequest.url! == URLRequest.downloads.url! {
- let downloads = Downloads(downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip", fileSize: 9494944)], dateModified: Date())])
+ let downloads = Downloads(resultCode: 0, resultsString: nil, downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip", fileSize: 9494944)], dateModified: Date())])
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .formatted(.downloadsDateModified)
let downloadsData = try! encoder.encode(downloads)