forked from TrueCloudLab/distribution
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
b7e26bac74
commit
14749fdce4
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