From e648a186d68dcb3ee0d6123b041c5aa66438cc89 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 31 Mar 2014 18:50:10 -0700 Subject: [PATCH 1/2] Allow push of a single tag Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes (github: creack) --- api/client/commands.go | 9 ++++++--- api/server/server.go | 1 + server/server.go | 33 ++++++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index 49cd07700f..ef9796b747 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1000,7 +1000,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 } @@ -1013,8 +1013,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 } @@ -1033,6 +1035,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 { @@ -1042,7 +1045,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, }) } diff --git a/api/server/server.go b/api/server/server.go index 18aefe42cd..5597d8b92c 100644 --- a/api/server/server.go +++ b/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) diff --git a/server/server.go b/server/server.go index 2cb3328d55..3e97481e0e 100644 --- a/server/server.go +++ b/server/server.go @@ -1401,7 +1401,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) @@ -1409,6 +1409,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) @@ -1435,25 +1438,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 { @@ -1488,8 +1495,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) { @@ -1575,6 +1586,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 { @@ -1600,11 +1612,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 From b8d660d946c5f0be3a4f01867b11f26a4f303293 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Tue, 1 Apr 2014 11:17:54 -0700 Subject: [PATCH 2/2] Update docs. Make PULL up to date, remove deprecated falg and update PUSH Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes (github: creack) --- docs/sources/reference/commandline/cli.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/sources/reference/commandline/cli.rst b/docs/sources/reference/commandline/cli.rst index 0c9db138c2..324b84b0ae 100644 --- a/docs/sources/reference/commandline/cli.rst +++ b/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