Skip to content

Commit f120d30

Browse files
committed
Speed up build-context archiving
1 parent 7f7ae0e commit f120d30

3 files changed

Lines changed: 290 additions & 126 deletions

File tree

Sources/ContainerBuild/BuildFSSync.swift

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import Foundation
2323
import GRPC
2424

2525
actor BuildFSSync: BuildPipelineHandler {
26+
private static let archiveRootURL = URL(filePath: "/", directoryHint: .isDirectory)
27+
2628
let contextDir: URL
2729

2830
init(_ contextDir: URL) throws {
@@ -114,7 +116,6 @@ actor BuildFSSync: BuildPipelineHandler {
114116
}
115117

116118
private struct DirEntry: Hashable {
117-
let url: URL
118119
let isDirectory: Bool
119120
let relativePath: String
120121

@@ -133,30 +134,32 @@ actor BuildFSSync: BuildPipelineHandler {
133134
_ buildID: String
134135
) async throws {
135136
let wantsTar = packet.mode() == "tar"
137+
let contextPath = contextDir.path
138+
let contextPrefix = contextPath.hasSuffix("/") ? contextPath : contextPath + "/"
136139

137140
var entries: [String: Set<DirEntry>] = [:]
138141
let followPaths: [String] = packet.followPaths() ?? []
139142

140143
let followPathsWalked = try walk(root: self.contextDir, includePatterns: followPaths)
141144
for url in followPathsWalked {
142-
guard self.contextDir.absoluteURL.cleanPath != url.absoluteURL.cleanPath else {
145+
let path = url.path
146+
guard path != contextPath else {
143147
continue
144148
}
145-
guard self.contextDir.parentOf(url) else {
149+
guard let relPath = Self.relativeChildPath(path: path, contextPath: contextPath, contextPrefix: contextPrefix) else {
146150
continue
147151
}
148152

149-
let relPath = try url.relativeChildPath(to: contextDir)
150-
let parentPath = try url.deletingLastPathComponent().relativeChildPath(to: contextDir)
151-
let entry = DirEntry(url: url, isDirectory: url.hasDirectoryPath, relativePath: relPath)
153+
let parentPath = Self.relativeParentPath(path: path, contextPath: contextPath, contextPrefix: contextPrefix)
154+
let entry = DirEntry(isDirectory: url.hasDirectoryPath, relativePath: relPath)
152155
entries[parentPath, default: []].insert(entry)
153156

154157
if url.isSymlink {
155158
let target: URL = url.resolvingSymlinksInPath()
156-
if self.contextDir.parentOf(target) {
157-
let relPath = try target.relativeChildPath(to: self.contextDir)
158-
let entry = DirEntry(url: target, isDirectory: target.hasDirectoryPath, relativePath: relPath)
159-
let parentPath: String = try target.deletingLastPathComponent().relativeChildPath(to: self.contextDir)
159+
let targetPath = target.path
160+
if let relPath = Self.relativeChildPath(path: targetPath, contextPath: contextPath, contextPrefix: contextPrefix) {
161+
let entry = DirEntry(isDirectory: target.hasDirectoryPath, relativePath: relPath)
162+
let parentPath = Self.relativeParentPath(path: targetPath, contextPath: contextPath, contextPrefix: contextPrefix)
160163
entries[parentPath, default: []].insert(entry)
161164
}
162165
}
@@ -200,35 +203,18 @@ actor BuildFSSync: BuildPipelineHandler {
200203
format: .paxRestricted,
201204
filter: .none)
202205

206+
let archiveEntries = fileOrder.map { rel in
207+
Archiver.ArchiveEntryInfo(
208+
pathOnHost: contextDir.appending(path: rel, directoryHint: .notDirectory),
209+
pathInArchive: URL(filePath: rel, directoryHint: .notDirectory, relativeTo: Self.archiveRootURL)
210+
)
211+
}
212+
203213
let tarHash = try Archiver.compress(
204-
source: contextDir,
214+
entries: archiveEntries,
205215
destination: tarURL,
206216
writerConfiguration: writerCfg
207-
) { url in
208-
guard let rel = try? url.relativeChildPath(to: contextDir) else {
209-
return nil
210-
}
211-
212-
guard let parent = try? url.deletingLastPathComponent().relativeChildPath(to: self.contextDir) else {
213-
return nil
214-
}
215-
216-
guard let items = entries[parent] else {
217-
return nil
218-
}
219-
220-
let include = items.contains { item in
221-
item.relativePath == rel
222-
}
223-
224-
guard include else {
225-
return nil
226-
}
227-
228-
return Archiver.ArchiveEntryInfo(
229-
pathOnHost: url,
230-
pathInArchive: URL(fileURLWithPath: rel))
231-
}
217+
)
232218

233219
let hash = tarHash.compactMap { String(format: "%02x", $0) }.joined()
234220
let header = BuildTransfer(
@@ -323,6 +309,21 @@ actor BuildFSSync: BuildPipelineHandler {
323309
}
324310
}
325311

312+
private static func relativeChildPath(path: String, contextPath: String, contextPrefix: String) -> String? {
313+
if path == contextPath {
314+
return ""
315+
}
316+
guard path.hasPrefix(contextPrefix) else {
317+
return nil
318+
}
319+
return String(path.dropFirst(contextPrefix.count))
320+
}
321+
322+
private static func relativeParentPath(path: String, contextPath: String, contextPrefix: String) -> String {
323+
let parentPath = (path as NSString).deletingLastPathComponent
324+
return relativeChildPath(path: parentPath, contextPath: contextPath, contextPrefix: contextPrefix) ?? ""
325+
}
326+
326327
struct FileInfo: Codable {
327328
let name: String
328329
let modTime: String

0 commit comments

Comments
 (0)