Move the VminitdCore library to the top-level package (#742)

External Swift Package Manager consumers can only see products declared
in the top-level `Package.swift`. The `VminitdCore` library was declared
inside the `vminitd` subpackage, so it was impossible to build a custom
`vminitd` against it via a URL dependency on `containerization`. This
change moves the `VminitdCore` to the top-level `Package.swift`.
This commit is contained in:
Dmitry Kovba authored and GitHub committed 2026-05-20 15:46:32 -07:00
1 parent db5b5b9840
commit c8fe3bbef9
29 files changed
+164 -79

No files matched your search

-1
View File
@@ -7,7 +7,6 @@ xcuserdata/
DerivedData/
.swiftpm/
.netrc
.swiftpm
workdir/
installer/
.venv/
+49
View File
@@ -21,6 +21,10 @@ import CompilerPluginSupport
import Foundation
import PackageDescription
let gitCommit = ProcessInfo.processInfo.environment["GIT_COMMIT"] ?? "unspecified"
let gitTag = ProcessInfo.processInfo.environment["GIT_TAG"] ?? ""
let buildTime = ProcessInfo.processInfo.environment["BUILD_TIME"] ?? "unspecified"
let package = Package(
name: "containerization",
platforms: [.macOS("15.0")],
@@ -33,6 +37,7 @@ let package = Package(
.library(name: "ContainerizationOS", targets: ["ContainerizationOS"]),
.library(name: "ContainerizationExtras", targets: ["ContainerizationExtras"]),
.library(name: "ContainerizationArchive", targets: ["ContainerizationArchive"]),
.library(name: "VminitdCore", targets: ["VminitdCore", "Cgroup", "LCShim"]),
.executable(name: "cctl", targets: ["cctl"]),
],
dependencies: [
@@ -259,6 +264,50 @@ let package = Package(
.target(
name: "CShim"
),
.target(
name: "CVersion",
path: "vminitd/Sources/CVersion",
cSettings: [
.define("GIT_COMMIT", to: "\"\(gitCommit)\""),
.define("GIT_TAG", to: "\"\(gitTag)\""),
.define("BUILD_TIME", to: "\"\(buildTime)\""),
]
),
.target(
name: "LCShim",
path: "vminitd/Sources/LCShim"
),
.target(
name: "Cgroup",
dependencies: [
.product(name: "Logging", package: "swift-log"),
"ContainerizationOCI",
"ContainerizationOS",
.product(name: "SystemPackage", package: "swift-system"),
"LCShim",
],
path: "vminitd/Sources/Cgroup"
),
.target(
name: "VminitdCore",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
"Containerization",
"ContainerizationArchive",
"ContainerizationNetlink",
"ContainerizationIO",
"ContainerizationOS",
.product(name: "SystemPackage", package: "swift-system"),
.product(name: "GRPCCore", package: "grpc-swift-2"),
.product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
.product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
"LCShim",
"CVersion",
"Cgroup",
],
path: "vminitd/Sources/VminitdCore"
),
]
)
+2 -53
View File
@@ -17,79 +17,29 @@
// The swift-tools-version declares the minimum version of Swift required to build this package.
import Foundation
import PackageDescription
let gitCommit = ProcessInfo.processInfo.environment["GIT_COMMIT"] ?? "unspecified"
let gitTag = ProcessInfo.processInfo.environment["GIT_TAG"] ?? ""
let buildTime = ProcessInfo.processInfo.environment["BUILD_TIME"] ?? "unspecified"
let package = Package(
name: "swift-vminitd",
platforms: [.macOS("15")],
products: [
.library(name: "VminitdCore", targets: ["VminitdCore"]),
.executable(name: "vminitd", targets: ["vminitd"]),
.executable(name: "vmexec", targets: ["vmexec"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.7.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.10.1"),
.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/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(name: "containerization", path: "../"),
],
targets: [
.target(
name: "CVersion",
cSettings: [
.define("GIT_COMMIT", to: "\"\(gitCommit)\""),
.define("GIT_TAG", to: "\"\(gitTag)\""),
.define("BUILD_TIME", to: "\"\(buildTime)\""),
]
),
.target(
name: "LCShim"
),
.target(
name: "Cgroup",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "ContainerizationOCI", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "SystemPackage", package: "swift-system"),
"LCShim",
]
),
.target(
name: "VminitdCore",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationArchive", package: "containerization"),
.product(name: "ContainerizationNetlink", package: "containerization"),
.product(name: "ContainerizationIO", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "SystemPackage", package: "swift-system"),
.product(name: "GRPCCore", package: "grpc-swift-2"),
.product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
.product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
"LCShim",
"CVersion",
"Cgroup",
]
),
.executableTarget(
name: "vminitd",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "Logging", package: "swift-log"),
"VminitdCore",
.product(name: "VminitdCore", package: "containerization"),
]
),
.executableTarget(
@@ -100,8 +50,7 @@ let package = Package(
.product(name: "SystemPackage", package: "swift-system"),
.product(name: "Containerization", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization"),
"LCShim",
"Cgroup",
.product(name: "VminitdCore", package: "containerization"),
]
),
]
+7 -7
View File
@@ -14,12 +14,12 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
// NOTE: Ideally this should live in ContainerizationOS/Linux, or just ContainerizationCgroups
// or something similar, but it's not there yet. It does what we need, but it'd need a lot more
// features and testing before it's ready to be public.
#if os(Linux)
#if canImport(Musl)
import Musl
#elseif canImport(Glibc)
@@ -43,8 +43,8 @@ package enum Cgroup2Controller: String {
// Extremely simple cgroup manager. Our needs are simple for now, and this is
// reflected in the type.
package struct Cgroup2Manager: Sendable {
package static let defaultMountPoint = URL(filePath: "/sys/fs/cgroup")
public struct Cgroup2Manager: Sendable {
public static let defaultMountPoint = URL(filePath: "/sys/fs/cgroup")
private static let killFile = "cgroup.kill"
private static let procsFile = "cgroup.procs"
@@ -66,7 +66,7 @@ package struct Cgroup2Manager: Sendable {
self.logger = logger
}
package static func load(
public static func load(
mountPoint: URL = Self.defaultMountPoint,
group: URL,
logger: Logger? = nil
@@ -183,7 +183,7 @@ package struct Cgroup2Manager: Sendable {
}
}
package func addProcess(pid: Int32) throws {
public func addProcess(pid: Int32) throws {
self.logger?.debug(
"adding new proc to cgroup",
metadata: [
@@ -199,7 +199,7 @@ package struct Cgroup2Manager: Sendable {
)
}
package func applyResources(resources: ContainerizationOCI.LinuxResources) throws {
public func applyResources(resources: ContainerizationOCI.LinuxResources) throws {
self.logger?.debug(
"applying cgroup resources",
metadata: [
+2
View File
@@ -22,7 +22,9 @@
#define __SYSCALL_H
#include <sys/types.h>
#ifdef __linux__
#include <sys/vfs.h>
#endif
// CLONE_* flags
#ifndef CLONE_NEWNS
+2
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#ifdef __linux__
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/syscall.h>
@@ -48,3 +49,4 @@ int CZ_setrlimit(int resource, unsigned long long soft,
limit.rlim_max = (rlim_t)hard;
return setrlimit(resource, &limit);
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ArgumentParser
import CVersion
import Cgroup
@@ -44,7 +46,7 @@ public struct AgentCommand: AsyncParsableCommand {
private static let foregroundEnvVar = "FOREGROUND"
public static let vsockPort = 1024
@OptionGroup public var options: LogLevelOption
@OptionGroup var options: LogLevelOption
public init() {}
@@ -214,3 +216,5 @@ public struct AgentCommand: AsyncParsableCommand {
}
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationOS
import Foundation
import Synchronization
@@ -102,3 +104,5 @@ final class ReaperCommandRunner: CommandRunner, Sendable {
}
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationOS
import Foundation
@@ -64,3 +66,5 @@ protocol ContainerProcess: Sendable {
/// Set the exit status of the process.
func setExit(_ status: Int32)
}
#endif
@@ -14,9 +14,13 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
struct HostStdio: Sendable {
let stdin: UInt32?
let stdout: UInt32?
let stderr: UInt32?
let terminal: Bool
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationOS
import Foundation
@@ -26,3 +28,5 @@ extension Terminal: IOCloser {
}
extension FileHandle: IOCloser {}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
protocol IOCloser: Sendable {
var fileDescriptor: Int32 { get }
@@ -31,3 +33,5 @@ struct UnownedIOCloser: IOCloser {
func close() throws {}
}
#endif
+4
View File
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationError
import ContainerizationOS
import Foundation
@@ -183,3 +185,5 @@ final class IOPair: Sendable {
}
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ArgumentParser
import ContainerizationOS
import LCShim
@@ -42,13 +44,13 @@ public struct InitCommand: ParsableCommand {
public init() {}
@Flag(name: .shortAndLong, help: "Send signals to the child's process group instead of just the child")
public var processGroup: Bool = false
var processGroup: Bool = false
@Argument(help: "The command to run")
public var command: String
var command: String
@Argument(parsing: .captureForPassthrough, help: "Arguments for the command")
public var arguments: [String] = []
var arguments: [String] = []
/// Signals that should NOT be forwarded to the child.
private static let ignoredSignals: Set<Int32> = [
@@ -107,3 +109,5 @@ public struct InitCommand: ParsableCommand {
_exit(childExitStatus ?? 1)
}
}
#endif
+6 -2
View File
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ArgumentParser
import Foundation
import Logging
@@ -21,7 +23,7 @@ import Synchronization
public struct LogLevelOption: ParsableArguments {
@Option(name: .long, help: "Set the log level (trace, debug, info, notice, warning, error, critical)")
public var logLevel: String = "info"
var logLevel: String = "info"
public init() {}
@@ -49,7 +51,7 @@ public struct LogLevelOption: ParsableArguments {
private let _loggingBootstrapped = Mutex(false)
public func makeLogger(label: String, level: Logger.Level) -> Logger {
func makeLogger(label: String, level: Logger.Level) -> Logger {
_loggingBootstrapped.withLock { bootstrapped in
if !bootstrapped {
LoggingSystem.bootstrap { label in StderrLogHandler(label: label) }
@@ -97,3 +99,5 @@ private struct StderrLogHandler: LogHandler {
return String(format: "%@.%03dZ", buf, ms)
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import Cgroup
import ContainerizationError
import ContainerizationOCI
@@ -280,3 +282,5 @@ extension ManagedContainer {
URL(fileURLWithPath: "/run/container").appending(path: id)
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import Cgroup
import Containerization
import ContainerizationError
@@ -342,3 +344,5 @@ extension ManagedProcess {
// when it exits and IO is closed via setExit()
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import Foundation
import LCShim
@@ -100,3 +102,5 @@ extension OSFile {
}
}
}
#endif
+4
View File
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import Foundation
struct OSFile: Sendable {
@@ -126,3 +128,5 @@ struct OSFile: Sendable {
return Self(fd: fd)
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ArgumentParser
import Dispatch
import Logging
@@ -34,7 +36,7 @@ public struct PauseCommand: ParsableCommand {
public init() {}
@OptionGroup public var options: LogLevelOption
@OptionGroup var options: LogLevelOption
public mutating func run() throws {
let log = makeLogger(label: "pause", level: options.resolvedLogLevel())
@@ -76,3 +78,5 @@ public struct PauseCommand: ParsableCommand {
_exit(42)
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationOS
import Foundation
import Logging
@@ -162,3 +164,5 @@ final class ProcessSupervisor: Sendable {
poller.shutdown()
}
}
#endif
@@ -14,21 +14,21 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationOS
import Foundation
#if os(Linux)
/// A Unix socket for receiving PTY master file descriptors from runc
public final class ConsoleSocket: Sendable {
final class ConsoleSocket: Sendable {
private let socket: Socket
private let socketPath: String
/// The path to the console socket
public var path: String { socketPath }
var path: String { socketPath }
/// Create a new console socket at the specified path
public init(path: String) throws {
init(path: String) throws {
let absPath = path.starts(with: "/") ? path : FileManager.default.currentDirectoryPath + "/" + path
self.socketPath = absPath
@@ -47,7 +47,7 @@ public final class ConsoleSocket: Sendable {
}
/// Create a temporary console socket in the runtime directory
public static func temporary() throws -> ConsoleSocket {
static func temporary() throws -> ConsoleSocket {
let tmpDir = "/tmp"
let socketDir = tmpDir + "/runc-console-\(UUID().uuidString)"
let socketPath = socketDir + "/console.sock"
@@ -63,14 +63,14 @@ public final class ConsoleSocket: Sendable {
}
/// Receive the PTY master file descriptor from runc
public func receiveMaster() throws -> Int32 {
func receiveMaster() throws -> Int32 {
let connection = try socket.accept()
defer { try? connection.close() }
return try connection.receiveFileDescriptor()
}
/// Close the socket and optionally remove the socket file
public func close() throws {
func close() throws {
try socket.close()
try FileManager.default.removeItem(atPath: socketPath)
}
@@ -80,4 +80,4 @@ public final class ConsoleSocket: Sendable {
}
}
#endif // os(Linux)
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationOCI
import ContainerizationOS
import Foundation
@@ -788,3 +790,5 @@ extension Runc {
let limit: UInt64?
}
}
#endif
@@ -561,4 +561,4 @@ final class RuncStandardIO: RuncProcess.IO & Sendable {
}
}
#endif // os(Linux)
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import Cgroup
import Containerization
import ContainerizationArchive
@@ -1659,3 +1661,5 @@ extension Initd {
ociSpec.process = process
}
}
#endif
+5 -1
View File
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationError
import Foundation
import GRPCCore
@@ -25,7 +27,7 @@ import NIOPosix
public final class Initd: Sendable {
public actor State {
public private(set) var containers: [String: ManagedContainer] = [:]
private(set) var containers: [String: ManagedContainer] = [:]
var proxies: [String: VsockProxy] = [:]
public typealias ContainerDeletedHandler = @Sendable (String) async -> Void
@@ -139,3 +141,5 @@ public final class Initd: Sendable {
}
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationError
import ContainerizationOS
import Foundation
@@ -169,3 +171,5 @@ final class StandardIO: ManagedProcess.IO & Sendable {
}
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationOS
import Foundation
import LCShim
@@ -163,3 +165,5 @@ final class TerminalIO: ManagedProcess.IO & Sendable {
}
}
}
#endif
@@ -14,6 +14,8 @@
// limitations under the License.
//===----------------------------------------------------------------------===//
#if os(Linux)
import ContainerizationIO
import ContainerizationOS
import Foundation
@@ -400,3 +402,5 @@ extension VsockProxy {
}
}
}
#endif