Skip to content

Commit 2e29672

Browse files
committed
imagetools: use docker/cli formatting
Use the formatting packages provided by docker/cli to comply with the official formatting documentation. https://docs.docker.com/config/formatting/ The use of the official formatting packages also fixes the format templating. Fixes: #1175 Signed-off-by: Thomas Way <[email protected]>
1 parent 687feca commit 2e29672

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+13069
-310
lines changed

commands/imagetools/formatter.go

+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
package commands
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
"github.com/docker/buildx/util/imagetools"
8+
"github.com/docker/cli/cli/command/formatter"
9+
"github.com/docker/distribution/reference"
10+
"github.com/moby/buildkit/util/appcontext"
11+
"github.com/opencontainers/go-digest"
12+
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
13+
)
14+
15+
const (
16+
tableFormat = "table {{ .Name }}\t{{ .MediaType }}\t{{ .Digest }}"
17+
prettyTemplate = `{{- if .Name }}
18+
Name: {{ .Name }}
19+
{{- end }}
20+
{{- if .MediaType }}
21+
MediaType: {{ .MediaType }}
22+
{{- end }}
23+
{{- if .Digest }}
24+
Digest: {{ .Digest }}
25+
{{- end }}
26+
{{- if .Manifests }}
27+
Manifests:
28+
{{- range $manifest := .Manifests }}
29+
{{ if $manifest.Name }}
30+
Name: {{ $manifest.Name }}
31+
{{- end }}
32+
{{- if $manifest.MediaType }}
33+
MediaType: {{ $manifest.MediaType }}
34+
{{- end }}
35+
{{- if $manifest.Platform }}
36+
Platform: {{ $manifest.Platform }}
37+
{{- end }}
38+
{{- if $manifest.OSVersion }}
39+
OSVersion: {{ $manifest.OSVersion }}
40+
{{- end }}
41+
{{- if $manifest.OSFeatures }}
42+
OSFeatures: {{ $manifest.OSFeatures }}
43+
{{- end }}
44+
{{- if $manifest.URLs }}
45+
URLs: {{ $manifest.URLs }}
46+
{{- end }}
47+
{{- if $manifest.Annotations }}
48+
{{ range $key, $value := $manifest.Annotations }}
49+
{{ $key }}: {{ $value }}
50+
{{- end }}
51+
{{- end }}
52+
{{- end }}
53+
{{- end }}`
54+
)
55+
56+
func makeFormat(source string) formatter.Format {
57+
switch source {
58+
case formatter.PrettyFormatKey:
59+
return prettyTemplate
60+
case formatter.TableFormatKey:
61+
return tableFormat
62+
case formatter.RawFormatKey:
63+
return formatter.JSONFormat
64+
}
65+
return formatter.Format(source)
66+
}
67+
68+
func inspectFormatWrite(ctx formatter.Context, name string, opt imagetools.Opt) error {
69+
resolver := imagetools.New(opt)
70+
return ctx.Write(&inspectContext{}, func(format func(formatter.SubContext) error) error {
71+
ref, err := imagetools.ParseRef(name)
72+
if err != nil {
73+
return fmt.Errorf("parse ref: %w", err)
74+
}
75+
76+
dt, mfst, err := resolver.Get(appcontext.Context(), ref.String())
77+
if err != nil {
78+
return err
79+
}
80+
81+
var index ocispecs.Index
82+
if err := json.Unmarshal(dt, &index); err != nil {
83+
return err
84+
}
85+
86+
return format(&inspectContext{
87+
ref: ref,
88+
index: index,
89+
descriptor: mfst,
90+
resolver: resolver,
91+
})
92+
})
93+
}
94+
95+
type inspectContext struct {
96+
formatter.HeaderContext
97+
ref reference.Named
98+
index ocispecs.Index
99+
descriptor ocispecs.Descriptor
100+
resolver *imagetools.Resolver
101+
}
102+
103+
func (ctx *inspectContext) MarshalJSON() ([]byte, error) {
104+
return formatter.MarshalJSON(ctx)
105+
}
106+
107+
func (ctx *inspectContext) Name() string {
108+
return ctx.ref.String()
109+
}
110+
111+
func (ctx *inspectContext) Manifest() manifestList {
112+
return manifestList{
113+
SchemaVersion: ctx.index.Versioned.SchemaVersion,
114+
MediaType: ctx.index.MediaType,
115+
Digest: ctx.descriptor.Digest,
116+
Size: ctx.descriptor.Size,
117+
Manifests: ctx.index.Manifests,
118+
Annotations: ctx.descriptor.Annotations,
119+
}
120+
}
121+
122+
func (ctx *inspectContext) Image() (*ocispecs.Image, error) {
123+
res, err := imagetools.
124+
NewLoader(ctx.resolver.Resolver()).
125+
Load(appcontext.Context(), ctx.ref.String())
126+
if err != nil {
127+
return nil, fmt.Errorf("load: %w", err)
128+
}
129+
var img *ocispecs.Image
130+
for _, v := range res.Configs() {
131+
img = v
132+
break
133+
}
134+
return img, nil
135+
}
136+
137+
type manifestList struct {
138+
SchemaVersion int
139+
MediaType string
140+
Digest digest.Digest
141+
Size int64
142+
Manifests []ocispecs.Descriptor
143+
Annotations map[string]string
144+
}
145+
146+
// type inspectManifestContext struct {
147+
// ref reference.Named
148+
// descriptor ocispecs.Descriptor
149+
// }
150+
151+
// func (ctx *inspectManifestContext) MarshalJSON() ([]byte, error) {
152+
// return formatter.MarshalJSON(ctx)
153+
// }
154+
155+
// func (ctx *inspectManifestContext) Name() (string, error) {
156+
// cc, err := reference.WithDigest(ctx.ref, ctx.descriptor.Digest)
157+
// if err != nil {
158+
// return "", fmt.Errorf("with digest: %w", err)
159+
// }
160+
// return cc.String(), nil
161+
// }
162+
163+
// func (ctx *inspectManifestContext) MediaType() string {
164+
// return ctx.descriptor.MediaType
165+
// }
166+
167+
// func (ctx *inspectManifestContext) Platform() *string {
168+
// if ctx.descriptor.Platform != nil {
169+
// s := platforms.Format(*ctx.descriptor.Platform)
170+
// return &s
171+
// }
172+
// return nil
173+
// }
174+
175+
// func (ctx *inspectManifestContext) OSVersion() string {
176+
// if ctx.descriptor.Platform != nil {
177+
// return ctx.descriptor.Platform.OSVersion
178+
// }
179+
// return ""
180+
// }
181+
182+
// func (ctx *inspectManifestContext) OSFeatures() []string {
183+
// if ctx.descriptor.Platform != nil {
184+
// return ctx.descriptor.Platform.OSFeatures
185+
// }
186+
// return nil
187+
// }
188+
189+
// func (ctx *inspectManifestContext) URLs() []string {
190+
// return ctx.descriptor.URLs
191+
// }

commands/imagetools/inspect.go

+52-39
Original file line numberDiff line numberDiff line change
@@ -2,66 +2,79 @@ package commands
22

33
import (
44
"github.com/docker/buildx/builder"
5-
"github.com/docker/buildx/util/cobrautil/completion"
6-
"github.com/docker/buildx/util/imagetools"
7-
"github.com/docker/cli-docs-tool/annotation"
85
"github.com/docker/cli/cli"
96
"github.com/docker/cli/cli/command"
10-
"github.com/moby/buildkit/util/appcontext"
11-
"github.com/pkg/errors"
7+
"github.com/docker/cli/cli/command/formatter"
8+
cliflags "github.com/docker/cli/cli/flags"
129
"github.com/spf13/cobra"
1310
)
1411

1512
type inspectOptions struct {
16-
builder string
17-
format string
18-
raw bool
13+
builderName string
14+
format string
15+
refs []string
1916
}
2017

21-
func runInspect(dockerCli command.Cli, in inspectOptions, name string) error {
22-
ctx := appcontext.Context()
18+
func inspectCmd(dockerCLI command.Cli, rootOpts RootOptions) *cobra.Command {
19+
var opts inspectOptions
2320

24-
if in.format != "" && in.raw {
25-
return errors.Errorf("format and raw cannot be used together")
21+
cmd := &cobra.Command{
22+
Use: "inspect [OPTIONS] IMAGE [IMAGE...]",
23+
Short: "Show detailed information on one or more images in the registry",
24+
Args: cli.RequiresMinArgs(1),
25+
RunE: func(cmd *cobra.Command, args []string) error {
26+
opts.builderName = *rootOpts.Builder
27+
opts.refs = args
28+
return runInspect(dockerCLI, opts, args[0])
29+
},
2630
}
2731

28-
b, err := builder.New(dockerCli, builder.WithName(in.builder))
29-
if err != nil {
30-
return err
31-
}
32-
imageopt, err := b.ImageOpt()
32+
flags := cmd.Flags()
33+
flags.StringVarP(&opts.format, "format", "f", "", cliflags.InspectFormatHelp)
34+
35+
return cmd
36+
}
37+
38+
func runInspect(dockerCli command.Cli, opts inspectOptions, name string) error {
39+
b, err := builder.New(dockerCli, builder.WithName(opts.builderName))
3340
if err != nil {
3441
return err
3542
}
3643

37-
p, err := imagetools.NewPrinter(ctx, imageopt, name, in.format)
44+
imageopt, err := b.ImageOpt()
3845
if err != nil {
3946
return err
4047
}
4148

42-
return p.Print(in.raw, dockerCli.Out())
49+
return inspectFormatWrite(formatter.Context{
50+
Output: dockerCli.Out(),
51+
Format: makeFormat(opts.format),
52+
}, name, imageopt)
4353
}
4454

45-
func inspectCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
46-
var options inspectOptions
55+
// func runInspect(dockerCLI command.Cli, opts inspectOptions, name string) error {
56+
// b, err := builder.New(dockerCLI, builder.WithName(opts.builderName))
57+
// if err != nil {
58+
// return fmt.Errorf("new builder: %w", err)
59+
// }
4760

48-
cmd := &cobra.Command{
49-
Use: "inspect [OPTIONS] NAME",
50-
Short: "Show details of an image in the registry",
51-
Args: cli.ExactArgs(1),
52-
RunE: func(cmd *cobra.Command, args []string) error {
53-
options.builder = *rootOpts.Builder
54-
return runInspect(dockerCli, options, args[0])
55-
},
56-
ValidArgsFunction: completion.Disable,
57-
}
61+
// imgopt, err := b.ImageOpt()
62+
// if err != nil {
63+
// return fmt.Errorf("image opt: %w", err)
64+
// }
5865

59-
flags := cmd.Flags()
60-
61-
flags.StringVar(&options.format, "format", "", "Format the output using the given Go template")
62-
flags.SetAnnotation("format", annotation.DefaultValue, []string{`"{{.Manifest}}"`})
63-
64-
flags.BoolVar(&options.raw, "raw", false, "Show original, unformatted JSON manifest")
66+
// resolver := imagetools.New(imgopt)
67+
// ctx := appcontext.Context()
68+
// return inspect.Inspect(dockerCLI.Out(), opts.refs, opts.format, func(ref string) (interface{}, []byte, error) {
69+
// newref, err := imagetools.ParseRef(ref)
70+
// if err != nil {
71+
// return nil, nil, err
72+
// }
6573

66-
return cmd
67-
}
74+
// dt, mfst, err := resolver.Get(ctx, newref.String())
75+
// if err != nil {
76+
// return nil, nil, err
77+
// }
78+
// return mfst, dt, err
79+
// })
80+
// }

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ require (
114114
github.com/klauspost/compress v1.16.3 // indirect
115115
github.com/kr/pretty v0.2.1 // indirect
116116
github.com/mailru/easyjson v0.7.6 // indirect
117+
github.com/mattn/go-runewidth v0.0.13 // indirect
117118
github.com/mattn/go-shellwords v1.0.12 // indirect
118119
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
119120
github.com/miekg/pkcs11 v1.1.1 // indirect
@@ -133,6 +134,7 @@ require (
133134
github.com/prometheus/client_model v0.3.0 // indirect
134135
github.com/prometheus/common v0.42.0 // indirect
135136
github.com/prometheus/procfs v0.9.0 // indirect
137+
github.com/rivo/uniseg v0.2.0 // indirect
136138
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
137139
github.com/sergi/go-diff v1.2.0 // indirect
138140
github.com/shibumi/go-pathspec v1.3.0 // indirect

go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
359359
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
360360
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
361361
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
362+
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
363+
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
362364
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
363365
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
364366
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -440,6 +442,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
440442
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
441443
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
442444
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
445+
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
446+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
443447
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
444448
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
445449
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=

util/imagetools/create.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func (r *Resolver) Push(ctx context.Context, ref reference.Named, desc ocispec.D
160160
ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto")
161161

162162
ref = reference.TagNameOnly(ref)
163-
p, err := r.resolver().Pusher(ctx, ref.String())
163+
p, err := r.Resolver().Pusher(ctx, ref.String())
164164
if err != nil {
165165
return err
166166
}
@@ -183,13 +183,13 @@ func (r *Resolver) Copy(ctx context.Context, src *Source, dest reference.Named)
183183
ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto")
184184

185185
dest = reference.TagNameOnly(dest)
186-
p, err := r.resolver().Pusher(ctx, dest.String())
186+
p, err := r.Resolver().Pusher(ctx, dest.String())
187187
if err != nil {
188188
return err
189189
}
190190

191191
srcRef := reference.TagNameOnly(src.Ref)
192-
f, err := r.resolver().Fetcher(ctx, srcRef.String())
192+
f, err := r.Resolver().Fetcher(ctx, srcRef.String())
193193
if err != nil {
194194
return err
195195
}

0 commit comments

Comments
 (0)