Pārlūkot izejas kodu

api: Extract parsing reference from repo and tag

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Paweł Gronowski 2 gadi atpakaļ
vecāks
revīzija
62be425bcc

+ 35 - 0
api/server/httputils/form.go

@@ -1,9 +1,12 @@
 package httputils // import "github.com/docker/docker/api/server/httputils"
 package httputils // import "github.com/docker/docker/api/server/httputils"
 
 
 import (
 import (
+	"fmt"
 	"net/http"
 	"net/http"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
+
+	"github.com/docker/distribution/reference"
 )
 )
 
 
 // BoolValue transforms a form value in different formats into a boolean type.
 // BoolValue transforms a form value in different formats into a boolean type.
@@ -41,6 +44,38 @@ func Int64ValueOrDefault(r *http.Request, field string, def int64) (int64, error
 	return def, nil
 	return def, nil
 }
 }
 
 
+// RepoTagReference parses form values "repo" and "tag" and returns a valid
+// reference with repository and tag.
+// If repo is empty, then a nil reference is returned.
+// If no tag is given, then the default "latest" tag is set.
+func RepoTagReference(repo, tag string) (reference.NamedTagged, error) {
+	if repo == "" {
+		return nil, nil
+	}
+
+	ref, err := reference.ParseNormalizedNamed(repo)
+	if err != nil {
+		return nil, err
+	}
+
+	if _, isDigested := ref.(reference.Digested); isDigested {
+		return nil, fmt.Errorf("cannot import digest reference")
+	}
+
+	if tag != "" {
+		return reference.WithTag(ref, tag)
+	}
+
+	withDefaultTag := reference.TagNameOnly(ref)
+
+	namedTagged, ok := withDefaultTag.(reference.NamedTagged)
+	if !ok {
+		return nil, fmt.Errorf("unexpected reference: %q", ref.String())
+	}
+
+	return namedTagged, nil
+}
+
 // ArchiveOptions stores archive information for different operations.
 // ArchiveOptions stores archive information for different operations.
 type ArchiveOptions struct {
 type ArchiveOptions struct {
 	Name string
 	Name string

+ 6 - 2
api/server/router/container/container_routes.go

@@ -48,10 +48,14 @@ func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter,
 		return err
 		return err
 	}
 	}
 
 
+	ref, err := httputils.RepoTagReference(r.Form.Get("repo"), r.Form.Get("tag"))
+	if err != nil {
+		return errdefs.InvalidParameter(err)
+	}
+
 	commitCfg := &backend.CreateImageConfig{
 	commitCfg := &backend.CreateImageConfig{
 		Pause:   pause,
 		Pause:   pause,
-		Repo:    r.Form.Get("repo"),
-		Tag:     r.Form.Get("tag"),
+		Tag:     ref,
 		Author:  r.Form.Get("author"),
 		Author:  r.Form.Get("author"),
 		Comment: r.Form.Get("comment"),
 		Comment: r.Form.Get("comment"),
 		Config:  config,
 		Config:  config,

+ 6 - 37
api/server/router/image/image_routes.go

@@ -72,25 +72,9 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
 	} else { // import
 	} else { // import
 		src := r.Form.Get("fromSrc")
 		src := r.Form.Get("fromSrc")
 
 
-		var ref reference.Named
-		if repo != "" {
-			var err error
-			ref, err = reference.ParseNormalizedNamed(repo)
-			if err != nil {
-				return errdefs.InvalidParameter(err)
-			}
-			if _, isDigested := ref.(reference.Digested); isDigested {
-				return errdefs.InvalidParameter(errors.New("cannot import digest reference"))
-			}
-
-			if tag != "" {
-				ref, err = reference.WithTag(ref, tag)
-				if err != nil {
-					return errdefs.InvalidParameter(err)
-				}
-			} else {
-				ref = reference.TagNameOnly(ref)
-			}
+		tagRef, err := httputils.RepoTagReference(repo, tag)
+		if err != nil {
+			return errdefs.InvalidParameter(err)
 		}
 		}
 
 
 		if len(comment) == 0 {
 		if len(comment) == 0 {
@@ -121,7 +105,7 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
 		}
 		}
 
 
 		var id image.ID
 		var id image.ID
-		id, progressErr = ir.backend.ImportImage(ctx, ref, platform, comment, layerReader, r.Form["changes"])
+		id, progressErr = ir.backend.ImportImage(ctx, tagRef, platform, comment, layerReader, r.Form["changes"])
 
 
 		if progressErr == nil {
 		if progressErr == nil {
 			output.Write(streamformatter.FormatStatus("", id.String()))
 			output.Write(streamformatter.FormatStatus("", id.String()))
@@ -370,26 +354,11 @@ func (ir *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter,
 		return err
 		return err
 	}
 	}
 
 
-	repo := r.Form.Get("repo")
-	tag := r.Form.Get("tag")
-
-	ref, err := reference.ParseNormalizedNamed(repo)
-	if err != nil {
+	ref, err := httputils.RepoTagReference(r.Form.Get("repo"), r.Form.Get("tag"))
+	if ref == nil || err != nil {
 		return errdefs.InvalidParameter(err)
 		return errdefs.InvalidParameter(err)
 	}
 	}
 
 
-	if _, isDigested := ref.(reference.Digested); isDigested {
-		return errdefs.InvalidParameter(errors.New("tag reference can't have a digest"))
-	}
-
-	if tag != "" {
-		if ref, err = reference.WithTag(reference.TrimNamed(ref), tag); err != nil {
-			return errdefs.InvalidParameter(err)
-		}
-	} else {
-		ref = reference.TagNameOnly(ref)
-	}
-
 	img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{})
 	img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{})
 	if err != nil {
 	if err != nil {
 		return errdefs.NotFound(err)
 		return errdefs.NotFound(err)

+ 2 - 2
api/types/backend/backend.go

@@ -5,6 +5,7 @@ import (
 	"io"
 	"io"
 	"time"
 	"time"
 
 
+	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/container"
 )
 )
 
 
@@ -102,8 +103,7 @@ type ExecProcessConfig struct {
 // CreateImageConfig is the configuration for creating an image from a
 // CreateImageConfig is the configuration for creating an image from a
 // container.
 // container.
 type CreateImageConfig struct {
 type CreateImageConfig struct {
-	Repo    string
-	Tag     string
+	Tag     reference.NamedTagged
 	Pause   bool
 	Pause   bool
 	Author  string
 	Author  string
 	Comment string
 	Comment string

+ 3 - 22
daemon/commit.go

@@ -121,25 +121,6 @@ func merge(userConf, imageConf *containertypes.Config) error {
 func (daemon *Daemon) CreateImageFromContainer(ctx context.Context, name string, c *backend.CreateImageConfig) (string, error) {
 func (daemon *Daemon) CreateImageFromContainer(ctx context.Context, name string, c *backend.CreateImageConfig) (string, error) {
 	start := time.Now()
 	start := time.Now()
 
 
-	var newRef reference.Named
-	if c.Repo != "" {
-		ref, err := reference.ParseNormalizedNamed(c.Repo)
-		if err != nil {
-			return "", errdefs.InvalidParameter(err)
-		}
-
-		if c.Tag != "" {
-			ref, err = reference.WithTag(ref, c.Tag)
-			if err != nil {
-				return "", errdefs.InvalidParameter(err)
-			}
-		} else {
-			ref = reference.TagNameOnly(ref)
-		}
-
-		newRef = ref
-	}
-
 	container, err := daemon.GetContainer(name)
 	container, err := daemon.GetContainer(name)
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
@@ -191,12 +172,12 @@ func (daemon *Daemon) CreateImageFromContainer(ctx context.Context, name string,
 	}
 	}
 
 
 	imageRef := ""
 	imageRef := ""
-	if newRef != nil {
-		err = daemon.imageService.TagImage(ctx, id, newRef)
+	if c.Tag != nil {
+		err = daemon.imageService.TagImage(ctx, id, c.Tag)
 		if err != nil {
 		if err != nil {
 			return "", err
 			return "", err
 		}
 		}
-		imageRef = reference.FamiliarString(newRef)
+		imageRef = reference.FamiliarString(c.Tag)
 	}
 	}
 	daemon.LogContainerEventWithAttributes(container, "commit", map[string]string{
 	daemon.LogContainerEventWithAttributes(container, "commit", map[string]string{
 		"comment":  c.Comment,
 		"comment":  c.Comment,