mirror of
https://github.com/apple/container.git
synced 2026-09-12 18:55:43 +00:00
## Type of Change - [ ] Bug fix - [x] New feature - [ ] Breaking change - [ ] Documentation update ## Motivation and Context Authors of CLI plugins for container will be able to reuse the container flags defined in the CLI package, instead of having to duplicate them in their project ## Testing - [ ] Tested locally - [ ] Added/updated tests - [ ] Added/updated docs
352 lines
11 KiB
Swift
352 lines
11 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// Copyright © 2026 Apple Inc. and the container project authors.
|
|
//
|
|
// 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 ContainerizationError
|
|
import Foundation
|
|
|
|
public struct Flags {
|
|
public struct Logging: ParsableArguments {
|
|
public init() {}
|
|
|
|
public init(debug: Bool) {
|
|
self.debug = debug
|
|
}
|
|
|
|
@Flag(name: .long, help: "Enable debug output [environment: CONTAINER_DEBUG]")
|
|
public var debug = false
|
|
}
|
|
|
|
public struct Process: ParsableArguments {
|
|
public init() {}
|
|
|
|
public init(
|
|
cwd: String?,
|
|
env: [String],
|
|
envFile: [String],
|
|
gid: UInt32?,
|
|
interactive: Bool,
|
|
tty: Bool,
|
|
uid: UInt32?,
|
|
ulimits: [String],
|
|
user: String?
|
|
) {
|
|
self.cwd = cwd
|
|
self.env = env
|
|
self.envFile = envFile
|
|
self.gid = gid
|
|
self.interactive = interactive
|
|
self.tty = tty
|
|
self.uid = uid
|
|
self.ulimits = ulimits
|
|
self.user = user
|
|
}
|
|
|
|
@Option(name: .shortAndLong, help: "Set environment variables (key=value, or just key to inherit from host)")
|
|
public var env: [String] = []
|
|
|
|
@Option(
|
|
name: .long,
|
|
help: "Read in a file of environment variables (key=value format, ignores # comments and blank lines)"
|
|
)
|
|
public var envFile: [String] = []
|
|
|
|
@Option(name: .long, help: "Set the group ID for the process")
|
|
public var gid: UInt32?
|
|
|
|
@Flag(name: .shortAndLong, help: "Keep the standard input open even if not attached")
|
|
public var interactive = false
|
|
|
|
@Flag(name: .shortAndLong, help: "Open a TTY with the process")
|
|
public var tty = false
|
|
|
|
@Option(name: .shortAndLong, help: "Set the user for the process (format: name|uid[:gid])")
|
|
public var user: String?
|
|
|
|
@Option(name: .long, help: "Set the user ID for the process")
|
|
public var uid: UInt32?
|
|
|
|
@Option(
|
|
name: [.customShort("w"), .customLong("workdir"), .long],
|
|
help: .init(
|
|
"Set the initial working directory inside the container",
|
|
valueName: "dir"
|
|
)
|
|
)
|
|
public var cwd: String?
|
|
|
|
@Option(
|
|
name: .customLong("ulimit"),
|
|
help: .init(
|
|
"Set resource limits (format: <type>=<soft>[:<hard>])",
|
|
valueName: "limit"
|
|
)
|
|
)
|
|
public var ulimits: [String] = []
|
|
}
|
|
|
|
public struct Resource: ParsableArguments {
|
|
public init() {}
|
|
|
|
public init(cpus: Int64?, memory: String?) {
|
|
self.cpus = cpus
|
|
self.memory = memory
|
|
}
|
|
|
|
@Option(name: .shortAndLong, help: "Number of CPUs to allocate to the container")
|
|
public var cpus: Int64?
|
|
|
|
@Option(
|
|
name: .shortAndLong,
|
|
help: "Amount of memory (1MiByte granularity), with optional K, M, G, T, or P suffix"
|
|
)
|
|
public var memory: String?
|
|
}
|
|
|
|
public struct DNS: ParsableArguments {
|
|
public init() {}
|
|
|
|
public init(domain: String?, nameservers: [String], options: [String], searchDomains: [String]) {
|
|
self.domain = domain
|
|
self.nameservers = nameservers
|
|
self.options = options
|
|
self.searchDomains = searchDomains
|
|
}
|
|
|
|
@Option(
|
|
name: .customLong("dns"),
|
|
help: .init("DNS nameserver IP address", valueName: "ip")
|
|
)
|
|
public var nameservers: [String] = []
|
|
|
|
@Option(
|
|
name: .customLong("dns-domain"),
|
|
help: .init("Default DNS domain", valueName: "domain")
|
|
)
|
|
public var domain: String? = nil
|
|
|
|
@Option(
|
|
name: .customLong("dns-option"),
|
|
help: .init("DNS options", valueName: "option")
|
|
)
|
|
public var options: [String] = []
|
|
|
|
@Option(
|
|
name: .customLong("dns-search"),
|
|
help: .init("DNS search domains", valueName: "domain")
|
|
)
|
|
public var searchDomains: [String] = []
|
|
}
|
|
|
|
public struct Registry: ParsableArguments {
|
|
public init() {}
|
|
|
|
public init(scheme: String) {
|
|
self.scheme = scheme
|
|
}
|
|
|
|
@Option(help: "Scheme to use when connecting to the container registry. One of (http, https, auto)")
|
|
public var scheme: String = "auto"
|
|
}
|
|
|
|
public struct Management: ParsableArguments {
|
|
public init() {}
|
|
|
|
public init(
|
|
arch: String,
|
|
cidfile: String,
|
|
detach: Bool,
|
|
dns: Flags.DNS,
|
|
dnsDisabled: Bool,
|
|
entrypoint: String?,
|
|
initImage: String?,
|
|
kernel: String?,
|
|
labels: [String],
|
|
mounts: [String],
|
|
name: String?,
|
|
networks: [String],
|
|
os: String,
|
|
platform: String?,
|
|
publishPorts: [String],
|
|
publishSockets: [String],
|
|
readOnly: Bool,
|
|
remove: Bool,
|
|
rosetta: Bool,
|
|
runtime: String?,
|
|
ssh: Bool,
|
|
tmpFs: [String],
|
|
virtualization: Bool,
|
|
volumes: [String]
|
|
) {
|
|
self.arch = arch
|
|
self.cidfile = cidfile
|
|
self.detach = detach
|
|
self.dns = dns
|
|
self.dnsDisabled = dnsDisabled
|
|
self.entrypoint = entrypoint
|
|
self.initImage = initImage
|
|
self.kernel = kernel
|
|
self.labels = labels
|
|
self.mounts = mounts
|
|
self.name = name
|
|
self.networks = networks
|
|
self.os = os
|
|
self.platform = platform
|
|
self.publishPorts = publishPorts
|
|
self.publishSockets = publishSockets
|
|
self.readOnly = readOnly
|
|
self.remove = remove
|
|
self.rosetta = rosetta
|
|
self.runtime = runtime
|
|
self.ssh = ssh
|
|
self.tmpFs = tmpFs
|
|
self.virtualization = virtualization
|
|
self.volumes = volumes
|
|
}
|
|
|
|
@Option(name: .shortAndLong, help: "Set arch if image can target multiple architectures")
|
|
public var arch: String = Arch.hostArchitecture().rawValue
|
|
|
|
@Option(name: .long, help: "Write the container ID to the path provided")
|
|
public var cidfile = ""
|
|
|
|
@Flag(name: .shortAndLong, help: "Run the container and detach from the process")
|
|
public var detach = false
|
|
|
|
@OptionGroup
|
|
public var dns: Flags.DNS
|
|
|
|
@Option(
|
|
name: .long,
|
|
help: .init(
|
|
"Override the entrypoint of the image",
|
|
valueName: "cmd"
|
|
)
|
|
)
|
|
public var entrypoint: String?
|
|
|
|
@Option(
|
|
name: .shortAndLong,
|
|
help: .init("Set a custom kernel path", valueName: "path"),
|
|
completion: .file(),
|
|
transform: { str in
|
|
URL(fileURLWithPath: str, relativeTo: .currentDirectory()).absoluteURL.path(percentEncoded: false)
|
|
}
|
|
)
|
|
public var kernel: String?
|
|
|
|
@Option(
|
|
name: .long,
|
|
help: .init("Use a custom init image instead of the default", valueName: "image")
|
|
)
|
|
public var initImage: String?
|
|
|
|
@Option(name: [.short, .customLong("label")], help: "Add a key=value label to the container")
|
|
public var labels: [String] = []
|
|
|
|
@Option(name: .customLong("mount"), help: "Add a mount to the container (format: type=<>,source=<>,target=<>,readonly)")
|
|
public var mounts: [String] = []
|
|
|
|
@Option(name: .long, help: "Use the specified name as the container ID")
|
|
public var name: String?
|
|
|
|
@Option(name: [.customLong("network")], help: "Attach the container to a network (format: <name>[,mac=XX:XX:XX:XX:XX:XX])")
|
|
public var networks: [String] = []
|
|
|
|
@Flag(name: [.customLong("no-dns")], help: "Do not configure DNS in the container")
|
|
public var dnsDisabled = false
|
|
|
|
@Option(name: .long, help: "Set OS if image can target multiple operating systems")
|
|
public var os = "linux"
|
|
|
|
@Option(
|
|
name: [.customShort("p"), .customLong("publish")],
|
|
help: .init(
|
|
"Publish a port from container to host (format: [host-ip:]host-port:container-port[/protocol])",
|
|
valueName: "spec"
|
|
)
|
|
)
|
|
public var publishPorts: [String] = []
|
|
|
|
@Option(name: .long, help: "Platform for the image if it's multi-platform. This takes precedence over --os and --arch")
|
|
public var platform: String?
|
|
|
|
@Option(
|
|
name: .customLong("publish-socket"),
|
|
help: .init(
|
|
"Publish a socket from container to host (format: host_path:container_path)",
|
|
valueName: "spec"
|
|
)
|
|
)
|
|
public var publishSockets: [String] = []
|
|
|
|
@Flag(name: [.customLong("rm"), .long], help: "Remove the container after it stops")
|
|
public var remove = false
|
|
|
|
@Flag(name: .long, help: "Enable Rosetta in the container")
|
|
public var rosetta = false
|
|
|
|
@Flag(name: .long, help: "Forward SSH agent socket to container")
|
|
public var ssh = false
|
|
|
|
@Option(name: .customLong("tmpfs"), help: "Add a tmpfs mount to the container at the given path")
|
|
public var tmpFs: [String] = []
|
|
|
|
@Option(name: [.customLong("volume"), .short], help: "Bind mount a volume into the container")
|
|
public var volumes: [String] = []
|
|
|
|
@Flag(
|
|
name: .long,
|
|
help:
|
|
"Expose virtualization capabilities to the container (requires host and guest support)"
|
|
)
|
|
public var virtualization: Bool = false
|
|
|
|
@Flag(name: .long, help: "Mount the container's root filesystem as read-only")
|
|
public var readOnly = false
|
|
|
|
@Option(name: .long, help: "Set the runtime handler for the container (default: container-runtime-linux)")
|
|
public var runtime: String?
|
|
}
|
|
|
|
public struct Progress: ParsableArguments {
|
|
public init() {}
|
|
|
|
public init(progress: ProgressType) {
|
|
self.progress = progress
|
|
}
|
|
|
|
public enum ProgressType: String, ExpressibleByArgument {
|
|
case none
|
|
case ansi
|
|
}
|
|
|
|
@Option(name: .long, help: ArgumentHelp("Progress type (format: none|ansi)", valueName: "type"))
|
|
public var progress: ProgressType = .ansi
|
|
}
|
|
|
|
public struct ImageFetch: ParsableArguments {
|
|
public init() {}
|
|
|
|
public init(maxConcurrentDownloads: Int) {
|
|
self.maxConcurrentDownloads = maxConcurrentDownloads
|
|
}
|
|
|
|
@Option(name: .long, help: "Maximum number of concurrent downloads (default: 3)")
|
|
public var maxConcurrentDownloads: Int = 3
|
|
}
|
|
}
|