Skip to content

Commit

Permalink
podman images: sort repository with tags
Browse files Browse the repository at this point in the history
When you sort by repository a user most likely also want the tags to be
sorted as well. At the very least to get a stable output as the order
could be changed pull podman tag/pull even if they keep using the same
tag name.

Fixes #23803

Signed-off-by: Paul Holzinger <[email protected]>
  • Loading branch information
Luap99 committed Sep 6, 2024
1 parent 2be86b7 commit 0abbcfa
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 28 deletions.
59 changes: 31 additions & 28 deletions cmd/podman/images/list.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package images

import (
"cmp"
"errors"
"fmt"
"os"
"sort"
"slices"
"strings"
"time"
"unicode"
Expand Down Expand Up @@ -249,7 +250,35 @@ func sortImages(imageS []*entities.ImageSummary) ([]imageReporter, error) {
listFlag.readOnly = e.IsReadOnly()
}

sort.Slice(imgs, sortFunc(listFlag.sort, imgs))
slices.SortFunc(imgs, func(a, b imageReporter) int {
switch listFlag.sort {
case "id":
return cmp.Compare(a.ID(), b.ID())

case "repository":
r := cmp.Compare(a.Repository, b.Repository)
if r == 0 {
// if repository is the same imply tag sorting
return cmp.Compare(a.Tag, b.Tag)
}
return r
case "size":
return cmp.Compare(a.size(), b.size())
case "tag":
return cmp.Compare(a.Tag, b.Tag)
case "created":
if a.created().After(b.created()) {
return -1
}
if a.created().Equal(b.created()) {
return 0
}
return 1
default:
return 0
}
})

return imgs, err
}

Expand Down Expand Up @@ -284,32 +313,6 @@ func tokenRepoTag(ref string) (string, string, error) {
return name, tag, nil
}

func sortFunc(key string, data []imageReporter) func(i, j int) bool {
switch key {
case "id":
return func(i, j int) bool {
return data[i].ID() < data[j].ID()
}
case "repository":
return func(i, j int) bool {
return data[i].Repository < data[j].Repository
}
case "size":
return func(i, j int) bool {
return data[i].size() < data[j].size()
}
case "tag":
return func(i, j int) bool {
return data[i].Tag < data[j].Tag
}
default:
// case "created":
return func(i, j int) bool {
return data[i].created().After(data[j].created())
}
}
}

func lsFormatFromFlags(flags listFlagType) string {
row := []string{
"{{if .Repository}}{{.Repository}}{{else}}<none>{{end}}",
Expand Down
1 change: 1 addition & 0 deletions docs/source/markdown/podman-images.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ Lists only the image IDs.
#### **--sort**=*sort*

Sort by *created*, *id*, *repository*, *size* or *tag* (default: **created**)
When sorting by *repository* it also sorts by the *tag* as second criteria to provide a stable output.

## EXAMPLE

Expand Down
19 changes: 19 additions & 0 deletions test/system/020-tag.bats
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ function _tag_and_check() {
# prepended and ":latest" is appended.
_tag_and_check image localhost/image:latest

# The order is intentionally wrong here to check the sorting
# https://github.com/containers/podman/issues/23803
local image1="registry.com/image:1"
run_podman tag $IMAGE $image1
local image3="registry.com/image:3"
run_podman tag $IMAGE $image3
local image2="registry.com/image:2"
run_podman tag $IMAGE $image2

local imageA="registry.com/aaa:a"
run_podman tag $IMAGE $imageA

local nl="
"
run_podman images --format '{{.Repository}}:{{.Tag}}' --sort repository
assert "$output" =~ "$imageA${nl}$image1${nl}$image2${nl}$image3" "images are sorted by repository and tag"

run_podman untag $IMAGE $imageA $image1 $image2 $image3

# Test error case.
run_podman 125 untag $IMAGE registry.com/foo:bar
is "$output" "Error: registry.com/foo:bar: tag not known"
Expand Down

0 comments on commit 0abbcfa

Please sign in to comment.