forked from Carthage/Carthage
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BinaryProject.swift
70 lines (60 loc) · 2.3 KB
/
BinaryProject.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import Foundation
import Result
/// Represents a binary dependency
public struct BinaryProject: Equatable {
private static let jsonDecoder = JSONDecoder()
public var versions: [PinnedVersion: [URL]]
public static func from(jsonData: Data) -> Result<BinaryProject, BinaryJSONError> {
return Result<[String: String], AnyError>(attempt: { try jsonDecoder.decode([String: String].self, from: jsonData) })
.mapError { .invalidJSON($0.error) }
.flatMap { json -> Result<BinaryProject, BinaryJSONError> in
var versions = [PinnedVersion: [URL]]()
for (key, value) in json {
let pinnedVersion: PinnedVersion
switch SemanticVersion.from(Scanner(string: key)) {
case .success:
pinnedVersion = PinnedVersion(key)
case let .failure(error):
return .failure(BinaryJSONError.invalidVersion(error))
}
guard var components = URLComponents(string: value) else {
return .failure(BinaryJSONError.invalidURL(value))
}
struct ExtractedURLs {
var remainingQueryItems: [URLQueryItem]? = nil
var urlStrings: [String] = []
}
let extractedURLs = components.queryItems?.reduce(into: ExtractedURLs()) { state, item in
if item.name == "alt", let value = item.value {
state.urlStrings.append(value)
} else if state.remainingQueryItems == nil {
state.remainingQueryItems = [item]
} else {
state.remainingQueryItems!.append(item)
}
}
components.queryItems = extractedURLs?.remainingQueryItems
guard let firstURL = components.url else {
return .failure(BinaryJSONError.invalidURL(value))
}
guard firstURL.scheme == "file" || firstURL.scheme == "https" else {
return .failure(BinaryJSONError.nonHTTPSURL(firstURL))
}
var binaryURLs: [URL] = [firstURL]
if let extractedURLs = extractedURLs {
for string in extractedURLs.urlStrings {
guard let binaryURL = URL(string: string) else {
return .failure(BinaryJSONError.invalidURL(string))
}
guard binaryURL.scheme == "file" || binaryURL.scheme == "https" else {
return .failure(BinaryJSONError.nonHTTPSURL(binaryURL))
}
binaryURLs.append(binaryURL)
}
}
versions[pinnedVersion] = binaryURLs
}
return .success(BinaryProject(versions: versions))
}
}
}