Merge pull request #4948 from creack/push_single_tag

Allow push of a single tag
This commit is contained in:
Victor Vieux 2014-04-01 12:54:15 -07:00
commit e175a55eb9
4 changed files with 33 additions and 16 deletions

View File

@ -1004,7 +1004,7 @@ func (cli *DockerCli) CmdImport(args ...string) error {
} }
func (cli *DockerCli) CmdPush(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 { if err := cmd.Parse(args); err != nil {
return nil return nil
} }
@ -1017,8 +1017,10 @@ func (cli *DockerCli) CmdPush(args ...string) error {
cli.LoadConfigFile() cli.LoadConfigFile()
remote, tag := utils.ParseRepositoryTag(name)
// Resolve the Repository name from fqn to hostname + name // Resolve the Repository name from fqn to hostname + name
hostname, _, err := registry.ResolveRepositoryName(name) hostname, _, err := registry.ResolveRepositoryName(remote)
if err != nil { if err != nil {
return err return err
} }
@ -1037,6 +1039,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
} }
v := url.Values{} v := url.Values{}
v.Set("tag", tag)
push := func(authConfig registry.AuthConfig) error { push := func(authConfig registry.AuthConfig) error {
buf, err := json.Marshal(authConfig) buf, err := json.Marshal(authConfig)
if err != nil { if err != nil {
@ -1046,7 +1049,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
base64.URLEncoding.EncodeToString(buf), 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, "X-Registry-Auth": registryAuthHeader,
}) })
} }

View File

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

View File

@ -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 Pull an image or a repository from the registry
-t, --tag="": Download tagged image in repository
.. _cli_push: .. _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 Push an image or a repository to the registry

View File

@ -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 // 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 ( var (
imageList []string imageList []string
imagesSeen map[string]bool = make(map[string]bool) 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 { for tag, id := range localRepo {
if requestedTag != "" && requestedTag != tag {
continue
}
var imageListForThisTag []string var imageListForThisTag []string
tagsByImage[id] = append(tagsByImage[id], tag) 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 // append to main image list
imageList = append(imageList, imageListForThisTag...) 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("Image list: %v", imageList)
utils.Debugf("Tags by image: %v", tagsByImage) utils.Debugf("Tags by image: %v", tagsByImage)
return imageList, tagsByImage, nil 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) out = utils.NewWriteFlusher(out)
utils.Debugf("Local repo: %s", localRepo) utils.Debugf("Local repo: %s", localRepo)
imgList, tagsByImage, err := srv.getImageList(localRepo) imgList, tagsByImage, err := srv.getImageList(localRepo, tag)
if err != nil { if err != nil {
return err return err
} }
out.Write(sf.FormatStatus("", "Sending image list")) out.Write(sf.FormatStatus("", "Sending image list"))
var repoData *registry.RepositoryData var (
var imageIndex []*registry.ImgData repoData *registry.RepositoryData
imageIndex []*registry.ImgData
)
for _, imgId := range imgList { for _, imgId := range imgList {
if tags, exists := tagsByImage[imgId]; exists { if tags, exists := tagsByImage[imgId]; exists {
@ -1492,8 +1499,12 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName
return err return err
} }
nTag := 1
if tag == "" {
nTag = len(localRepo)
}
for _, ep := range repoData.Endpoints { 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 { for _, imgId := range imgList {
if r.LookupRemoteImage(imgId, ep, repoData.Tokens) { if r.LookupRemoteImage(imgId, ep, repoData.Tokens) {
@ -1579,6 +1590,7 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
metaHeaders map[string][]string metaHeaders map[string][]string
) )
tag := job.Getenv("tag")
job.GetenvJson("authConfig", authConfig) job.GetenvJson("authConfig", authConfig)
job.GetenvJson("metaHeaders", metaHeaders) job.GetenvJson("metaHeaders", metaHeaders)
if _, err := srv.poolAdd("push", localName); err != nil { if _, err := srv.poolAdd("push", localName); err != nil {
@ -1604,11 +1616,14 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
} }
if err != nil { 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)) 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 it fails, try to get the repository
if localRepo, exists := srv.runtime.Repositories().Repositories[localName]; exists { 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 job.Error(err)
} }
return engine.StatusOK return engine.StatusOK