github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/command/image/push.go (about) 1 package image 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 8 "github.com/docker/cli/cli" 9 "github.com/docker/cli/cli/command" 10 "github.com/docker/cli/cli/command/completion" 11 "github.com/docker/cli/cli/streams" 12 "github.com/docker/distribution/reference" 13 "github.com/docker/docker/api/types" 14 "github.com/docker/docker/pkg/jsonmessage" 15 "github.com/docker/docker/registry" 16 "github.com/pkg/errors" 17 "github.com/spf13/cobra" 18 ) 19 20 type pushOptions struct { 21 all bool 22 remote string 23 untrusted bool 24 quiet bool 25 } 26 27 // NewPushCommand creates a new `docker push` command 28 func NewPushCommand(dockerCli command.Cli) *cobra.Command { 29 var opts pushOptions 30 31 cmd := &cobra.Command{ 32 Use: "push [OPTIONS] NAME[:TAG]", 33 Short: "Upload an image to a registry", 34 Args: cli.ExactArgs(1), 35 RunE: func(cmd *cobra.Command, args []string) error { 36 opts.remote = args[0] 37 return RunPush(dockerCli, opts) 38 }, 39 Annotations: map[string]string{ 40 "category-top": "6", 41 "aliases": "docker image push, docker push", 42 }, 43 ValidArgsFunction: completion.ImageNames(dockerCli), 44 } 45 46 flags := cmd.Flags() 47 flags.BoolVarP(&opts.all, "all-tags", "a", false, "Push all tags of an image to the repository") 48 flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress verbose output") 49 command.AddTrustSigningFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled()) 50 51 return cmd 52 } 53 54 // RunPush performs a push against the engine based on the specified options 55 func RunPush(dockerCli command.Cli, opts pushOptions) error { 56 ref, err := reference.ParseNormalizedNamed(opts.remote) 57 switch { 58 case err != nil: 59 return err 60 case opts.all && !reference.IsNameOnly(ref): 61 return errors.New("tag can't be used with --all-tags/-a") 62 case !opts.all && reference.IsNameOnly(ref): 63 ref = reference.TagNameOnly(ref) 64 if tagged, ok := ref.(reference.Tagged); ok && !opts.quiet { 65 _, _ = fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", tagged.Tag()) 66 } 67 } 68 69 // Resolve the Repository name from fqn to RepositoryInfo 70 repoInfo, err := registry.ParseRepositoryInfo(ref) 71 if err != nil { 72 return err 73 } 74 75 ctx := context.Background() 76 77 // Resolve the Auth config relevant for this server 78 authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) 79 encodedAuth, err := command.EncodeAuthToBase64(authConfig) 80 if err != nil { 81 return err 82 } 83 requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push") 84 options := types.ImagePushOptions{ 85 All: opts.all, 86 RegistryAuth: encodedAuth, 87 PrivilegeFunc: requestPrivilege, 88 } 89 90 responseBody, err := dockerCli.Client().ImagePush(ctx, reference.FamiliarString(ref), options) 91 if err != nil { 92 return err 93 } 94 95 defer responseBody.Close() 96 if !opts.untrusted { 97 // TODO PushTrustedReference currently doesn't respect `--quiet` 98 return PushTrustedReference(dockerCli, repoInfo, ref, authConfig, responseBody) 99 } 100 101 if opts.quiet { 102 err = jsonmessage.DisplayJSONMessagesToStream(responseBody, streams.NewOut(io.Discard), nil) 103 if err == nil { 104 fmt.Fprintln(dockerCli.Out(), ref.String()) 105 } 106 return err 107 } 108 return jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), nil) 109 }