mirror of
https://github.com/apple/container.git
synced 2026-07-15 05:57:01 +00:00
16f2630126
We're working on making a pure swift container image build system that leverages containerization. This PR represents our initial design and initial work towards this goal. The native builder is still in active development and most of the implementation has not been started or completed. We will be opening a series of issues that represent various (but not necessarily all) pieces of work that need to be done here. There are docs included in this PR that describe the overall design of each component and outline some of our goals. The easiest way to view the docs by themselves (since this is a massive PR) is to look at the docs commit in the `Commits` tab. We'd love any feedback! @wlan0 --------- Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
314 lines
8.2 KiB
Swift
314 lines
8.2 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// Copyright © 2025 Apple Inc. and the container project authors. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Foundation
|
|
|
|
/// Represents filesystem operations (COPY, ADD, etc.).
|
|
///
|
|
/// Design rationale:
|
|
/// - Unified handling of all filesystem modifications
|
|
/// - Preserves source context (local, stage, URL)
|
|
/// - Supports advanced features like ownership and permissions
|
|
/// - Extensible for future filesystem operations
|
|
public struct FilesystemOperation: Operation, Hashable {
|
|
public static let operationKind = OperationKind.filesystem
|
|
public var operationKind: OperationKind { Self.operationKind }
|
|
|
|
/// The filesystem action to perform
|
|
public let action: FilesystemAction
|
|
|
|
/// Source of the files
|
|
public let source: FilesystemSource
|
|
|
|
/// Destination path
|
|
public let destination: String
|
|
|
|
/// File metadata (ownership, permissions)
|
|
public let fileMetadata: FileMetadata
|
|
|
|
/// Copy options
|
|
public let options: FilesystemOptions
|
|
|
|
/// Operation metadata
|
|
public let metadata: OperationMetadata
|
|
|
|
public init(
|
|
action: FilesystemAction,
|
|
source: FilesystemSource,
|
|
destination: String,
|
|
fileMetadata: FileMetadata = FileMetadata(),
|
|
options: FilesystemOptions = FilesystemOptions(),
|
|
metadata: OperationMetadata = OperationMetadata()
|
|
) {
|
|
self.action = action
|
|
self.source = source
|
|
self.destination = destination
|
|
self.fileMetadata = fileMetadata
|
|
self.options = options
|
|
self.metadata = metadata
|
|
}
|
|
|
|
public func accept<V: OperationVisitor>(_ visitor: V) throws -> V.Result {
|
|
try visitor.visit(self)
|
|
}
|
|
}
|
|
|
|
// MARK: - Filesystem Action
|
|
|
|
/// Type of filesystem action.
|
|
///
|
|
/// Design rationale:
|
|
/// - Covers all Dockerfile filesystem operations
|
|
/// - Extensible for future operations
|
|
/// - Clear semantics for each action
|
|
public enum FilesystemAction: String, Hashable, Sendable {
|
|
/// Copy files (COPY instruction)
|
|
case copy
|
|
|
|
/// Add files with URL/tar support (ADD instruction)
|
|
case add
|
|
|
|
/// Remove files
|
|
case remove
|
|
|
|
/// Create directory
|
|
case mkdir
|
|
|
|
/// Create symlink
|
|
case symlink
|
|
|
|
/// Create hard link
|
|
case hardlink
|
|
}
|
|
|
|
// MARK: - Filesystem Source
|
|
|
|
/// Source of filesystem content.
|
|
///
|
|
/// Design rationale:
|
|
/// - Type-safe source specifications
|
|
/// - Supports all Dockerfile source types
|
|
/// - Extensible for future sources
|
|
public enum FilesystemSource: Hashable, Sendable {
|
|
/// Files from build context
|
|
case context(ContextSource)
|
|
|
|
/// Files from another stage
|
|
case stage(StageReference, paths: [String])
|
|
|
|
/// Files from an image
|
|
case image(ImageReference, paths: [String])
|
|
|
|
/// URL to download
|
|
case url(URL)
|
|
|
|
/// Git repository
|
|
case git(GitSource)
|
|
|
|
/// Inline content
|
|
case inline(Data)
|
|
|
|
/// Empty/scratch
|
|
case scratch
|
|
}
|
|
|
|
/// Build context source.
|
|
public struct ContextSource: Hashable, Sendable {
|
|
/// Name of the context
|
|
public let name: String
|
|
|
|
/// Paths relative to context root
|
|
public let paths: [String]
|
|
|
|
/// Include patterns (if empty, all files match)
|
|
public let includes: [String]
|
|
|
|
/// Exclude patterns
|
|
public let excludes: [String]
|
|
|
|
public init(name: String = "default", paths: [String], includes: [String] = [], excludes: [String] = []) {
|
|
self.name = name
|
|
self.paths = paths
|
|
self.includes = includes
|
|
self.excludes = excludes
|
|
}
|
|
}
|
|
|
|
/// Git repository source.
|
|
public struct GitSource: Hashable, Sendable {
|
|
public let repository: String
|
|
public let reference: String? // branch, tag, commit
|
|
public let submodules: Bool
|
|
|
|
public init(repository: String, reference: String? = nil, submodules: Bool = false) {
|
|
self.repository = repository
|
|
self.reference = reference
|
|
self.submodules = submodules
|
|
}
|
|
}
|
|
|
|
// MARK: - File Metadata
|
|
|
|
/// Metadata for created/modified files.
|
|
///
|
|
/// Design rationale:
|
|
/// - Captures all file attributes
|
|
/// - Platform-aware (Unix permissions vs Windows ACLs)
|
|
/// - Preserves source metadata by default
|
|
public struct FileMetadata: Hashable, Sendable {
|
|
/// File ownership
|
|
public let ownership: Ownership?
|
|
|
|
/// File permissions (Unix mode)
|
|
public let permissions: Permissions?
|
|
|
|
/// Timestamps
|
|
public let timestamps: Timestamps?
|
|
|
|
/// Extended attributes
|
|
public let xattrs: [String: Data]
|
|
|
|
public init(
|
|
ownership: Ownership? = nil,
|
|
permissions: Permissions? = nil,
|
|
timestamps: Timestamps? = nil,
|
|
xattrs: [String: Data] = [:]
|
|
) {
|
|
self.ownership = ownership
|
|
self.permissions = permissions
|
|
self.timestamps = timestamps
|
|
self.xattrs = xattrs
|
|
}
|
|
}
|
|
|
|
public enum OwnershipID: Hashable, Sendable {
|
|
/// Numeric UID/GID
|
|
case numeric(id: UInt32)
|
|
|
|
/// Named user/group
|
|
case named(id: String)
|
|
}
|
|
|
|
/// File ownership.
|
|
public struct Ownership: Hashable, Sendable {
|
|
public let userID: OwnershipID?
|
|
public let groupID: OwnershipID?
|
|
|
|
public init(user: OwnershipID? = nil, group: OwnershipID? = nil) {
|
|
self.userID = user
|
|
self.groupID = group
|
|
}
|
|
}
|
|
|
|
/// File permissions.
|
|
public enum Permissions: Hashable, Sendable {
|
|
/// Unix mode (e.g., 0755)
|
|
case mode(UInt32)
|
|
|
|
/// Symbolic (e.g., "u+x")
|
|
case symbolic(String)
|
|
|
|
/// Preserve from source
|
|
case preserve
|
|
}
|
|
|
|
/// File timestamps.
|
|
public struct Timestamps: Hashable, Sendable {
|
|
public let created: Date?
|
|
public let modified: Date?
|
|
public let accessed: Date?
|
|
|
|
public init(created: Date? = nil, modified: Date? = nil, accessed: Date? = nil) {
|
|
self.created = created
|
|
self.modified = modified
|
|
self.accessed = accessed
|
|
}
|
|
}
|
|
|
|
// MARK: - Filesystem Options
|
|
|
|
/// Options for filesystem operations.
|
|
///
|
|
/// Design rationale:
|
|
/// - Controls operation behavior
|
|
/// - Platform-specific handling
|
|
/// - Performance optimizations
|
|
public struct FilesystemOptions: Hashable, Sendable {
|
|
/// Follow symlinks in source
|
|
public let followSymlinks: Bool
|
|
|
|
/// Preserve timestamps
|
|
public let preserveTimestamps: Bool
|
|
|
|
/// Merge directories (don't replace)
|
|
public let merge: Bool
|
|
|
|
/// Create parent directories
|
|
public let createParents: Bool
|
|
|
|
/// For ADD: auto-extract archives
|
|
public let extractArchives: Bool
|
|
|
|
/// Copy strategy
|
|
public let copyStrategy: CopyStrategy
|
|
|
|
public init(
|
|
followSymlinks: Bool = true,
|
|
preserveTimestamps: Bool = false,
|
|
merge: Bool = true,
|
|
createParents: Bool = true,
|
|
extractArchives: Bool = true,
|
|
copyStrategy: CopyStrategy = .auto
|
|
) {
|
|
self.followSymlinks = followSymlinks
|
|
self.preserveTimestamps = preserveTimestamps
|
|
self.merge = merge
|
|
self.createParents = createParents
|
|
self.extractArchives = extractArchives
|
|
self.copyStrategy = copyStrategy
|
|
}
|
|
}
|
|
|
|
/// Strategy for copying files.
|
|
public enum CopyStrategy: String, Hashable, Sendable {
|
|
/// Automatically choose best method
|
|
case auto
|
|
|
|
/// Copy-on-write if available
|
|
case cow
|
|
|
|
/// Hard link if possible
|
|
case hardlink
|
|
|
|
/// Always full copy
|
|
case copy
|
|
}
|
|
|
|
// MARK: - Codable
|
|
|
|
extension FilesystemOperation: Codable {}
|
|
extension FilesystemAction: Codable {}
|
|
extension FilesystemSource: Codable {}
|
|
extension ContextSource: Codable {}
|
|
extension GitSource: Codable {}
|
|
extension FileMetadata: Codable {}
|
|
extension OwnershipID: Codable {}
|
|
extension Ownership: Codable {}
|
|
extension Permissions: Codable {}
|
|
extension Timestamps: Codable {}
|
|
extension FilesystemOptions: Codable {}
|
|
extension CopyStrategy: Codable {}
|