forked from toolshed/abra
		
	
		
			
				
	
	
		
			108 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package docker
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/containers/image/docker/reference"
 | |
| 	"github.com/containers/image/image"
 | |
| 	"github.com/containers/image/types"
 | |
| 	"github.com/pkg/errors"
 | |
| )
 | |
| 
 | |
| // Image is a Docker-specific implementation of types.ImageCloser with a few extra methods
 | |
| // which are specific to Docker.
 | |
| type Image struct {
 | |
| 	types.ImageCloser
 | |
| 	src *dockerImageSource
 | |
| }
 | |
| 
 | |
| // newImage returns a new Image interface type after setting up
 | |
| // a client to the registry hosting the given image.
 | |
| // The caller must call .Close() on the returned Image.
 | |
| func newImage(ctx context.Context, sys *types.SystemContext, ref dockerReference) (types.ImageCloser, error) {
 | |
| 	s, err := newImageSource(ctx, sys, ref)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	img, err := image.FromSource(ctx, sys, s)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return &Image{ImageCloser: img, src: s}, nil
 | |
| }
 | |
| 
 | |
| // SourceRefFullName returns a fully expanded name for the repository this image is in.
 | |
| func (i *Image) SourceRefFullName() string {
 | |
| 	return i.src.ref.ref.Name()
 | |
| }
 | |
| 
 | |
| // GetRepositoryTags list all tags available in the repository. The tag
 | |
| // provided inside the ImageReference will be ignored. (This is a
 | |
| // backward-compatible shim method which calls the module-level
 | |
| // GetRepositoryTags)
 | |
| func (i *Image) GetRepositoryTags(ctx context.Context) ([]string, error) {
 | |
| 	return GetRepositoryTags(ctx, i.src.c.sys, i.src.ref)
 | |
| }
 | |
| 
 | |
| // GetRepositoryTags list all tags available in the repository. The tag
 | |
| // provided inside the ImageReference will be ignored.
 | |
| func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.ImageReference) ([]string, error) {
 | |
| 	dr, ok := ref.(dockerReference)
 | |
| 	if !ok {
 | |
| 		return nil, errors.Errorf("ref must be a dockerReference")
 | |
| 	}
 | |
| 
 | |
| 	path := fmt.Sprintf(tagsPath, reference.Path(dr.ref))
 | |
| 	client, err := newDockerClientFromRef(sys, dr, false, "pull")
 | |
| 	if err != nil {
 | |
| 		return nil, errors.Wrap(err, "failed to create client")
 | |
| 	}
 | |
| 
 | |
| 	tags := make([]string, 0)
 | |
| 
 | |
| 	for {
 | |
| 		res, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		defer res.Body.Close()
 | |
| 		if res.StatusCode != http.StatusOK {
 | |
| 			// print url also
 | |
| 			return nil, errors.Errorf("Invalid status code returned when fetching tags list %d (%s)", res.StatusCode, http.StatusText(res.StatusCode))
 | |
| 		}
 | |
| 
 | |
| 		var tagsHolder struct {
 | |
| 			Tags []string
 | |
| 		}
 | |
| 		if err = json.NewDecoder(res.Body).Decode(&tagsHolder); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		tags = append(tags, tagsHolder.Tags...)
 | |
| 
 | |
| 		link := res.Header.Get("Link")
 | |
| 		if link == "" {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		linkURLStr := strings.Trim(strings.Split(link, ";")[0], "<>")
 | |
| 		linkURL, err := url.Parse(linkURLStr)
 | |
| 		if err != nil {
 | |
| 			return tags, err
 | |
| 		}
 | |
| 
 | |
| 		// can be relative or absolute, but we only want the path (and I
 | |
| 		// guess we're in trouble if it forwards to a new place...)
 | |
| 		path = linkURL.Path
 | |
| 		if linkURL.RawQuery != "" {
 | |
| 			path += "?"
 | |
| 			path += linkURL.RawQuery
 | |
| 		}
 | |
| 	}
 | |
| 	return tags, nil
 | |
| }
 |