Browse code

Merge pull request #4948 from creack/push_single_tag

Allow push of a single tag

Victor Vieux authored on 2014/04/02 04:54:15
Showing 4 changed files
... ...
@@ -1004,7 +1004,7 @@ func (cli *DockerCli) CmdImport(args ...string) error {
1004 1004
 }
1005 1005
 
1006 1006
 func (cli *DockerCli) CmdPush(args ...string) error {
1007
-	cmd := cli.Subcmd("push", "NAME", "Push an image or a repository to the registry")
1007
+	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
1008 1008
 	if err := cmd.Parse(args); err != nil {
1009 1009
 		return nil
1010 1010
 	}
... ...
@@ -1017,8 +1017,10 @@ func (cli *DockerCli) CmdPush(args ...string) error {
1017 1017
 
1018 1018
 	cli.LoadConfigFile()
1019 1019
 
1020
+	remote, tag := utils.ParseRepositoryTag(name)
1021
+
1020 1022
 	// Resolve the Repository name from fqn to hostname + name
1021
-	hostname, _, err := registry.ResolveRepositoryName(name)
1023
+	hostname, _, err := registry.ResolveRepositoryName(remote)
1022 1024
 	if err != nil {
1023 1025
 		return err
1024 1026
 	}
... ...
@@ -1037,6 +1039,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
1037 1037
 	}
1038 1038
 
1039 1039
 	v := url.Values{}
1040
+	v.Set("tag", tag)
1040 1041
 	push := func(authConfig registry.AuthConfig) error {
1041 1042
 		buf, err := json.Marshal(authConfig)
1042 1043
 		if err != nil {
... ...
@@ -1046,7 +1049,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
1046 1046
 			base64.URLEncoding.EncodeToString(buf),
1047 1047
 		}
1048 1048
 
1049
-		return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
1049
+		return cli.stream("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
1050 1050
 			"X-Registry-Auth": registryAuthHeader,
1051 1051
 		})
1052 1052
 	}
... ...
@@ -517,6 +517,7 @@ func postImagesPush(eng *engine.Engine, version version.Version, w http.Response
517 517
 	job := eng.Job("push", vars["name"])
518 518
 	job.SetenvJson("metaHeaders", metaHeaders)
519 519
 	job.SetenvJson("authConfig", authConfig)
520
+	job.Setenv("tag", r.Form.Get("tag"))
520 521
 	if version.GreaterThan("1.0") {
521 522
 		job.SetenvBool("json", true)
522 523
 		streamJSON(job, w, true)
... ...
@@ -1007,12 +1007,10 @@ The last container is marked as a ``Ghost`` container. It is a container that wa
1007 1007
 
1008 1008
 ::
1009 1009
 
1010
-    Usage: docker pull NAME
1010
+    Usage: docker pull NAME[:TAG]
1011 1011
 
1012 1012
     Pull an image or a repository from the registry
1013 1013
 
1014
-      -t, --tag="": Download tagged image in repository
1015
-
1016 1014
 
1017 1015
 .. _cli_push:
1018 1016
 
... ...
@@ -1021,7 +1019,7 @@ The last container is marked as a ``Ghost`` container. It is a container that wa
1021 1021
 
1022 1022
 ::
1023 1023
 
1024
-    Usage: docker push NAME
1024
+    Usage: docker push NAME[:TAG]
1025 1025
 
1026 1026
     Push an image or a repository to the registry
1027 1027
 
... ...
@@ -1405,7 +1405,7 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status {
1405 1405
 }
1406 1406
 
1407 1407
 // Retrieve the all the images to be uploaded in the correct order
1408
-func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[string][]string, error) {
1408
+func (srv *Server) getImageList(localRepo map[string]string, requestedTag string) ([]string, map[string][]string, error) {
1409 1409
 	var (
1410 1410
 		imageList   []string
1411 1411
 		imagesSeen  map[string]bool     = make(map[string]bool)
... ...
@@ -1413,6 +1413,9 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[stri
1413 1413
 	)
1414 1414
 
1415 1415
 	for tag, id := range localRepo {
1416
+		if requestedTag != "" && requestedTag != tag {
1417
+			continue
1418
+		}
1416 1419
 		var imageListForThisTag []string
1417 1420
 
1418 1421
 		tagsByImage[id] = append(tagsByImage[id], tag)
... ...
@@ -1439,25 +1442,29 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[stri
1439 1439
 		// append to main image list
1440 1440
 		imageList = append(imageList, imageListForThisTag...)
1441 1441
 	}
1442
-
1442
+	if len(imageList) == 0 {
1443
+		return nil, nil, fmt.Errorf("No images found for the requested repository / tag")
1444
+	}
1443 1445
 	utils.Debugf("Image list: %v", imageList)
1444 1446
 	utils.Debugf("Tags by image: %v", tagsByImage)
1445 1447
 
1446 1448
 	return imageList, tagsByImage, nil
1447 1449
 }
1448 1450
 
1449
-func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, sf *utils.StreamFormatter) error {
1451
+func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, tag string, sf *utils.StreamFormatter) error {
1450 1452
 	out = utils.NewWriteFlusher(out)
1451 1453
 	utils.Debugf("Local repo: %s", localRepo)
1452
-	imgList, tagsByImage, err := srv.getImageList(localRepo)
1454
+	imgList, tagsByImage, err := srv.getImageList(localRepo, tag)
1453 1455
 	if err != nil {
1454 1456
 		return err
1455 1457
 	}
1456 1458
 
1457 1459
 	out.Write(sf.FormatStatus("", "Sending image list"))
1458 1460
 
1459
-	var repoData *registry.RepositoryData
1460
-	var imageIndex []*registry.ImgData
1461
+	var (
1462
+		repoData   *registry.RepositoryData
1463
+		imageIndex []*registry.ImgData
1464
+	)
1461 1465
 
1462 1466
 	for _, imgId := range imgList {
1463 1467
 		if tags, exists := tagsByImage[imgId]; exists {
... ...
@@ -1492,8 +1499,12 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName
1492 1492
 		return err
1493 1493
 	}
1494 1494
 
1495
+	nTag := 1
1496
+	if tag == "" {
1497
+		nTag = len(localRepo)
1498
+	}
1495 1499
 	for _, ep := range repoData.Endpoints {
1496
-		out.Write(sf.FormatStatus("", "Pushing repository %s (%d tags)", localName, len(localRepo)))
1500
+		out.Write(sf.FormatStatus("", "Pushing repository %s (%d tags)", localName, nTag))
1497 1501
 
1498 1502
 		for _, imgId := range imgList {
1499 1503
 			if r.LookupRemoteImage(imgId, ep, repoData.Tokens) {
... ...
@@ -1579,6 +1590,7 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
1579 1579
 		metaHeaders map[string][]string
1580 1580
 	)
1581 1581
 
1582
+	tag := job.Getenv("tag")
1582 1583
 	job.GetenvJson("authConfig", authConfig)
1583 1584
 	job.GetenvJson("metaHeaders", metaHeaders)
1584 1585
 	if _, err := srv.poolAdd("push", localName); err != nil {
... ...
@@ -1604,11 +1616,14 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
1604 1604
 	}
1605 1605
 
1606 1606
 	if err != nil {
1607
-		reposLen := len(srv.runtime.Repositories().Repositories[localName])
1607
+		reposLen := 1
1608
+		if tag == "" {
1609
+			reposLen = len(srv.runtime.Repositories().Repositories[localName])
1610
+		}
1608 1611
 		job.Stdout.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", localName, reposLen))
1609 1612
 		// If it fails, try to get the repository
1610 1613
 		if localRepo, exists := srv.runtime.Repositories().Repositories[localName]; exists {
1611
-			if err := srv.pushRepository(r, job.Stdout, localName, remoteName, localRepo, sf); err != nil {
1614
+			if err := srv.pushRepository(r, job.Stdout, localName, remoteName, localRepo, tag, sf); err != nil {
1612 1615
 				return job.Error(err)
1613 1616
 			}
1614 1617
 			return engine.StatusOK