DockerCLI/cli/command/image/push.go

109 lines
3.2 KiB
Go

package image
import (
"context"
"fmt"
"io"
"github.com/distribution/reference"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/registry"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type pushOptions struct {
all bool
remote string
untrusted bool
quiet bool
}
// NewPushCommand creates a new `docker push` command
func NewPushCommand(dockerCli command.Cli) *cobra.Command {
var opts pushOptions
cmd := &cobra.Command{
Use: "push [OPTIONS] NAME[:TAG]",
Short: "Upload an image to a registry",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.remote = args[0]
return RunPush(cmd.Context(), dockerCli, opts)
},
Annotations: map[string]string{
"category-top": "6",
"aliases": "docker image push, docker push",
},
ValidArgsFunction: completion.ImageNames(dockerCli),
}
flags := cmd.Flags()
flags.BoolVarP(&opts.all, "all-tags", "a", false, "Push all tags of an image to the repository")
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress verbose output")
command.AddTrustSigningFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
return cmd
}
// RunPush performs a push against the engine based on the specified options
func RunPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error {
ref, err := reference.ParseNormalizedNamed(opts.remote)
switch {
case err != nil:
return err
case opts.all && !reference.IsNameOnly(ref):
return errors.New("tag can't be used with --all-tags/-a")
case !opts.all && reference.IsNameOnly(ref):
ref = reference.TagNameOnly(ref)
if tagged, ok := ref.(reference.Tagged); ok && !opts.quiet {
_, _ = fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", tagged.Tag())
}
}
// Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil {
return err
}
// Resolve the Auth config relevant for this server
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
if err != nil {
return err
}
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
options := types.ImagePushOptions{
All: opts.all,
RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege,
}
responseBody, err := dockerCli.Client().ImagePush(ctx, reference.FamiliarString(ref), options)
if err != nil {
return err
}
defer responseBody.Close()
if !opts.untrusted {
// TODO PushTrustedReference currently doesn't respect `--quiet`
return PushTrustedReference(dockerCli, repoInfo, ref, authConfig, responseBody)
}
if opts.quiet {
err = jsonmessage.DisplayJSONMessagesToStream(responseBody, streams.NewOut(io.Discard), nil)
if err == nil {
fmt.Fprintln(dockerCli.Out(), ref.String())
}
return err
}
return jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), nil)
}