瀏覽代碼

Merge pull request #4948 from creack/push_single_tag

Allow push of a single tag
Victor Vieux 11 年之前
父節點
當前提交
e175a55eb9
共有 4 個文件被更改,包括 33 次插入16 次删除
  1. 6 3
      api/client/commands.go
  2. 1 0
      api/server/server.go
  3. 2 4
      docs/sources/reference/commandline/cli.rst
  4. 24 9
      server/server.go

+ 6 - 3
api/client/commands.go

@@ -1004,7 +1004,7 @@ func (cli *DockerCli) CmdImport(args ...string) error {
 }
 
 func (cli *DockerCli) CmdPush(args ...string) error {
-	cmd := cli.Subcmd("push", "NAME", "Push an image or a repository to the registry")
+	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -1017,8 +1017,10 @@ func (cli *DockerCli) CmdPush(args ...string) error {
 
 	cli.LoadConfigFile()
 
+	remote, tag := utils.ParseRepositoryTag(name)
+
 	// Resolve the Repository name from fqn to hostname + name
-	hostname, _, err := registry.ResolveRepositoryName(name)
+	hostname, _, err := registry.ResolveRepositoryName(remote)
 	if err != nil {
 		return err
 	}
@@ -1037,6 +1039,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
 	}
 
 	v := url.Values{}
+	v.Set("tag", tag)
 	push := func(authConfig registry.AuthConfig) error {
 		buf, err := json.Marshal(authConfig)
 		if err != nil {
@@ -1046,7 +1049,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
 			base64.URLEncoding.EncodeToString(buf),
 		}
 
-		return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
+		return cli.stream("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
 			"X-Registry-Auth": registryAuthHeader,
 		})
 	}

+ 1 - 0
api/server/server.go

@@ -517,6 +517,7 @@ func postImagesPush(eng *engine.Engine, version version.Version, w http.Response
 	job := eng.Job("push", vars["name"])
 	job.SetenvJson("metaHeaders", metaHeaders)
 	job.SetenvJson("authConfig", authConfig)
+	job.Setenv("tag", r.Form.Get("tag"))
 	if version.GreaterThan("1.0") {
 		job.SetenvBool("json", true)
 		streamJSON(job, w, true)

+ 2 - 4
docs/sources/reference/commandline/cli.rst

@@ -1007,12 +1007,10 @@ The last container is marked as a ``Ghost`` container. It is a container that wa
 
 ::
 
-    Usage: docker pull NAME
+    Usage: docker pull NAME[:TAG]
 
     Pull an image or a repository from the registry
 
-      -t, --tag="": Download tagged image in repository
-
 
 .. _cli_push:
 
@@ -1021,7 +1019,7 @@ The last container is marked as a ``Ghost`` container. It is a container that wa
 
 ::
 
-    Usage: docker push NAME
+    Usage: docker push NAME[:TAG]
 
     Push an image or a repository to the registry
 

+ 24 - 9
server/server.go

@@ -1405,7 +1405,7 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status {
 }
 
 // Retrieve the all the images to be uploaded in the correct order
-func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[string][]string, error) {
+func (srv *Server) getImageList(localRepo map[string]string, requestedTag string) ([]string, map[string][]string, error) {
 	var (
 		imageList   []string
 		imagesSeen  map[string]bool     = make(map[string]bool)
@@ -1413,6 +1413,9 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[stri
 	)
 
 	for tag, id := range localRepo {
+		if requestedTag != "" && requestedTag != tag {
+			continue
+		}
 		var imageListForThisTag []string
 
 		tagsByImage[id] = append(tagsByImage[id], tag)
@@ -1439,25 +1442,29 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[stri
 		// append to main image list
 		imageList = append(imageList, imageListForThisTag...)
 	}
-
+	if len(imageList) == 0 {
+		return nil, nil, fmt.Errorf("No images found for the requested repository / tag")
+	}
 	utils.Debugf("Image list: %v", imageList)
 	utils.Debugf("Tags by image: %v", tagsByImage)
 
 	return imageList, tagsByImage, nil
 }
 
-func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, sf *utils.StreamFormatter) error {
+func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, tag string, sf *utils.StreamFormatter) error {
 	out = utils.NewWriteFlusher(out)
 	utils.Debugf("Local repo: %s", localRepo)
-	imgList, tagsByImage, err := srv.getImageList(localRepo)
+	imgList, tagsByImage, err := srv.getImageList(localRepo, tag)
 	if err != nil {
 		return err
 	}
 
 	out.Write(sf.FormatStatus("", "Sending image list"))
 
-	var repoData *registry.RepositoryData
-	var imageIndex []*registry.ImgData
+	var (
+		repoData   *registry.RepositoryData
+		imageIndex []*registry.ImgData
+	)
 
 	for _, imgId := range imgList {
 		if tags, exists := tagsByImage[imgId]; exists {
@@ -1492,8 +1499,12 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName
 		return err
 	}
 
+	nTag := 1
+	if tag == "" {
+		nTag = len(localRepo)
+	}
 	for _, ep := range repoData.Endpoints {
-		out.Write(sf.FormatStatus("", "Pushing repository %s (%d tags)", localName, len(localRepo)))
+		out.Write(sf.FormatStatus("", "Pushing repository %s (%d tags)", localName, nTag))
 
 		for _, imgId := range imgList {
 			if r.LookupRemoteImage(imgId, ep, repoData.Tokens) {
@@ -1579,6 +1590,7 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
 		metaHeaders map[string][]string
 	)
 
+	tag := job.Getenv("tag")
 	job.GetenvJson("authConfig", authConfig)
 	job.GetenvJson("metaHeaders", metaHeaders)
 	if _, err := srv.poolAdd("push", localName); err != nil {
@@ -1604,11 +1616,14 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
 	}
 
 	if err != nil {
-		reposLen := len(srv.runtime.Repositories().Repositories[localName])
+		reposLen := 1
+		if tag == "" {
+			reposLen = len(srv.runtime.Repositories().Repositories[localName])
+		}
 		job.Stdout.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", localName, reposLen))
 		// If it fails, try to get the repository
 		if localRepo, exists := srv.runtime.Repositories().Repositories[localName]; exists {
-			if err := srv.pushRepository(r, job.Stdout, localName, remoteName, localRepo, sf); err != nil {
+			if err := srv.pushRepository(r, job.Stdout, localName, remoteName, localRepo, tag, sf); err != nil {
 				return job.Error(err)
 			}
 			return engine.StatusOK