From cfb87f8fa69a9170b2332790477a4b6c195e39cb Mon Sep 17 00:00:00 2001 From: Roland Kammerer Date: Tue, 23 Apr 2019 14:44:30 +0200 Subject: [PATCH] server: add sort option This adds a '--sort' to the 'server' sub-command. Currently there is only one sort option, which is by create date. I assumed that his is useful in general, compared to a random order, so I made this the default. This is slightly over engineered, but makes it easier to add additional sorting options later. One that comes to my mind is sorting by tag (some kind of natsort/semversort). Signed-off-by: Roland Kammerer --- README.md | 24 +++++++++++++----------- handlers.go | 17 +++++++++++++++++ server.go | 10 ++++++++++ 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3b1b661f8..16dc2a4cb 100644 --- a/README.md +++ b/README.md @@ -225,22 +225,24 @@ Run a static UI server for a registry. Flags: - -u, --username username for the registry (default: ) - --listen-address address to listen on (default: ) --asset-path Path to assets and templates (default: ) - -f, --force-non-ssl force allow use of non-ssl (default: false) - --once generate the templates once and then exit (default: false) - --skip-ping skip pinging the registry while establishing connection (default: false) - --timeout timeout for HTTP requests (default: 1m0s) + --auth-url alternate URL for registry authentication (ex. auth.docker.io) (default: ) --cert path to ssl cert (default: ) + --clair url to clair instance (default: ) -d enable debug logging (default: false) + -f, --force-non-ssl force allow use of non-ssl (default: false) + --interval interval to generate new index.html's at (default: 1h0m0s) + -k, --insecure do not verify tls certificates (default: false) --key path to ssl key (default: ) + --listen-address address to listen on (default: ) + --once generate the templates once and then exit (default: false) + -p, --password password for the registry (default: ) --port port for server to run on (default: 8080) -r, --registry URL to the private registry (ex. r.j3ss.co) (default: ) - --clair url to clair instance (default: ) - -k, --insecure do not verify tls certificates (default: false) - --interval interval to generate new index.html's at (default: 1h0m0s) - -p, --password password for the registry (default: ) + --skip-ping skip pinging the registry while establishing connection (default: false) + --sort generate tag templates sorted by property (one of: created) (default: created) + --timeout timeout for HTTP requests (default: 1m0s) + -u, --username username for the registry (default: ) ``` **Screenshots:** @@ -283,4 +285,4 @@ against an insecure registry. **OR** Run `make dind dtest` to avoid having to change your local docker config and -to run the tests as docker-in-docker. \ No newline at end of file +to run the tests as docker-in-docker. diff --git a/handlers.go b/handlers.go index 362041685..594fea169 100644 --- a/handlers.go +++ b/handlers.go @@ -11,6 +11,7 @@ import ( "net/url" "os" "path/filepath" + "sort" "strings" "sync" "time" @@ -28,6 +29,7 @@ type registryController struct { l sync.Mutex tmpl *template.Template generateOnly bool + repoSortBy string } type v1Compatibility struct { @@ -44,6 +46,16 @@ type Repository struct { VulnerabilityReport clair.VulnerabilityReport `json:"vulnerability"` } +const ( + sortByCreated = "created" +) + +type repoByDate []Repository + +func (r repoByDate) Len() int { return len(r) } +func (r repoByDate) Less(i, j int) bool { return r[i].Created.Before(r[j].Created) } +func (r repoByDate) Swap(i, j int) { r[i], r[j] = r[j], r[i] } + // An AnalysisResult holds all vulnerabilities of a scan type AnalysisResult struct { Repositories []Repository `json:"repositories"` @@ -228,6 +240,11 @@ func (rc *registryController) generateTagsTemplate(ctx context.Context, repo str result.Repositories = append(result.Repositories, rp) } + switch rc.repoSortBy { + case sortByCreated: + sort.Sort(sort.Reverse(repoByDate(result.Repositories))) + } + // Execute the template. var buf bytes.Buffer if err := rc.tmpl.ExecuteTemplate(&buf, "tags", result); err != nil { diff --git a/server.go b/server.go index fcd4cd71e..b6ae6752e 100644 --- a/server.go +++ b/server.go @@ -43,6 +43,10 @@ func (cmd *serverCommand) Register(fs *flag.FlagSet) { fs.StringVar(&cmd.assetPath, "asset-path", "", "Path to assets and templates") fs.BoolVar(&cmd.generateAndExit, "once", false, "generate the templates once and then exit") + + sortOpts := []string{sortByCreated} + fs.StringVar(&cmd.repoSortBy, "sort", sortByCreated, + fmt.Sprintf("generate tag templates sorted by property (one of: %s)", strings.Join(sortOpts, ","))) } type serverCommand struct { @@ -57,6 +61,7 @@ type serverCommand struct { listenAddress string port string assetPath string + repoSortBy string } func (cmd *serverCommand) Run(ctx context.Context, args []string) error { @@ -66,10 +71,15 @@ func (cmd *serverCommand) Run(ctx context.Context, args []string) error { return err } + if cmd.repoSortBy != sortByCreated { + return fmt.Errorf("sort option invalid; '%s' is not valid", cmd.repoSortBy) + } + // Create the registry controller for the handlers. rc := registryController{ reg: r, generateOnly: cmd.generateAndExit, + repoSortBy: cmd.repoSortBy, } // Create a clair client if the user passed in a server address.