mirror of https://github.com/docker/buildx.git
Compare commits
39 Commits
v0.25.0-rc
...
master
Author | SHA1 | Date |
---|---|---|
|
0bed0b5653 | |
|
b034cff8c2 | |
|
fdb0ebc6cb | |
|
25a9ad6abd | |
|
a11757121a | |
|
7a05ca4547 | |
|
63bb3db985 | |
|
fba5d5e554 | |
|
179aad79b5 | |
|
d44ffb4bd4 | |
|
4c1e7b2119 | |
|
2d3a9ef229 | |
|
ec45eb6ebc | |
|
e9b6a01aef | |
|
c48ccdee36 | |
|
22f776f664 | |
|
8da4f0fe64 | |
|
2588b66fd9 | |
|
931e714919 | |
|
d5f914a263 | |
|
d09eb752a5 | |
|
3c2decea38 | |
|
18041a5855 | |
|
96ebe9d9a9 | |
|
08dd378b59 | |
|
cb29cd0efb | |
|
99f1c4b15c | |
|
77e4a88781 | |
|
7660acf9c7 | |
|
03737f11bc | |
|
4a22b92775 | |
|
ba782f195b | |
|
989978a42b | |
|
cb54ddb9fe | |
|
eb43f4c237 | |
|
43e2f27cac | |
|
7f5ff6b797 | |
|
640541cefa | |
|
c1209acb27 |
|
@ -54,9 +54,9 @@ jobs:
|
|||
- master
|
||||
- latest
|
||||
- buildx-stable-1
|
||||
- v0.23.1
|
||||
- v0.22.0
|
||||
- v0.21.1
|
||||
- v0.20.2
|
||||
worker:
|
||||
- docker-container
|
||||
- remote
|
||||
|
@ -535,7 +535,7 @@ jobs:
|
|||
-
|
||||
name: GitHub Release
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
|
||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
|
|
@ -5,13 +5,13 @@ ARG ALPINE_VERSION=3.21
|
|||
ARG XX_VERSION=1.6.1
|
||||
|
||||
# for testing
|
||||
ARG DOCKER_VERSION=28.2.2
|
||||
ARG DOCKER_VERSION=28.3.0
|
||||
ARG DOCKER_VERSION_ALT_27=27.5.1
|
||||
ARG DOCKER_VERSION_ALT_26=26.1.3
|
||||
ARG DOCKER_CLI_VERSION=${DOCKER_VERSION}
|
||||
ARG GOTESTSUM_VERSION=v1.12.0
|
||||
ARG REGISTRY_VERSION=3.0.0
|
||||
ARG BUILDKIT_VERSION=v0.22.0
|
||||
ARG BUILDKIT_VERSION=v0.23.1
|
||||
ARG UNDOCK_VERSION=0.9.0
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
|
|
@ -125,10 +125,8 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf
|
|||
extraHosts := map[string]*string{}
|
||||
if s.Build.ExtraHosts != nil {
|
||||
for k, v := range s.Build.ExtraHosts {
|
||||
for _, ip := range v {
|
||||
vv := ip
|
||||
extraHosts[k] = &vv
|
||||
}
|
||||
vv := strings.Join(v, ",")
|
||||
extraHosts[k] = &vv
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ services:
|
|||
- type=local,dest=path/to/cache
|
||||
extra_hosts:
|
||||
- "somehost:162.242.195.82"
|
||||
- "somehost:162.242.195.83"
|
||||
- "myhostv6:::1"
|
||||
ssh:
|
||||
- key=/path/to/key
|
||||
|
@ -79,7 +80,7 @@ secrets:
|
|||
require.Equal(t, ptrstr("123"), c.Targets[1].Args["buildno"])
|
||||
require.Equal(t, []string{"type=local,src=path/to/cache"}, stringify(c.Targets[1].CacheFrom))
|
||||
require.Equal(t, []string{"type=local,dest=path/to/cache"}, stringify(c.Targets[1].CacheTo))
|
||||
require.Equal(t, map[string]*string{"myhostv6": ptrstr("::1"), "somehost": ptrstr("162.242.195.82")}, c.Targets[1].ExtraHosts)
|
||||
require.Equal(t, map[string]*string{"myhostv6": ptrstr("::1"), "somehost": ptrstr("162.242.195.82,162.242.195.83")}, c.Targets[1].ExtraHosts)
|
||||
require.Equal(t, "none", *c.Targets[1].NetworkMode)
|
||||
require.Equal(t, []string{"default", "key=/path/to/key"}, stringify(c.Targets[1].SSH))
|
||||
require.Equal(t, []string{
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/containerd/containerd/v2/core/content/proxy"
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"
|
||||
controlapi "github.com/moby/buildkit/api/services/control"
|
||||
"github.com/moby/buildkit/client"
|
||||
provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
|
||||
|
@ -22,15 +23,6 @@ import (
|
|||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type provenancePredicate struct {
|
||||
Builder *provenanceBuilder `json:"builder,omitempty"`
|
||||
provenancetypes.ProvenancePredicateSLSA02
|
||||
}
|
||||
|
||||
type provenanceBuilder struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func setRecordProvenance(ctx context.Context, c *client.Client, sr *client.SolveResponse, ref string, mode confutil.MetadataProvenanceMode, pw progress.Writer) error {
|
||||
if mode == confutil.MetadataProvenanceModeDisabled {
|
||||
return nil
|
||||
|
@ -69,7 +61,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con
|
|||
continue
|
||||
}
|
||||
if ev.Record.Result != nil {
|
||||
desc := lookupProvenance(ev.Record.Result)
|
||||
desc, predicateType := lookupProvenance(ev.Record.Result)
|
||||
if desc == nil {
|
||||
continue
|
||||
}
|
||||
|
@ -78,7 +70,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con
|
|||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to load provenance blob from build record")
|
||||
}
|
||||
prv, err := encodeProvenance(dt, mode)
|
||||
prv, err := encodeProvenance(dt, predicateType, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -92,7 +84,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con
|
|||
})
|
||||
} else if ev.Record.Results != nil {
|
||||
for platform, res := range ev.Record.Results {
|
||||
desc := lookupProvenance(res)
|
||||
desc, predicateType := lookupProvenance(res)
|
||||
if desc == nil {
|
||||
continue
|
||||
}
|
||||
|
@ -101,7 +93,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con
|
|||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to load provenance blob from build record")
|
||||
}
|
||||
prv, err := encodeProvenance(dt, mode)
|
||||
prv, err := encodeProvenance(dt, predicateType, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -119,7 +111,7 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con
|
|||
return out, eg.Wait()
|
||||
}
|
||||
|
||||
func lookupProvenance(res *controlapi.BuildResultInfo) *ocispecs.Descriptor {
|
||||
func lookupProvenance(res *controlapi.BuildResultInfo) (*ocispecs.Descriptor, string) {
|
||||
for _, a := range res.Attestations {
|
||||
if a.MediaType == "application/vnd.in-toto+json" && strings.HasPrefix(a.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") {
|
||||
return &ocispecs.Descriptor{
|
||||
|
@ -127,27 +119,29 @@ func lookupProvenance(res *controlapi.BuildResultInfo) *ocispecs.Descriptor {
|
|||
Size: a.Size,
|
||||
MediaType: a.MediaType,
|
||||
Annotations: a.Annotations,
|
||||
}
|
||||
}, a.Annotations["in-toto.io/predicate-type"]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func encodeProvenance(dt []byte, mode confutil.MetadataProvenanceMode) (string, error) {
|
||||
var prv provenancePredicate
|
||||
if err := json.Unmarshal(dt, &prv); err != nil {
|
||||
func encodeProvenance(dt []byte, predicateType string, mode confutil.MetadataProvenanceMode) (string, error) {
|
||||
var pred *provenancetypes.ProvenancePredicateSLSA02
|
||||
if predicateType == slsa1.PredicateSLSAProvenance {
|
||||
var pred1 *provenancetypes.ProvenancePredicateSLSA1
|
||||
if err := json.Unmarshal(dt, &pred1); err != nil {
|
||||
return "", errors.Wrapf(err, "failed to unmarshal provenance")
|
||||
}
|
||||
pred = pred1.ConvertToSLSA02()
|
||||
} else if err := json.Unmarshal(dt, &pred); err != nil {
|
||||
return "", errors.Wrapf(err, "failed to unmarshal provenance")
|
||||
}
|
||||
if prv.Builder != nil && prv.Builder.ID == "" {
|
||||
// reset builder if id is empty
|
||||
prv.Builder = nil
|
||||
}
|
||||
if mode == confutil.MetadataProvenanceModeMin {
|
||||
// reset fields for minimal provenance
|
||||
prv.BuildConfig = nil
|
||||
prv.Metadata = nil
|
||||
pred.BuildConfig = nil
|
||||
pred.Metadata = nil
|
||||
}
|
||||
dtprv, err := json.Marshal(prv)
|
||||
dtprv, err := json.Marshal(pred)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to marshal provenance")
|
||||
}
|
||||
|
|
|
@ -77,24 +77,30 @@ func toBuildkitExtraHosts(ctx context.Context, inp []string, nodeDriver *driver.
|
|||
}
|
||||
// If the IP Address is a "host-gateway", replace this value with the
|
||||
// IP address provided by the worker's label.
|
||||
var ips []string
|
||||
if ip == mobyHostGatewayName {
|
||||
hgip, err := nodeDriver.HostGatewayIP(ctx)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "unable to derive the IP value for host-gateway")
|
||||
}
|
||||
ip = hgip.String()
|
||||
ips = append(ips, hgip.String())
|
||||
} else {
|
||||
// If the address is enclosed in square brackets, extract it (for IPv6, but
|
||||
// permit it for IPv4 as well; we don't know the address family here, but it's
|
||||
// unambiguous).
|
||||
if len(ip) > 2 && ip[0] == '[' && ip[len(ip)-1] == ']' {
|
||||
ip = ip[1 : len(ip)-1]
|
||||
}
|
||||
if net.ParseIP(ip) == nil {
|
||||
return "", errors.Errorf("invalid host %s", h)
|
||||
for _, v := range strings.Split(ip, ",") {
|
||||
// If the address is enclosed in square brackets, extract it
|
||||
// (for IPv6, but permit it for IPv4 as well; we don't know the
|
||||
// address family here, but it's unambiguous).
|
||||
if len(v) > 2 && v[0] == '[' && v[len(v)-1] == ']' {
|
||||
v = v[1 : len(v)-1]
|
||||
}
|
||||
if net.ParseIP(v) == nil {
|
||||
return "", errors.Errorf("invalid host %s", h)
|
||||
}
|
||||
ips = append(ips, v)
|
||||
}
|
||||
}
|
||||
hosts = append(hosts, host+"="+ip)
|
||||
for _, v := range ips {
|
||||
hosts = append(hosts, host+"="+v)
|
||||
}
|
||||
}
|
||||
return strings.Join(hosts, ","), nil
|
||||
}
|
||||
|
|
|
@ -72,6 +72,11 @@ func TestToBuildkitExtraHosts(t *testing.T) {
|
|||
doc: "IPv6 localhost, non-canonical, eq sep",
|
||||
input: []string{`ipv6local=0:0:0:0:0:0:0:1`},
|
||||
},
|
||||
{
|
||||
doc: "Multi IPs",
|
||||
input: []string{`myhost=162.242.195.82,162.242.195.83`},
|
||||
expectedOut: `myhost=162.242.195.82,myhost=162.242.195.83`,
|
||||
},
|
||||
{
|
||||
doc: "IPv6 localhost, non-canonical, eq sep, brackets",
|
||||
input: []string{`ipv6local=[0:0:0:0:0:0:0:1]`},
|
||||
|
|
|
@ -40,6 +40,11 @@ import (
|
|||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
const (
|
||||
bakeEnvFileSeparator = "BUILDX_BAKE_PATH_SEPARATOR"
|
||||
bakeEnvFilePath = "BUILDX_BAKE_FILE"
|
||||
)
|
||||
|
||||
type bakeOptions struct {
|
||||
files []string
|
||||
overrides []string
|
||||
|
@ -62,7 +67,7 @@ type bakeOptions struct {
|
|||
listVars bool
|
||||
}
|
||||
|
||||
func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in bakeOptions, cFlags commonFlags) (err error) {
|
||||
func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in bakeOptions, cFlags commonFlags, filesFromEnv bool) (err error) {
|
||||
mp := dockerCli.MeterProvider()
|
||||
|
||||
ctx, end, err := tracing.TraceCurrentCommand(ctx, append([]string{"bake"}, targets...),
|
||||
|
@ -162,7 +167,13 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
|
|||
attributes := bakeMetricAttributes(dockerCli, driverType, url, cmdContext, targets, &in)
|
||||
|
||||
progressMode := progressui.DisplayMode(cFlags.progress)
|
||||
|
||||
var printer *progress.Printer
|
||||
defer func() {
|
||||
if printer != nil {
|
||||
printer.Wait()
|
||||
}
|
||||
}()
|
||||
|
||||
makePrinter := func() error {
|
||||
var err error
|
||||
|
@ -180,7 +191,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
|
|||
return err
|
||||
}
|
||||
|
||||
files, inp, err := readBakeFiles(ctx, nodes, url, in.files, dockerCli.In(), printer)
|
||||
files, inp, err := readBakeFiles(ctx, nodes, url, in.files, dockerCli.In(), printer, filesFromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -452,6 +463,15 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
|||
Aliases: []string{"f"},
|
||||
Short: "Build from a file",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
filesFromEnv := false
|
||||
if len(options.files) == 0 {
|
||||
envFiles, err := bakeEnvFiles(os.LookupEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.files = envFiles
|
||||
filesFromEnv = true
|
||||
}
|
||||
// reset to nil to avoid override is unset
|
||||
if !cmd.Flags().Lookup("no-cache").Changed {
|
||||
cFlags.noCache = nil
|
||||
|
@ -469,7 +489,7 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
|||
options.builder = rootOpts.builder
|
||||
options.metadataFile = cFlags.metadataFile
|
||||
// Other common flags (noCache, pull and progress) are processed in runBake function.
|
||||
return runBake(cmd.Context(), dockerCli, args, options, cFlags)
|
||||
return runBake(cmd.Context(), dockerCli, args, options, cFlags, filesFromEnv)
|
||||
},
|
||||
ValidArgsFunction: completion.BakeTargets(options.files),
|
||||
}
|
||||
|
@ -504,6 +524,37 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func bakeEnvFiles(lookup func(string string) (string, bool)) ([]string, error) {
|
||||
sep, _ := lookup(bakeEnvFileSeparator)
|
||||
if sep == "" {
|
||||
sep = string(os.PathListSeparator)
|
||||
}
|
||||
f, ok := lookup(bakeEnvFilePath)
|
||||
if ok {
|
||||
return cleanPaths(strings.Split(f, sep))
|
||||
}
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
func cleanPaths(p []string) ([]string, error) {
|
||||
var paths []string
|
||||
for _, f := range p {
|
||||
f = strings.TrimSpace(f)
|
||||
if f == "" {
|
||||
continue
|
||||
}
|
||||
if f == "-" {
|
||||
paths = append(paths, f)
|
||||
continue
|
||||
}
|
||||
if _, err := os.Stat(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paths = append(paths, f)
|
||||
}
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string, bo map[string]build.Options) error {
|
||||
l, err := localstate.New(confutil.NewConfig(dockerCli))
|
||||
if err != nil {
|
||||
|
@ -553,7 +604,7 @@ func bakeArgs(args []string) (url, cmdContext string, targets []string) {
|
|||
return url, cmdContext, targets
|
||||
}
|
||||
|
||||
func readBakeFiles(ctx context.Context, nodes []builder.Node, url string, names []string, stdin io.Reader, pw progress.Writer) (files []bake.File, inp *bake.Input, err error) {
|
||||
func readBakeFiles(ctx context.Context, nodes []builder.Node, url string, names []string, stdin io.Reader, pw progress.Writer, filesFromEnv bool) (files []bake.File, inp *bake.Input, err error) {
|
||||
var lnames []string // local
|
||||
var rnames []string // remote
|
||||
var anames []string // both
|
||||
|
@ -578,7 +629,11 @@ func readBakeFiles(ctx context.Context, nodes []builder.Node, url string, names
|
|||
|
||||
if len(lnames) > 0 || url == "" {
|
||||
var lfiles []bake.File
|
||||
progress.Wrap("[internal] load local bake definitions", pw.Write, func(sub progress.SubLogger) error {
|
||||
where := ""
|
||||
if filesFromEnv {
|
||||
where = " from " + bakeEnvFilePath + " env"
|
||||
}
|
||||
progress.Wrap("[internal] load local bake definitions"+where, pw.Write, func(sub progress.SubLogger) error {
|
||||
if url != "" {
|
||||
lfiles, err = bake.ReadLocalFiles(lnames, stdin, sub)
|
||||
} else {
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"github.com/containerd/console"
|
||||
"github.com/docker/buildx/build"
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/commands/debug"
|
||||
"github.com/docker/buildx/monitor"
|
||||
"github.com/docker/buildx/store"
|
||||
"github.com/docker/buildx/store/storeutil"
|
||||
|
@ -441,20 +440,7 @@ func runBuildWithOptions(ctx context.Context, dockerCli command.Cli, opts *Build
|
|||
}
|
||||
}
|
||||
|
||||
func newDebuggableBuild(dockerCli command.Cli, rootOpts *rootOptions) debug.DebuggableCmd {
|
||||
return &debuggableBuild{dockerCli: dockerCli, rootOpts: rootOpts}
|
||||
}
|
||||
|
||||
type debuggableBuild struct {
|
||||
dockerCli command.Cli
|
||||
rootOpts *rootOptions
|
||||
}
|
||||
|
||||
func (b *debuggableBuild) NewDebugger(cfg *debug.DebugConfig) *cobra.Command {
|
||||
return buildCmd(b.dockerCli, b.rootOpts, cfg)
|
||||
}
|
||||
|
||||
func buildCmd(dockerCli command.Cli, rootOpts *rootOptions, debugConfig *debug.DebugConfig) *cobra.Command {
|
||||
func buildCmd(dockerCli command.Cli, rootOpts *rootOptions, debugConfig *debugOptions) *cobra.Command {
|
||||
cFlags := &commonFlags{}
|
||||
options := &buildOptions{}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"github.com/docker/buildx/util/cobrautil"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type debugOptions struct {
|
||||
// InvokeFlag is a flag to configure the launched debugger and the commaned executed on the debugger.
|
||||
InvokeFlag string
|
||||
|
||||
// OnFlag is a flag to configure the timing of launching the debugger.
|
||||
OnFlag string
|
||||
}
|
||||
|
||||
func debugCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
var options debugOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "debug",
|
||||
Short: "Start debugger",
|
||||
}
|
||||
cobrautil.MarkCommandExperimental(cmd)
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.StringVar(&options.InvokeFlag, "invoke", "", "Launch a monitor with executing specified command")
|
||||
flags.StringVar(&options.OnFlag, "on", "error", "When to launch the monitor ([always, error])")
|
||||
|
||||
cobrautil.MarkFlagsExperimental(flags, "invoke", "on")
|
||||
|
||||
cmd.AddCommand(buildCmd(dockerCli, rootOpts, &options))
|
||||
return cmd
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package debug
|
||||
|
||||
import (
|
||||
"github.com/docker/buildx/util/cobrautil"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// DebugConfig is a user-specified configuration for the debugger.
|
||||
type DebugConfig struct {
|
||||
// InvokeFlag is a flag to configure the launched debugger and the commaned executed on the debugger.
|
||||
InvokeFlag string
|
||||
|
||||
// OnFlag is a flag to configure the timing of launching the debugger.
|
||||
OnFlag string
|
||||
}
|
||||
|
||||
// DebuggableCmd is a command that supports debugger with recognizing the user-specified DebugConfig.
|
||||
type DebuggableCmd interface {
|
||||
// NewDebugger returns the new *cobra.Command with support for the debugger with recognizing DebugConfig.
|
||||
NewDebugger(*DebugConfig) *cobra.Command
|
||||
}
|
||||
|
||||
func RootCmd(dockerCli command.Cli, children ...DebuggableCmd) *cobra.Command {
|
||||
var progressMode string
|
||||
var options DebugConfig
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "debug",
|
||||
Short: "Start debugger",
|
||||
}
|
||||
cobrautil.MarkCommandExperimental(cmd)
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.StringVar(&options.InvokeFlag, "invoke", "", "Launch a monitor with executing specified command")
|
||||
flags.StringVar(&options.OnFlag, "on", "error", "When to launch the monitor ([always, error])")
|
||||
flags.StringVar(&progressMode, "progress", "auto", `Set type of progress output ("auto", "plain", "tty", "rawjson") for the monitor. Use plain to show container output`)
|
||||
|
||||
cobrautil.MarkFlagsExperimental(flags, "invoke", "on")
|
||||
|
||||
for _, c := range children {
|
||||
cmd.AddCommand(c.NewDebugger(&options))
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
|
@ -426,23 +426,32 @@ workers0:
|
|||
}
|
||||
|
||||
provIndex := slices.IndexFunc(attachments, func(a attachment) bool {
|
||||
return descrType(a.descr) == slsa02.PredicateSLSAProvenance
|
||||
return strings.HasPrefix(descrType(a.descr), "https://slsa.dev/provenance/")
|
||||
})
|
||||
if provIndex != -1 {
|
||||
prov := attachments[provIndex]
|
||||
predType := descrType(prov.descr)
|
||||
dt, err := content.ReadBlob(ctx, store, prov.descr)
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to read provenance %s: %v", prov.descr.Digest, err)
|
||||
}
|
||||
var pred provenancetypes.ProvenancePredicateSLSA02
|
||||
if err := json.Unmarshal(dt, &pred); err != nil {
|
||||
var pred *provenancetypes.ProvenancePredicateSLSA1
|
||||
if predType == slsa02.PredicateSLSAProvenance {
|
||||
var pred02 *provenancetypes.ProvenancePredicateSLSA02
|
||||
if err := json.Unmarshal(dt, &pred02); err != nil {
|
||||
return errors.Errorf("failed to unmarshal provenance %s: %v", prov.descr.Digest, err)
|
||||
}
|
||||
pred = pred02.ConvertToSLSA1()
|
||||
} else if err := json.Unmarshal(dt, &pred); err != nil {
|
||||
return errors.Errorf("failed to unmarshal provenance %s: %v", prov.descr.Digest, err)
|
||||
}
|
||||
for _, m := range pred.Materials {
|
||||
out.Materials = append(out.Materials, materialOutput{
|
||||
URI: m.URI,
|
||||
Digests: digestSetToDigests(m.Digest),
|
||||
})
|
||||
if pred != nil {
|
||||
for _, m := range pred.BuildDefinition.ResolvedDependencies {
|
||||
out.Materials = append(out.Materials, materialOutput{
|
||||
URI: m.URI,
|
||||
Digests: digestSetToDigests(m.Digest),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/docker/cli/cli/command"
|
||||
intoto "github.com/in-toto/in-toto-golang/in_toto"
|
||||
slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
|
||||
slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -76,25 +77,30 @@ func runAttachment(ctx context.Context, dockerCli command.Cli, opts attachmentOp
|
|||
return err
|
||||
}
|
||||
|
||||
typ := opts.typ
|
||||
switch typ {
|
||||
types := make(map[string]struct{})
|
||||
switch opts.typ {
|
||||
case "index":
|
||||
typ = ocispecs.MediaTypeImageIndex
|
||||
types[ocispecs.MediaTypeImageIndex] = struct{}{}
|
||||
case "manifest":
|
||||
typ = ocispecs.MediaTypeImageManifest
|
||||
types[ocispecs.MediaTypeImageManifest] = struct{}{}
|
||||
case "image":
|
||||
typ = ocispecs.MediaTypeImageConfig
|
||||
types[ocispecs.MediaTypeImageConfig] = struct{}{}
|
||||
case "provenance":
|
||||
typ = slsa02.PredicateSLSAProvenance
|
||||
types[slsa1.PredicateSLSAProvenance] = struct{}{}
|
||||
types[slsa02.PredicateSLSAProvenance] = struct{}{}
|
||||
case "sbom":
|
||||
typ = intoto.PredicateSPDX
|
||||
types[intoto.PredicateSPDX] = struct{}{}
|
||||
default:
|
||||
if opts.typ != "" {
|
||||
types[opts.typ] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
for _, a := range attachments {
|
||||
if opts.platform != "" && (a.platform == nil || platforms.FormatAll(*a.platform) != opts.platform) {
|
||||
continue
|
||||
}
|
||||
if typ != "" && descrType(a.descr) != typ {
|
||||
if _, ok := types[descrType(a.descr)]; opts.typ != "" && !ok {
|
||||
continue
|
||||
}
|
||||
ra, err := store.ReaderAt(ctx, a.descr)
|
||||
|
@ -112,9 +118,9 @@ func attachmentCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
|
|||
var options attachmentOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "attachment [OPTIONS] REF [DIGEST]",
|
||||
Use: "attachment [OPTIONS] [REF [DIGEST]]",
|
||||
Short: "Inspect a build record attachment",
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
Args: cobra.MaximumNArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 0 {
|
||||
options.ref = args[0]
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
debugcmd "github.com/docker/buildx/commands/debug"
|
||||
historycmd "github.com/docker/buildx/commands/history"
|
||||
imagetoolscmd "github.com/docker/buildx/commands/imagetools"
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
|
@ -120,9 +119,7 @@ func addCommands(cmd *cobra.Command, opts *rootOptions, dockerCli command.Cli) {
|
|||
historycmd.RootCmd(cmd, dockerCli, historycmd.RootOptions{Builder: &opts.builder}),
|
||||
)
|
||||
if confutil.IsExperimental() {
|
||||
cmd.AddCommand(debugcmd.RootCmd(dockerCli,
|
||||
newDebuggableBuild(dockerCli, opts),
|
||||
))
|
||||
cmd.AddCommand(debugCmd(dockerCli, opts))
|
||||
}
|
||||
|
||||
cmd.RegisterFlagCompletionFunc( //nolint:errcheck
|
||||
|
|
|
@ -73,6 +73,13 @@ target "lint-gopls" {
|
|||
target = "gopls-analyze"
|
||||
}
|
||||
|
||||
target "modernize-fix" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/lint.Dockerfile"
|
||||
target = "modernize-fix"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "validate-vendor" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
|
||||
|
|
|
@ -143,6 +143,11 @@ Use the `-f` / `--file` option to specify the build definition file to use.
|
|||
The file can be an HCL, JSON or Compose file. If multiple files are specified,
|
||||
all are read and the build configurations are combined.
|
||||
|
||||
Alternatively, the environment variable `BUILDX_BAKE_FILE` can be used to specify the build definition to use.
|
||||
This is mutually exclusive with `-f` / `--file`; if both are specified, the environment variable is ignored.
|
||||
Multiple definitions can be specified by separating them with the system's path separator
|
||||
(typically `;` on Windows and `:` elsewhere), but can be changed with `BUILDX_BAKE_PATH_SEPARATOR`.
|
||||
|
||||
You can pass the names of the targets to build, to build only specific target(s).
|
||||
The following example builds the `db` and `webapp-release` targets that are
|
||||
defined in the `docker-bake.dev.hcl` file:
|
||||
|
|
|
@ -12,13 +12,12 @@ Start debugger (EXPERIMENTAL)
|
|||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------|:---------|:--------|:--------------------------------------------------------------------------------------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `-D`, `--debug` | `bool` | | Enable debug logging |
|
||||
| `--invoke` | `string` | | Launch a monitor with executing specified command (EXPERIMENTAL) |
|
||||
| `--on` | `string` | `error` | When to launch the monitor ([always, error]) (EXPERIMENTAL) |
|
||||
| `--progress` | `string` | `auto` | Set type of progress output (`auto`, `plain`, `tty`, `rawjson`) for the monitor. Use plain to show container output |
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------|:---------|:--------|:-----------------------------------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `-D`, `--debug` | `bool` | | Enable debug logging |
|
||||
| `--invoke` | `string` | | Launch a monitor with executing specified command (EXPERIMENTAL) |
|
||||
| `--on` | `string` | `error` | When to launch the monitor ([always, error]) (EXPERIMENTAL) |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# docker buildx history inspect attachment
|
||||
|
||||
```text
|
||||
docker buildx history inspect attachment [OPTIONS] REF [DIGEST]
|
||||
docker buildx history inspect attachment [OPTIONS] [REF [DIGEST]]
|
||||
```
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
|
@ -9,12 +9,12 @@ Inspect a build record attachment
|
|||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------------|:---------|:--------|:-----------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `-D`, `--debug` | `bool` | | Enable debug logging |
|
||||
| `--platform` | `string` | | Platform of attachment |
|
||||
| [`--type`](#type) | `string` | | Type of attachment |
|
||||
| Name | Type | Default | Description |
|
||||
|:--------------------------|:---------|:--------|:-----------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `-D`, `--debug` | `bool` | | Enable debug logging |
|
||||
| [`--platform`](#platform) | `string` | | Platform of attachment |
|
||||
| [`--type`](#type) | `string` | | Type of attachment |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
@ -27,48 +27,160 @@ platform-specific.
|
|||
|
||||
## Examples
|
||||
|
||||
### <a name="type"></a> Inspect a provenance attachment from a build (--type)
|
||||
|
||||
Supported types include `provenance` and `sbom`.
|
||||
### <a name="platform"></a> Inspect an attachment by platform (--platform)
|
||||
|
||||
```console
|
||||
$ docker buildx history inspect attachment qu2gsuo8ejqrwdfii23xkkckt --type provenance
|
||||
$ docker buildx history inspect attachment --platform linux/amd64
|
||||
{
|
||||
"_type": "https://slsa.dev/provenance/v0.2",
|
||||
"buildDefinition": {
|
||||
"buildType": "https://build.docker.com/BuildKit@v1",
|
||||
"externalParameters": {
|
||||
"target": "app",
|
||||
"platforms": ["linux/amd64"]
|
||||
}
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:814e63f06465bc78123775714e4df1ebdda37e6403e0b4f481df74947c047163",
|
||||
"size": 600
|
||||
},
|
||||
"runDetails": {
|
||||
"builder": "docker",
|
||||
"by": "ci@docker.com"
|
||||
}
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:36537f3920ae948ce3e12b4ae34c21190280e6e7d58eeabde0dff3fdfb43b6b0",
|
||||
"size": 21664137
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Inspect a SBOM for linux/amd64
|
||||
### <a name="type"></a> Inspect an attachment by type (--type)
|
||||
|
||||
Supported types include:
|
||||
* `index`
|
||||
* `manifest`
|
||||
* `image`
|
||||
* `provenance`
|
||||
* `sbom`
|
||||
|
||||
#### Index
|
||||
|
||||
```console
|
||||
$ docker buildx history inspect attachment ^0 \
|
||||
--type sbom \
|
||||
--platform linux/amd64
|
||||
$ docker buildx history inspect attachment --type index
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.5",
|
||||
"version": 1,
|
||||
"components": [
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.index.v1+json",
|
||||
"manifests": [
|
||||
{
|
||||
"type": "library",
|
||||
"name": "alpine",
|
||||
"version": "3.18.2"
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:a194e24f47dc6d0e65992c09577b9bc4e7bd0cd5cc4f81e7738918f868aa397b",
|
||||
"size": 481,
|
||||
"platform": {
|
||||
"architecture": "amd64",
|
||||
"os": "linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:49e40223d6a96ea0667a12737fd3dde004cf217eb48cb28c9191288cd44c6ace",
|
||||
"size": 839,
|
||||
"annotations": {
|
||||
"vnd.docker.reference.digest": "sha256:a194e24f47dc6d0e65992c09577b9bc4e7bd0cd5cc4f81e7738918f868aa397b",
|
||||
"vnd.docker.reference.type": "attestation-manifest"
|
||||
},
|
||||
"platform": {
|
||||
"architecture": "unknown",
|
||||
"os": "unknown"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Manifest
|
||||
|
||||
```console
|
||||
$ docker buildx history inspect attachment --type manifest
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:814e63f06465bc78123775714e4df1ebdda37e6403e0b4f481df74947c047163",
|
||||
"size": 600
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:36537f3920ae948ce3e12b4ae34c21190280e6e7d58eeabde0dff3fdfb43b6b0",
|
||||
"size": 21664137
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Provenance
|
||||
|
||||
```console
|
||||
$ docker buildx history inspect attachment --type provenance
|
||||
{
|
||||
"builder": {
|
||||
"id": ""
|
||||
},
|
||||
"buildType": "https://mobyproject.org/buildkit@v1",
|
||||
"materials": [
|
||||
{
|
||||
"uri": "pkg:docker/docker/dockerfile@1",
|
||||
"digest": {
|
||||
"sha256": "9ba7531bd80fb0a858632727cf7a112fbfd19b17e94c4e84ced81e24ef1a0dbc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"uri": "pkg:docker/golang@1.19.4-alpine?platform=linux%2Farm64",
|
||||
"digest": {
|
||||
"sha256": "a9b24b67dc83b3383d22a14941c2b2b2ca6a103d805cac6820fd1355943beaf1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"invocation": {
|
||||
"configSource": {
|
||||
"entryPoint": "Dockerfile"
|
||||
},
|
||||
"parameters": {
|
||||
"frontend": "gateway.v0",
|
||||
"args": {
|
||||
"cmdline": "docker/dockerfile:1",
|
||||
"source": "docker/dockerfile:1",
|
||||
"target": "binaries"
|
||||
},
|
||||
"locals": [
|
||||
{
|
||||
"name": "context"
|
||||
},
|
||||
{
|
||||
"name": "dockerfile"
|
||||
}
|
||||
]
|
||||
},
|
||||
"environment": {
|
||||
"platform": "linux/arm64"
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"buildInvocationID": "c4a87v0sxhliuewig10gnsb6v",
|
||||
"buildStartedOn": "2022-12-16T08:26:28.651359794Z",
|
||||
"buildFinishedOn": "2022-12-16T08:26:29.625483253Z",
|
||||
"reproducible": false,
|
||||
"completeness": {
|
||||
"parameters": true,
|
||||
"environment": true,
|
||||
"materials": false
|
||||
},
|
||||
"https://mobyproject.org/buildkit@v1#metadata": {
|
||||
"vcs": {
|
||||
"revision": "a9ba846486420e07d30db1107411ac3697ecab68",
|
||||
"source": "git@github.com:<org>/<repo>.git"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Inspect an attachment by digest
|
||||
|
||||
You can inspect an attachment directly using its digset, which you can get from
|
||||
|
|
|
@ -286,6 +286,10 @@ func (f *factory) processDriverOpts(deploymentName string, namespace string, cfg
|
|||
if v != "" {
|
||||
deploymentOpt.Qemu.Image = v
|
||||
}
|
||||
case "buildkit-root-volume-memory":
|
||||
if v != "" {
|
||||
deploymentOpt.BuildKitRootVolumeMemory = v
|
||||
}
|
||||
case "default-load":
|
||||
defaultLoad, err = strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
|
|
|
@ -32,6 +32,7 @@ type DeploymentOpt struct {
|
|||
// files mounted at /etc/buildkitd
|
||||
ConfigFiles map[string][]byte
|
||||
|
||||
BuildKitRootVolumeMemory string
|
||||
Rootless bool
|
||||
NodeSelector map[string]string
|
||||
CustomAnnotations map[string]string
|
||||
|
@ -50,6 +51,8 @@ const (
|
|||
containerName = "buildkitd"
|
||||
AnnotationPlatform = "buildx.docker.com/platform"
|
||||
LabelApp = "app"
|
||||
rootVolumeName = "buildkit-memory"
|
||||
rootVolumePath = "/var/lib/buildkit"
|
||||
)
|
||||
|
||||
type ErrReservedAnnotationPlatform struct{}
|
||||
|
@ -247,6 +250,26 @@ func NewDeployment(opt *DeploymentOpt) (d *appsv1.Deployment, c []*corev1.Config
|
|||
d.Spec.Template.Spec.Containers[0].Resources.Limits[corev1.ResourceEphemeralStorage] = limEphemeralStorage
|
||||
}
|
||||
|
||||
if opt.BuildKitRootVolumeMemory != "" {
|
||||
buildKitRootVolumeMemory, err := resource.ParseQuantity(opt.BuildKitRootVolumeMemory)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
d.Spec.Template.Spec.Volumes = append(d.Spec.Template.Spec.Volumes, corev1.Volume{
|
||||
Name: rootVolumeName,
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
EmptyDir: &corev1.EmptyDirVolumeSource{
|
||||
Medium: "Memory",
|
||||
SizeLimit: &buildKitRootVolumeMemory,
|
||||
},
|
||||
},
|
||||
})
|
||||
d.Spec.Template.Spec.Containers[0].VolumeMounts = append(d.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
|
||||
Name: rootVolumeName,
|
||||
MountPath: rootVolumePath,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
6
go.mod
6
go.mod
|
@ -16,9 +16,9 @@ require (
|
|||
github.com/creack/pty v1.1.24
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/cli v28.2.2+incompatible
|
||||
github.com/docker/cli v28.3.0+incompatible
|
||||
github.com/docker/cli-docs-tool v0.10.0
|
||||
github.com/docker/docker v28.2.2+incompatible
|
||||
github.com/docker/docker v28.3.0+incompatible
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/gofrs/flock v0.12.1
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
|
@ -28,7 +28,7 @@ require (
|
|||
github.com/hashicorp/hcl/v2 v2.23.0
|
||||
github.com/in-toto/in-toto-golang v0.9.0
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/moby/buildkit v0.23.0-rc1
|
||||
github.com/moby/buildkit v0.23.0-rc1.0.20250618182037-9b91d20367db // master
|
||||
github.com/moby/go-archive v0.1.0
|
||||
github.com/moby/sys/atomicwriter v0.1.0
|
||||
github.com/moby/sys/mountinfo v0.7.2
|
||||
|
|
12
go.sum
12
go.sum
|
@ -106,15 +106,15 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v28.2.2+incompatible h1:qzx5BNUDFqlvyq4AHzdNB7gSyVTmU4cgsyN9SdInc1A=
|
||||
github.com/docker/cli v28.2.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v28.3.0+incompatible h1:s+ttruVLhB5ayeuf2BciwDVxYdKi+RoUlxmwNHV3Vfo=
|
||||
github.com/docker/cli v28.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli-docs-tool v0.10.0 h1:bOD6mKynPQgojQi3s2jgcUWGp/Ebqy1SeCr9VfKQLLU=
|
||||
github.com/docker/cli-docs-tool v0.10.0/go.mod h1:5EM5zPnT2E7yCLERZmrDA234Vwn09fzRHP4aX1qwp1U=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
|
||||
github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.3.0+incompatible h1:ffS62aKWupCWdvcee7nBU9fhnmknOqDPaJAMtfK0ImQ=
|
||||
github.com/docker/docker v28.3.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||
|
@ -250,8 +250,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX
|
|||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/moby/buildkit v0.23.0-rc1 h1:RIAEITsycLbXUt//rEPEfZUFnKUcm1cvpuWOfOidiWU=
|
||||
github.com/moby/buildkit v0.23.0-rc1/go.mod h1:v5jMDvQgUyidk3wu3NvVAAd5JJo83nfet9Gf/o0+EAQ=
|
||||
github.com/moby/buildkit v0.23.0-rc1.0.20250618182037-9b91d20367db h1:ZzrDuG9G1A/RwJvuogNplxCEKsIUQh1CqEnqbOGFgKE=
|
||||
github.com/moby/buildkit v0.23.0-rc1.0.20250618182037-9b91d20367db/go.mod h1:v5jMDvQgUyidk3wu3NvVAAd5JJo83nfet9Gf/o0+EAQ=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
ARG GO_VERSION=1.24
|
||||
ARG ALPINE_VERSION=3.21
|
||||
|
||||
ARG GOVULNCHECK_VERSION=v1.1.3
|
||||
ARG GOVULNCHECK_VERSION=v1.1.4
|
||||
ARG FORMAT="text"
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base
|
||||
|
@ -20,12 +20,6 @@ RUN --mount=type=bind,target=. <<EOT
|
|||
set -ex
|
||||
mkdir /out
|
||||
govulncheck -format ${FORMAT} ./... | tee /out/govulncheck.out
|
||||
if [ "${FORMAT}" = "sarif" ]; then
|
||||
# Make sure "results" field is defined in SARIF output otherwise GitHub Code Scanning
|
||||
# will fail when uploading report with "Invalid SARIF. Missing 'results' array in run."
|
||||
# Relates to https://github.com/golang/vuln/blob/ffdef74cc44d7eb71931d8d414c478b966812488/internal/sarif/sarif.go#L69
|
||||
jq '(.runs[] | select(.results == null) | .results) |= []' /out/govulncheck.out | tee >(sponge /out/govulncheck.out)
|
||||
fi
|
||||
EOT
|
||||
|
||||
FROM scratch AS output
|
||||
|
|
|
@ -91,4 +91,25 @@ RUN --mount=target=. \
|
|||
done
|
||||
EOF
|
||||
|
||||
FROM base AS modernize-fix-run
|
||||
COPY --link --from=xx / /
|
||||
ARG TARGETNAME
|
||||
ARG TARGETPLATFORM
|
||||
WORKDIR /go/src/github.com/docker/buildx
|
||||
RUN --mount=target=.,rw \
|
||||
--mount=target=/root/.cache,type=cache,id=lint-cache-${TARGETNAME}-${TARGETPLATFORM} \
|
||||
--mount=target=/gopls-analyzers,from=gopls,source=/out <<EOF
|
||||
set -ex
|
||||
xx-go --wrap
|
||||
mkdir /out
|
||||
/gopls-analyzers/modernize -fix ./...
|
||||
for file in $(git status --porcelain | awk '/^ M/ {print $2}'); do
|
||||
mkdir -p /out/$(dirname $file)
|
||||
cp $file /out/$file
|
||||
done
|
||||
EOF
|
||||
|
||||
FROM scratch AS modernize-fix
|
||||
COPY --link --from=modernize-fix-run /out /
|
||||
|
||||
FROM lint
|
||||
|
|
165
tests/bake.go
165
tests/bake.go
|
@ -81,6 +81,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
|
|||
testBakeMultiPlatform,
|
||||
testBakeCheckCallOutput,
|
||||
testBakeExtraHosts,
|
||||
testBakeFileFromEnvironment,
|
||||
}
|
||||
|
||||
func testBakePrint(t *testing.T, sb integration.Sandbox) {
|
||||
|
@ -1398,7 +1399,7 @@ target "default" {
|
|||
|
||||
var prv provenancetypes.ProvenancePredicateSLSA02
|
||||
require.NoError(t, json.Unmarshal(dtprv, &prv))
|
||||
require.Equal(t, provenancetypes.BuildKitBuildType, prv.BuildType)
|
||||
require.Equal(t, provenancetypes.BuildKitBuildType02, prv.BuildType)
|
||||
}
|
||||
|
||||
func testBakeMetadataWarnings(t *testing.T, sb integration.Sandbox) {
|
||||
|
@ -2167,11 +2168,14 @@ func testBakeExtraHosts(t *testing.T, sb integration.Sandbox) {
|
|||
dockerfile := []byte(`
|
||||
FROM busybox
|
||||
RUN cat /etc/hosts | grep myhost | grep 1.2.3.4
|
||||
RUN cat /etc/hosts | grep myhostmulti | grep 162.242.195.81
|
||||
RUN cat /etc/hosts | grep myhostmulti | grep 162.242.195.82
|
||||
`)
|
||||
bakefile := []byte(`
|
||||
target "default" {
|
||||
extra-hosts = {
|
||||
myhost = "1.2.3.4"
|
||||
myhostmulti = "162.242.195.81,162.242.195.82"
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
@ -2188,6 +2192,165 @@ target "default" {
|
|||
require.NoError(t, err, out)
|
||||
}
|
||||
|
||||
func testBakeFileFromEnvironment(t *testing.T, sb integration.Sandbox) {
|
||||
bakeFileFirst := []byte(`
|
||||
target "first" {
|
||||
dockerfile-inline = "FROM scratch\nCOPY first /"
|
||||
}
|
||||
`)
|
||||
bakeFileSecond := []byte(`
|
||||
target "second" {
|
||||
dockerfile-inline = "FROM scratch\nCOPY second /"
|
||||
}
|
||||
`)
|
||||
|
||||
t.Run("single file", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=first.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions from BUILDX_BAKE_FILE env`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
})
|
||||
|
||||
t.Run("single file, default ignored if present", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("docker-bake.hcl", []byte("invalid bake file"), 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=first.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions from BUILDX_BAKE_FILE env`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
require.NotContains(t, string(dt), "docker-bake.hcl")
|
||||
})
|
||||
|
||||
t.Run("multiple files", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("second.hcl", bakeFileSecond, 0600),
|
||||
fstest.CreateFile("second", []byte("second"), 0600),
|
||||
)
|
||||
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "second", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=first.hcl"+string(os.PathListSeparator)+"second.hcl"))
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions from BUILDX_BAKE_FILE env`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
require.Contains(t, string(dt), `#1 reading second.hcl`)
|
||||
})
|
||||
|
||||
t.Run("multiple files, custom separator", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("second.hcl", bakeFileSecond, 0600),
|
||||
fstest.CreateFile("second", []byte("second"), 0600),
|
||||
)
|
||||
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "second", "first"),
|
||||
withEnv("BUILDX_BAKE_PATH_SEPARATOR=@", "BUILDX_BAKE_FILE=first.hcl@second.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions from BUILDX_BAKE_FILE env`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
require.Contains(t, string(dt), `#1 reading second.hcl`)
|
||||
})
|
||||
|
||||
t.Run("multiple files, one STDIN", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("second", []byte("second"), 0600),
|
||||
)
|
||||
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "second", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=first.hcl"+string(os.PathListSeparator)+"-"))
|
||||
w, err := cmd.StdinPipe()
|
||||
require.NoError(t, err)
|
||||
go func() {
|
||||
defer w.Close()
|
||||
w.Write(bakeFileSecond)
|
||||
}()
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions from BUILDX_BAKE_FILE env`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
require.Contains(t, string(dt), `#1 reading from stdin`)
|
||||
})
|
||||
|
||||
t.Run("env ignored if file arg passed", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("second.hcl", bakeFileSecond, 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "-f", "first.hcl", "first", "second"),
|
||||
withEnv("BUILDX_BAKE_FILE=second.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(dt))
|
||||
require.Contains(t, string(dt), "failed to find target second")
|
||||
})
|
||||
|
||||
t.Run("file does not exist", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=wrong.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(dt))
|
||||
require.Contains(t, string(dt), "wrong.hcl: no such file or directory")
|
||||
})
|
||||
|
||||
for kind, val := range map[string]string{"missing": "", "whitespace": " "} {
|
||||
t.Run(kind+" value ignored", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "first"),
|
||||
withEnv(fmt.Sprintf("BUILDX_BAKE_FILE=%s", val)))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(dt))
|
||||
require.Contains(t, string(dt), "couldn't find a bake definition")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func writeTempPrivateKey(fp string) error {
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
|
|
|
@ -77,6 +77,7 @@ var buildTests = []func(t *testing.T, sb integration.Sandbox){
|
|||
testBuildDefaultLoad,
|
||||
testBuildCall,
|
||||
testCheckCallOutput,
|
||||
testBuildExtraHosts,
|
||||
}
|
||||
|
||||
func testBuild(t *testing.T, sb integration.Sandbox) {
|
||||
|
@ -834,7 +835,7 @@ func buildMetadataProvenance(t *testing.T, sb integration.Sandbox, metadataMode
|
|||
|
||||
var prv provenancetypes.ProvenancePredicateSLSA02
|
||||
require.NoError(t, json.Unmarshal(dtprv, &prv))
|
||||
require.Equal(t, provenancetypes.BuildKitBuildType, prv.BuildType)
|
||||
require.Equal(t, provenancetypes.BuildKitBuildType02, prv.BuildType)
|
||||
}
|
||||
|
||||
func testBuildMetadataWarnings(t *testing.T, sb integration.Sandbox) {
|
||||
|
@ -1322,6 +1323,24 @@ cOpy Dockerfile .
|
|||
})
|
||||
}
|
||||
|
||||
func testBuildExtraHosts(t *testing.T, sb integration.Sandbox) {
|
||||
dockerfile := []byte(`
|
||||
FROM busybox
|
||||
RUN cat /etc/hosts | grep myhost | grep 1.2.3.4
|
||||
RUN cat /etc/hosts | grep myhostmulti | grep 162.242.195.81
|
||||
RUN cat /etc/hosts | grep myhostmulti | grep 162.242.195.82
|
||||
`)
|
||||
dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600))
|
||||
cmd := buildxCmd(sb, withArgs("build",
|
||||
"--add-host=myhost=1.2.3.4",
|
||||
"--add-host=myhostmulti=162.242.195.81",
|
||||
"--add-host=myhostmulti=162.242.195.82",
|
||||
"--output=type=cacheonly", dir),
|
||||
)
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(out))
|
||||
}
|
||||
|
||||
func createTestProject(t *testing.T) string {
|
||||
dockerfile := []byte(`
|
||||
FROM busybox:latest AS base
|
||||
|
|
|
@ -51,8 +51,8 @@ type Printer struct {
|
|||
func (p *Printer) Wait() error {
|
||||
p.closeOnce.Do(func() {
|
||||
close(p.status)
|
||||
<-p.done
|
||||
})
|
||||
<-p.done
|
||||
return p.err
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,7 @@ func NewPrinter(ctx context.Context, out console.File, mode progressui.DisplayMo
|
|||
interrupt: make(chan interruptRequest),
|
||||
state: printerStateRunning,
|
||||
done: make(chan struct{}),
|
||||
metrics: opt.mw,
|
||||
}
|
||||
go pw.run(ctx, d)
|
||||
|
||||
|
@ -155,21 +156,21 @@ func (p *Printer) run(ctx context.Context, d progressui.Display) {
|
|||
defer close(p.interrupt)
|
||||
|
||||
var ss []*client.SolveStatus
|
||||
for p.state != printerStateDone {
|
||||
for {
|
||||
switch p.state {
|
||||
case printerStatePaused:
|
||||
ss, p.err = p.bufferDisplay(ctx, ss)
|
||||
case printerStateRunning:
|
||||
var warnings []client.VertexWarning
|
||||
warnings, ss, p.err = p.updateDisplay(ctx, d, ss)
|
||||
p.warnings = append(p.warnings, warnings...)
|
||||
|
||||
d, _ = p.newDisplay()
|
||||
p.warnings, ss, p.err = p.updateDisplay(ctx, d, ss)
|
||||
if p.opt.onclose != nil {
|
||||
p.opt.onclose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.opt.onclose != nil {
|
||||
p.opt.onclose()
|
||||
if p.state == printerStateDone {
|
||||
break
|
||||
}
|
||||
d, _ = p.newDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ const (
|
|||
const authConfigKey = "https://index.docker.io/v1/"
|
||||
|
||||
// RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info
|
||||
// for the given command.
|
||||
// for the given command to prompt the user for username and password.
|
||||
func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInfo, cmdName string) registrytypes.RequestAuthConfig {
|
||||
configKey := getAuthConfigKey(index.Name)
|
||||
isDefaultRegistry := configKey == authConfigKey || index.Official
|
||||
|
@ -43,7 +43,7 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
|
|||
_, _ = fmt.Fprintf(cli.Out(), "\nLogin prior to %s:\n", cmdName)
|
||||
authConfig, err := GetDefaultAuthConfig(cli.ConfigFile(), true, configKey, isDefaultRegistry)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", authConfigKey, err)
|
||||
_, _ = fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", configKey, err)
|
||||
}
|
||||
|
||||
select {
|
||||
|
@ -52,7 +52,7 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
|
|||
default:
|
||||
}
|
||||
|
||||
authConfig, err = PromptUserForCredentials(ctx, cli, "", "", authConfig.Username, authConfigKey)
|
||||
authConfig, err = PromptUserForCredentials(ctx, cli, "", "", authConfig.Username, configKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -3,12 +3,14 @@ package configfile
|
|||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/config/credentials"
|
||||
"github.com/docker/cli/cli/config/memorystore"
|
||||
"github.com/docker/cli/cli/config/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -46,6 +48,31 @@ type ConfigFile struct {
|
|||
Experimental string `json:"experimental,omitempty"`
|
||||
}
|
||||
|
||||
type configEnvAuth struct {
|
||||
Auth string `json:"auth"`
|
||||
}
|
||||
|
||||
type configEnv struct {
|
||||
AuthConfigs map[string]configEnvAuth `json:"auths"`
|
||||
}
|
||||
|
||||
// dockerEnvConfig is an environment variable that contains a JSON encoded
|
||||
// credential config. It only supports storing the credentials as a base64
|
||||
// encoded string in the format base64("username:pat").
|
||||
//
|
||||
// Adding additional fields will produce a parsing error.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// {
|
||||
// "auths": {
|
||||
// "example.test": {
|
||||
// "auth": base64-encoded-username-pat
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
const dockerEnvConfig = "DOCKER_AUTH_CONFIG"
|
||||
|
||||
// ProxyConfig contains proxy configuration settings
|
||||
type ProxyConfig struct {
|
||||
HTTPProxy string `json:"httpProxy,omitempty"`
|
||||
|
@ -263,10 +290,64 @@ func decodeAuth(authStr string) (string, string, error) {
|
|||
// GetCredentialsStore returns a new credentials store from the settings in the
|
||||
// configuration file
|
||||
func (configFile *ConfigFile) GetCredentialsStore(registryHostname string) credentials.Store {
|
||||
store := credentials.NewFileStore(configFile)
|
||||
|
||||
if helper := getConfiguredCredentialStore(configFile, registryHostname); helper != "" {
|
||||
return newNativeStore(configFile, helper)
|
||||
store = newNativeStore(configFile, helper)
|
||||
}
|
||||
return credentials.NewFileStore(configFile)
|
||||
|
||||
envConfig := os.Getenv(dockerEnvConfig)
|
||||
if envConfig == "" {
|
||||
return store
|
||||
}
|
||||
|
||||
authConfig, err := parseEnvConfig(envConfig)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "Failed to create credential store from DOCKER_AUTH_CONFIG: ", err)
|
||||
return store
|
||||
}
|
||||
|
||||
// use DOCKER_AUTH_CONFIG if set
|
||||
// it uses the native or file store as a fallback to fetch and store credentials
|
||||
envStore, err := memorystore.New(
|
||||
memorystore.WithAuthConfig(authConfig),
|
||||
memorystore.WithFallbackStore(store),
|
||||
)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "Failed to create credential store from DOCKER_AUTH_CONFIG: ", err)
|
||||
return store
|
||||
}
|
||||
|
||||
return envStore
|
||||
}
|
||||
|
||||
func parseEnvConfig(v string) (map[string]types.AuthConfig, error) {
|
||||
envConfig := &configEnv{}
|
||||
decoder := json.NewDecoder(strings.NewReader(v))
|
||||
decoder.DisallowUnknownFields()
|
||||
if err := decoder.Decode(envConfig); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, err
|
||||
}
|
||||
if decoder.More() {
|
||||
return nil, errors.New("DOCKER_AUTH_CONFIG does not support more than one JSON object")
|
||||
}
|
||||
|
||||
authConfigs := make(map[string]types.AuthConfig)
|
||||
for addr, envAuth := range envConfig.AuthConfigs {
|
||||
if envAuth.Auth == "" {
|
||||
return nil, fmt.Errorf("DOCKER_AUTH_CONFIG environment variable is missing key `auth` for %s", addr)
|
||||
}
|
||||
username, password, err := decodeAuth(envAuth.Auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authConfigs[addr] = types.AuthConfig{
|
||||
Username: username,
|
||||
Password: password,
|
||||
ServerAddress: addr,
|
||||
}
|
||||
}
|
||||
return authConfigs, nil
|
||||
}
|
||||
|
||||
// var for unit testing.
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
//go:build go1.23
|
||||
|
||||
package memorystore
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/cli/cli/config/credentials"
|
||||
"github.com/docker/cli/cli/config/types"
|
||||
)
|
||||
|
||||
var errValueNotFound = errors.New("value not found")
|
||||
|
||||
func IsErrValueNotFound(err error) bool {
|
||||
return errors.Is(err, errValueNotFound)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
lock sync.RWMutex
|
||||
memoryCredentials map[string]types.AuthConfig
|
||||
fallbackStore credentials.Store
|
||||
}
|
||||
|
||||
func (e *Config) Erase(serverAddress string) error {
|
||||
e.lock.Lock()
|
||||
defer e.lock.Unlock()
|
||||
delete(e.memoryCredentials, serverAddress)
|
||||
|
||||
if e.fallbackStore != nil {
|
||||
err := e.fallbackStore.Erase(serverAddress)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "memorystore: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Config) Get(serverAddress string) (types.AuthConfig, error) {
|
||||
e.lock.RLock()
|
||||
defer e.lock.RUnlock()
|
||||
authConfig, ok := e.memoryCredentials[serverAddress]
|
||||
if !ok {
|
||||
if e.fallbackStore != nil {
|
||||
return e.fallbackStore.Get(serverAddress)
|
||||
}
|
||||
return types.AuthConfig{}, errValueNotFound
|
||||
}
|
||||
return authConfig, nil
|
||||
}
|
||||
|
||||
func (e *Config) GetAll() (map[string]types.AuthConfig, error) {
|
||||
e.lock.RLock()
|
||||
defer e.lock.RUnlock()
|
||||
creds := make(map[string]types.AuthConfig)
|
||||
|
||||
if e.fallbackStore != nil {
|
||||
fileCredentials, err := e.fallbackStore.GetAll()
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "memorystore: ", err)
|
||||
} else {
|
||||
creds = fileCredentials
|
||||
}
|
||||
}
|
||||
|
||||
maps.Copy(creds, e.memoryCredentials)
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
func (e *Config) Store(authConfig types.AuthConfig) error {
|
||||
e.lock.Lock()
|
||||
defer e.lock.Unlock()
|
||||
e.memoryCredentials[authConfig.ServerAddress] = authConfig
|
||||
|
||||
if e.fallbackStore != nil {
|
||||
return e.fallbackStore.Store(authConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithFallbackStore sets a fallback store.
|
||||
//
|
||||
// Write operations will be performed on both the memory store and the
|
||||
// fallback store.
|
||||
//
|
||||
// Read operations will first check the memory store, and if the credential
|
||||
// is not found, it will then check the fallback store.
|
||||
//
|
||||
// Retrieving all credentials will return from both the memory store and the
|
||||
// fallback store, merging the results from both stores into a single map.
|
||||
//
|
||||
// Data stored in the memory store will take precedence over data in the
|
||||
// fallback store.
|
||||
func WithFallbackStore(store credentials.Store) Options {
|
||||
return func(s *Config) error {
|
||||
s.fallbackStore = store
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithAuthConfig allows to set the initial credentials in the memory store.
|
||||
func WithAuthConfig(config map[string]types.AuthConfig) Options {
|
||||
return func(s *Config) error {
|
||||
s.memoryCredentials = config
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type Options func(*Config) error
|
||||
|
||||
// New creates a new in memory credential store
|
||||
func New(opts ...Options) (credentials.Store, error) {
|
||||
m := &Config{
|
||||
memoryCredentials: make(map[string]types.AuthConfig),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
if err := opt(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package api // import "github.com/docker/docker/api"
|
||||
package api
|
||||
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// DefaultVersion of the current REST API.
|
||||
DefaultVersion = "1.50"
|
||||
DefaultVersion = "1.51"
|
||||
|
||||
// MinSupportedAPIVersion is the minimum API version that can be supported
|
||||
// by the API server, specified as "major.minor". Note that the daemon
|
||||
|
|
|
@ -19,10 +19,10 @@ produces:
|
|||
consumes:
|
||||
- "application/json"
|
||||
- "text/plain"
|
||||
basePath: "/v1.50"
|
||||
basePath: "/v1.51"
|
||||
info:
|
||||
title: "Docker Engine API"
|
||||
version: "1.50"
|
||||
version: "1.51"
|
||||
x-logo:
|
||||
url: "https://docs.docker.com/assets/images/logo-docker-main.png"
|
||||
description: |
|
||||
|
@ -56,7 +56,7 @@ info:
|
|||
is returned.
|
||||
|
||||
If you omit the version-prefix, the current version of the API (v1.50) is used.
|
||||
For example, calling `/info` is the same as calling `/v1.50/info`. Using the
|
||||
For example, calling `/info` is the same as calling `/v1.51/info`. Using the
|
||||
API without a version-prefix is deprecated and will be removed in a future release.
|
||||
|
||||
Engine releases in the near future should support this version of the API,
|
||||
|
@ -2196,8 +2196,7 @@ definitions:
|
|||
Number of containers using this image. Includes both stopped and running
|
||||
containers.
|
||||
|
||||
This size is not calculated by default, and depends on which API endpoint
|
||||
is used. `-1` indicates that the value has not been set / calculated.
|
||||
`-1` indicates that the value has not been set / calculated.
|
||||
x-nullable: false
|
||||
type: "integer"
|
||||
example: 2
|
||||
|
@ -5863,7 +5862,7 @@ definitions:
|
|||
type: "integer"
|
||||
format: "uint64"
|
||||
x-nullable: true
|
||||
example: 18446744073709551615
|
||||
example: "18446744073709551615"
|
||||
|
||||
ContainerThrottlingData:
|
||||
description: |
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package blkiodev // import "github.com/docker/docker/api/types/blkiodev"
|
||||
package blkiodev
|
||||
|
||||
import "fmt"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package types // import "github.com/docker/docker/api/types"
|
||||
package types
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package container // import "github.com/docker/docker/api/types/container"
|
||||
package container
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
|
|
@ -18,11 +18,13 @@ type ExecOptions struct {
|
|||
AttachStdin bool // Attach the standard input, makes possible user interaction
|
||||
AttachStderr bool // Attach the standard error
|
||||
AttachStdout bool // Attach the standard output
|
||||
Detach bool // Execute in detach mode
|
||||
DetachKeys string // Escape keys for detach
|
||||
Env []string // Environment variables
|
||||
WorkingDir string // Working directory
|
||||
Cmd []string // Execution commands and args
|
||||
|
||||
// Deprecated: the Detach field is not used, and will be removed in a future release.
|
||||
Detach bool
|
||||
}
|
||||
|
||||
// ExecStartOptions is a temp struct used by execStart
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package container // import "github.com/docker/docker/api/types/container"
|
||||
package container
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//go:build !windows
|
||||
|
||||
package container // import "github.com/docker/docker/api/types/container"
|
||||
package container
|
||||
|
||||
import "github.com/docker/docker/api/types/network"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package container // import "github.com/docker/docker/api/types/container"
|
||||
package container
|
||||
|
||||
import "github.com/docker/docker/api/types/network"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package container // import "github.com/docker/docker/api/types/container"
|
||||
package container
|
||||
|
||||
// WaitCondition is a type used to specify a container state for which
|
||||
// to wait.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
package events // import "github.com/docker/docker/api/types/events"
|
||||
package events
|
||||
|
||||
import "github.com/docker/docker/api/types/filters"
|
||||
|
||||
// Type is used for event-types.
|
||||
|
@ -111,11 +112,14 @@ type Actor struct {
|
|||
|
||||
// Message represents the information an event contains
|
||||
type Message struct {
|
||||
// Deprecated information from JSONMessage.
|
||||
// Deprecated: use Action instead.
|
||||
// Information from JSONMessage.
|
||||
// With data only in container events.
|
||||
Status string `json:"status,omitempty"` // Deprecated: use Action instead.
|
||||
ID string `json:"id,omitempty"` // Deprecated: use Actor.ID instead.
|
||||
From string `json:"from,omitempty"` // Deprecated: use Actor.Attributes["image"] instead.
|
||||
Status string `json:"status,omitempty"`
|
||||
// Deprecated: use Actor.ID instead.
|
||||
ID string `json:"id,omitempty"`
|
||||
// Deprecated: use Actor.Attributes["image"] instead.
|
||||
From string `json:"from,omitempty"`
|
||||
|
||||
Type Type
|
||||
Action Action
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Package filters provides tools for encoding a mapping of keys to a set of
|
||||
multiple values.
|
||||
*/
|
||||
package filters // import "github.com/docker/docker/api/types/filters"
|
||||
package filters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package image // import "github.com/docker/docker/api/types/image"
|
||||
package image
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Code generated by `swagger generate operation`. DO NOT EDIT.
|
||||
|
|
|
@ -75,6 +75,8 @@ type ListOptions struct {
|
|||
SharedSize bool
|
||||
|
||||
// ContainerCount indicates whether container count should be computed.
|
||||
//
|
||||
// Deprecated: This field has been unused and is no longer required and will be removed in a future version.
|
||||
ContainerCount bool
|
||||
|
||||
// Manifests indicates whether the image manifests should be returned.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package mount // import "github.com/docker/docker/api/types/mount"
|
||||
package mount
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package network // import "github.com/docker/docker/api/types/network"
|
||||
package network
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package types // import "github.com/docker/docker/api/types"
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
package registry // import "github.com/docker/docker/api/types/registry"
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package registry // import "github.com/docker/docker/api/types/registry"
|
||||
package registry
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.23
|
||||
|
||||
package registry // import "github.com/docker/docker/api/types/registry"
|
||||
package registry
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package strslice // import "github.com/docker/docker/api/types/strslice"
|
||||
package strslice
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/network"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import "github.com/docker/docker/api/types/filters"
|
||||
|
||||
// Node represents a node.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
// RuntimeType is the type of runtime used for the TaskSpec
|
||||
type RuntimeType string
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
//go:generate protoc --gogofaster_out=import_path=github.com/docker/docker/api/types/swarm/runtime:. plugin.proto
|
||||
|
||||
package runtime // import "github.com/docker/docker/api/types/swarm/runtime"
|
||||
package runtime
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package time // import "github.com/docker/docker/api/types/time"
|
||||
package time
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package types // import "github.com/docker/docker/api/types"
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/build"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package versions // import "github.com/docker/docker/api/types/versions"
|
||||
package versions
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package volume // import "github.com/docker/docker/api/types/volume"
|
||||
package volume
|
||||
|
||||
import "github.com/docker/docker/api/types/filters"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package volume // import "github.com/docker/docker/api/types/volume"
|
||||
package volume
|
||||
|
||||
// UpdateOptions is configuration to update a Volume with.
|
||||
type UpdateOptions struct {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -39,7 +39,7 @@ For example, to list running containers (the equivalent of "docker ps"):
|
|||
}
|
||||
}
|
||||
*/
|
||||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//go:build !windows
|
||||
|
||||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
|
||||
// (EnvOverrideHost) environment variable is unset or empty.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
|
||||
// (EnvOverrideHost) environment variable is unset or empty.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import "context"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import "context"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package client // import "github.com/docker/docker/client"
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -15,10 +15,10 @@ func (cli *Client) ContainerStart(ctx context.Context, containerID string, optio
|
|||
}
|
||||
|
||||
query := url.Values{}
|
||||
if len(options.CheckpointID) != 0 {
|
||||
if options.CheckpointID != "" {
|
||||
query.Set("checkpoint", options.CheckpointID)
|
||||
}
|
||||
if len(options.CheckpointDir) != 0 {
|
||||
if options.CheckpointDir != "" {
|
||||
query.Set("checkpoint-dir", options.CheckpointDir)
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue