Files
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

114 lines
4.0 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 ContainerBuildCache
import ContainerBuildExecutor
import ContainerBuildIR
import ContainerBuildReporting
import ContainerBuildSnapshotter
import Foundation
public actor DummySnapshotter: Snapshotter {
public init() {}
public func prepare(_ snapshot: Snapshot) async throws -> Snapshot {
if let mount = snapshot.state.mountpoint {
var isDir: ObjCBool = false
if !FileManager.default.fileExists(atPath: mount.path, isDirectory: &isDir) {
try FileManager.default.createDirectory(at: mount, withIntermediateDirectories: true)
}
}
return snapshot
}
public func commit(_ snapshot: Snapshot) async throws -> Snapshot {
// Produce a minimal committed snapshot; layer fields are optional
Snapshot(
id: snapshot.id,
digest: snapshot.digest,
size: snapshot.size,
parent: snapshot.parent,
createdAt: snapshot.createdAt,
state: .committed()
)
}
public func remove(_ snapshot: Snapshot) async throws {
if let mount = snapshot.state.mountpoint {
try? FileManager.default.removeItem(at: mount)
}
}
}
/// A simple demonstration of the build execution system.
public struct Demo {
public static func runDemo() async throws {
// Set up the build environment first
let snapshotter = DummySnapshotter()
let cache = NoOpBuildCache()
let reporter = Reporter()
// Create a build graph with parallel operations, passing the reporter
let graph = try IRExample.createParallelBuild(reporter: reporter)
let config = Scheduler.Configuration(
maxConcurrency: ProcessInfo.processInfo.activeProcessorCount,
failFast: true,
enableProgressReporting: true
)
let executor = Scheduler(
snapshotter: snapshotter,
cache: cache,
reporter: reporter,
configuration: config
)
// Create progress consumer
let consumer = PlainProgressConsumer(
configuration: .init()
)
// Start progress monitoring task
let progressTask = Task {
try await consumer.consume(reporter: reporter)
}
// Register completion handler to wait for progress task
executor.onCompletion {
try? await progressTask.value
}
// Execute the build - this will wait for progress to complete before returning
_ = try await executor.execute(graph)
// Get build statistics
let stats = consumer.getStatistics()
// Print build summary based on statistics
if let duration = stats.duration {
if stats.success == true {
print("\nBuild completed successfully in \(String(format: "%.2f", duration))s")
// print(" Total operations: \(stats.totalOperations)")
// print(" Cache hits: \(stats.cacheHits)")
// print(" Executed: \(stats.executedOperations)")
} else {
print("\nBuild failed after \(String(format: "%.2f", duration))s")
// print(" Failed operations: \(stats.failedOperations)")
}
}
}
}