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 <patrick.devine@docker.com>
This commit is contained in:
Patrick Devine 2015-07-22 15:18:03 -07:00
parent b7e26bac74
commit 14749fdce4
2 changed files with 90 additions and 60 deletions

View file

@ -21,6 +21,83 @@ import (
"github.com/docker/distribution/registry/storage/cache/memory" "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 &registry{
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 // 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) { func NewRepository(ctx context.Context, name, baseURL string, transport http.RoundTripper) (distribution.Repository, error) {
if err := v2.ValidateRepositoryName(name); err != nil { if err := v2.ValidateRepositoryName(name); err != nil {
@ -458,60 +535,3 @@ func buildCatalogValues(maxEntries int, last string) url.Values {
return 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
}

View file

@ -768,8 +768,13 @@ func TestCatalog(t *testing.T) {
entries := make([]string, 5) entries := make([]string, 5)
r, err := NewRegistry(context.Background(), e, nil)
if err != nil {
t.Fatal(err)
}
ctx := context.Background() ctx := context.Background()
numFilled, err := Repositories(ctx, e, entries, "", nil) numFilled, err := r.Repositories(ctx, entries, "")
if err != io.EOF { if err != io.EOF {
t.Fatal(err) t.Fatal(err)
} }
@ -795,8 +800,13 @@ func TestCatalogInParts(t *testing.T) {
entries := make([]string, 2) entries := make([]string, 2)
r, err := NewRegistry(context.Background(), e, nil)
if err != nil {
t.Fatal(err)
}
ctx := context.Background() ctx := context.Background()
numFilled, err := Repositories(ctx, e, entries, "", nil) numFilled, err := r.Repositories(ctx, entries, "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -805,7 +815,7 @@ func TestCatalogInParts(t *testing.T) {
t.Fatalf("Got wrong number of repos") 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 { if err != io.EOF {
t.Fatal(err) t.Fatal(err)
} }