55 "encoding/json"
66 "fmt"
77 "io"
8+ "io/ioutil"
9+ "os"
810
911 "github.com/docker/cli/cli"
1012 "github.com/docker/cli/cli/command"
@@ -14,14 +16,17 @@ import (
1416 "github.com/docker/distribution/manifest/schema2"
1517 "github.com/docker/distribution/reference"
1618 "github.com/docker/docker/registry"
19+
1720 "github.com/pkg/errors"
1821 "github.com/spf13/cobra"
22+ yaml "gopkg.in/yaml.v2"
1923)
2024
2125type pushOpts struct {
2226 insecure bool
2327 purge bool
2428 target string
29+ file string
2530}
2631
2732type mountRequest struct {
@@ -42,32 +47,63 @@ type pushRequest struct {
4247 insecure bool
4348}
4449
50+ type yamlManifestList struct {
51+ Image string
52+ Manifests []yamlManifest
53+ }
54+
55+ type yamlManifest struct {
56+ Image string
57+ Platform manifestlist.PlatformSpec
58+ }
59+
4560func newPushListCommand (dockerCli command.Cli ) * cobra.Command {
4661 opts := pushOpts {}
4762
4863 cmd := & cobra.Command {
49- Use : "push [OPTIONS] MANIFEST_LIST" ,
64+ Use : "push [OPTIONS] [ MANIFEST_LIST] " ,
5065 Short : "Push a manifest list to a repository" ,
51- Args : cli .ExactArgs ( 1 ),
66+ Args : cli .RequiresRangeArgs ( 0 , 1 ),
5267 RunE : func (cmd * cobra.Command , args []string ) error {
53- opts .target = args [0 ]
68+ if len (args ) == 1 {
69+ opts .target = args [0 ]
70+ }
5471 return runPush (dockerCli , opts )
5572 },
5673 }
5774
5875 flags := cmd .Flags ()
59- flags .BoolVarP (& opts .purge , "purge" , "p" , false , "Remove the local manifest list after push" )
60- flags .BoolVar (& opts .insecure , "insecure" , false , "Allow push to an insecure registry" )
76+ flags .BoolVarP (& opts .purge , "purge" , "p" , false , "remove the local manifest list after push" )
77+ flags .BoolVar (& opts .insecure , "insecure" , false , "allow push to an insecure registry" )
78+ flags .StringVar (& opts .file , "filename" , "" , "create, annotate, and push using a yaml file" )
6179 return cmd
6280}
6381
6482func runPush (dockerCli command.Cli , opts pushOpts ) error {
6583
84+ if opts .target == "" && opts .file == "" {
85+ return errors .New ("please specify either a file or local manifest name" )
86+ }
87+
88+ if opts .file != "" {
89+ yamlInput , err := getYamlManifestList (dockerCli , opts .file )
90+ if err != nil {
91+ return err
92+ }
93+ if err := createListFromYaml (dockerCli , yamlInput , opts .insecure ); err != nil {
94+ return err
95+ }
96+ if err := annotateListFromYaml (dockerCli , yamlInput ); err != nil {
97+ return err
98+ }
99+ opts .purge = true
100+ opts .target = yamlInput .Image
101+ }
102+
66103 targetRef , err := normalizeReference (opts .target )
67104 if err != nil {
68105 return err
69106 }
70-
71107 manifests , err := dockerCli .ManifestStore ().GetList (targetRef )
72108 if err != nil {
73109 return err
@@ -271,3 +307,47 @@ func mountBlobs(ctx context.Context, client registryclient.RegistryClient, ref r
271307 }
272308 return nil
273309}
310+
311+ func annotateListFromYaml (cli command.Cli , yaml yamlManifestList ) error {
312+
313+ for _ , manifest := range yaml .Manifests {
314+ opts := annotateOptions {
315+ target : yaml .Image ,
316+ image : manifest .Image ,
317+ variant : manifest .Platform .Variant ,
318+ os : manifest .Platform .OS ,
319+ arch : manifest .Platform .Architecture ,
320+ osFeatures : manifest .Platform .OSFeatures ,
321+ }
322+ if err := runManifestAnnotate (cli , opts ); err != nil {
323+ return err
324+ }
325+ }
326+ return nil
327+ }
328+
329+ func createListFromYaml (cli command.Cli , yamlInput yamlManifestList , insecureRegistry bool ) error {
330+
331+ var args []string
332+ args = append (args , yamlInput .Image )
333+ for _ , manifest := range yamlInput .Manifests {
334+ args = append (args , manifest .Image )
335+ }
336+ return createManifestList (cli , args , createOpts {amend : false , insecure : insecureRegistry })
337+ }
338+
339+ func getYamlManifestList (dockerCli command.Cli , yamlFile string ) (yamlManifestList , error ) {
340+ var yamlInput yamlManifestList
341+
342+ if _ , err := os .Stat (yamlFile ); err != nil {
343+ return yamlManifestList {}, err
344+ }
345+ yamlBuf , err := ioutil .ReadFile (yamlFile )
346+ if err != nil {
347+ return yamlManifestList {}, err
348+ }
349+ if err := yaml .UnmarshalStrict (yamlBuf , & yamlInput ); err != nil {
350+ return yamlManifestList {}, err
351+ }
352+ return yamlInput , nil
353+ }
0 commit comments