...

Source file src/github.com/google/go-containerregistry/pkg/v1/remote/catalog.go

Documentation: github.com/google/go-containerregistry/pkg/v1/remote

     1  // Copyright 2019 Google LLC All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package remote
    16  
    17  import (
    18  	"context"
    19  	"encoding/json"
    20  	"fmt"
    21  	"net/http"
    22  	"net/url"
    23  
    24  	"github.com/google/go-containerregistry/pkg/name"
    25  	"github.com/google/go-containerregistry/pkg/v1/remote/transport"
    26  )
    27  
    28  type Catalogs struct {
    29  	Repos []string `json:"repositories"`
    30  	Next  string   `json:"next,omitempty"`
    31  }
    32  
    33  // CatalogPage calls /_catalog, returning the list of repositories on the registry.
    34  func CatalogPage(target name.Registry, last string, n int, options ...Option) ([]string, error) {
    35  	o, err := makeOptions(options...)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	f, err := newPuller(o).fetcher(o.context, target)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	uri := url.URL{
    46  		Scheme:   target.Scheme(),
    47  		Host:     target.RegistryStr(),
    48  		Path:     "/v2/_catalog",
    49  		RawQuery: fmt.Sprintf("last=%s&n=%d", url.QueryEscape(last), n),
    50  	}
    51  
    52  	req, err := http.NewRequest(http.MethodGet, uri.String(), nil)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	resp, err := f.client.Do(req.WithContext(o.context))
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	defer resp.Body.Close()
    61  
    62  	if err := transport.CheckError(resp, http.StatusOK); err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	var parsed Catalogs
    67  	if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	return parsed.Repos, nil
    72  }
    73  
    74  // Catalog calls /_catalog, returning the list of repositories on the registry.
    75  func Catalog(ctx context.Context, target name.Registry, options ...Option) ([]string, error) {
    76  	o, err := makeOptions(options...)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	// WithContext overrides the ctx passed directly.
    82  	if o.context != context.Background() {
    83  		ctx = o.context
    84  	}
    85  
    86  	return newPuller(o).catalog(ctx, target, o.pageSize)
    87  }
    88  
    89  func (f *fetcher) catalogPage(ctx context.Context, reg name.Registry, next string, pageSize int) (*Catalogs, error) {
    90  	if next == "" {
    91  		uri := &url.URL{
    92  			Scheme: reg.Scheme(),
    93  			Host:   reg.RegistryStr(),
    94  			Path:   "/v2/_catalog",
    95  		}
    96  		if pageSize > 0 {
    97  			uri.RawQuery = fmt.Sprintf("n=%d", pageSize)
    98  		}
    99  		next = uri.String()
   100  	}
   101  
   102  	req, err := http.NewRequestWithContext(ctx, "GET", next, nil)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	resp, err := f.client.Do(req)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	if err := transport.CheckError(resp, http.StatusOK); err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	parsed := Catalogs{}
   117  	if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	if err := resp.Body.Close(); err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	uri, err := getNextPageURL(resp)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	if uri != nil {
   131  		parsed.Next = uri.String()
   132  	}
   133  
   134  	return &parsed, nil
   135  }
   136  
   137  type Catalogger struct {
   138  	f        *fetcher
   139  	reg      name.Registry
   140  	pageSize int
   141  
   142  	page *Catalogs
   143  	err  error
   144  
   145  	needMore bool
   146  }
   147  
   148  func (l *Catalogger) Next(ctx context.Context) (*Catalogs, error) {
   149  	if l.needMore {
   150  		l.page, l.err = l.f.catalogPage(ctx, l.reg, l.page.Next, l.pageSize)
   151  	} else {
   152  		l.needMore = true
   153  	}
   154  	return l.page, l.err
   155  }
   156  
   157  func (l *Catalogger) HasNext() bool {
   158  	return l.page != nil && (!l.needMore || l.page.Next != "")
   159  }
   160  

View as plain text