Reorganize client libraries. (#1020)

- Closes #461.
- Extract core types into ContainerResources target.
- Extract ContainerNetworkServiceClient from ContainerNetworkService.
- Relocate sandbox client from ContainerClient to
ContainerSandboxServiceClient.
- Relocate ContainerClient to ContainerAPIServiceClient.
- Common structure from services and clients under Source/Services.

Updated project hierarchy:

```
Sources/CAuditToken - audit token access wrapper
Sources/CLI - CLI executable
Sources/ContainerBuild - builder
Sources/ContainerCommands - CLI command implementations
Sources/ContainerLog - logging helpers
Sources/ContainerPersistence - persistent data and system property helpers
Sources/ContainerPlugin - plugin system
Sources/ContainerResource - resource (container, image, volume, network) types
Sources/ContainerVersion - version helpers
Sources/ContainerXPC - XPC helpers
Sources/CVersion - injected project version
Sources/DNSServer - container DNS resolver
Sources/Helpers - service executables
Sources/Services/*/Client - service clients
Sources/Services/*/Server - service implementations
Sources/SocketForwarder - port forwarding
Sources/TerminalProgress - progress bar
```

## Type of Change
- [ ] Bug fix
- [ ] New feature  
- [x] Breaking change
- [ ] Documentation update

## Motivation and Context
The ContainerClient library was a bit of a grab bag. This refactor
applies a more sensible project and library structure for resource data
types, services, and clients.

## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
This commit is contained in:
J Logan
2026-01-06 08:27:14 -08:00
committed by GitHub
parent 8c439cd356
commit 356c8d2f88
165 changed files with 643 additions and 472 deletions
+6 -1
View File
@@ -3,10 +3,15 @@ builder:
configs:
-
documentation_targets:
- ContainerAPIService
- ContainerAPIClient
- ContainerSandboxService
- ContainerSandboxServiceClient
- ContainerNetworkService
- ContainerNetworkServiceClient
- ContainerImagesService
- ContainerClient
- ContainerImagesServiceClient
- ContainerResource
- ContainerLog
- ContainerPlugin
- ContainerXPC
+162 -116
View File
@@ -29,13 +29,14 @@ let package = Package(
name: "container",
platforms: [.macOS("15")],
products: [
.library(name: "ContainerAPIService", targets: ["ContainerAPIService"]),
.library(name: "ContainerSandboxService", targets: ["ContainerSandboxService"]),
.library(name: "ContainerNetworkService", targets: ["ContainerNetworkService"]),
.library(name: "ContainerImagesService", targets: ["ContainerImagesService", "ContainerImagesServiceClient"]),
.library(name: "ContainerCommands", targets: ["ContainerCommands"]),
.library(name: "ContainerClient", targets: ["ContainerClient"]),
.library(name: "ContainerBuild", targets: ["ContainerBuild"]),
.library(name: "ContainerAPIService", targets: ["ContainerAPIService"]),
.library(name: "ContainerAPIClient", targets: ["ContainerAPIClient"]),
.library(name: "ContainerImagesService", targets: ["ContainerImagesService", "ContainerImagesServiceClient"]),
.library(name: "ContainerNetworkService", targets: ["ContainerNetworkService", "ContainerNetworkServiceClient"]),
.library(name: "ContainerSandboxService", targets: ["ContainerSandboxService", "ContainerSandboxServiceClient"]),
.library(name: "ContainerResource", targets: ["ContainerResource"]),
.library(name: "ContainerLog", targets: ["ContainerLog"]),
.library(name: "ContainerPersistence", targets: ["ContainerPersistence"]),
.library(name: "ContainerPlugin", targets: ["ContainerPlugin"]),
@@ -61,11 +62,23 @@ let package = Package(
name: "container",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
"ContainerClient",
"ContainerAPIClient",
"ContainerCommands",
],
path: "Sources/CLI"
),
.testTarget(
name: "CLITests",
dependencies: [
.product(name: "AsyncHTTPClient", package: "async-http-client"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
"ContainerBuild",
"ContainerResource",
],
path: "Tests/CLITests"
),
.target(
name: "ContainerCommands",
dependencies: [
@@ -76,15 +89,34 @@ let package = Package(
.product(name: "ContainerizationOCI", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
"ContainerBuild",
"ContainerClient",
"ContainerAPIClient",
"ContainerLog",
"ContainerPersistence",
"ContainerPlugin",
"ContainerResource",
"ContainerVersion",
"TerminalProgress",
],
path: "Sources/ContainerCommands"
),
.target(
name: "ContainerBuild",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIO", 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"),
"ContainerAPIClient",
]
),
.testTarget(
name: "ContainerBuildTests",
dependencies: [
"ContainerBuild"
]
),
.executableTarget(
name: "container-apiserver",
dependencies: [
@@ -96,11 +128,12 @@ let package = Package(
.product(name: "GRPC", package: "grpc-swift"),
.product(name: "Logging", package: "swift-log"),
"ContainerAPIService",
"ContainerClient",
"ContainerAPIClient",
"ContainerLog",
"ContainerNetworkService",
"ContainerPersistence",
"ContainerPlugin",
"ContainerResource",
"ContainerVersion",
"ContainerXPC",
"DNSServer",
@@ -111,83 +144,49 @@ let package = Package(
name: "ContainerAPIService",
dependencies: [
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationArchive", package: "containerization"),
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "Logging", package: "swift-log"),
"ContainerClient",
"ContainerNetworkService",
"CVersion",
"ContainerAPIClient",
"ContainerNetworkServiceClient",
"ContainerPersistence",
"ContainerPlugin",
"ContainerSandboxService",
"ContainerResource",
"ContainerSandboxServiceClient",
"ContainerVersion",
"ContainerXPC",
"CVersion",
"TerminalProgress",
],
path: "Sources/Services/ContainerAPIService"
),
.executableTarget(
name: "container-runtime-linux",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
.product(name: "GRPC", package: "grpc-swift"),
.product(name: "Containerization", package: "containerization"),
"ContainerLog",
"ContainerNetworkService",
"ContainerSandboxService",
"ContainerVersion",
"ContainerXPC",
],
path: "Sources/Helpers/RuntimeLinux"
path: "Sources/Services/ContainerAPIService/Server"
),
.target(
name: "ContainerSandboxService",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
"ContainerClient",
"ContainerNetworkService",
"ContainerPersistence",
"ContainerXPC",
"SocketForwarder",
],
path: "Sources/Services/ContainerSandboxService"
),
.executableTarget(
name: "container-network-vmnet",
name: "ContainerAPIClient",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationIO", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
"ContainerLog",
"ContainerNetworkService",
"ContainerVersion",
"ContainerXPC",
],
path: "Sources/Helpers/NetworkVmnet"
),
.target(
name: "ContainerNetworkService",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationArchive", package: "containerization"),
.product(name: "ContainerizationOCI", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
"ContainerImagesServiceClient",
"ContainerPersistence",
"ContainerPlugin",
"ContainerResource",
"ContainerXPC",
"TerminalProgress",
],
path: "Sources/Services/ContainerNetworkService"
path: "Sources/Services/ContainerAPIService/Client"
),
.testTarget(
name: "ContainerNetworkServiceTests",
name: "ContainerAPIClientTests",
dependencies: [
"ContainerNetworkService"
.product(name: "Containerization", package: "containerization"),
"ContainerAPIClient",
"ContainerPersistence",
]
),
.executableTarget(
@@ -209,10 +208,17 @@ let package = Package(
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Containerization", package: "containerization"),
"ContainerXPC",
"ContainerLog",
"ContainerClient",
.product(name: "ContainerizationArchive", package: "containerization"),
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationOCI", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
"ContainerAPIClient",
"ContainerImagesServiceClient",
"ContainerLog",
"ContainerPersistence",
"ContainerResource",
"ContainerXPC",
"TerminalProgress",
],
path: "Sources/Services/ContainerImagesService/Server"
),
@@ -226,48 +232,107 @@ let package = Package(
],
path: "Sources/Services/ContainerImagesService/Client"
),
.target(
name: "ContainerBuild",
.executableTarget(
name: "container-network-vmnet",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIO", 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"),
"ContainerClient",
]
),
.testTarget(
name: "ContainerBuildTests",
dependencies: [
"ContainerBuild"
]
),
.target(
name: "ContainerClient",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationOCI", package: "containerization"),
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationIO", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "ContainerizationArchive", package: "containerization"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
"ContainerImagesServiceClient",
"ContainerLog",
"ContainerNetworkService",
"ContainerPlugin",
"ContainerNetworkServiceClient",
"ContainerResource",
"ContainerVersion",
"ContainerXPC",
"TerminalProgress",
],
path: "Sources/Helpers/NetworkVmnet"
),
.target(
name: "ContainerNetworkService",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
"ContainerNetworkServiceClient",
"ContainerPersistence",
"ContainerResource",
"ContainerXPC",
],
path: "Sources/Services/ContainerNetworkService/Server"
),
.target(
name: "ContainerNetworkServiceClient",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Containerization", package: "containerization"),
"ContainerLog",
"ContainerResource",
"ContainerXPC",
],
path: "Sources/Services/ContainerNetworkService/Client"
),
.executableTarget(
name: "container-runtime-linux",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
.product(name: "GRPC", package: "grpc-swift"),
.product(name: "Containerization", package: "containerization"),
"ContainerLog",
"ContainerResource",
"ContainerSandboxService",
"ContainerSandboxServiceClient",
"ContainerVersion",
"ContainerXPC",
],
path: "Sources/Helpers/RuntimeLinux"
),
.target(
name: "ContainerSandboxService",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
"ContainerAPIClient",
"ContainerNetworkServiceClient",
"ContainerPersistence",
"ContainerResource",
"ContainerSandboxServiceClient",
"ContainerXPC",
"SocketForwarder",
],
path: "Sources/Services/ContainerSandboxService/Server"
),
.target(
name: "ContainerSandboxServiceClient",
dependencies: [
"ContainerResource",
"ContainerXPC",
],
path: "Sources/Services/ContainerSandboxService/Client"
),
.target(
name: "ContainerResource",
dependencies: [
.product(name: "Containerization", package: "containerization")
]
),
.testTarget(
name: "ContainerClientTests",
name: "ContainerResourceTests",
dependencies: [
.product(name: "Containerization", package: "containerization"),
"ContainerClient",
"ContainerPersistence",
"ContainerResource",
]
),
.target(
name: "ContainerLog",
dependencies: [
.product(name: "Logging", package: "swift-log")
]
),
.target(
@@ -275,8 +340,8 @@ let package = Package(
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Containerization", package: "containerization"),
"ContainerVersion",
"CVersion",
"ContainerVersion",
]
),
.target(
@@ -293,12 +358,6 @@ let package = Package(
"ContainerPlugin"
]
),
.target(
name: "ContainerLog",
dependencies: [
.product(name: "Logging", package: "swift-log")
]
),
.target(
name: "ContainerXPC",
dependencies: [
@@ -347,19 +406,6 @@ let package = Package(
name: "SocketForwarderTests",
dependencies: ["SocketForwarder"]
),
.testTarget(
name: "CLITests",
dependencies: [
.product(name: "AsyncHTTPClient", package: "async-http-client"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationExtras", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
"ContainerBuild",
"ContainerClient",
"ContainerNetworkService",
],
path: "Tests/CLITests"
),
.target(
name: "ContainerVersion",
dependencies: [
+1 -1
View File
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerCommands
@main
+1 -1
View File
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import Collections
import ContainerClient
import ContainerAPIClient
import ContainerizationArchive
import ContainerizationOCI
import Foundation
@@ -14,7 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationOCI
import Foundation
@@ -14,7 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationArchive
import ContainerizationOCI
+1 -1
View File
@@ -14,7 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationOCI
import ContainerizationOS
+1 -1
View File
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerLog
import ContainerPlugin
import ContainerVersion
+1 -1
View File
@@ -15,8 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerAPIClient
import ContainerBuild
import ContainerClient
import ContainerImagesServiceClient
import Containerization
import ContainerizationError
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import Foundation
@@ -15,10 +15,10 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerAPIClient
import ContainerBuild
import ContainerClient
import ContainerNetworkService
import ContainerPersistence
import ContainerResource
import Containerization
import ContainerizationError
import ContainerizationExtras
@@ -164,7 +164,7 @@ extension Application {
].compactMap { $0 }
let id = "buildkit"
try ContainerClient.Utility.validEntityName(id)
try ContainerAPIClient.Utility.validEntityName(id)
let image = try await ClientImage.fetch(
reference: builderImage,
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import ContainerizationExtras
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import Foundation
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerResource
import ContainerizationError
import Foundation
import TerminalProgress
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import ContainerizationOS
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Foundation
import SwiftProtobuf
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import ContainerizationOS
import Darwin
@@ -15,8 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerNetworkService
import ContainerAPIClient
import ContainerResource
import ContainerizationExtras
import Foundation
import SwiftProtobuf
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import Darwin
import Dispatch
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerResource
import Containerization
import ContainerizationError
import ContainerizationExtras
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import ContainerizationOS
import TerminalProgress
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerResource
import ContainerizationError
import ContainerizationExtras
import Foundation
@@ -148,8 +149,8 @@ extension Application {
private struct StatsSnapshot {
let container: ClientContainer
let stats1: ContainerClient.ContainerStats
let stats2: ContainerClient.ContainerStats
let stats1: ContainerResource.ContainerStats
let stats2: ContainerResource.ContainerStats
}
private func collectStats(for containers: [ClientContainer]) async throws -> [StatsSnapshot] {
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerResource
import ContainerizationError
import ContainerizationOS
import Foundation
@@ -14,7 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationError
import ContainerizationOS
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPlugin
import Darwin
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationError
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import Foundation
import SwiftProtobuf
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationError
import ContainerizationOCI
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationError
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationOCI
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationOCI
import TerminalProgress
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationOCI
import TerminalProgress
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerResource
import Containerization
import ContainerizationError
import ContainerizationOCI
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
extension Application {
public struct ImageTag: AsyncParsableCommand {
@@ -15,8 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerNetworkService
import ContainerAPIClient
import ContainerResource
import ContainerizationError
import ContainerizationExtras
import Foundation
@@ -15,8 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerNetworkService
import ContainerAPIClient
import ContainerResource
import ContainerizationError
import Foundation
@@ -15,8 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerNetworkService
import ContainerAPIClient
import Foundation
import SwiftProtobuf
@@ -15,8 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerNetworkService
import ContainerAPIClient
import ContainerResource
import ContainerizationExtras
import Foundation
import SwiftProtobuf
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Foundation
extension Application.NetworkCommand {
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationError
import ContainerizationOCI
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Containerization
import ContainerizationOCI
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import ContainerizationExtras
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Foundation
extension Application {
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPersistence
import Containerization
import ContainerizationError
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPersistence
import ContainerizationError
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPersistence
import ContainerizationError
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPersistence
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPersistence
import ContainerizationError
import ContainerizationExtras
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerizationError
import ContainerizationOS
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPersistence
import ContainerPlugin
import ContainerizationError
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPlugin
import ContainerizationError
import Foundation
@@ -15,8 +15,9 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerPlugin
import ContainerResource
import ContainerizationOS
import Foundation
import Logging
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerVersion
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Foundation
extension Application.VolumeCommand {
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerResource
import ContainerizationError
import Foundation
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerResource
import Foundation
extension Application.VolumeCommand {
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import ContainerResource
import ContainerizationExtras
import Foundation
@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerAPIClient
import Foundation
extension Application.VolumeCommand {
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerNetworkService
import ContainerizationOCI
public struct ContainerConfiguration: Sendable, Codable {
@@ -83,16 +82,8 @@ public struct ContainerConfiguration: Sendable, Codable {
labels = try container.decodeIfPresent([String: String].self, forKey: .labels) ?? [:]
sysctls = try container.decodeIfPresent([String: String].self, forKey: .sysctls) ?? [:]
// NOTE: migrates [String] to [AttachmentConfiguration]; remove [String] support in a later release
if container.contains(.networks) {
do {
networks = try container.decode([AttachmentConfiguration].self, forKey: .networks)
} catch {
let networkIds = try container.decode([String].self, forKey: .networks)
// Parse old network IDs as simple network names without properties
let parsedNetworks = networkIds.map { Parser.ParsedNetwork(name: $0, macAddress: nil) }
networks = try Utility.getAttachmentConfigurations(containerId: id, networks: parsedNetworks)
}
networks = try container.decode([AttachmentConfiguration].self, forKey: .networks)
} else {
networks = []
}
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,8 +14,6 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerNetworkService
/// A snapshot of a container along with its configuration
/// and any runtime state information.
public struct ContainerSnapshot: Codable, Sendable {
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -72,3 +72,19 @@ public struct PublishPort: Sendable, Codable {
count = try container.decodeIfPresent(UInt16.self, forKey: .count) ?? 1
}
}
extension [PublishPort] {
public func hasOverlaps() -> Bool {
var hostPorts = Set<String>()
for publishPort in self {
for index in publishPort.hostPort..<(publishPort.hostPort + publishPort.count) {
let hostPortKey = "\(index)/\(publishPort.proto.rawValue)"
guard !hostPorts.contains(hostPortKey) else {
return true
}
hostPorts.insert(hostPortKey)
}
}
return false
}
}
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -27,40 +27,16 @@ public struct ImageDetail: Codable {
public let config: ContainerizationOCI.Image
public let size: Int64
init(platform: Platform, size: Int64, config: ContainerizationOCI.Image) {
public init(platform: Platform, size: Int64, config: ContainerizationOCI.Image) {
self.platform = platform
self.config = config
self.size = size
}
}
init(name: String, index: Descriptor, variants: [Variants]) {
public init(name: String, index: Descriptor, variants: [Variants]) {
self.name = name
self.index = index
self.variants = variants
}
}
extension ClientImage {
public func details() async throws -> ImageDetail {
let descriptor = try await self.resolved()
let reference = self.reference
var variants: [ImageDetail.Variants] = []
for desc in try await self.index().manifests {
guard let platform = desc.platform else {
continue
}
let config: ContainerizationOCI.Image
let manifest: ContainerizationOCI.Manifest
do {
config = try await self.config(for: platform)
manifest = try await self.manifest(for: platform)
} catch {
continue
}
let size = desc.size + manifest.config.size + manifest.layers.reduce(0, { (l, r) in l + r.size })
variants.append(.init(platform: platform, size: size, config: config))
}
return ImageDetail(name: reference, index: descriptor, variants: variants)
}
}
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,10 +15,11 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerAPIClient
import ContainerAPIService
import ContainerClient
import ContainerNetworkService
import ContainerPlugin
import ContainerResource
import ContainerXPC
import DNSServer
import Foundation
@@ -16,6 +16,8 @@
import ArgumentParser
import ContainerNetworkService
import ContainerNetworkServiceClient
import ContainerResource
import ContainerXPC
import ContainerizationExtras
import Foundation
@@ -14,7 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerNetworkService
import ContainerResource
import ContainerSandboxService
import ContainerXPC
import Containerization
@@ -14,7 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerNetworkService
import ContainerResource
import ContainerSandboxService
import ContainerXPC
import Containerization
@@ -15,9 +15,10 @@
//===----------------------------------------------------------------------===//
import ArgumentParser
import ContainerClient
import ContainerLog
import ContainerResource
import ContainerSandboxService
import ContainerSandboxServiceClient
import ContainerXPC
import Foundation
import Logging
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerNetworkService
import ContainerResource
import ContainerXPC
import Containerization
import ContainerizationError
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
import ContainerImagesServiceClient
import ContainerPersistence
import ContainerResource
import ContainerXPC
import Containerization
import ContainerizationError
@@ -498,3 +499,27 @@ extension ImageDescription {
return name
}
}
extension ClientImage {
public func details() async throws -> ImageDetail {
let descriptor = try await self.resolved()
let reference = self.reference
var variants: [ImageDetail.Variants] = []
for desc in try await self.index().manifests {
guard let platform = desc.platform else {
continue
}
let config: ContainerizationOCI.Image
let manifest: ContainerizationOCI.Manifest
do {
config = try await self.config(for: platform)
manifest = try await self.manifest(for: platform)
} catch {
continue
}
let size = desc.size + manifest.config.size + manifest.layers.reduce(0, { (l, r) in l + r.size })
variants.append(.init(platform: platform, size: size, config: config))
}
return ImageDetail(name: reference, index: descriptor, variants: variants)
}
}
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerNetworkService
import ContainerResource
import ContainerXPC
import ContainerizationError
import ContainerizationOS
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerNetworkService
import ContainerXPC
import Containerization
import ContainerizationError
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerResource
import ContainerXPC
import Containerization
import Foundation
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the container project authors.
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

Some files were not shown because too many files have changed in this diff Show More