Revert "Update builder API to use grpc-swift-2. (#1309)" (#1324)

This reverts commit 50900938c4, restoring
the grpc-swift-1 based builder API while preserving build secrets and
hidden docker dir support added in a00ec5c.

Signed-off-by: Eric Ernst <eric_ernst@apple.com>
This commit is contained in:
Eric Ernst
2026-03-18 01:33:21 -07:00
committed by GitHub
parent 9fd15f01bf
commit f8ba57ebd2
15 changed files with 1068 additions and 1435 deletions
+21 -39
View File
@@ -1,5 +1,5 @@
{
"originHash" : "1b173b9865bdf3b1fc4452aff048f169490a36552511ac607718cab6143f161d",
"originHash" : "040dd2e2c8649defb737f900e4032d270935f0af91ebf4a87d64391ecd4ea40b",
"pins" : [
{
"identity" : "async-http-client",
@@ -22,46 +22,28 @@
{
"identity" : "dns",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Bouke/DNS",
"location" : "https://github.com/Bouke/DNS.git",
"state" : {
"revision" : "78bbd1589890a90b202d11d5f9e1297050cf0eb2",
"version" : "1.2.0"
}
},
{
"identity" : "dnsclient",
"kind" : "remoteSourceControl",
"location" : "https://github.com/orlandos-nl/DNSClient.git",
"state" : {
"revision" : "551fbddbf4fa728d4cd86f6a5208fe4f925f0549",
"version" : "2.4.4"
}
},
{
"identity" : "grpc-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-swift.git",
"state" : {
"revision" : "ac715c584bb1e2e5cdfb7684ccb46fab8dafc641",
"version" : "1.27.4"
}
},
{
"identity" : "grpc-swift-2",
"kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-swift-2.git",
"state" : {
"revision" : "f28854bc760a116e053fdfc4a48a9428c34625c0",
"version" : "2.3.0"
}
},
{
"identity" : "grpc-swift-nio-transport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-swift-nio-transport.git",
"state" : {
"revision" : "f37e0c2d293cea668b11e10e1fb1c24cb40781ff",
"version" : "2.4.4"
}
},
{
"identity" : "grpc-swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-swift-protobuf.git",
"state" : {
"revision" : "19153231a03c2fda1f4ea60da1b92a2cb9c011d8",
"version" : "2.2.0"
"revision" : "a56a157218877ef3e9625f7e1f7b2cb7e46ead1b",
"version" : "1.26.1"
}
},
{
@@ -78,8 +60,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "c5d11a805e765f52ba34ec7284bd4fcd6ba68615",
"version" : "1.7.0"
"revision" : "309a47b2b1d9b5e991f36961c983ecec72275be3",
"version" : "1.6.1"
}
},
{
@@ -177,8 +159,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "bbd81b6725ae874c69e9b8c8804d462356b55523",
"version" : "1.10.1"
"revision" : "ce592ae52f982c847a4efc0dd881cc9eb32d29f2",
"version" : "1.6.4"
}
},
{
@@ -240,8 +222,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "86970144a0b86068c81ff48ee29b3f97cae0b879",
"version" : "1.36.0"
"revision" : "102a647b573f60f73afdce5613a51d71349fe507",
"version" : "1.30.0"
}
},
{
@@ -258,8 +240,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "7c6ad0fc39d0763e0b699210e4124afd5041c5df",
"version" : "1.6.4"
"revision" : "890830fff1a577dc83134890c7984020c5f6b43b",
"version" : "1.6.2"
}
},
{
+8 -16
View File
@@ -47,17 +47,16 @@ let package = Package(
.library(name: "TerminalProgress", targets: ["TerminalProgress"]),
],
dependencies: [
.package(url: "https://github.com/Bouke/DNS.git", from: "1.2.0"),
.package(url: "https://github.com/apple/containerization.git", exact: Version(stringLiteral: scVersion)),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.3.0"),
.package(url: "https://github.com/apple/swift-collections.git", from: "1.2.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.80.0"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.36.0"),
.package(url: "https://github.com/apple/swift-system.git", from: "1.6.4"),
.package(url: "https://github.com/Bouke/DNS.git", from: "1.2.0"),
.package(url: "https://github.com/grpc/grpc-swift-2.git", from: "2.3.0"),
.package(url: "https://github.com/grpc/grpc-swift-nio-transport.git", from: "2.4.4"),
.package(url: "https://github.com/grpc/grpc-swift-protobuf.git", from: "2.2.0"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.29.0"),
.package(url: "https://github.com/apple/swift-system.git", from: "1.4.0"),
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.26.0"),
.package(url: "https://github.com/orlandos-nl/DNSClient.git", from: "2.4.1"),
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.20.1"),
.package(url: "https://github.com/swiftlang/swift-docc-plugin.git", from: "1.1.0"),
],
@@ -112,14 +111,10 @@ let package = Package(
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIO", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationArchive", package: "containerization"),
.product(name: "ContainerizationOCI", package: "containerization"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "GRPCCore", package: "grpc-swift-2"),
.product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
.product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
"ContainerAPIClient",
]
),
@@ -138,9 +133,7 @@ let package = Package(
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "ContainerizationEXT4", package: "containerization"),
.product(name: "GRPCCore", package: "grpc-swift-2"),
.product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
.product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
.product(name: "GRPC", package: "grpc-swift"),
.product(name: "Logging", package: "swift-log"),
"ContainerAPIService",
"ContainerAPIClient",
@@ -307,9 +300,7 @@ let package = Package(
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
.product(name: "GRPCCore", package: "grpc-swift-2"),
.product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
.product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
.product(name: "GRPC", package: "grpc-swift"),
.product(name: "Containerization", package: "containerization"),
"ContainerLog",
"ContainerPlugin",
@@ -436,6 +427,7 @@ let package = Package(
dependencies: [
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "DNSClient", package: "DNSClient"),
.product(name: "DNS", package: "DNS"),
.product(name: "Logging", package: "swift-log"),
.product(name: "ContainerizationOS", package: "containerization"),
+2 -2
View File
@@ -37,7 +37,7 @@ $(PROTOC):
.PHONY: protoc-gen-swift
protoc-gen-swift:
@$(SWIFT) build --product protoc-gen-swift
@$(SWIFT) build --product protoc-gen-grpc-swift-2
@$(SWIFT) build --product protoc-gen-grpc-swift
.PHONY: protos
protos: $(PROTOC) protoc-gen-swift
@@ -47,7 +47,7 @@ protos: $(PROTOC) protoc-gen-swift
cd $(LOCAL_DIR) && git clone --branch $(BUILDER_SHIM_VERSION) --depth 1 $(BUILDER_SHIM_REPO); \
fi
@$(PROTOC) $(LOCAL_DIR)/container-builder-shim/pkg/api/Builder.proto \
--plugin=protoc-gen-grpc-swift=$(BUILD_BIN_DIR)/protoc-gen-grpc-swift-2 \
--plugin=protoc-gen-grpc-swift=$(BUILD_BIN_DIR)/protoc-gen-grpc-swift \
--plugin=protoc-gen-swift=$(BUILD_BIN_DIR)/protoc-gen-swift \
--proto_path=$(LOCAL_DIR)/container-builder-shim/pkg/api \
--grpc-swift_out="Sources/ContainerBuild" \
@@ -24,6 +24,10 @@ public typealias ClientStream = Com_Apple_Container_Build_V1_ClientStream
public typealias ServerStream = Com_Apple_Container_Build_V1_ServerStream
public typealias ImageTransfer = Com_Apple_Container_Build_V1_ImageTransfer
public typealias BuildTransfer = Com_Apple_Container_Build_V1_BuildTransfer
public typealias BuilderClient = Com_Apple_Container_Build_V1_BuilderNIOClient
public typealias BuilderClientAsync = Com_Apple_Container_Build_V1_BuilderAsyncClient
public typealias BuilderClientProtocol = Com_Apple_Container_Build_V1_BuilderClientProtocol
public typealias BuilderClientAsyncProtocol = Com_Apple_Container_Build_V1_BuilderAsyncClient
extension BuildTransfer {
func stage() -> String? {
+1 -1
View File
@@ -20,7 +20,7 @@ import ContainerizationArchive
import ContainerizationOCI
import CryptoKit
import Foundation
import GRPCCore
import GRPC
actor BuildFSSync: BuildPipelineHandler {
let contextDir: URL
@@ -18,7 +18,7 @@ import ContainerAPIClient
import Containerization
import ContainerizationOCI
import Foundation
import GRPCCore
import GRPC
import Logging
import TerminalProgress
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import Foundation
import GRPCCore
import GRPC
import NIO
protocol BuildPipelineHandler: Sendable {
@@ -35,10 +35,10 @@ public actor BuildPipeline {
]
}
public func run<S: AsyncSequence & Sendable>(
public func run(
sender: AsyncStream<ClientStream>.Continuation,
receiver: S
) async throws where S.Element == ServerStream {
receiver: GRPCAsyncResponseStream<ServerStream>
) async throws {
defer { sender.finish() }
try await untilFirstError { group in
for try await packet in receiver {
@@ -19,7 +19,7 @@ import Containerization
import ContainerizationArchive
import ContainerizationOCI
import Foundation
import GRPCCore
import GRPC
struct BuildRemoteContentProxy: BuildPipelineHandler {
let local: ContentStore
+1 -1
View File
@@ -16,7 +16,7 @@
import ContainerizationOS
import Foundation
import GRPCCore
import GRPC
import NIO
actor BuildStdio: BuildPipelineHandler {
File diff suppressed because it is too large Load Diff
+104 -33
View File
@@ -24,11 +24,7 @@
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
@@ -217,7 +213,7 @@ public struct Com_Apple_Container_Build_V1_ClientStream: @unchecked Sendable {
/// A unique ID for the build.
public var buildID: String {
get {_storage._buildID}
get {return _storage._buildID}
set {_uniqueStorage()._buildID = newValue}
}
@@ -318,7 +314,7 @@ public struct Com_Apple_Container_Build_V1_RunComplete: Sendable {
public init() {}
}
public struct Com_Apple_Container_Build_V1_BuildTransfer: Sendable {
public struct Com_Apple_Container_Build_V1_BuildTransfer: @unchecked Sendable {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
@@ -332,21 +328,21 @@ public struct Com_Apple_Container_Build_V1_BuildTransfer: Sendable {
/// The absolute path to the source from the server perspective.
public var source: String {
get {_source ?? String()}
get {return _source ?? String()}
set {_source = newValue}
}
/// Returns true if `source` has been explicitly set.
public var hasSource: Bool {self._source != nil}
public var hasSource: Bool {return self._source != nil}
/// Clears the value of `source`. Subsequent reads from it will return its default value.
public mutating func clearSource() {self._source = nil}
/// The absolute path for the destination from the server perspective.
public var destination: String {
get {_destination ?? String()}
get {return _destination ?? String()}
set {_destination = newValue}
}
/// Returns true if `destination` has been explicitly set.
public var hasDestination: Bool {self._destination != nil}
public var hasDestination: Bool {return self._destination != nil}
/// Clears the value of `destination`. Subsequent reads from it will return its default value.
public mutating func clearDestination() {self._destination = nil}
@@ -370,7 +366,7 @@ public struct Com_Apple_Container_Build_V1_BuildTransfer: Sendable {
fileprivate var _destination: String? = nil
}
public struct Com_Apple_Container_Build_V1_ImageTransfer: Sendable {
public struct Com_Apple_Container_Build_V1_ImageTransfer: @unchecked Sendable {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
@@ -387,11 +383,11 @@ public struct Com_Apple_Container_Build_V1_ImageTransfer: Sendable {
/// The descriptor for the image content.
public var descriptor: Com_Apple_Container_Build_V1_Descriptor {
get {_descriptor ?? Com_Apple_Container_Build_V1_Descriptor()}
get {return _descriptor ?? Com_Apple_Container_Build_V1_Descriptor()}
set {_descriptor = newValue}
}
/// Returns true if `descriptor` has been explicitly set.
public var hasDescriptor: Bool {self._descriptor != nil}
public var hasDescriptor: Bool {return self._descriptor != nil}
/// Clears the value of `descriptor`. Subsequent reads from it will return its default value.
public mutating func clearDescriptor() {self._descriptor = nil}
@@ -418,7 +414,7 @@ public struct Com_Apple_Container_Build_V1_ServerStream: @unchecked Sendable {
/// A unique ID for the build.
public var buildID: String {
get {_storage._buildID}
get {return _storage._buildID}
set {_uniqueStorage()._buildID = newValue}
}
@@ -485,7 +481,7 @@ public struct Com_Apple_Container_Build_V1_ServerStream: @unchecked Sendable {
fileprivate var _storage = _StorageClass.defaultInstance
}
public struct Com_Apple_Container_Build_V1_IO: Sendable {
public struct Com_Apple_Container_Build_V1_IO: @unchecked Sendable {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
@@ -555,11 +551,11 @@ public struct Com_Apple_Container_Build_V1_Descriptor: Sendable {
public var annotations: Dictionary<String,String> = [:]
public var platform: Com_Apple_Container_Build_V1_Platform {
get {_platform ?? Com_Apple_Container_Build_V1_Platform()}
get {return _platform ?? Com_Apple_Container_Build_V1_Platform()}
set {_platform = newValue}
}
/// Returns true if `platform` has been explicitly set.
public var hasPlatform: Bool {self._platform != nil}
public var hasPlatform: Bool {return self._platform != nil}
/// Clears the value of `platform`. Subsequent reads from it will return its default value.
public mutating func clearPlatform() {self._platform = nil}
@@ -575,15 +571,25 @@ public struct Com_Apple_Container_Build_V1_Descriptor: Sendable {
fileprivate let _protobuf_package = "com.apple.container.build.v1"
extension Com_Apple_Container_Build_V1_TransferDirection: SwiftProtobuf._ProtoNameProviding {
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0INTO\0\u{1}OUTOF\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "INTO"),
1: .same(proto: "OUTOF"),
]
}
extension Com_Apple_Container_Build_V1_Stdio: SwiftProtobuf._ProtoNameProviding {
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0STDIN\0\u{1}STDOUT\0\u{1}STDERR\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "STDIN"),
1: .same(proto: "STDOUT"),
2: .same(proto: "STDERR"),
]
}
extension Com_Apple_Container_Build_V1_BuildErrorType: SwiftProtobuf._ProtoNameProviding {
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0BUILD_FAILED\0\u{1}INTERNAL\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "BUILD_FAILED"),
1: .same(proto: "INTERNAL"),
]
}
extension Com_Apple_Container_Build_V1_InfoRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
@@ -626,7 +632,13 @@ extension Com_Apple_Container_Build_V1_InfoResponse: SwiftProtobuf.Message, Swif
extension Com_Apple_Container_Build_V1_CreateBuildRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".CreateBuildRequest"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}stage_name\0\u{1}tag\0\u{1}metadata\0\u{3}build_args\0\u{1}debug\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "stage_name"),
2: .same(proto: "tag"),
3: .same(proto: "metadata"),
4: .standard(proto: "build_args"),
5: .same(proto: "debug"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -676,7 +688,10 @@ extension Com_Apple_Container_Build_V1_CreateBuildRequest: SwiftProtobuf.Message
extension Com_Apple_Container_Build_V1_CreateBuildResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".CreateBuildResponse"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}build_id\0\u{1}metadata\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "build_id"),
2: .same(proto: "metadata"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -711,7 +726,13 @@ extension Com_Apple_Container_Build_V1_CreateBuildResponse: SwiftProtobuf.Messag
extension Com_Apple_Container_Build_V1_ClientStream: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".ClientStream"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}build_id\0\u{1}signal\0\u{1}command\0\u{3}build_transfer\0\u{3}image_transfer\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "build_id"),
2: .same(proto: "signal"),
3: .same(proto: "command"),
4: .standard(proto: "build_transfer"),
5: .standard(proto: "image_transfer"),
]
fileprivate class _StorageClass {
var _buildID: String = String()
@@ -855,7 +876,9 @@ extension Com_Apple_Container_Build_V1_ClientStream: SwiftProtobuf.Message, Swif
extension Com_Apple_Container_Build_V1_Signal: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".Signal"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}signal\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "signal"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -885,7 +908,10 @@ extension Com_Apple_Container_Build_V1_Signal: SwiftProtobuf.Message, SwiftProto
extension Com_Apple_Container_Build_V1_Run: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".Run"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}id\0\u{1}command\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "id"),
2: .same(proto: "command"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -920,7 +946,9 @@ extension Com_Apple_Container_Build_V1_Run: SwiftProtobuf.Message, SwiftProtobuf
extension Com_Apple_Container_Build_V1_RunComplete: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".RunComplete"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}id\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "id"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -950,7 +978,16 @@ extension Com_Apple_Container_Build_V1_RunComplete: SwiftProtobuf.Message, Swift
extension Com_Apple_Container_Build_V1_BuildTransfer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".BuildTransfer"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}id\0\u{1}direction\0\u{1}source\0\u{1}destination\0\u{1}data\0\u{1}complete\0\u{3}is_directory\0\u{1}metadata\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "id"),
2: .same(proto: "direction"),
3: .same(proto: "source"),
4: .same(proto: "destination"),
5: .same(proto: "data"),
6: .same(proto: "complete"),
7: .standard(proto: "is_directory"),
8: .same(proto: "metadata"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -1019,7 +1056,15 @@ extension Com_Apple_Container_Build_V1_BuildTransfer: SwiftProtobuf.Message, Swi
extension Com_Apple_Container_Build_V1_ImageTransfer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".ImageTransfer"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}id\0\u{1}direction\0\u{1}tag\0\u{1}descriptor\0\u{1}data\0\u{1}complete\0\u{1}metadata\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "id"),
2: .same(proto: "direction"),
3: .same(proto: "tag"),
4: .same(proto: "descriptor"),
5: .same(proto: "data"),
6: .same(proto: "complete"),
7: .same(proto: "metadata"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -1083,7 +1128,14 @@ extension Com_Apple_Container_Build_V1_ImageTransfer: SwiftProtobuf.Message, Swi
extension Com_Apple_Container_Build_V1_ServerStream: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".ServerStream"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}build_id\0\u{1}io\0\u{3}build_error\0\u{3}command_complete\0\u{3}build_transfer\0\u{3}image_transfer\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "build_id"),
2: .same(proto: "io"),
3: .standard(proto: "build_error"),
4: .standard(proto: "command_complete"),
5: .standard(proto: "build_transfer"),
6: .standard(proto: "image_transfer"),
]
fileprivate class _StorageClass {
var _buildID: String = String()
@@ -1244,7 +1296,10 @@ extension Com_Apple_Container_Build_V1_ServerStream: SwiftProtobuf.Message, Swif
extension Com_Apple_Container_Build_V1_IO: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".IO"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}type\0\u{1}data\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "type"),
2: .same(proto: "data"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -1279,7 +1334,10 @@ extension Com_Apple_Container_Build_V1_IO: SwiftProtobuf.Message, SwiftProtobuf.
extension Com_Apple_Container_Build_V1_BuildError: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".BuildError"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}type\0\u{1}message\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "type"),
2: .same(proto: "message"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -1314,7 +1372,13 @@ extension Com_Apple_Container_Build_V1_BuildError: SwiftProtobuf.Message, SwiftP
extension Com_Apple_Container_Build_V1_Platform: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".Platform"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}architecture\0\u{1}os\0\u{3}os_version\0\u{3}os_features\0\u{1}variant\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "architecture"),
2: .same(proto: "os"),
3: .standard(proto: "os_version"),
4: .standard(proto: "os_features"),
5: .same(proto: "variant"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
@@ -1364,7 +1428,14 @@ extension Com_Apple_Container_Build_V1_Platform: SwiftProtobuf.Message, SwiftPro
extension Com_Apple_Container_Build_V1_Descriptor: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".Descriptor"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}media_type\0\u{1}digest\0\u{1}size\0\u{1}urls\0\u{1}annotations\0\u{1}platform\0")
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "media_type"),
2: .same(proto: "digest"),
3: .same(proto: "size"),
4: .same(proto: "urls"),
5: .same(proto: "annotations"),
6: .same(proto: "platform"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
+81 -148
View File
@@ -19,72 +19,58 @@ import Containerization
import ContainerizationOCI
import ContainerizationOS
import Foundation
import GRPCCore
import GRPCNIOTransportHTTP2
import Logging
import GRPC
import NIO
import NIOCore
import NIOHPACK
import NIOHTTP2
import NIOPosix
public struct Builder: Sendable {
public static let builderContainerId = "buildkit"
let client: Com_Apple_Container_Build_V1_Builder.Client<HTTP2ClientTransport.WrappedChannel>
let grpcClient: GRPCClient<HTTP2ClientTransport.WrappedChannel>
let client: BuilderClientProtocol
let clientAsync: BuilderClientAsyncProtocol
let group: EventLoopGroup
let builderShimSocket: FileHandle
let clientTask: Task<Void, any Swift.Error>
let logger: Logger
let channel: GRPCChannel
public init(socket: FileHandle, group: EventLoopGroup, logger: Logger) throws {
public init(socket: FileHandle, group: EventLoopGroup) throws {
try socket.setSendBufSize(4 << 20)
try socket.setRecvBufSize(2 << 20)
let channel = try ClientBootstrap(group: group)
.channelInitializer { channel in
channel.eventLoop.makeCompletedFuture(withResultOf: {
try channel.pipeline.syncOperations.addHandler(HTTP2ConnectBufferingHandler())
})
}
.withConnectedSocket(socket.fileDescriptor)
.wait()
let transport = HTTP2ClientTransport.WrappedChannel.wrapping(
channel: channel
var config = ClientConnection.Configuration.default(
target: .connectedSocket(socket.fileDescriptor),
eventLoopGroup: group
)
config.connectionIdleTimeout = TimeAmount(.seconds(600))
config.connectionKeepalive = .init(
interval: TimeAmount(.seconds(600)),
timeout: TimeAmount(.seconds(500)),
permitWithoutCalls: true
)
config.connectionBackoff = .init(
initialBackoff: TimeInterval(1),
maximumBackoff: TimeInterval(10)
)
config.callStartBehavior = .fastFailure
config.httpMaxFrameSize = 8 << 10
config.maximumReceiveMessageLength = 512 << 20
config.httpTargetWindowSize = 16 << 10
let grpcClient = GRPCClient(transport: transport)
self.grpcClient = grpcClient
self.client = Com_Apple_Container_Build_V1_Builder.Client(wrapping: grpcClient)
let channel = ClientConnection(configuration: config)
self.channel = channel
self.clientAsync = BuilderClientAsync(channel: channel)
self.client = BuilderClient(channel: channel)
self.group = group
self.builderShimSocket = socket
self.logger = logger
}
// Start the client connection loop in a background task
self.clientTask = Task {
do {
try await grpcClient.runConnections()
} catch is CancellationError {
// Expected during graceful shutdown - re-throw
throw CancellationError()
} catch let error as RPCError where error.code == .unavailable {
// Connection closed - this is expected when the container stops
logger.debug("gRPC connection closed: \(error)")
throw error
} catch {
// Log unexpected connection errors
logger.error("gRPC client connection error: \(error)")
throw error
}
}
public func info() throws -> InfoResponse {
let resp = self.client.info(InfoRequest(), callOptions: CallOptions())
return try resp.response.wait()
}
public func info() async throws -> InfoResponse {
var opts = CallOptions.defaults
opts.timeout = .seconds(30)
return try await self.client.info(InfoRequest(), options: opts)
let opts = CallOptions(timeLimit: .timeout(.seconds(30)))
return try await self.clientAsync.info(InfoRequest(), callOptions: opts)
}
// TODO
@@ -133,23 +119,12 @@ public struct Builder: Sendable {
}
}
let respStream = self.clientAsync.performBuild(reqStream, callOptions: try CallOptions(config))
let pipeline = try await BuildPipeline(config)
do {
try await self.client.performBuild(
metadata: try Self.buildMetadata(config),
options: .defaults,
requestProducer: { writer in
for await message in reqStream {
try await writer.write(message)
}
},
onResponse: { response in
try await pipeline.run(sender: continuation, receiver: response.messages)
}
)
try await pipeline.run(sender: continuation, receiver: respStream)
} catch Error.buildComplete {
self.grpcClient.beginGracefulShutdown()
self.clientTask.cancel()
_ = channel.close()
try await group.shutdownGracefully()
return
}
@@ -320,48 +295,6 @@ public struct Builder: Sendable {
self.pull = pull
}
}
static func buildMetadata(_ config: BuildConfig) throws -> Metadata {
var metadata = Metadata()
metadata.addString(config.buildID, forKey: "build-id")
metadata.addString(URL(filePath: config.contextDir).path(percentEncoded: false), forKey: "context")
metadata.addString(config.dockerfile.base64EncodedString(), forKey: "dockerfile")
metadata.addString(config.terminal != nil ? "tty" : "plain", forKey: "progress")
metadata.addString(config.target, forKey: "target")
if let hiddenDockerDir = config.hiddenDockerDir {
metadata.addString(hiddenDockerDir, forKey: "hidden-docker-dir")
}
for tag in config.tags {
metadata.addString(tag, forKey: "tag")
}
for platform in config.platforms {
metadata.addString(platform.description, forKey: "platforms")
}
if config.noCache {
metadata.addString("", forKey: "no-cache")
}
for label in config.labels {
metadata.addString(label, forKey: "labels")
}
for buildArg in config.buildArgs {
metadata.addString(buildArg, forKey: "build-args")
}
for (id, data) in config.secrets {
metadata.addString(id + "=" + data.base64EncodedString(), forKey: "secrets")
}
for output in config.exports {
metadata.addString(try output.stringValue, forKey: "outputs")
}
for cacheIn in config.cacheIn {
metadata.addString(cacheIn, forKey: "cache-in")
}
for cacheOut in config.cacheOut {
metadata.addString(cacheOut, forKey: "cache-out")
}
return metadata
}
}
extension Builder {
@@ -383,6 +316,52 @@ extension Builder {
}
}
extension CallOptions {
public init(_ config: Builder.BuildConfig) throws {
var headers: [(String, String)] = [
("build-id", config.buildID),
("context", URL(filePath: config.contextDir).path(percentEncoded: false)),
("dockerfile", config.dockerfile.base64EncodedString()),
("progress", config.terminal != nil ? "tty" : "plain"),
("target", config.target),
]
if let hiddenDockerDir = config.hiddenDockerDir {
headers.append(("hidden-docker-dir", hiddenDockerDir))
}
for tag in config.tags {
headers.append(("tag", tag))
}
for platform in config.platforms {
headers.append(("platforms", platform.description))
}
if config.noCache {
headers.append(("no-cache", ""))
}
for label in config.labels {
headers.append(("labels", label))
}
for buildArg in config.buildArgs {
headers.append(("build-args", buildArg))
}
for (id, data) in config.secrets {
headers.append(("secrets", id + "=" + data.base64EncodedString()))
}
for output in config.exports {
headers.append(("outputs", try output.stringValue))
}
for cacheIn in config.cacheIn {
headers.append(("cache-in", cacheIn))
}
for cacheOut in config.cacheOut {
headers.append(("cache-out", cacheOut))
}
self.init(
customMetadata: HPACKHeaders(headers)
)
}
}
extension FileHandle {
@discardableResult
func setSendBufSize(_ bytes: Int) throws -> Int {
@@ -425,49 +404,3 @@ extension FileHandle {
}
}
}
/// Buffers incoming bytes until the full gRPC HTTP/2 pipeline is configured, then replays them.
///
/// See the equivalent in Containerization/Vminitd.swift for a full explanation.
private final class HTTP2ConnectBufferingHandler: ChannelDuplexHandler, RemovableChannelHandler {
typealias InboundIn = ByteBuffer
typealias InboundOut = ByteBuffer
typealias OutboundIn = ByteBuffer
typealias OutboundOut = ByteBuffer
private var removalScheduled = false
private var bufferedReads: [NIOAny] = []
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
bufferedReads.append(data)
}
func channelReadComplete(context: ChannelHandlerContext) {}
func flush(context: ChannelHandlerContext) {
if !removalScheduled {
removalScheduled = true
context.eventLoop.assumeIsolatedUnsafeUnchecked().execute {
context.pipeline.syncOperations.removeHandler(self, promise: nil)
}
}
context.flush()
}
func removeHandler(context: ChannelHandlerContext, removalToken: ChannelHandlerContext.RemovalToken) {
var didRead = false
while !bufferedReads.isEmpty {
context.fireChannelRead(bufferedReads.removeFirst())
didRead = true
}
if didRead {
context.fireChannelReadComplete()
}
context.leavePipeline(removalToken: removalToken)
}
func channelInactive(context: ChannelHandlerContext) {
bufferedReads.removeAll()
context.fireChannelInactive()
}
}
+1 -1
View File
@@ -176,7 +176,7 @@ extension Application {
let fh = try await client.dial(id: "buildkit", port: vsockPort)
let threadGroup: MultiThreadedEventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
let b = try Builder(socket: fh, group: threadGroup, logger: log)
let b = try Builder(socket: fh, group: threadGroup)
// If this call succeeds, then BuildKit is running.
let _ = try await b.info()
+9 -20
View File
@@ -46,42 +46,31 @@ public struct StderrLogHandler: LogHandler {
let data: Data
switch logLevel {
case .debug, .trace:
let timestamp = isoTimestamp()
let timestamp = ISO8601DateFormatter().string(from: Date())
if let metadata, !metadata.isEmpty {
data =
"\(timestamp) \(message.description): \(metadata.description)\n"
"\(timestamp) \(message.description): \(metadata.description)"
.data(using: .utf8) ?? Data()
} else {
data =
"\(timestamp) \(message.description)\n"
"\(timestamp) \(message.description)"
.data(using: .utf8) ?? Data()
}
default:
if let metadata, !metadata.isEmpty {
data =
"\(message.description): \(metadata.description)\n"
"\(message.description): \(metadata.description)"
.data(using: .utf8) ?? Data()
} else {
data =
"\(message.description)\n"
message.description
.data(using: .utf8) ?? Data()
}
}
FileHandle.standardError.write(data)
}
private func isoTimestamp() -> String {
let date = Date()
var time = time_t(date.timeIntervalSince1970)
var ms = Int(date.timeIntervalSince1970 * 1000) % 1000
if ms < 0 { ms += 1000 }
var tm = tm()
gmtime_r(&time, &tm)
let buf = withUnsafeTemporaryAllocation(of: CChar.self, capacity: 32) { ptr -> String in
strftime(ptr.baseAddress!, 32, "%Y-%m-%dT%H:%M:%S", &tm)
return String(cString: ptr.baseAddress!)
}
return String(format: "%@.%03dZ", buf, ms)
// Use a single write call for atomicity
var output = data
output.append("\n".data(using: .utf8)!)
FileHandle.standardError.write(output)
}
}
+1 -1
View File
@@ -17,6 +17,6 @@ if command -v .local/bin/hawkeye >/dev/null 2>&1; then
echo "hawkeye already installed"
else
echo "Installing hawkeye"
export VERSION=v6.5.1
export VERSION=v6.1.0
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/korandoru/hawkeye/releases/download/${VERSION}/hawkeye-installer.sh | CARGO_HOME=.local sh -s -- --no-modify-path
fi