From cd6aeaf97912a0c18994c978a4b58678e671d9ee Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sat, 3 Aug 2013 15:33:51 -0700 Subject: [PATCH 1/2] Sort APIImages by most recent creation date. Fixes #985. --- server.go | 2 ++ sorter.go | 36 ++++++++++++++++++++++++++++++++++++ sorter_test.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 sorter.go create mode 100644 sorter_test.go diff --git a/server.go b/server.go index cb7b2cf1be..5e30dd0118 100644 --- a/server.go +++ b/server.go @@ -241,6 +241,8 @@ func (srv *Server) Images(all bool, filter string) ([]APIImages, error) { outs = append(outs, out) } } + + sortImagesByCreation(outs) return outs, nil } diff --git a/sorter.go b/sorter.go new file mode 100644 index 0000000000..a61be0ef75 --- /dev/null +++ b/sorter.go @@ -0,0 +1,36 @@ +package docker + +import "sort" + +type imageSorter struct { + images []APIImages + by func(i1, i2 *APIImages) bool // Closure used in the Less method. +} + +// Len is part of sort.Interface. +func (s *imageSorter) Len() int { + return len(s.images) +} + +// Swap is part of sort.Interface. +func (s *imageSorter) Swap(i, j int) { + s.images[i], s.images[j] = s.images[j], s.images[i] +} + +// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter. +func (s *imageSorter) Less(i, j int) bool { + return s.by(&s.images[i], &s.images[j]) +} + +// Sort []ApiImages by most recent creation date. +func sortImagesByCreation(images []APIImages) { + creation := func(i1, i2 *APIImages) bool { + return i1.Created > i2.Created + } + + sorter := &imageSorter{ + images: images, + by: creation} + + sort.Sort(sorter) +} diff --git a/sorter_test.go b/sorter_test.go new file mode 100644 index 0000000000..3c4b3b4874 --- /dev/null +++ b/sorter_test.go @@ -0,0 +1,30 @@ +package docker + +import ( + "testing" +) + +func TestServerListOrderedImages(t *testing.T) { + runtime := mkRuntime(t) + defer nuke(runtime) + + archive, err := fakeTar() + if err != nil { + t.Fatal(err) + } + _, err = runtime.graph.Create(archive, nil, "Testing", "", nil) + if err != nil { + t.Fatal(err) + } + + srv := &Server{runtime: runtime} + + images, err := srv.Images(true, "") + if err != nil { + t.Fatal(err) + } + + if images[0].Created < images[1].Created { + t.Error("Expected []APIImges to be ordered by most recent creation date.") + } +} From e6affb1b1ac0a172ce345d14162f6944ec68da4e Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sat, 17 Aug 2013 22:11:34 -0700 Subject: [PATCH 2/2] Sort images by tag name when the creation date is the same. This establishes a strict alphabetical order for tags with the same creation date. --- server.go | 2 +- sorter.go | 10 +++++----- sorter_test.go | 29 ++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/server.go b/server.go index 5e30dd0118..5e019a4c37 100644 --- a/server.go +++ b/server.go @@ -242,7 +242,7 @@ func (srv *Server) Images(all bool, filter string) ([]APIImages, error) { } } - sortImagesByCreation(outs) + sortImagesByCreationAndTag(outs) return outs, nil } diff --git a/sorter.go b/sorter.go index a61be0ef75..a818841486 100644 --- a/sorter.go +++ b/sorter.go @@ -22,15 +22,15 @@ func (s *imageSorter) Less(i, j int) bool { return s.by(&s.images[i], &s.images[j]) } -// Sort []ApiImages by most recent creation date. -func sortImagesByCreation(images []APIImages) { - creation := func(i1, i2 *APIImages) bool { - return i1.Created > i2.Created +// Sort []ApiImages by most recent creation date and tag name. +func sortImagesByCreationAndTag(images []APIImages) { + creationAndTag := func(i1, i2 *APIImages) bool { + return i1.Created > i2.Created || (i1.Created == i2.Created && i2.Tag > i1.Tag) } sorter := &imageSorter{ images: images, - by: creation} + by: creationAndTag} sort.Sort(sorter) } diff --git a/sorter_test.go b/sorter_test.go index 3c4b3b4874..5519708ece 100644 --- a/sorter_test.go +++ b/sorter_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -func TestServerListOrderedImages(t *testing.T) { +func TestServerListOrderedImagesByCreationDate(t *testing.T) { runtime := mkRuntime(t) defer nuke(runtime) @@ -28,3 +28,30 @@ func TestServerListOrderedImages(t *testing.T) { t.Error("Expected []APIImges to be ordered by most recent creation date.") } } + +func TestServerListOrderedImagesByCreationDateAndTag(t *testing.T) { + runtime := mkRuntime(t) + defer nuke(runtime) + + archive, err := fakeTar() + if err != nil { + t.Fatal(err) + } + image, err := runtime.graph.Create(archive, nil, "Testing", "", nil) + if err != nil { + t.Fatal(err) + } + + srv := &Server{runtime: runtime} + srv.ContainerTag(image.ID, "repo", "foo", false) + srv.ContainerTag(image.ID, "repo", "bar", false) + + images, err := srv.Images(true, "") + if err != nil { + t.Fatal(err) + } + + if images[0].Created != images[1].Created || images[0].Tag >= images[1].Tag { + t.Error("Expected []APIImges to be ordered by most recent creation date and tag name.") + } +}