Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ let package = Package(
"ContainerBuild"
]
),
.testTarget(
name: "ContainerCommandsTests",
dependencies: [
"ContainerCommands",
"ContainerResource",
]
),
.executableTarget(
name: "container-apiserver",
dependencies: [
Expand Down
5 changes: 0 additions & 5 deletions Sources/ContainerCommands/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,6 @@ extension Application {
print(altered)
}

public enum ListFormat: String, CaseIterable, ExpressibleByArgument {
case json
case table
}

func isTranslated() throws -> Bool {
do {
return try Sysctl.byName("sysctl.proc_translated") == 1
Expand Down
73 changes: 33 additions & 40 deletions Sources/ContainerCommands/Builder/BuilderStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,60 +45,53 @@ extension Application {
do {
let client = ContainerClient()
let container = try await client.get(id: "buildkit")
try printContainers(containers: [container], format: format)

if format == .json {
try emit(renderJSON([PrintableContainer(container)]))
return
}

if quiet && container.status != .running {
return
}

emit(renderList([PrintableBuilder(container)], quiet: quiet))
} catch {
if error is ContainerizationError {
if (error as? ContainerizationError)?.code == .notFound && !quiet {
if let czError = error as? ContainerizationError, czError.code == .notFound {
if !quiet {
print("builder is not running")
return
}
}
throw error
}
}
}
}

private func createHeader() -> [[String]] {
[["ID", "IMAGE", "STATE", "ADDR", "CPUS", "MEMORY"]]
}

private func printContainers(containers: [ContainerSnapshot], format: ListFormat) throws {
if format == .json {
let printables = containers.map {
PrintableContainer($0)
}
let data = try JSONEncoder().encode(printables)
print(String(decoding: data, as: UTF8.self))

return
}

if self.quiet {
containers
.filter { $0.status == .running }
.forEach { print($0.id) }
return
}
private struct PrintableBuilder: ListDisplayable {
let snapshot: ContainerSnapshot

var rows = createHeader()
for container in containers {
rows.append(container.asRow)
}
init(_ snapshot: ContainerSnapshot) {
self.snapshot = snapshot
}

let formatter = TableOutput(rows: rows)
print(formatter.format())
}
static var tableHeader: [String] {
["ID", "IMAGE", "STATE", "ADDR", "CPUS", "MEMORY"]
}
}

extension ContainerSnapshot {
fileprivate var asRow: [String] {
var tableRow: [String] {
[
self.id,
self.configuration.image.reference,
self.status.rawValue,
self.networks.compactMap { $0.ipv4Address.description }.joined(separator: ","),
"\(self.configuration.resources.cpus)",
"\(self.configuration.resources.memoryInBytes / (1024 * 1024)) MB",
snapshot.id,
snapshot.configuration.image.reference,
snapshot.status.rawValue,
snapshot.networks.map { $0.ipv4Address.description }.joined(separator: ","),
"\(snapshot.configuration.resources.cpus)",
"\(snapshot.configuration.resources.memoryInBytes / (1024 * 1024)) MB",
]
}

var quietValue: String {
snapshot.id
}
}
4 changes: 2 additions & 2 deletions Sources/ContainerCommands/Container/ContainerInspect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ extension Application {

public func run() async throws {
let client = ContainerClient()
let objects: [any Codable] = try await client.list().filter {
let containers = try await client.list().filter {
containerIds.contains($0.id)
}.map {
PrintableContainer($0)
}
print(try objects.jsonArray())
try emit(renderJSON(containers))
}
}
}
54 changes: 19 additions & 35 deletions Sources/ContainerCommands/Container/ContainerList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,59 +46,43 @@ extension Application {
let client = ContainerClient()
let filters = self.all ? ContainerListFilters.all : ContainerListFilters(status: .running)
let containers = try await client.list(filters: filters)
try printContainers(containers: containers, format: format)
}

private func createHeader() -> [[String]] {
[["ID", "IMAGE", "OS", "ARCH", "STATE", "ADDR", "CPUS", "MEMORY", "STARTED"]]
}
let items = containers.map { PrintableContainer($0) }

private func printContainers(containers: [ContainerSnapshot], format: ListFormat) throws {
if format == .json {
let printables = containers.map {
PrintableContainer($0)
}
let data = try JSONEncoder().encode(printables)
print(String(decoding: data, as: UTF8.self))

return
}

if self.quiet {
containers.forEach {
print($0.id)
}
try emit(renderJSON(items))
return
}

var rows = createHeader()
for container in containers {
rows.append(container.asRow)
}

let formatter = TableOutput(rows: rows)
print(formatter.format())
emit(renderList(items, quiet: quiet))
}
}
}

extension ContainerSnapshot {
fileprivate var asRow: [String] {
extension PrintableContainer: ListDisplayable {
static var tableHeader: [String] {
["ID", "IMAGE", "OS", "ARCH", "STATE", "ADDR", "CPUS", "MEMORY", "STARTED"]
}

var tableRow: [String] {
[
self.id,
self.configuration.id,
self.configuration.image.reference,
self.platform.os,
self.platform.architecture,
self.configuration.platform.os,
self.configuration.platform.architecture,
self.status.rawValue,
self.networks.compactMap { $0.ipv4Address.description }.joined(separator: ","),
self.networks.map { $0.ipv4Address.description }.joined(separator: ","),
"\(self.configuration.resources.cpus)",
"\(self.configuration.resources.memoryInBytes / (1024 * 1024)) MB",
self.startedDate.map { ISO8601DateFormatter().string(from: $0) } ?? "",
self.startedDate?.ISO8601Format() ?? "",
]
}

var quietValue: String {
self.configuration.id
}
}

struct PrintableContainer: Codable {
struct PrintableContainer: Codable, Sendable {
let status: RuntimeStatus
let configuration: ContainerConfiguration
let networks: [Attachment]
Expand Down
3 changes: 1 addition & 2 deletions Sources/ContainerCommands/Container/ContainerStats.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ extension Application {

if format == .json {
let jsonStats = statsData.map { $0.stats2 }
let data = try JSONEncoder().encode(jsonStats)
print(String(decoding: data, as: UTF8.self))
try emit(renderJSON(jsonStats))
return
}

Expand Down
5 changes: 3 additions & 2 deletions Sources/ContainerCommands/Image/ImageInspect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import ArgumentParser
import ContainerAPIClient
import ContainerLog
import ContainerResource
import ContainerizationError
import Foundation
import Logging
Expand All @@ -42,7 +43,7 @@ extension Application {
}

public func run() async throws {
var printable = [any Codable]()
var printable: [ImageDetail] = []
var succeededImages: [String] = []
var allErrors: [(String, Error)] = []

Expand All @@ -59,7 +60,7 @@ extension Application {
}

if !printable.isEmpty {
print(try printable.jsonArray())
try emit(renderJSON(printable))
}

if !allErrors.isEmpty {
Expand Down
Loading
Loading