From 14749fdce40d405b020beff9e5f139734e4b9347 Mon Sep 17 00:00:00 2001 From: Patrick Devine Date: Wed, 22 Jul 2015 15:18:03 -0700 Subject: [PATCH] Add Registry to client bindings for Repositories The way Repositories() was initially called was somewhat different than other parts of the client bindings because there was no way to instantiate a Namespace. This change implements a NewRegistry() function which changes it so that Repositories() can be called the way one would expect. It doesn't implement any of the other functions of Namespaces. Signed-off-by: Patrick Devine --- registry/client/repository.go | 134 +++++++++++++++++------------ registry/client/repository_test.go | 16 +++- 2 files changed, 90 insertions(+), 60 deletions(-) diff --git a/registry/client/repository.go b/registry/client/repository.go index 6979cc4d2..29effcce8 100644 --- a/registry/client/repository.go +++ b/registry/client/repository.go @@ -21,6 +21,83 @@ import ( "github.com/docker/distribution/registry/storage/cache/memory" ) +// Registry provides an interface for calling Repositories, which returns a catalog of repositories. +type Registry interface { + Repositories(ctx context.Context, repos []string, last string) (n int, err error) +} + +// NewRegistry creates a registry namespace which can be used to get a listing of repositories +func NewRegistry(ctx context.Context, baseURL string, transport http.RoundTripper) (Registry, error) { + ub, err := v2.NewURLBuilderFromString(baseURL) + if err != nil { + return nil, err + } + + client := &http.Client{ + Transport: transport, + Timeout: 1 * time.Minute, + } + + return ®istry{ + client: client, + ub: ub, + context: ctx, + }, nil +} + +type registry struct { + client *http.Client + ub *v2.URLBuilder + context context.Context +} + +// Repositories returns a lexigraphically sorted catalog given a base URL. The 'entries' slice will be filled up to the size +// of the slice, starting at the value provided in 'last'. The number of entries will be returned along with io.EOF if there +// are no more entries +func (r *registry) Repositories(ctx context.Context, entries []string, last string) (int, error) { + var numFilled int + var returnErr error + + values := buildCatalogValues(len(entries), last) + u, err := r.ub.BuildCatalogURL(values) + if err != nil { + return 0, err + } + + resp, err := r.client.Get(u) + if err != nil { + return 0, err + } + defer resp.Body.Close() + + switch resp.StatusCode { + case http.StatusOK: + var ctlg struct { + Repositories []string `json:"repositories"` + } + decoder := json.NewDecoder(resp.Body) + + if err := decoder.Decode(&ctlg); err != nil { + return 0, err + } + + for cnt := range ctlg.Repositories { + entries[cnt] = ctlg.Repositories[cnt] + } + numFilled = len(ctlg.Repositories) + + link := resp.Header.Get("Link") + if link == "" { + returnErr = io.EOF + } + + default: + return 0, handleErrorResponse(resp) + } + + return numFilled, returnErr +} + // NewRepository creates a new Repository for the given repository name and base URL func NewRepository(ctx context.Context, name, baseURL string, transport http.RoundTripper) (distribution.Repository, error) { if err := v2.ValidateRepositoryName(name); err != nil { @@ -458,60 +535,3 @@ func buildCatalogValues(maxEntries int, last string) url.Values { return values } - -// Repositories returns a lexigraphically sorted catalog given a base URL. The 'entries' slice will be filled up to the size -// of the slice, starting at the value provided in 'last'. The number of entries will be returned along with io.EOF if there -// are no more entries -func Repositories(ctx context.Context, baseURL string, entries []string, last string, transport http.RoundTripper) (int, error) { - var numFilled int - var returnErr error - - ub, err := v2.NewURLBuilderFromString(baseURL) - if err != nil { - return 0, err - } - - client := &http.Client{ - Transport: transport, - Timeout: 1 * time.Minute, - } - - values := buildCatalogValues(len(entries), last) - u, err := ub.BuildCatalogURL(values) - if err != nil { - return 0, err - } - - resp, err := client.Get(u) - if err != nil { - return 0, err - } - defer resp.Body.Close() - - switch resp.StatusCode { - case http.StatusOK: - var ctlg struct { - Repositories []string `json:"repositories"` - } - decoder := json.NewDecoder(resp.Body) - - if err := decoder.Decode(&ctlg); err != nil { - return 0, err - } - - for cnt := range ctlg.Repositories { - entries[cnt] = ctlg.Repositories[cnt] - } - numFilled = len(ctlg.Repositories) - - link := resp.Header.Get("Link") - if link == "" { - returnErr = io.EOF - } - - default: - return 0, handleErrorResponse(resp) - } - - return numFilled, returnErr -} diff --git a/registry/client/repository_test.go b/registry/client/repository_test.go index b803d754b..232501aa3 100644 --- a/registry/client/repository_test.go +++ b/registry/client/repository_test.go @@ -768,8 +768,13 @@ func TestCatalog(t *testing.T) { entries := make([]string, 5) + r, err := NewRegistry(context.Background(), e, nil) + if err != nil { + t.Fatal(err) + } + ctx := context.Background() - numFilled, err := Repositories(ctx, e, entries, "", nil) + numFilled, err := r.Repositories(ctx, entries, "") if err != io.EOF { t.Fatal(err) } @@ -795,8 +800,13 @@ func TestCatalogInParts(t *testing.T) { entries := make([]string, 2) + r, err := NewRegistry(context.Background(), e, nil) + if err != nil { + t.Fatal(err) + } + ctx := context.Background() - numFilled, err := Repositories(ctx, e, entries, "", nil) + numFilled, err := r.Repositories(ctx, entries, "") if err != nil { t.Fatal(err) } @@ -805,7 +815,7 @@ func TestCatalogInParts(t *testing.T) { t.Fatalf("Got wrong number of repos") } - numFilled, err = Repositories(ctx, e, entries, "baz", nil) + numFilled, err = r.Repositories(ctx, entries, "baz") if err != io.EOF { t.Fatal(err) }