github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/api/server/backend/build/tag.go (about)

     1  package build // import "github.com/docker/docker/api/server/backend/build"
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/docker/distribution/reference"
     8  	"github.com/docker/docker/image"
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  // Tagger is responsible for tagging an image created by a builder
    13  type Tagger struct {
    14  	imageComponent ImageComponent
    15  	stdout         io.Writer
    16  	repoAndTags    []reference.Named
    17  }
    18  
    19  // NewTagger returns a new Tagger for tagging the images of a build.
    20  // If any of the names are invalid tags an error is returned.
    21  func NewTagger(backend ImageComponent, stdout io.Writer, names []string) (*Tagger, error) {
    22  	reposAndTags, err := sanitizeRepoAndTags(names)
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  	return &Tagger{
    27  		imageComponent: backend,
    28  		stdout:         stdout,
    29  		repoAndTags:    reposAndTags,
    30  	}, nil
    31  }
    32  
    33  // TagImages creates image tags for the imageID
    34  func (bt *Tagger) TagImages(imageID image.ID) error {
    35  	for _, rt := range bt.repoAndTags {
    36  		if err := bt.imageComponent.TagImageWithReference(imageID, rt); err != nil {
    37  			return err
    38  		}
    39  		fmt.Fprintf(bt.stdout, "Successfully tagged %s\n", reference.FamiliarString(rt))
    40  	}
    41  	return nil
    42  }
    43  
    44  // sanitizeRepoAndTags parses the raw "t" parameter received from the client
    45  // to a slice of repoAndTag.
    46  // It also validates each repoName and tag.
    47  func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
    48  	var (
    49  		repoAndTags []reference.Named
    50  		// This map is used for deduplicating the "-t" parameter.
    51  		uniqNames = make(map[string]struct{})
    52  	)
    53  	for _, repo := range names {
    54  		if repo == "" {
    55  			continue
    56  		}
    57  
    58  		ref, err := reference.ParseNormalizedNamed(repo)
    59  		if err != nil {
    60  			return nil, err
    61  		}
    62  
    63  		if _, isCanonical := ref.(reference.Canonical); isCanonical {
    64  			return nil, errors.New("build tag cannot contain a digest")
    65  		}
    66  
    67  		ref = reference.TagNameOnly(ref)
    68  
    69  		nameWithTag := ref.String()
    70  
    71  		if _, exists := uniqNames[nameWithTag]; !exists {
    72  			uniqNames[nameWithTag] = struct{}{}
    73  			repoAndTags = append(repoAndTags, ref)
    74  		}
    75  	}
    76  	return repoAndTags, nil
    77  }