-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathZipper.swift
152 lines (125 loc) · 4.51 KB
/
Zipper.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//
// Zipper.swift
// swift-create-xcframework
//
// Created by Rob Amos on 13/5/20.
//
#if canImport(Basics)
import Basics
#endif
import Foundation
#if swift(>=5.6)
import PackageGraph
#endif
import PackageModel
import TSCBasic
import Workspace
struct Zipper {
// MARK: - Properties
let package: PackageInfo
init (package: PackageInfo) {
self.package = package
}
// MARK: - Zippering
func zip (target: String, version: String?, file: Foundation.URL) throws -> Foundation.URL {
let suffix = self.versionSuffix(target: target, default: version) ?? ""
let zipPath = file.path.replacingOccurrences(of: "\\.xcframework$", with: "\(suffix).zip", options: .regularExpression)
let zipURL = URL(fileURLWithPath: zipPath)
let process = TSCBasic.Process (
arguments: self.zipCommand(source: file, target: zipURL),
outputRedirection: .none
)
print("\nPackaging \(file.path) into \(zipURL.path)\n\n")
try process.launch()
let result = try process.waitUntilExit()
switch result.exitStatus {
case let .terminated(code: code):
if code != 0 {
throw XcodeBuilder.Error.nonZeroExit("ditto", code)
}
case let .signalled(signal: signal):
throw XcodeBuilder.Error.signalExit("ditto", signal)
}
return zipURL
}
func checksum (file: Foundation.URL) throws -> Foundation.URL {
#if swift(>=5.7)
let sum = try checksum(forBinaryArtifactAt: AbsolutePath(validating: file.path))
#elseif swift(>=5.6)
let sum = try self.package.workspace.checksum(forBinaryArtifactAt: AbsolutePath(file.path))
#else
let sum = self.package.workspace.checksum(forBinaryArtifactAt: AbsolutePath(file.path), diagnostics: self.package.diagnostics)
#endif
let checksumFile = file.deletingPathExtension().appendingPathExtension("sha256")
try Data(sum.utf8).write(to: checksumFile)
return checksumFile
}
private func zipCommand (source: Foundation.URL, target: Foundation.URL) -> [String] {
return [
"ditto",
"-c",
"-k",
"--keepParent",
source.path,
target.path
]
}
private func versionSuffix (target: String, default fallback: String?) -> String? {
// find the package that contains our target
guard let packageRef = self.package.graph.packages.first(where: { $0.targets.contains(where: { $0.name == target }) }) else { return nil }
#if swift(>=5.6)
guard
let dependency = self.package.workspace.state.dependencies[packageRef.identity],
case let .custom(version, _) = dependency.state
else {
return fallback.flatMap { "-" + $0 }
}
#else
guard
let dependency = self.package.workspace.state.dependencies[forNameOrIdentity: packageRef.packageName],
case let .checkout(checkout) = dependency.state,
let version = checkout.version
else {
return fallback.flatMap { "-" + $0 }
}
#endif
return "-" + version.description
}
// MARK: - Cleaning
func clean (file: Foundation.URL) throws {
try FileManager.default.removeItem(at: file)
}
#if swift(>=5.7)
private func checksum(forBinaryArtifactAt path: TSCBasic.AbsolutePath) throws -> String {
let fileSystem = TSCBasic.localFileSystem
let checksumAlgorithm = SHA256()
let archiver = ZipArchiver(fileSystem: fileSystem)
// Validate the path has a supported extension.
guard let pathExtension = path.extension, archiver.supportedExtensions.contains(pathExtension) else {
let supportedExtensionList = archiver.supportedExtensions.joined(separator: ", ")
throw StringError("unexpected file type; supported extensions are: \(supportedExtensionList)")
}
// Ensure that the path with the accepted extension is a file.
guard fileSystem.isFile(path) else {
throw StringError("file not found at path: \(path.pathString)")
}
let contents = try fileSystem.readFileContents(path)
return checksumAlgorithm.hash(contents).hexadecimalRepresentation
}
#endif
}
#if swift(>=5.6)
// Intentionally left blank
#elseif swift(>=5.5)
private extension ResolvedPackage {
var packageName: String {
self.manifestName
}
}
#else
private extension ResolvedPackage {
var packageName: String {
self.name
}
}
#endif