Skip to content

Commit 1f94a83

Browse files
authored
Cleans up build subcommand options. (apple#658)
- Part of apple#515. - Order options alphabetically. - Use `container ls` options for `builder status`. ## Type of Change - [ ] Bug fix - [ ] New feature - [x] Breaking change - Change options and output of `builder status`. - [x] Documentation update ## Motivation and Context See apple#515. ## Testing - [x] Tested locally - [ ] Added/updated tests - [x] Added/updated docs
1 parent 7d905bd commit 1f94a83

File tree

6 files changed

+91
-61
lines changed

6 files changed

+91
-61
lines changed

Sources/ContainerCommands/Builder/BuilderDelete.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,22 @@ import Foundation
2121

2222
extension Application {
2323
public struct BuilderDelete: AsyncParsableCommand {
24-
public init() {}
25-
2624
public static var configuration: CommandConfiguration {
2725
var config = CommandConfiguration()
2826
config.commandName = "delete"
2927
config.aliases = ["rm"]
30-
config._superCommandName = "builder"
31-
config.abstract = "Delete builder"
32-
config.usage = "\n\t builder delete [command options]"
33-
config.helpNames = NameSpecification(arrayLiteral: .customShort("h"), .customLong("help"))
28+
config.abstract = "Delete the builder container"
3429
return config
3530
}
3631

37-
@Flag(name: .shortAndLong, help: "Force delete builder even if it is running")
32+
@Flag(name: .shortAndLong, help: "Delete the builder even if it is running")
3833
var force = false
3934

35+
@OptionGroup
36+
var global: Flags.Global
37+
38+
public init() {}
39+
4040
public func run() async throws {
4141
do {
4242
let container = try await ClientContainer.get(id: "buildkit")

Sources/ContainerCommands/Builder/BuilderStart.swift

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,27 @@ import TerminalProgress
2828

2929
extension Application {
3030
public struct BuilderStart: AsyncParsableCommand {
31-
public init() {}
32-
3331
public static var configuration: CommandConfiguration {
3432
var config = CommandConfiguration()
3533
config.commandName = "start"
36-
config._superCommandName = "builder"
37-
config.abstract = "Start builder"
38-
config.usage = "\nbuilder start [command options]"
39-
config.helpNames = NameSpecification(arrayLiteral: .customShort("h"), .customLong("help"))
34+
config.abstract = "Start the builder container"
4035
return config
4136
}
4237

43-
@Option(name: [.customLong("cpus"), .customShort("c")], help: "Number of CPUs to allocate to the container")
38+
@Option(name: .shortAndLong, help: "Number of CPUs to allocate to the builder container")
4439
var cpus: Int64 = 2
4540

4641
@Option(
47-
name: [.customLong("memory"), .customShort("m")],
48-
help:
49-
"Amount of memory in bytes, kilobytes (K), megabytes (M), or gigabytes (G) for the container, with MB granularity (for example, 1024K will result in 1MB being allocated for the container)"
42+
name: .shortAndLong,
43+
help: "Amount of builder container memory (1MiByte granularity), with optional K, M, G, T, or P suffix"
5044
)
5145
var memory: String = "2048MB"
5246

47+
@OptionGroup
48+
var global: Flags.Global
49+
50+
public init() {}
51+
5352
public func run() async throws {
5453
let progressConfig = try ProgressConfig(
5554
showTasks: true,

Sources/ContainerCommands/Builder/BuilderStatus.swift

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,57 +17,86 @@
1717
import ArgumentParser
1818
import ContainerClient
1919
import ContainerizationError
20+
import ContainerizationExtras
2021
import Foundation
2122

2223
extension Application {
2324
public struct BuilderStatus: AsyncParsableCommand {
24-
public init() {}
25-
2625
public static var configuration: CommandConfiguration {
2726
var config = CommandConfiguration()
2827
config.commandName = "status"
29-
config._superCommandName = "builder"
30-
config.abstract = "Print builder status"
31-
config.usage = "\n\t builder status [command options]"
32-
config.helpNames = NameSpecification(arrayLiteral: .customShort("h"), .customLong("help"))
28+
config.abstract = "Display the builder container status"
3329
return config
3430
}
3531

36-
@Flag(name: .long, help: ArgumentHelp("Display detailed status in json format"))
37-
var json: Bool = false
32+
@Option(name: .long, help: "Format of the output")
33+
var format: ListFormat = .table
3834

39-
public func run() async throws {
40-
do {
41-
let container = try await ClientContainer.get(id: "buildkit")
42-
if json {
43-
let encoder = JSONEncoder()
44-
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
45-
let jsonData = try encoder.encode(container)
35+
@Flag(name: .shortAndLong, help: "Only output the container ID")
36+
var quiet = false
4637

47-
guard let jsonString = String(data: jsonData, encoding: .utf8) else {
48-
throw ContainerizationError(.internalError, message: "failed to encode BuildKit container as json")
49-
}
50-
print(jsonString)
51-
return
52-
}
38+
@OptionGroup
39+
var global: Flags.Global
5340

54-
let image = container.configuration.image.reference
55-
let resources = container.configuration.resources
56-
let cpus = resources.cpus
57-
let memory = resources.memoryInBytes / (1024 * 1024) // bytes to MB
58-
let addr = ""
41+
public init() {}
5942

60-
print("ID IMAGE STATE ADDR CPUS MEMORY")
61-
print("\(container.id) \(image) \(container.status.rawValue.uppercased()) \(addr) \(cpus) \(memory) MB")
43+
public func run() async throws {
44+
do {
45+
let container = try await ClientContainer.get(id: "buildkit")
46+
try printContainers(containers: [container], format: format)
6247
} catch {
6348
if error is ContainerizationError {
64-
if (error as? ContainerizationError)?.code == .notFound {
49+
if (error as? ContainerizationError)?.code == .notFound && !quiet {
6550
print("builder is not running")
6651
return
6752
}
6853
}
6954
throw error
7055
}
7156
}
57+
58+
private func createHeader() -> [[String]] {
59+
[["ID", "IMAGE", "STATE", "ADDR", "CPUS", "MEMORY"]]
60+
}
61+
62+
private func printContainers(containers: [ClientContainer], format: ListFormat) throws {
63+
if format == .json {
64+
let printables = containers.map {
65+
PrintableContainer($0)
66+
}
67+
let data = try JSONEncoder().encode(printables)
68+
print(String(data: data, encoding: .utf8)!)
69+
70+
return
71+
}
72+
73+
if self.quiet {
74+
containers
75+
.filter { $0.status == .running }
76+
.forEach { print($0.id) }
77+
return
78+
}
79+
80+
var rows = createHeader()
81+
for container in containers {
82+
rows.append(container.asRow)
83+
}
84+
85+
let formatter = TableOutput(rows: rows)
86+
print(formatter.format())
87+
}
88+
}
89+
}
90+
91+
extension ClientContainer {
92+
fileprivate var asRow: [String] {
93+
[
94+
self.id,
95+
self.configuration.image.reference,
96+
self.status.rawValue,
97+
self.networks.compactMap { try? CIDRAddress($0.address).address.description }.joined(separator: ","),
98+
"\(self.configuration.resources.cpus)",
99+
"\(self.configuration.resources.memoryInBytes / (1024 * 1024)) MB",
100+
]
72101
}
73102
}

Sources/ContainerCommands/Builder/BuilderStop.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,18 @@ import Foundation
2121

2222
extension Application {
2323
public struct BuilderStop: AsyncParsableCommand {
24-
public init() {}
25-
2624
public static var configuration: CommandConfiguration {
2725
var config = CommandConfiguration()
2826
config.commandName = "stop"
29-
config._superCommandName = "builder"
30-
config.abstract = "Stop builder"
31-
config.usage = "\n\t builder stop"
32-
config.helpNames = NameSpecification(arrayLiteral: .customShort("h"), .customLong("help"))
27+
config.abstract = "Stop the builder container"
3328
return config
3429
}
3530

31+
@OptionGroup
32+
var global: Flags.Global
33+
34+
public init() {}
35+
3636
public func run() async throws {
3737
do {
3838
let container = try await ClientContainer.get(id: "buildkit")

Sources/ContainerCommands/Container/ContainerDelete.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extension Application {
2828
abstract: "Delete one or more containers",
2929
aliases: ["rm"])
3030

31-
@Flag(name: .shortAndLong, help: "Force the removal of one or more running containers")
31+
@Flag(name: .shortAndLong, help: "Delete containers even if they are running")
3232
var force = false
3333

3434
@Flag(name: .shortAndLong, help: "Remove all containers")

Sources/ContainerCommands/Container/ContainerList.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,32 @@ import SwiftProtobuf
2323

2424
extension Application {
2525
public struct ContainerList: AsyncParsableCommand {
26-
public init() {}
27-
2826
public static let configuration = CommandConfiguration(
2927
commandName: "list",
3028
abstract: "List containers",
3129
aliases: ["ls"])
3230

33-
@Flag(name: .shortAndLong, help: "Show stopped containers as well")
31+
@Flag(name: .shortAndLong, help: "Include containers that are not running")
3432
var all = false
3533

36-
@Flag(name: .shortAndLong, help: "Only output the container ID")
37-
var quiet = false
38-
3934
@Option(name: .long, help: "Format of the output")
4035
var format: ListFormat = .table
4136

37+
@Flag(name: .shortAndLong, help: "Only output the container ID")
38+
var quiet = false
39+
4240
@OptionGroup
4341
var global: Flags.Global
4442

43+
public init() {}
44+
4545
public func run() async throws {
4646
let containers = try await ClientContainer.list()
4747
try printContainers(containers: containers, format: format)
4848
}
4949

5050
private func createHeader() -> [[String]] {
51-
[["ID", "IMAGE", "OS", "ARCH", "STATE", "ADDR"]]
51+
[["ID", "IMAGE", "OS", "ARCH", "STATE", "ADDR", "CPUS", "MEMORY"]]
5252
}
5353

5454
private func printContainers(containers: [ClientContainer], format: ListFormat) throws {
@@ -87,14 +87,16 @@ extension Application {
8787
}
8888

8989
extension ClientContainer {
90-
var asRow: [String] {
90+
fileprivate var asRow: [String] {
9191
[
9292
self.id,
9393
self.configuration.image.reference,
9494
self.configuration.platform.os,
9595
self.configuration.platform.architecture,
9696
self.status.rawValue,
9797
self.networks.compactMap { try? CIDRAddress($0.address).address.description }.joined(separator: ","),
98+
"\(self.configuration.resources.cpus)",
99+
"\(self.configuration.resources.memoryInBytes / (1024 * 1024)) MB",
98100
]
99101
}
100102
}

0 commit comments

Comments
 (0)