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:
parent
bf62b7ebb7
commit
a49594a0e1
2 changed files with 90 additions and 60 deletions
|
@ -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 ®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
|
// 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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue