history: support go template format for inspect

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2025-02-07 12:09:05 +01:00
parent e236b86297
commit 417af36abc
No known key found for this signature in database
GPG Key ID: ADE44D8C9D44FBE4
2 changed files with 132 additions and 75 deletions

View File

@ -13,6 +13,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"text/template"
"time" "time"
"github.com/containerd/containerd/v2/core/content" "github.com/containerd/containerd/v2/core/content"
@ -62,81 +63,83 @@ type inspectOptions struct {
} }
type inspectOutput struct { type inspectOutput struct {
Name string `json:"name,omitempty"` Name string `json:",omitempty"`
Context string `json:"context,omitempty"` Ref string
Dockerfile string `json:"dockerfile,omitempty"`
VCSRepository string `json:"vcs_repository,omitempty"`
VCSRevision string `json:"vcs_revision,omitempty"`
Target string `json:"target,omitempty"`
Platform []string `json:"platform,omitempty"`
KeepGitDir bool `json:"keep_git_dir,omitempty"`
NamedContexts []keyValueOutput `json:"named_contexts,omitempty"` Context string `json:",omitempty"`
Dockerfile string `json:",omitempty"`
VCSRepository string `json:",omitempty"`
VCSRevision string `json:",omitempty"`
Target string `json:",omitempty"`
Platform []string `json:",omitempty"`
KeepGitDir bool `json:",omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"` NamedContexts []keyValueOutput `json:",omitempty"`
CompletedAt *time.Time `json:"complete_at,omitempty"`
Duration time.Duration `json:"duration,omitempty"`
Status statusT `json:"status,omitempty"`
Error *errorOutput `json:"error,omitempty"`
NumCompletedSteps int32 `json:"num_completed_steps"` StartedAt *time.Time `json:",omitempty"`
NumTotalSteps int32 `json:"num_total_steps"` CompletedAt *time.Time `json:",omitempty"`
NumCachedSteps int32 `json:"num_cached_steps"` Duration time.Duration `json:",omitempty"`
Status statusT `json:",omitempty"`
Error *errorOutput `json:",omitempty"`
BuildArgs []keyValueOutput `json:"build_args,omitempty"` NumCompletedSteps int32
Labels []keyValueOutput `json:"labels,omitempty"` NumTotalSteps int32
NumCachedSteps int32
Config configOutput `json:"config,omitempty"` BuildArgs []keyValueOutput `json:",omitempty"`
Labels []keyValueOutput `json:",omitempty"`
Materials []materialOutput `json:"materials,omitempty"` Config configOutput `json:",omitempty"`
Attachments []attachmentOutput `json:"attachments,omitempty"`
Errors []string `json:"errors,omitempty"` Materials []materialOutput `json:",omitempty"`
Attachments []attachmentOutput `json:",omitempty"`
Errors []string `json:",omitempty"`
} }
type configOutput struct { type configOutput struct {
Network string `json:"network,omitempty"` Network string `json:",omitempty"`
ExtraHosts []string `json:"extra_hosts,omitempty"` ExtraHosts []string `json:",omitempty"`
Hostname string `json:"hostname,omitempty"` Hostname string `json:",omitempty"`
CgroupParent string `json:"cgroup_parent,omitempty"` CgroupParent string `json:",omitempty"`
ImageResolveMode string `json:"image_resolve_mode,omitempty"` ImageResolveMode string `json:",omitempty"`
MultiPlatform bool `json:"multi_platform,omitempty"` MultiPlatform bool `json:",omitempty"`
NoCache bool `json:"no_cache,omitempty"` NoCache bool `json:",omitempty"`
NoCacheFilter []string `json:"no_cache_filter,omitempty"` NoCacheFilter []string `json:",omitempty"`
ShmSize string `json:"shm_size,omitempty"` ShmSize string `json:",omitempty"`
Ulimit string `json:"ulimit,omitempty"` Ulimit string `json:",omitempty"`
CacheMountNS string `json:"cache_mount_ns,omitempty"` CacheMountNS string `json:",omitempty"`
DockerfileCheckConfig string `json:"dockerfile_check_config,omitempty"` DockerfileCheckConfig string `json:",omitempty"`
SourceDateEpoch string `json:"source_date_epoch,omitempty"` SourceDateEpoch string `json:",omitempty"`
SandboxHostname string `json:"sandbox_hostname,omitempty"` SandboxHostname string `json:",omitempty"`
RestRaw []keyValueOutput `json:"rest_raw,omitempty"` RestRaw []keyValueOutput `json:",omitempty"`
} }
type materialOutput struct { type materialOutput struct {
URI string `json:"uri,omitempty"` URI string `json:",omitempty"`
Digests []string `json:"digests,omitempty"` Digests []string `json:",omitempty"`
} }
type attachmentOutput struct { type attachmentOutput struct {
Digest string `json:"digest,omitempty"` Digest string `json:",omitempty"`
Platform string `json:"platform,omitempty"` Platform string `json:",omitempty"`
Type string `json:"type,omitempty"` Type string `json:",omitempty"`
} }
type errorOutput struct { type errorOutput struct {
Code int `json:"code,omitempty"` Code int `json:",omitempty"`
Message string `json:"message,omitempty"` Message string `json:",omitempty"`
Name string `json:"name,omitempty"` Name string `json:",omitempty"`
Logs []string `json:"logs,omitempty"` Logs []string `json:",omitempty"`
Sources []byte `json:"sources,omitempty"` Sources []byte `json:",omitempty"`
Stack []byte `json:"stack,omitempty"` Stack []byte `json:",omitempty"`
} }
type keyValueOutput struct { type keyValueOutput struct {
Name string `json:"name,omitempty"` Name string `json:",omitempty"`
Value string `json:"value,omitempty"` Value string `json:",omitempty"`
} }
func readAttr[T any](attrs map[string]string, k string, dest *T, f func(v string) (T, bool)) { func readAttr[T any](attrs map[string]string, k string, dest *T, f func(v string) (T, bool)) {
@ -259,6 +262,8 @@ workers0:
delete(attrs, "filename") delete(attrs, "filename")
out.Name = buildName(rec.FrontendAttrs, st) out.Name = buildName(rec.FrontendAttrs, st)
out.Ref = rec.Ref
out.Context = context out.Context = context
out.Dockerfile = dockerfile out.Dockerfile = dockerfile
@ -467,11 +472,26 @@ workers0:
enc.SetIndent("", " ") enc.SetIndent("", " ")
return enc.Encode(out) return enc.Encode(out)
} else if opts.format != formatter.RawFormatKey { } else if opts.format != formatter.RawFormatKey {
return errors.Errorf("unsupported format %q", opts.format) tmpl, err := template.New("inspect").Parse(opts.format)
if err != nil {
return errors.Wrapf(err, "failed to parse format template")
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, out); err != nil {
return errors.Wrapf(err, "failed to execute format template")
}
fmt.Fprintln(dockerCli.Out(), buf.String())
return nil
} }
tw := tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0) tw := tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
if out.Name != "" {
fmt.Fprintf(tw, "Name:\t%s\n", out.Name)
}
if opts.ref == "" && out.Ref != "" {
fmt.Fprintf(tw, "Ref:\t%s\n", out.Ref)
}
if out.Context != "" { if out.Context != "" {
fmt.Fprintf(tw, "Context:\t%s\n", out.Context) fmt.Fprintf(tw, "Context:\t%s\n", out.Context)
} }

View File

@ -25,22 +25,25 @@ Inspect a build
### <a name="format"></a> Format the output (--format) ### <a name="format"></a> Format the output (--format)
Output format can be one of `raw`, `json`. The formatting options (`--format`) pretty-prints the output to `raw` (default),
`json` or using a Go template.
```console ```console
$ docker buildx history inspect --format raw $ docker buildx history inspect
Name: buildx (binaries)
Context: . Context: .
Dockerfile: Dockerfile Dockerfile: Dockerfile
VCS Repository: https://github.com/crazy-max/buildx.git VCS Repository: https://github.com/crazy-max/buildx.git
VCS Revision: 04aab6958cb5feb012a3c607569573b5cab141e1 VCS Revision: f15eaa1ee324ffbbab29605600d27a84cab86361
Target: binaries Target: binaries
Platforms: linux/amd64 Platforms: linux/amd64
Keep Git Dir: true Keep Git Dir: true
Started: 2025-02-06 16:15:13 Started: 2025-02-07 11:56:24
Duration: 1m 3s Duration: 1m 1s
Build Steps: 16/16 (25% cached) Build Steps: 16/16 (25% cached)
Image Resolve Mode: local
Materials: Materials:
URI DIGEST URI DIGEST
@ -50,31 +53,65 @@ pkg:docker/tonistiigi/xx@1.6.1?platform=linux%2Famd64 sha256:923441d7c
Attachments: Attachments:
DIGEST PLATFORM TYPE DIGEST PLATFORM TYPE
sha256:1b44912514074d3e309d80f8a5886a4d89eeeb52bef4d3e57ced17d1781bfce1 https://slsa.dev/provenance/v0.2 sha256:217329d2af959d4f02e3a96dcbe62bf100cab1feb8006a047ddfe51a5397f7e3 https://slsa.dev/provenance/v0.2
Print build logs: docker buildx history logs qrdbfvaoarfz42ye54lzx9aoy Print build logs: docker buildx history logs g9808bwrjrlkbhdamxklx660b
``` ```
```console ```console
$ docker buildx history inspect --format json $ docker buildx history inspect --format json
{ {
"name": "buildx (binaries)", "Name": "buildx (binaries)",
"context": ".", "Ref": "5w7vkqfi0rf59hw4hnmn627r9",
"dockerfile": "Dockerfile", "Context": ".",
"vcs_repository": "https://github.com/crazy-max/buildx.git", "Dockerfile": "Dockerfile",
"vcs_revision": "04aab6958cb5feb012a3c607569573b5cab141e1", "VCSRepository": "https://github.com/crazy-max/buildx.git",
"target": "binaries", "VCSRevision": "f15eaa1ee324ffbbab29605600d27a84cab86361",
"platform": [ "Target": "binaries",
"Platform": [
"linux/amd64" "linux/amd64"
], ],
"keep_git_dir": true, "KeepGitDir": true,
"started_at": "2025-02-06T16:15:13.077644732+01:00", "StartedAt": "2025-02-07T12:01:05.75807272+01:00",
"complete_at": "2025-02-06T16:16:17.046656296+01:00", "CompletedAt": "2025-02-07T12:02:07.991778875+01:00",
"duration": 63969011564, "Duration": 62233706155,
"status": "completed", "Status": "completed",
"num_completed_steps": 16, "NumCompletedSteps": 16,
"num_total_steps": 16, "NumTotalSteps": 16,
"num_cached_steps": 4, "NumCachedSteps": 4,
"config": {} "Config": {
"ImageResolveMode": "local"
},
"Materials": [
{
"URI": "pkg:docker/docker/dockerfile@1",
"Digests": [
"sha256:93bfd3b68c109427185cd78b4779fc82b484b0b7618e36d0f104d4d801e66d25"
]
},
{
"URI": "pkg:docker/golang@1.23-alpine3.21?platform=linux%2Famd64",
"Digests": [
"sha256:2c49857f2295e89b23b28386e57e018a86620a8fede5003900f2d138ba9c4037"
]
},
{
"URI": "pkg:docker/tonistiigi/xx@1.6.1?platform=linux%2Famd64",
"Digests": [
"sha256:923441d7c25f1e2eb5789f82d987693c47b8ed987c4ab3b075d6ed2b5d6779a3"
]
}
],
"Attachments": [
{
"Digest": "sha256:450fdd2e6b868fecd69e9891c2c404ba461aa38a47663b4805edeb8d2baf80b1",
"Type": "https://slsa.dev/provenance/v0.2"
}
]
} }
``` ```
```console
$ docker buildx history inspect --format "{{.Name}}: {{.VCSRepository}} ({{.VCSRevision}})"
buildx (binaries): https://github.com/crazy-max/buildx.git (f15eaa1ee324ffbbab29605600d27a84cab86361)
```