Files
container/Sources/NativeBuilder/ContainerBuildExecutor/Executors/ExecOperationExecutor.swift
T
Sidhartha Mani d2f48982c1 Native Builder: Define Snapshotter protocol (#491)
This PR defines the snapshotter protocol

```swift
    ///Mount a snapshot and all its previous layers
    func prepare(_ snapshot: Snapshot) async throws -> Snapshot

    /// Commit a snapshot, making it permanent.
    func commit(_ snapshot: Snapshot) async throws -> Snapshot

    /// Remove a snapshot from snapshot store
    func remove(_ snapshot: Snapshot) async throws
```

It updates executors to work with this new protocol
2025-08-12 23:30:56 -07:00

110 lines
4.3 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 ContainerBuildIR
import ContainerBuildSnapshotter
import Foundation
/// Executes ExecOperation (RUN commands).
public struct ExecOperationExecutor: OperationExecutor {
public let capabilities: ExecutorCapabilities
public init() {
self.capabilities = ExecutorCapabilities(
supportedOperations: [.exec],
maxConcurrency: 5
)
}
public func execute(_ operation: ContainerBuildIR.Operation, context: ExecutionContext) async throws -> ExecutionResult {
guard let execOp = operation as? ExecOperation else {
throw ExecutorError(
type: .invalidConfiguration,
context: ExecutorError.ErrorContext(
operation: operation, underlyingError: NSError(domain: "Executor", code: 1, userInfo: [NSLocalizedDescriptionKey: "Unsupported operation"]),
diagnostics: ExecutorError.Diagnostics(environment: [:], workingDirectory: "", recentLogs: [])))
}
let startTime = Date()
do {
let (output, finalSnapshot) = try await context.withSnapshot { snapshot in
try await executeCommand(execOp, in: snapshot, context: context)
}
let duration = Date().timeIntervalSince(startTime)
return ExecutionResult(
environmentChanges: [:], // TODO: Extract environment changes from command execution
metadataChanges: [:],
snapshot: finalSnapshot,
duration: duration,
output: output
)
} catch {
// Collect diagnostics
let environment = context.environment.effectiveEnvironment
let diagnostics = ExecutorError.Diagnostics(
environment: environment,
workingDirectory: context.workingDirectory,
recentLogs: ["Failed to execute: \(execOp.command.displayString)", "Error: \(error.localizedDescription)"]
)
throw ExecutorError(
type: .executionFailed,
context: ExecutorError.ErrorContext(
operation: operation,
underlyingError: error,
diagnostics: diagnostics
)
)
}
}
/// Execute a command in the prepared snapshot environment.
///
/// This simulates command execution for development and testing purposes.
/// The snapshotter is fully functional and creates real filesystem snapshots,
/// but the actual command execution is simulated to avoid system dependencies.
///
/// - Parameters:
/// - operation: The exec operation to perform
/// - snapshot: The prepared snapshot with working directory
/// - context: The execution context
/// - Returns: The simulated execution output
private func executeCommand(
_ operation: ExecOperation,
in snapshot: Snapshot,
context: ExecutionContext
) async throws -> ExecutionOutput {
let commandString = operation.command.displayString
// Simulate command execution
// The snapshotter will still properly track any filesystem changes
// that would result from this operation
return ExecutionOutput(
stdout: "[SIMULATED] Executing: \(commandString)\nOutput from command execution...\nDone.",
stderr: "",
exitCode: 0
)
}
public func canExecute(_ operation: ContainerBuildIR.Operation) -> Bool {
operation is ExecOperation
}
}