Show rootfs sizes in image list

Replace the noisy rootfs path column in `banger image list` with the current rootfs file size so the table is easier to scan.

Render a ROOTFS SIZE column from the on-disk image size, fall back to `-` when the artifact cannot be statted, and keep the existing image summary output unchanged.

Add CLI coverage for both the formatted size case and the missing-file fallback, then rebuild and check the live command output.
This commit is contained in:
Thales Maciel 2026-03-21 21:55:01 -03:00
parent 14d8563f3c
commit 3b7e77a2de
No known key found for this signature in database
GPG key ID: 33112E6833C34679
2 changed files with 78 additions and 6 deletions

View file

@ -809,12 +809,7 @@ func newImageListCommand() *cobra.Command {
if err != nil {
return err
}
w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 8, 2, ' ', 0)
fmt.Fprintln(w, "ID\tNAME\tMANAGED\tROOTFS\tCREATED")
for _, image := range result.Images {
fmt.Fprintf(w, "%s\t%s\t%t\t%s\t%s\n", shortID(image.ID), image.Name, image.Managed, image.RootfsPath, relativeTime(image.CreatedAt))
}
return w.Flush()
return printImageListTable(cmd.OutOrStdout(), result.Images)
},
}
}
@ -1318,6 +1313,38 @@ func printImageSummary(out anyWriter, image model.Image) error {
return err
}
func printImageListTable(out anyWriter, images []model.Image) error {
w := tabwriter.NewWriter(out, 0, 8, 2, ' ', 0)
if _, err := fmt.Fprintln(w, "ID\tNAME\tMANAGED\tROOTFS SIZE\tCREATED"); err != nil {
return err
}
for _, image := range images {
if _, err := fmt.Fprintf(
w,
"%s\t%s\t%t\t%s\t%s\n",
shortID(image.ID),
image.Name,
image.Managed,
rootfsSizeLabel(image.RootfsPath),
relativeTime(image.CreatedAt),
); err != nil {
return err
}
}
return w.Flush()
}
func rootfsSizeLabel(path string) string {
info, err := os.Stat(path)
if err != nil {
return "-"
}
if info.Size() <= 0 {
return "0"
}
return model.FormatSizeBytes(info.Size())
}
func printVMPortsTable(out anyWriter, result api.VMPortsResult) error {
type portRow struct {
Proto string

View file

@ -474,6 +474,51 @@ func TestAbsolutizeImageRegisterPaths(t *testing.T) {
}
}
func TestPrintImageListTableShowsRootfsSizes(t *testing.T) {
rootfs := filepath.Join(t.TempDir(), "rootfs.ext4")
if err := os.WriteFile(rootfs, nil, 0o644); err != nil {
t.Fatalf("WriteFile(%s): %v", rootfs, err)
}
if err := os.Truncate(rootfs, 8*1024); err != nil {
t.Fatalf("Truncate(%s): %v", rootfs, err)
}
var out bytes.Buffer
err := printImageListTable(&out, []model.Image{
{
ID: "0123456789abcdef",
Name: "alpine",
Managed: true,
RootfsPath: rootfs,
CreatedAt: time.Now().Add(-1 * time.Hour),
},
{
ID: "fedcba9876543210",
Name: "missing",
Managed: false,
RootfsPath: filepath.Join(t.TempDir(), "missing.ext4"),
CreatedAt: time.Now().Add(-2 * time.Hour),
},
})
if err != nil {
t.Fatalf("printImageListTable() error = %v", err)
}
output := out.String()
if !strings.Contains(output, "ROOTFS SIZE") {
t.Fatalf("output = %q, want rootfs size header", output)
}
if !strings.Contains(output, "alpine") || !strings.Contains(output, "8K") {
t.Fatalf("output = %q, want alpine row with 8K size", output)
}
if strings.Contains(output, rootfs) {
t.Fatalf("output = %q, should not include rootfs path", output)
}
if !strings.Contains(output, "missing") || !strings.Contains(output, "-") {
t.Fatalf("output = %q, want fallback size for missing image", output)
}
}
func TestPrintVMPortsTableSortsAndRendersURLEndpoints(t *testing.T) {
result := api.VMPortsResult{
Name: "alpha",