From ee9e736bbddf7f0a56d380d3d0a76af4b12402fd Mon Sep 17 00:00:00 2001 From: Danny Canter Date: Thu, 9 Apr 2026 20:37:11 -0700 Subject: [PATCH] Start converting libraries to use FoundationEssentials This helps on binary size if we can successfully get all Foundation imports out of our dep chain. It seems Foundation brings in a 30MiB ICU blob, which bloats vmexec and vminitd. --- .../AsyncSignalHandler.swift | 10 ++++++- Sources/ContainerizationOS/File.swift | 16 ++++++++++-- .../Keychain/KeychainQuery.swift | 4 +++ .../Keychain/RegistryInfo.swift | 4 +++ Sources/ContainerizationOS/Linux/Binfmt.swift | 4 +++ .../Linux/Capabilities.swift | 5 ++++ Sources/ContainerizationOS/Linux/Epoll.swift | 4 +++ Sources/ContainerizationOS/Mount/Mount.swift | 5 ++++ .../POSIXError+Helpers.swift | 12 +++++++++ Sources/ContainerizationOS/Path.swift | 4 +++ Sources/ContainerizationOS/Reaper.swift | 11 ++++++++ .../Socket/BidirectionalRelay.swift | 16 +++++++++++- Sources/ContainerizationOS/Sysctl.swift | 7 +++++ .../ContainerizationOS/URL+Extensions.swift | 26 ++++++++++++++++--- Sources/ContainerizationOS/User.swift | 5 ++++ 15 files changed, 125 insertions(+), 8 deletions(-) diff --git a/Sources/ContainerizationOS/AsyncSignalHandler.swift b/Sources/ContainerizationOS/AsyncSignalHandler.swift index 69497dfa..f7d3fbe7 100644 --- a/Sources/ContainerizationOS/AsyncSignalHandler.swift +++ b/Sources/ContainerizationOS/AsyncSignalHandler.swift @@ -14,9 +14,17 @@ // limitations under the License. //===----------------------------------------------------------------------===// -import Foundation +import Dispatch import Synchronization +#if canImport(Musl) +import Musl +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Darwin) +import Darwin +#endif + /// Async friendly wrapper around `DispatchSourceSignal`. Provides an `AsyncStream` /// interface to get notified of received signals. public final class AsyncSignalHandler: Sendable { diff --git a/Sources/ContainerizationOS/File.swift b/Sources/ContainerizationOS/File.swift index 6653dfe3..25cd05e6 100644 --- a/Sources/ContainerizationOS/File.swift +++ b/Sources/ContainerizationOS/File.swift @@ -14,7 +14,19 @@ // limitations under the License. //===----------------------------------------------------------------------===// -import Foundation +#if canImport(Musl) +import Musl +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Darwin) +import Darwin +#endif + +#if canImport(FoundationEssentials) +import struct FoundationEssentials.URL +#else +import struct Foundation.URL +#endif /// Trivial type to discover information about a given file (uid, gid, mode...). public struct File: Sendable { @@ -52,7 +64,7 @@ public struct File: Sendable { /// `FileInfo` holds and provides easy access to stat(2) data /// for a file. public struct FileInfo: Sendable { - private let _stat_t: Foundation.stat + private let _stat_t: stat private let _path: String init(_ path: String, stat: stat) { diff --git a/Sources/ContainerizationOS/Keychain/KeychainQuery.swift b/Sources/ContainerizationOS/Keychain/KeychainQuery.swift index fab385c1..0c45df94 100644 --- a/Sources/ContainerizationOS/Keychain/KeychainQuery.swift +++ b/Sources/ContainerizationOS/Keychain/KeychainQuery.swift @@ -15,7 +15,11 @@ //===----------------------------------------------------------------------===// #if os(macOS) +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif /// Holds the result of a query to the keychain. public struct KeychainQueryResult { diff --git a/Sources/ContainerizationOS/Keychain/RegistryInfo.swift b/Sources/ContainerizationOS/Keychain/RegistryInfo.swift index 12dd67d9..d81bd0dd 100644 --- a/Sources/ContainerizationOS/Keychain/RegistryInfo.swift +++ b/Sources/ContainerizationOS/Keychain/RegistryInfo.swift @@ -14,7 +14,11 @@ // limitations under the License. //===----------------------------------------------------------------------===// +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif /// Holds the stored attributes for a registry. public struct RegistryInfo: Sendable { diff --git a/Sources/ContainerizationOS/Linux/Binfmt.swift b/Sources/ContainerizationOS/Linux/Binfmt.swift index ca2507ee..e065f7d5 100644 --- a/Sources/ContainerizationOS/Linux/Binfmt.swift +++ b/Sources/ContainerizationOS/Linux/Binfmt.swift @@ -14,7 +14,11 @@ // limitations under the License. //===----------------------------------------------------------------------===// +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif #if canImport(Musl) import Musl diff --git a/Sources/ContainerizationOS/Linux/Capabilities.swift b/Sources/ContainerizationOS/Linux/Capabilities.swift index 9bcda38d..651d8b01 100644 --- a/Sources/ContainerizationOS/Linux/Capabilities.swift +++ b/Sources/ContainerizationOS/Linux/Capabilities.swift @@ -15,7 +15,12 @@ //===----------------------------------------------------------------------===// import CShim + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif // MARK: - Configuration Types diff --git a/Sources/ContainerizationOS/Linux/Epoll.swift b/Sources/ContainerizationOS/Linux/Epoll.swift index 9ef2ce8e..226e3f3e 100644 --- a/Sources/ContainerizationOS/Linux/Epoll.swift +++ b/Sources/ContainerizationOS/Linux/Epoll.swift @@ -15,7 +15,11 @@ //===----------------------------------------------------------------------===// #if os(Linux) +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif #if canImport(Musl) import Musl diff --git a/Sources/ContainerizationOS/Mount/Mount.swift b/Sources/ContainerizationOS/Mount/Mount.swift index 004143b3..b4f40617 100644 --- a/Sources/ContainerizationOS/Mount/Mount.swift +++ b/Sources/ContainerizationOS/Mount/Mount.swift @@ -15,7 +15,12 @@ //===----------------------------------------------------------------------===// import CShim + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif #if canImport(Musl) import Musl diff --git a/Sources/ContainerizationOS/POSIXError+Helpers.swift b/Sources/ContainerizationOS/POSIXError+Helpers.swift index ef058c04..233e78d6 100644 --- a/Sources/ContainerizationOS/POSIXError+Helpers.swift +++ b/Sources/ContainerizationOS/POSIXError+Helpers.swift @@ -14,7 +14,19 @@ // limitations under the License. //===----------------------------------------------------------------------===// +#if canImport(Musl) +import Musl +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Darwin) +import Darwin +#endif + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif extension POSIXError { public static func fromErrno() -> POSIXError { diff --git a/Sources/ContainerizationOS/Path.swift b/Sources/ContainerizationOS/Path.swift index 5eb32a41..1281a846 100644 --- a/Sources/ContainerizationOS/Path.swift +++ b/Sources/ContainerizationOS/Path.swift @@ -14,7 +14,11 @@ // limitations under the License. //===----------------------------------------------------------------------===// +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif /// `Path` provides utilities to look for binaries in the current PATH, /// or to return the current PATH. diff --git a/Sources/ContainerizationOS/Reaper.swift b/Sources/ContainerizationOS/Reaper.swift index 9fbf0cd0..84a31dbf 100644 --- a/Sources/ContainerizationOS/Reaper.swift +++ b/Sources/ContainerizationOS/Reaper.swift @@ -14,7 +14,18 @@ // limitations under the License. //===----------------------------------------------------------------------===// +#if canImport(Musl) +import Musl +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Darwin) +import Darwin +#endif +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif /// A process reaper that returns exited processes along /// with their exit status. diff --git a/Sources/ContainerizationOS/Socket/BidirectionalRelay.swift b/Sources/ContainerizationOS/Socket/BidirectionalRelay.swift index 728a9937..96420f97 100644 --- a/Sources/ContainerizationOS/Socket/BidirectionalRelay.swift +++ b/Sources/ContainerizationOS/Socket/BidirectionalRelay.swift @@ -15,10 +15,24 @@ //===----------------------------------------------------------------------===// import ContainerizationError -import Foundation +import Dispatch import Logging import Synchronization +#if canImport(Musl) +import Musl +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Darwin) +import Darwin +#endif + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + /// Manages bidirectional data relay between two file descriptors using `DispatchSource`. public final class BidirectionalRelay: Sendable { private let fd1: Int32 diff --git a/Sources/ContainerizationOS/Sysctl.swift b/Sources/ContainerizationOS/Sysctl.swift index 01893bd9..7a265f52 100644 --- a/Sources/ContainerizationOS/Sysctl.swift +++ b/Sources/ContainerizationOS/Sysctl.swift @@ -14,7 +14,14 @@ // limitations under the License. //===----------------------------------------------------------------------===// +#if canImport(Darwin) +import Darwin +#endif +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif /// Helper type to deal with system control functionalities. public struct Sysctl { diff --git a/Sources/ContainerizationOS/URL+Extensions.swift b/Sources/ContainerizationOS/URL+Extensions.swift index 787344df..a5c6331a 100644 --- a/Sources/ContainerizationOS/URL+Extensions.swift +++ b/Sources/ContainerizationOS/URL+Extensions.swift @@ -14,7 +14,19 @@ // limitations under the License. //===----------------------------------------------------------------------===// +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif + +#if canImport(Musl) +import Musl +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Darwin) +import Darwin +#endif /// The `resolvingSymlinksInPath` method of the `URL` struct does not resolve the symlinks /// for directories under `/private` which include`tmp`, `var` and `etc` @@ -34,9 +46,11 @@ extension URL { let parts = url.pathComponents if parts.count > 1 { if (parts.first == "/") && ["tmp", "var", "etc"].contains(parts[1]) { - if let resolved = NSURL.fileURL(withPathComponents: ["/", "private"] + parts[1...]) { - return resolved + var resolved = URL(filePath: "/private") + for part in parts[1...] { + resolved.append(path: part) } + return resolved } } #endif @@ -44,10 +58,14 @@ extension URL { } public var isDirectory: Bool { - (try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true + var st = stat() + guard stat(self.path, &st) == 0 else { return false } + return (st.st_mode & S_IFMT) == S_IFDIR } public var isSymlink: Bool { - (try? resourceValues(forKeys: [.isSymbolicLinkKey]))?.isSymbolicLink == true + var st = stat() + guard lstat(self.path, &st) == 0 else { return false } + return (st.st_mode & S_IFMT) == S_IFLNK } } diff --git a/Sources/ContainerizationOS/User.swift b/Sources/ContainerizationOS/User.swift index e8166781..723530de 100644 --- a/Sources/ContainerizationOS/User.swift +++ b/Sources/ContainerizationOS/User.swift @@ -15,7 +15,12 @@ //===----------------------------------------------------------------------===// import ContainerizationError + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif /// `User` provides utilities to ensure that a given username exists in /// /etc/passwd (and /etc/group). Largely inspired by runc (and moby's)