Skip to content

Commit 407b474

Browse files
committed
Feat: container registry list
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
1 parent 960f21a commit 407b474

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

Sources/ContainerCommands/Registry/RegistryCommand.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ extension Application {
2525
subcommands: [
2626
RegistryLogin.self,
2727
RegistryLogout.self,
28+
RegistryList.self,
2829
],
2930
aliases: ["r"]
3031
)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//===----------------------------------------------------------------------===//
2+
// Copyright © 2026 Apple Inc. and the container project authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//===----------------------------------------------------------------------===//
16+
17+
import ArgumentParser
18+
import ContainerAPIClient
19+
import ContainerizationOCI
20+
import ContainerizationOS
21+
import Foundation
22+
23+
extension Application {
24+
public struct RegistryList: AsyncLoggableCommand {
25+
@OptionGroup
26+
public var logOptions: Flags.Logging
27+
28+
@Option(name: .long, help: "Format of the output")
29+
var format: ListFormat = .table
30+
31+
@Flag(name: .shortAndLong, help: "Only output the registry name")
32+
var quiet = false
33+
34+
@Flag(name: .shortAndLong, help: "Verbose output")
35+
var verbose = false
36+
37+
public init() {}
38+
public static let configuration = CommandConfiguration(
39+
commandName: "list",
40+
abstract: "List image registry logins",
41+
aliases: ["ls"])
42+
43+
public func run() async throws {
44+
let keychain = KeychainHelper(securityDomain: Constants.keychainID)
45+
let registries = try keychain.list()
46+
try printRegistries(registries: registries, format: format)
47+
}
48+
49+
private func createHeader() -> [[String]] {
50+
[["HOSTNAME", "USERNAME", "MODIFIED", "CREATED"]]
51+
}
52+
53+
private func printRegistries(registries: [RegistryInfo], format: ListFormat) throws {
54+
if format == .json {
55+
let printables = registries.map {
56+
PrintableRegistry($0)
57+
}
58+
let data = try JSONEncoder().encode(printables)
59+
print(String(decoding: data, as: UTF8.self))
60+
61+
return
62+
}
63+
64+
if self.quiet {
65+
registries.forEach {
66+
print($0.hostname)
67+
}
68+
return
69+
}
70+
71+
var rows = createHeader()
72+
for registry in registries {
73+
rows.append(registry.asRow)
74+
}
75+
76+
let formatter = TableOutput(rows: rows)
77+
print(formatter.format())
78+
}
79+
}
80+
}
81+
extension RegistryInfo {
82+
fileprivate var asRow: [String] {
83+
[
84+
self.hostname,
85+
self.username,
86+
self.createdDate.ISO8601Format(),
87+
self.modifiedDate.ISO8601Format(),
88+
]
89+
}
90+
}
91+
struct PrintableRegistry: Codable {
92+
let hostname: String
93+
let username: String
94+
let modifiedDate: Date
95+
let createdDate: Date
96+
97+
init(_ registry: RegistryInfo) {
98+
self.hostname = registry.hostname
99+
self.username = registry.username
100+
self.modifiedDate = registry.modifiedDate
101+
self.createdDate = registry.createdDate
102+
}
103+
}

0 commit comments

Comments
 (0)