Files
container/Sources/CLI/Image/ImagePull.swift
T
J Logan a8c779fd65 Uniform support for --platform, --os, --arch. (#545)
- Fixes #231.
- Extends #313 (@dcantah) so that all of `container create`, `container
run`, `container build`, `container image pull`, and `container image
save` accept the three options.
- `container build` now processes comma-separated lists for
`--platform`, `--arch`, and `--os`. It first checks `--platform`,
assembling the union of all platform values. If that set is non-empty,
the builder builds the values in the set. Otherwise, the set consists of
all combinations of the specified architecture and os values, finally
defaulting to `linux` and the host architecture if no options are
provided.
- All other commands work accept a single platform, preferring the
`--platform` option over `--arch` and `--os` when both are specified.
`--os` defaults to `linux`, and `--arch` defaults to the host
architecture.
- Clarify help messages and present the args in consistent order, with
platform first since it takes precedence if present.
- Deduplicate redundant platform options for `container build`.
2025-08-27 13:26:01 -07:00

115 lines
4.1 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 ArgumentParser
import ContainerClient
import Containerization
import ContainerizationError
import ContainerizationOCI
import TerminalProgress
extension Application {
struct ImagePull: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "pull",
abstract: "Pull an image"
)
@OptionGroup
var global: Flags.Global
@OptionGroup
var registry: Flags.Registry
@OptionGroup
var progressFlags: Flags.Progress
@Option(
help: "Platform string in the form 'os/arch/variant'. Example 'linux/arm64/v8', 'linux/amd64'. This takes precedence over --os and --arch"
)
var platform: String?
@Option(
help: "Set OS if image can target multiple operating systems"
)
var os: String = "linux"
@Option(
name: [.customLong("arch"), .customShort("a")],
help: "Set arch if image can target multiple architectures"
)
var arch: String = Arch.hostArchitecture().rawValue
@Argument var reference: String
init() {}
init(platform: String? = nil, scheme: String = "auto", reference: String, disableProgress: Bool = false) {
self.global = Flags.Global()
self.registry = Flags.Registry(scheme: scheme)
self.progressFlags = Flags.Progress(disableProgressUpdates: disableProgress)
self.platform = platform
self.reference = reference
}
func run() async throws {
var p: Platform?
if let platform {
p = try Platform(from: platform)
} else {
p = try Platform(from: "\(os)/\(arch)")
}
let scheme = try RequestScheme(registry.scheme)
let processedReference = try ClientImage.normalizeReference(reference)
var progressConfig: ProgressConfig
if self.progressFlags.disableProgressUpdates {
progressConfig = try ProgressConfig(disableProgressUpdates: self.progressFlags.disableProgressUpdates)
} else {
progressConfig = try ProgressConfig(
showTasks: true,
showItems: true,
ignoreSmallSize: true,
totalTasks: 2
)
}
let progress = ProgressBar(config: progressConfig)
defer {
progress.finish()
}
progress.start()
progress.set(description: "Fetching image")
progress.set(itemsName: "blobs")
let taskManager = ProgressTaskCoordinator()
let fetchTask = await taskManager.startTask()
let image = try await ClientImage.pull(
reference: processedReference, platform: p, scheme: scheme, progressUpdate: ProgressTaskCoordinator.handler(for: fetchTask, from: progress.handler)
)
progress.set(description: "Unpacking image")
progress.set(itemsName: "entries")
let unpackTask = await taskManager.startTask()
try await image.unpack(platform: p, progressUpdate: ProgressTaskCoordinator.handler(for: unpackTask, from: progress.handler))
await taskManager.finish()
progress.finish()
}
}
}