Improve indexing error messages

This commit is contained in:
2025-07-05 19:22:44 +10:00
parent 34059e5947
commit 45ef34ec64
2 changed files with 35 additions and 16 deletions

View File

@ -3,6 +3,8 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
import Foundation
public struct ApkIndex: Sendable { public struct ApkIndex: Sendable {
public let packages: [ApkIndexPackage] public let packages: [ApkIndexPackage]
} }
@ -32,9 +34,13 @@ public extension ApkIndex {
} }
extension ApkIndex { extension ApkIndex {
init(raw: ApkRawIndex) throws { init(raw: ApkRawIndex) throws(ApkIndexError) {
self.packages = try raw.packages.map { self.packages = try raw.packages.map { records throws(ApkIndexError) in
try ApkIndexPackage(raw: $0) do {
return try ApkIndexPackage(raw: records)
} catch {
throw .parseError(records.lookup("P") ?? "UNKNOWN", error)
}
} }
} }
} }
@ -44,3 +50,16 @@ extension ApkIndex: CustomStringConvertible {
self.packages.map(String.init).joined(separator: "\n") self.packages.map(String.init).joined(separator: "\n")
} }
} }
public enum ApkIndexError: Error {
case parseError(String, any Error)
}
extension ApkIndexError: LocalizedError {
public var errorDescription: String? {
switch self {
case .parseError(let packageName, let cause):
return "Failed to parse index for \"\(packageName)\": \(cause.localizedDescription)"
}
}
}

View File

@ -74,32 +74,32 @@ extension ApkIndexPackage {
do { do {
dependencies = try record.value.split(separator: " ") dependencies = try record.value.split(separator: " ")
.map { .init(requirement: try .init(extract: $0)) } .map { .init(requirement: try .init(extract: $0)) }
} catch { throw .badValue(key: record.key) } } catch { throw .badValue(key: record.key, cause: error.localizedDescription) }
case "C": case "C":
guard let digest = ApkIndexDigest(decode: record.value) else { guard let digest = ApkIndexDigest(decode: record.value) else {
throw .badValue(key: record.key) throw .badValue(key: record.key, cause: "Invalid SHA digest")
} }
indexChecksum = digest indexChecksum = digest
case "S": case "S":
guard let value = UInt64(record.value, radix: 10) else { guard let value = UInt64(record.value, radix: 10) else {
throw .badValue(key: record.key) throw .badValue(key: record.key, cause: "Invalid size value")
} }
packageSize = value packageSize = value
case "I": case "I":
guard let value = UInt64(record.value, radix: 10) else { guard let value = UInt64(record.value, radix: 10) else {
throw .badValue(key: record.key) throw .badValue(key: record.key, cause: "Invalid installed size value")
} }
installedSize = value installedSize = value
case "p": case "p":
do { do {
provides = try record.value.split(separator: " ") provides = try record.value.split(separator: " ")
.map { .init(requirement: try .init(extract: $0)) } .map { .init(requirement: try .init(extract: $0)) }
} catch { throw .badValue(key: record.key) } } catch { throw .badValue(key: record.key, cause: error.localizedDescription) }
case "i": case "i":
do { do {
installIf = try record.value.split(separator: " ") installIf = try record.value.split(separator: " ")
.map { .init(requirement: try .init(extract: $0)) } .map { .init(requirement: try .init(extract: $0)) }
} catch { throw .badValue(key: record.key) } } catch { throw .badValue(key: record.key, cause: error.localizedDescription) }
case "o": case "o":
origin = record.value origin = record.value
case "m": case "m":
@ -107,7 +107,7 @@ extension ApkIndexPackage {
case "t": case "t":
guard let timet = UInt64(record.value, radix: 10), guard let timet = UInt64(record.value, radix: 10),
let timetInterval = TimeInterval(exactly: timet) else { let timetInterval = TimeInterval(exactly: timet) else {
throw .badValue(key: record.key) throw .badValue(key: record.key, cause: "Invalid build time value")
} }
buildTime = Date(timeIntervalSince1970: timetInterval) buildTime = Date(timeIntervalSince1970: timetInterval)
case "c": case "c":
@ -115,7 +115,7 @@ extension ApkIndexPackage {
case "k": case "k":
guard let value = UInt64(record.value, radix: 10), guard let value = UInt64(record.value, radix: 10),
(0..<UInt64(UInt16.max)).contains(value) else { (0..<UInt64(UInt16.max)).contains(value) else {
throw .badValue(key: record.key) throw .badValue(key: record.key, cause: "Invalid provider priority value")
} }
providerPriority = UInt16(truncatingIfNeeded: value) providerPriority = UInt16(truncatingIfNeeded: value)
case "F", "M", "R", "Z", "r", "q", "a", "s", "f": case "F", "M", "R", "Z", "r", "q", "a", "s", "f":
@ -123,7 +123,7 @@ extension ApkIndexPackage {
default: default:
// Safe to ignore // Safe to ignore
guard record.key.isLowercase else { guard record.key.isLowercase else {
throw .badValue(key: record.key) throw .unexpectedKey(key: record.key)
} }
} }
} }
@ -150,15 +150,15 @@ extension ApkIndexPackage {
} }
public enum ParseError: Error, LocalizedError { public enum ParseError: Error, LocalizedError {
case badValue(key: Character) case badValue(key: Character, cause: String)
case unexpectedKey(key: Character) case unexpectedKey(key: Character)
case required(key: Character) case required(key: Character)
public var errorDescription: String? { public var errorDescription: String? {
switch self { switch self {
case .badValue(let key): "Bad value for key \"\(key)\"" case .badValue(let key, let cause): "Bad value for key \"\(key)\": \(cause)"
case .unexpectedKey(let key): "Unexpected key \"\(key)\"" case .unexpectedKey(let key): "Unexpected key \"\(key)\""
case .required(let key): "Missing required key \"\(key)\"" case .required(let key): "Missing required key \"\(key)\""
} }
} }
} }