mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
Replaces StoreApp.setVersions() preconditionFailure with runtime error
It’s more common than expected for apps to not have any app versions, so better to fail gracefully than crash.
This commit is contained in:
@@ -193,8 +193,13 @@ private extension BrowseViewController
|
||||
throw error
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch var error as NSError
|
||||
{
|
||||
if error.localizedTitle == nil
|
||||
{
|
||||
error = error.withLocalizedTitle(NSLocalizedString("Unable to Refresh Store", comment: ""))
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if self.dataSource.itemCount > 0
|
||||
{
|
||||
|
||||
@@ -210,8 +210,13 @@ private extension NewsViewController
|
||||
throw error
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch var error as NSError
|
||||
{
|
||||
if error.localizedTitle == nil
|
||||
{
|
||||
error = error.withLocalizedTitle(NSLocalizedString("Unable to Refresh Store", comment: ""))
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if self.dataSource.itemCount > 0
|
||||
{
|
||||
|
||||
@@ -10,6 +10,60 @@ import CoreData
|
||||
|
||||
import Roxas
|
||||
|
||||
extension MergeError
|
||||
{
|
||||
enum Code: Int, ALTErrorCode
|
||||
{
|
||||
typealias Error = MergeError
|
||||
|
||||
case noVersions
|
||||
}
|
||||
|
||||
static func noVersions(for app: AppProtocol) -> MergeError { .init(code: .noVersions, appName: app.name, appBundleID: app.bundleIdentifier) }
|
||||
}
|
||||
|
||||
struct MergeError: ALTLocalizedError
|
||||
{
|
||||
static var errorDomain: String { "AltStore.MergeError" }
|
||||
|
||||
let code: Code
|
||||
var errorTitle: String?
|
||||
var errorFailure: String?
|
||||
|
||||
var appName: String?
|
||||
var appBundleID: String?
|
||||
|
||||
var errorFailureReason: String {
|
||||
switch self.code
|
||||
{
|
||||
case .noVersions:
|
||||
var appName = NSLocalizedString("At least one app", comment: "")
|
||||
if let name = self.appName, let bundleID = self.appBundleID
|
||||
{
|
||||
appName = name + " (\(bundleID))"
|
||||
}
|
||||
|
||||
return String(format: NSLocalizedString("%@ does not have any app versions.", comment: ""), appName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension Error
|
||||
{
|
||||
func serialized(withFailure failure: String) -> NSError
|
||||
{
|
||||
// We need to serialize Swift errors thrown during merge conflict to preserve error messages.
|
||||
|
||||
let serializedError = (self as NSError).withLocalizedFailure(failure).sanitizedForSerialization()
|
||||
|
||||
var userInfo = serializedError.userInfo
|
||||
userInfo[NSLocalizedDescriptionKey] = nil // Remove NSLocalizedDescriptionKey value to prevent duplicating localized failure in localized description.
|
||||
|
||||
let error = NSError(domain: serializedError.domain, code: serializedError.code, userInfo: userInfo)
|
||||
return error
|
||||
}
|
||||
}
|
||||
|
||||
open class MergePolicy: RSTRelationshipPreservingMergePolicy
|
||||
{
|
||||
open override func resolve(constraintConflicts conflicts: [NSConstraintConflict]) throws
|
||||
@@ -108,7 +162,15 @@ open class MergePolicy: RSTRelationshipPreservingMergePolicy
|
||||
return indexA < indexB
|
||||
}
|
||||
|
||||
databaseObject.setVersions(sortedVersions)
|
||||
do
|
||||
{
|
||||
try databaseObject.setVersions(sortedVersions)
|
||||
}
|
||||
catch
|
||||
{
|
||||
let nsError = error.serialized(withFailure: NSLocalizedString("AltStore's database could not be saved.", comment: ""))
|
||||
throw nsError
|
||||
}
|
||||
}
|
||||
|
||||
case let databaseObject as Source:
|
||||
@@ -146,8 +208,16 @@ open class MergePolicy: RSTRelationshipPreservingMergePolicy
|
||||
switch conflict.databaseObject
|
||||
{
|
||||
case let databaseObject as StoreApp:
|
||||
// Update versions post-merging to make sure latestSupportedVersion is correct.
|
||||
databaseObject.setVersions(databaseObject.versions)
|
||||
do
|
||||
{
|
||||
// Update versions post-merging to make sure latestSupportedVersion is correct.
|
||||
try databaseObject.setVersions(databaseObject.versions)
|
||||
}
|
||||
catch
|
||||
{
|
||||
let nsError = error.serialized(withFailure: NSLocalizedString("AltStore's database could not be saved.", comment: ""))
|
||||
throw nsError
|
||||
}
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
@@ -267,12 +267,12 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
|
||||
} else {
|
||||
throw DecodingError.dataCorruptedError(forKey: .downloadURL, in: container, debugDescription: "E downloadURL:String or downloadURLs:[[Platform:URL]] key required.")
|
||||
}
|
||||
|
||||
|
||||
// else {
|
||||
// throw DecodingError.dataCorruptedError(forKey: .downloadURL, in: container, debugDescription: "E downloadURL:String or downloadURLs:[[Platform:URL]] key required.")
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
if let tintColorHex = try container.decodeIfPresent(String.self, forKey: .tintColor)
|
||||
{
|
||||
guard let tintColor = UIColor(hexString: tintColorHex) else {
|
||||
@@ -293,13 +293,13 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
|
||||
if (versions.count == 0){
|
||||
throw DecodingError.dataCorruptedError(forKey: .versions, in: container, debugDescription: "At least one version is required in key: versions")
|
||||
}
|
||||
|
||||
|
||||
for version in versions
|
||||
{
|
||||
version.appBundleID = self.bundleIdentifier
|
||||
}
|
||||
|
||||
self.setVersions(versions)
|
||||
try self.setVersions(versions)
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -317,7 +317,7 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
|
||||
size: Int64(size),
|
||||
appBundleID: self.bundleIdentifier,
|
||||
in: context)
|
||||
self.setVersions([appVersion])
|
||||
try self.setVersions([appVersion])
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -334,8 +334,12 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
|
||||
|
||||
internal extension StoreApp
|
||||
{
|
||||
func setVersions(_ versions: [AppVersion])
|
||||
func setVersions(_ versions: [AppVersion]) throws
|
||||
{
|
||||
guard let latestVersion = versions.first else {
|
||||
throw MergeError.noVersions(for: self)
|
||||
}
|
||||
|
||||
self._versions = NSOrderedSet(array: versions)
|
||||
|
||||
let latestSupportedVersion = versions.first(where: { $0.isSupported })
|
||||
@@ -355,7 +359,6 @@ internal extension StoreApp
|
||||
}
|
||||
|
||||
// Preserve backwards compatibility by assigning legacy property values.
|
||||
guard let latestVersion = versions.first else { preconditionFailure("StoreApp must have at least one AppVersion.") }
|
||||
self.latestVersionString = latestVersion.version
|
||||
self._versionDate = latestVersion.date
|
||||
self._versionDescription = latestVersion.localizedDescription
|
||||
@@ -393,7 +396,7 @@ public extension StoreApp
|
||||
appBundleID: app.bundleIdentifier,
|
||||
sourceID: Source.altStoreIdentifier,
|
||||
in: context)
|
||||
app.setVersions([appVersion])
|
||||
try? app.setVersions([appVersion])
|
||||
|
||||
print("makeAltStoreApp StoreApp: \(String(describing: app))")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user