Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes <guillaume@charmes.net> (github: creack)
| ... | ... |
@@ -1000,7 +1000,7 @@ func (cli *DockerCli) CmdImport(args ...string) error {
|
| 1000 | 1000 |
} |
| 1001 | 1001 |
|
| 1002 | 1002 |
func (cli *DockerCli) CmdPush(args ...string) error {
|
| 1003 |
- cmd := cli.Subcmd("push", "NAME", "Push an image or a repository to the registry")
|
|
| 1003 |
+ cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
|
|
| 1004 | 1004 |
if err := cmd.Parse(args); err != nil {
|
| 1005 | 1005 |
return nil |
| 1006 | 1006 |
} |
| ... | ... |
@@ -1013,8 +1013,10 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
| 1013 | 1013 |
|
| 1014 | 1014 |
cli.LoadConfigFile() |
| 1015 | 1015 |
|
| 1016 |
+ remote, tag := utils.ParseRepositoryTag(name) |
|
| 1017 |
+ |
|
| 1016 | 1018 |
// Resolve the Repository name from fqn to hostname + name |
| 1017 |
- hostname, _, err := registry.ResolveRepositoryName(name) |
|
| 1019 |
+ hostname, _, err := registry.ResolveRepositoryName(remote) |
|
| 1018 | 1020 |
if err != nil {
|
| 1019 | 1021 |
return err |
| 1020 | 1022 |
} |
| ... | ... |
@@ -1033,6 +1035,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
| 1033 | 1033 |
} |
| 1034 | 1034 |
|
| 1035 | 1035 |
v := url.Values{}
|
| 1036 |
+ v.Set("tag", tag)
|
|
| 1036 | 1037 |
push := func(authConfig registry.AuthConfig) error {
|
| 1037 | 1038 |
buf, err := json.Marshal(authConfig) |
| 1038 | 1039 |
if err != nil {
|
| ... | ... |
@@ -1042,7 +1045,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
| 1042 | 1042 |
base64.URLEncoding.EncodeToString(buf), |
| 1043 | 1043 |
} |
| 1044 | 1044 |
|
| 1045 |
- return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
|
|
| 1045 |
+ return cli.stream("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
|
|
| 1046 | 1046 |
"X-Registry-Auth": registryAuthHeader, |
| 1047 | 1047 |
}) |
| 1048 | 1048 |
} |
| ... | ... |
@@ -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) |
| ... | ... |
@@ -1401,7 +1401,7 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status {
|
| 1401 | 1401 |
} |
| 1402 | 1402 |
|
| 1403 | 1403 |
// Retrieve the all the images to be uploaded in the correct order |
| 1404 |
-func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[string][]string, error) {
|
|
| 1404 |
+func (srv *Server) getImageList(localRepo map[string]string, requestedTag string) ([]string, map[string][]string, error) {
|
|
| 1405 | 1405 |
var ( |
| 1406 | 1406 |
imageList []string |
| 1407 | 1407 |
imagesSeen map[string]bool = make(map[string]bool) |
| ... | ... |
@@ -1409,6 +1409,9 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[stri |
| 1409 | 1409 |
) |
| 1410 | 1410 |
|
| 1411 | 1411 |
for tag, id := range localRepo {
|
| 1412 |
+ if requestedTag != "" && requestedTag != tag {
|
|
| 1413 |
+ continue |
|
| 1414 |
+ } |
|
| 1412 | 1415 |
var imageListForThisTag []string |
| 1413 | 1416 |
|
| 1414 | 1417 |
tagsByImage[id] = append(tagsByImage[id], tag) |
| ... | ... |
@@ -1435,25 +1438,29 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[stri |
| 1435 | 1435 |
// append to main image list |
| 1436 | 1436 |
imageList = append(imageList, imageListForThisTag...) |
| 1437 | 1437 |
} |
| 1438 |
- |
|
| 1438 |
+ if len(imageList) == 0 {
|
|
| 1439 |
+ return nil, nil, fmt.Errorf("No images found for the requested repository / tag")
|
|
| 1440 |
+ } |
|
| 1439 | 1441 |
utils.Debugf("Image list: %v", imageList)
|
| 1440 | 1442 |
utils.Debugf("Tags by image: %v", tagsByImage)
|
| 1441 | 1443 |
|
| 1442 | 1444 |
return imageList, tagsByImage, nil |
| 1443 | 1445 |
} |
| 1444 | 1446 |
|
| 1445 |
-func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, sf *utils.StreamFormatter) error {
|
|
| 1447 |
+func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, tag string, sf *utils.StreamFormatter) error {
|
|
| 1446 | 1448 |
out = utils.NewWriteFlusher(out) |
| 1447 | 1449 |
utils.Debugf("Local repo: %s", localRepo)
|
| 1448 |
- imgList, tagsByImage, err := srv.getImageList(localRepo) |
|
| 1450 |
+ imgList, tagsByImage, err := srv.getImageList(localRepo, tag) |
|
| 1449 | 1451 |
if err != nil {
|
| 1450 | 1452 |
return err |
| 1451 | 1453 |
} |
| 1452 | 1454 |
|
| 1453 | 1455 |
out.Write(sf.FormatStatus("", "Sending image list"))
|
| 1454 | 1456 |
|
| 1455 |
- var repoData *registry.RepositoryData |
|
| 1456 |
- var imageIndex []*registry.ImgData |
|
| 1457 |
+ var ( |
|
| 1458 |
+ repoData *registry.RepositoryData |
|
| 1459 |
+ imageIndex []*registry.ImgData |
|
| 1460 |
+ ) |
|
| 1457 | 1461 |
|
| 1458 | 1462 |
for _, imgId := range imgList {
|
| 1459 | 1463 |
if tags, exists := tagsByImage[imgId]; exists {
|
| ... | ... |
@@ -1488,8 +1495,12 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName |
| 1488 | 1488 |
return err |
| 1489 | 1489 |
} |
| 1490 | 1490 |
|
| 1491 |
+ nTag := 1 |
|
| 1492 |
+ if tag == "" {
|
|
| 1493 |
+ nTag = len(localRepo) |
|
| 1494 |
+ } |
|
| 1491 | 1495 |
for _, ep := range repoData.Endpoints {
|
| 1492 |
- out.Write(sf.FormatStatus("", "Pushing repository %s (%d tags)", localName, len(localRepo)))
|
|
| 1496 |
+ out.Write(sf.FormatStatus("", "Pushing repository %s (%d tags)", localName, nTag))
|
|
| 1493 | 1497 |
|
| 1494 | 1498 |
for _, imgId := range imgList {
|
| 1495 | 1499 |
if r.LookupRemoteImage(imgId, ep, repoData.Tokens) {
|
| ... | ... |
@@ -1575,6 +1586,7 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
|
| 1575 | 1575 |
metaHeaders map[string][]string |
| 1576 | 1576 |
) |
| 1577 | 1577 |
|
| 1578 |
+ tag := job.Getenv("tag")
|
|
| 1578 | 1579 |
job.GetenvJson("authConfig", authConfig)
|
| 1579 | 1580 |
job.GetenvJson("metaHeaders", metaHeaders)
|
| 1580 | 1581 |
if _, err := srv.poolAdd("push", localName); err != nil {
|
| ... | ... |
@@ -1600,11 +1612,14 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
|
| 1600 | 1600 |
} |
| 1601 | 1601 |
|
| 1602 | 1602 |
if err != nil {
|
| 1603 |
- reposLen := len(srv.runtime.Repositories().Repositories[localName]) |
|
| 1603 |
+ reposLen := 1 |
|
| 1604 |
+ if tag == "" {
|
|
| 1605 |
+ reposLen = len(srv.runtime.Repositories().Repositories[localName]) |
|
| 1606 |
+ } |
|
| 1604 | 1607 |
job.Stdout.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", localName, reposLen))
|
| 1605 | 1608 |
// If it fails, try to get the repository |
| 1606 | 1609 |
if localRepo, exists := srv.runtime.Repositories().Repositories[localName]; exists {
|
| 1607 |
- if err := srv.pushRepository(r, job.Stdout, localName, remoteName, localRepo, sf); err != nil {
|
|
| 1610 |
+ if err := srv.pushRepository(r, job.Stdout, localName, remoteName, localRepo, tag, sf); err != nil {
|
|
| 1608 | 1611 |
return job.Error(err) |
| 1609 | 1612 |
} |
| 1610 | 1613 |
return engine.StatusOK |