Merge pull request #1487 from vrothberg/vendor-common

move optional-flag code to c/common/pkg/flag
This commit is contained in:
Valentin Rothberg 2021-10-26 16:15:36 +02:00 committed by GitHub
commit 49f709576a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 172 additions and 348 deletions

View File

@ -7,6 +7,7 @@ import (
"io/ioutil" "io/ioutil"
"strings" "strings"
commonFlag "github.com/containers/common/pkg/flag"
"github.com/containers/common/pkg/retry" "github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/copy" "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/docker/reference"
@ -24,16 +25,16 @@ type copyOptions struct {
srcImage *imageOptions srcImage *imageOptions
destImage *imageDestOptions destImage *imageDestOptions
retryOpts *retry.RetryOptions retryOpts *retry.RetryOptions
additionalTags []string // For docker-archive: destinations, in addition to the name:tag specified as destination, also add these additionalTags []string // For docker-archive: destinations, in addition to the name:tag specified as destination, also add these
removeSignatures bool // Do not copy signatures from the source image removeSignatures bool // Do not copy signatures from the source image
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
digestFile string // Write digest to this file digestFile string // Write digest to this file
format optionalString // Force conversion of the image to a specified format format commonFlag.OptionalString // Force conversion of the image to a specified format
quiet bool // Suppress output information when copying images quiet bool // Suppress output information when copying images
all bool // Copy all of the images if the source is a list all bool // Copy all of the images if the source is a list
encryptLayer []int // The list of layers to encrypt encryptLayer []int // The list of layers to encrypt
encryptionKeys []string // Keys needed to encrypt the image encryptionKeys []string // Keys needed to encrypt the image
decryptionKeys []string // Keys needed to decrypt the image decryptionKeys []string // Keys needed to decrypt the image
} }
func copyCmd(global *globalOptions) *cobra.Command { func copyCmd(global *globalOptions) *cobra.Command {
@ -74,7 +75,7 @@ See skopeo(1) section "IMAGE NAMES" for the expected format
flags.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from SOURCE-IMAGE") flags.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from SOURCE-IMAGE")
flags.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`") flags.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`")
flags.StringVar(&opts.digestFile, "digestfile", "", "Write the digest of the pushed image to the specified file") flags.StringVar(&opts.digestFile, "digestfile", "", "Write the digest of the pushed image to the specified file")
flags.VarP(newOptionalStringValue(&opts.format), "format", "f", `MANIFEST TYPE (oci, v2s1, or v2s2) to use in the destination (default is manifest type of source, with fallbacks)`) flags.VarP(commonFlag.NewOptionalStringValue(&opts.format), "format", "f", `MANIFEST TYPE (oci, v2s1, or v2s2) to use in the destination (default is manifest type of source, with fallbacks)`)
flags.StringSliceVar(&opts.encryptionKeys, "encryption-key", []string{}, "*Experimental* key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)") flags.StringSliceVar(&opts.encryptionKeys, "encryption-key", []string{}, "*Experimental* key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
flags.IntSliceVar(&opts.encryptLayer, "encrypt-layer", []int{}, "*Experimental* the 0-indexed layer indices, with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer)") flags.IntSliceVar(&opts.encryptLayer, "encrypt-layer", []int{}, "*Experimental* the 0-indexed layer indices, with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer)")
flags.StringSliceVar(&opts.decryptionKeys, "decryption-key", []string{}, "*Experimental* key needed to decrypt the image") flags.StringSliceVar(&opts.decryptionKeys, "decryption-key", []string{}, "*Experimental* key needed to decrypt the image")
@ -117,8 +118,8 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
} }
var manifestType string var manifestType string
if opts.format.present { if opts.format.Present() {
manifestType, err = parseManifestFormat(opts.format.value) manifestType, err = parseManifestFormat(opts.format.Value())
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,222 +0,0 @@
package main
import (
"testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOptionalBoolSet(t *testing.T) {
for _, c := range []struct {
input string
accepted bool
value bool
}{
// Valid inputs documented for strconv.ParseBool == flag.BoolVar
{"1", true, true},
{"t", true, true},
{"T", true, true},
{"TRUE", true, true},
{"true", true, true},
{"True", true, true},
{"0", true, false},
{"f", true, false},
{"F", true, false},
{"FALSE", true, false},
{"false", true, false},
{"False", true, false},
// A few invalid inputs
{"", false, false},
{"yes", false, false},
{"no", false, false},
{"2", false, false},
} {
var ob optionalBool
v := internalNewOptionalBoolValue(&ob)
require.False(t, ob.present)
err := v.Set(c.input)
if c.accepted {
assert.NoError(t, err, c.input)
assert.Equal(t, c.value, ob.value)
} else {
assert.Error(t, err, c.input)
assert.False(t, ob.present) // Just to be extra paranoid.
}
}
// Nothing actually explicitly says that .Set() is never called when the flag is not present on the command line;
// so, check that it is not being called, at least in the straightforward case (it's not possible to test that it
// is not called in any possible situation).
var globalOB, commandOB optionalBool
actionRun := false
app := &cobra.Command{
Use: "app",
}
optionalBoolFlag(app.PersistentFlags(), &globalOB, "global-OB", "")
cmd := &cobra.Command{
Use: "cmd",
RunE: func(cmd *cobra.Command, args []string) error {
assert.False(t, globalOB.present)
assert.False(t, commandOB.present)
actionRun = true
return nil
},
}
optionalBoolFlag(cmd.Flags(), &commandOB, "command-OB", "")
app.AddCommand(cmd)
app.SetArgs([]string{"cmd"})
err := app.Execute()
require.NoError(t, err)
assert.True(t, actionRun)
}
func TestOptionalBoolString(t *testing.T) {
for _, c := range []struct {
input optionalBool
expected string
}{
{optionalBool{present: true, value: true}, "true"},
{optionalBool{present: true, value: false}, "false"},
{optionalBool{present: false, value: true}, ""},
{optionalBool{present: false, value: false}, ""},
} {
var ob optionalBool
v := internalNewOptionalBoolValue(&ob)
ob = c.input
res := v.String()
assert.Equal(t, c.expected, res)
}
}
func TestOptionalBoolIsBoolFlag(t *testing.T) {
// IsBoolFlag means that the argument value must either be part of the same argument, with =;
// if there is no =, the value is set to true.
// This differs form other flags, where the argument is required and may be either separated with = or supplied in the next argument.
for _, c := range []struct {
input []string
expectedOB optionalBool
expectedArgs []string
}{
{[]string{"1", "2"}, optionalBool{present: false}, []string{"1", "2"}}, // Flag not present
{[]string{"--OB=true", "1", "2"}, optionalBool{present: true, value: true}, []string{"1", "2"}}, // --OB=true
{[]string{"--OB=false", "1", "2"}, optionalBool{present: true, value: false}, []string{"1", "2"}}, // --OB=false
{[]string{"--OB", "true", "1", "2"}, optionalBool{present: true, value: true}, []string{"true", "1", "2"}}, // --OB true
{[]string{"--OB", "false", "1", "2"}, optionalBool{present: true, value: true}, []string{"false", "1", "2"}}, // --OB false
} {
var ob optionalBool
actionRun := false
app := &cobra.Command{Use: "app"}
cmd := &cobra.Command{
Use: "cmd",
RunE: func(cmd *cobra.Command, args []string) error {
assert.Equal(t, c.expectedOB, ob)
assert.Equal(t, c.expectedArgs, args)
actionRun = true
return nil
},
}
optionalBoolFlag(cmd.Flags(), &ob, "OB", "")
app.AddCommand(cmd)
app.SetArgs(append([]string{"cmd"}, c.input...))
err := app.Execute()
require.NoError(t, err)
assert.True(t, actionRun)
}
}
func TestOptionalStringSet(t *testing.T) {
// Really just a smoke test, but differentiating between not present and empty.
for _, c := range []string{"", "hello"} {
var os optionalString
v := newOptionalStringValue(&os)
require.False(t, os.present)
err := v.Set(c)
assert.NoError(t, err, c)
assert.Equal(t, c, os.value)
}
// Nothing actually explicitly says that .Set() is never called when the flag is not present on the command line;
// so, check that it is not being called, at least in the straightforward case (it's not possible to test that it
// is not called in any possible situation).
var globalOS, commandOS optionalString
actionRun := false
app := &cobra.Command{
Use: "app",
}
app.PersistentFlags().Var(newOptionalStringValue(&globalOS), "global-OS", "")
cmd := &cobra.Command{
Use: "cmd",
RunE: func(cmd *cobra.Command, args []string) error {
assert.False(t, globalOS.present)
assert.False(t, commandOS.present)
actionRun = true
return nil
},
}
cmd.Flags().Var(newOptionalStringValue(&commandOS), "command-OS", "")
app.AddCommand(cmd)
app.SetArgs([]string{"cmd"})
err := app.Execute()
require.NoError(t, err)
assert.True(t, actionRun)
}
func TestOptionalStringString(t *testing.T) {
for _, c := range []struct {
input optionalString
expected string
}{
{optionalString{present: true, value: "hello"}, "hello"},
{optionalString{present: true, value: ""}, ""},
{optionalString{present: false, value: "hello"}, ""},
{optionalString{present: false, value: ""}, ""},
} {
var os optionalString
v := newOptionalStringValue(&os)
os = c.input
res := v.String()
assert.Equal(t, c.expected, res)
}
}
func TestOptionalStringIsBoolFlag(t *testing.T) {
// NOTE: optionalStringValue does not implement IsBoolFlag!
// IsBoolFlag means that the argument value must either be part of the same argument, with =;
// if there is no =, the value is set to true.
// This differs form other flags, where the argument is required and may be either separated with = or supplied in the next argument.
for _, c := range []struct {
input []string
expectedOS optionalString
expectedArgs []string
}{
{[]string{"1", "2"}, optionalString{present: false}, []string{"1", "2"}}, // Flag not present
{[]string{"--OS=hello", "1", "2"}, optionalString{present: true, value: "hello"}, []string{"1", "2"}}, // --OS=true
{[]string{"--OS=", "1", "2"}, optionalString{present: true, value: ""}, []string{"1", "2"}}, // --OS=false
{[]string{"--OS", "hello", "1", "2"}, optionalString{present: true, value: "hello"}, []string{"1", "2"}}, // --OS true
{[]string{"--OS", "", "1", "2"}, optionalString{present: true, value: ""}, []string{"1", "2"}}, // --OS false
} {
var os optionalString
actionRun := false
app := &cobra.Command{
Use: "app",
}
cmd := &cobra.Command{
Use: "cmd",
RunE: func(cmd *cobra.Command, args []string) error {
assert.Equal(t, c.expectedOS, os)
assert.Equal(t, c.expectedArgs, args)
actionRun = true
return nil
},
}
cmd.Flags().Var(newOptionalStringValue(&os), "OS", "")
app.AddCommand(cmd)
app.SetArgs(append([]string{"cmd"}, c.input...))
err := app.Execute()
require.NoError(t, err)
assert.True(t, actionRun)
}
}

View File

@ -5,6 +5,7 @@ import (
"os" "os"
"github.com/containers/common/pkg/auth" "github.com/containers/common/pkg/auth"
commonFlag "github.com/containers/common/pkg/flag"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -12,7 +13,7 @@ import (
type loginOptions struct { type loginOptions struct {
global *globalOptions global *globalOptions
loginOpts auth.LoginOptions loginOpts auth.LoginOptions
tlsVerify optionalBool tlsVerify commonFlag.OptionalBool
} }
func loginCmd(global *globalOptions) *cobra.Command { func loginCmd(global *globalOptions) *cobra.Command {
@ -28,7 +29,7 @@ func loginCmd(global *globalOptions) *cobra.Command {
} }
adjustUsage(cmd) adjustUsage(cmd)
flags := cmd.Flags() flags := cmd.Flags()
optionalBoolFlag(flags, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the registry") commonFlag.OptionalBoolFlag(flags, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the registry")
flags.AddFlagSet(auth.GetLoginFlags(&opts.loginOpts)) flags.AddFlagSet(auth.GetLoginFlags(&opts.loginOpts))
return cmd return cmd
} }
@ -40,8 +41,8 @@ func (opts *loginOptions) run(args []string, stdout io.Writer) error {
opts.loginOpts.Stdin = os.Stdin opts.loginOpts.Stdin = os.Stdin
opts.loginOpts.AcceptRepositories = true opts.loginOpts.AcceptRepositories = true
sys := opts.global.newSystemContext() sys := opts.global.newSystemContext()
if opts.tlsVerify.present { if opts.tlsVerify.Present() {
sys.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value) sys.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.Value())
} }
return auth.Login(ctx, sys, &opts.loginOpts, args) return auth.Login(ctx, sys, &opts.loginOpts, args)
} }

View File

@ -4,6 +4,7 @@ import (
"io" "io"
"github.com/containers/common/pkg/auth" "github.com/containers/common/pkg/auth"
commonFlag "github.com/containers/common/pkg/flag"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -11,7 +12,7 @@ import (
type logoutOptions struct { type logoutOptions struct {
global *globalOptions global *globalOptions
logoutOpts auth.LogoutOptions logoutOpts auth.LogoutOptions
tlsVerify optionalBool tlsVerify commonFlag.OptionalBool
} }
func logoutCmd(global *globalOptions) *cobra.Command { func logoutCmd(global *globalOptions) *cobra.Command {
@ -27,7 +28,7 @@ func logoutCmd(global *globalOptions) *cobra.Command {
} }
adjustUsage(cmd) adjustUsage(cmd)
flags := cmd.Flags() flags := cmd.Flags()
optionalBoolFlag(flags, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the registry") commonFlag.OptionalBoolFlag(flags, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the registry")
flags.AddFlagSet(auth.GetLogoutFlags(&opts.logoutOpts)) flags.AddFlagSet(auth.GetLogoutFlags(&opts.logoutOpts))
return cmd return cmd
} }
@ -36,8 +37,8 @@ func (opts *logoutOptions) run(args []string, stdout io.Writer) error {
opts.logoutOpts.Stdout = stdout opts.logoutOpts.Stdout = stdout
opts.logoutOpts.AcceptRepositories = true opts.logoutOpts.AcceptRepositories = true
sys := opts.global.newSystemContext() sys := opts.global.newSystemContext()
if opts.tlsVerify.present { if opts.tlsVerify.Present() {
sys.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value) sys.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.Value())
} }
return auth.Logout(sys, &opts.logoutOpts, args) return auth.Logout(sys, &opts.logoutOpts, args)
} }

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"time" "time"
commonFlag "github.com/containers/common/pkg/flag"
"github.com/containers/image/v5/signature" "github.com/containers/image/v5/signature"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/containers/skopeo/version" "github.com/containers/skopeo/version"
@ -20,17 +21,17 @@ var gitCommit = ""
var defaultUserAgent = "skopeo/" + version.Version var defaultUserAgent = "skopeo/" + version.Version
type globalOptions struct { type globalOptions struct {
debug bool // Enable debug output debug bool // Enable debug output
tlsVerify optionalBool // Require HTTPS and verify certificates (for docker: and docker-daemon:) tlsVerify commonFlag.OptionalBool // Require HTTPS and verify certificates (for docker: and docker-daemon:)
policyPath string // Path to a signature verification policy file policyPath string // Path to a signature verification policy file
insecurePolicy bool // Use an "allow everything" signature verification policy insecurePolicy bool // Use an "allow everything" signature verification policy
registriesDirPath string // Path to a "registries.d" registry configuration directory registriesDirPath string // Path to a "registries.d" registry configuration directory
overrideArch string // Architecture to use for choosing images, instead of the runtime one overrideArch string // Architecture to use for choosing images, instead of the runtime one
overrideOS string // OS to use for choosing images, instead of the runtime one overrideOS string // OS to use for choosing images, instead of the runtime one
overrideVariant string // Architecture variant to use for choosing images, instead of the runtime one overrideVariant string // Architecture variant to use for choosing images, instead of the runtime one
commandTimeout time.Duration // Timeout for the command execution commandTimeout time.Duration // Timeout for the command execution
registriesConfPath string // Path to the "registries.conf" file registriesConfPath string // Path to the "registries.conf" file
tmpDir string // Path to use for big temporary files tmpDir string // Path to use for big temporary files
} }
// createApp returns a cobra.Command, and the underlying globalOptions object, to be run or tested. // createApp returns a cobra.Command, and the underlying globalOptions object, to be run or tested.
@ -78,7 +79,7 @@ func createApp() (*cobra.Command, *globalOptions) {
logrus.Fatal("unable to mark registries-conf flag as hidden") logrus.Fatal("unable to mark registries-conf flag as hidden")
} }
rootCommand.PersistentFlags().StringVar(&opts.tmpDir, "tmpdir", "", "directory used to store temporary files") rootCommand.PersistentFlags().StringVar(&opts.tmpDir, "tmpdir", "", "directory used to store temporary files")
flag := optionalBoolFlag(rootCommand.Flags(), &opts.tlsVerify, "tls-verify", "Require HTTPS and verify certificates when accessing the registry") flag := commonFlag.OptionalBoolFlag(rootCommand.Flags(), &opts.tlsVerify, "tls-verify", "Require HTTPS and verify certificates when accessing the registry")
flag.Hidden = true flag.Hidden = true
rootCommand.AddCommand( rootCommand.AddCommand(
copyCmd(&opts), copyCmd(&opts),
@ -103,7 +104,7 @@ func (opts *globalOptions) before(cmd *cobra.Command) error {
if opts.debug { if opts.debug {
logrus.SetLevel(logrus.DebugLevel) logrus.SetLevel(logrus.DebugLevel)
} }
if opts.tlsVerify.present { if opts.tlsVerify.Present() {
logrus.Warn("'--tls-verify' is deprecated, please set this on the specific subcommand") logrus.Warn("'--tls-verify' is deprecated, please set this on the specific subcommand")
} }
return nil return nil
@ -160,8 +161,8 @@ func (opts *globalOptions) newSystemContext() *types.SystemContext {
DockerRegistryUserAgent: defaultUserAgent, DockerRegistryUserAgent: defaultUserAgent,
} }
// DEPRECATED: We support this for backward compatibility, but override it if a per-image flag is provided. // DEPRECATED: We support this for backward compatibility, but override it if a per-image flag is provided.
if opts.tlsVerify.present { if opts.tlsVerify.Present() {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value) ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.Value())
} }
return ctx return ctx
} }

View File

@ -11,6 +11,7 @@ import (
"regexp" "regexp"
"strings" "strings"
commonFlag "github.com/containers/common/pkg/flag"
"github.com/containers/common/pkg/retry" "github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/copy" "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/directory" "github.com/containers/image/v5/directory"
@ -32,14 +33,14 @@ type syncOptions struct {
srcImage *imageOptions // Source image options srcImage *imageOptions // Source image options
destImage *imageDestOptions // Destination image options destImage *imageDestOptions // Destination image options
retryOpts *retry.RetryOptions retryOpts *retry.RetryOptions
removeSignatures bool // Do not copy signatures from the source image removeSignatures bool // Do not copy signatures from the source image
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
format optionalString // Force conversion of the image to a specified format format commonFlag.OptionalString // Force conversion of the image to a specified format
source string // Source repository name source string // Source repository name
destination string // Destination registry name destination string // Destination registry name
scoped bool // When true, namespace copied images at destination using the source repository name scoped bool // When true, namespace copied images at destination using the source repository name
all bool // Copy all of the images if an image in the source is a list all bool // Copy all of the images if an image in the source is a list
keepGoing bool // Whether or not to abort the sync if there are any errors during syncing the images keepGoing bool // Whether or not to abort the sync if there are any errors during syncing the images
} }
// repoDescriptor contains information of a single repository used as a sync source. // repoDescriptor contains information of a single repository used as a sync source.
@ -100,7 +101,7 @@ See skopeo-sync(1) for details.
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from SOURCE images") flags.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from SOURCE images")
flags.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`") flags.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`")
flags.VarP(newOptionalStringValue(&opts.format), "format", "f", `MANIFEST TYPE (oci, v2s1, or v2s2) to use when syncing image(s) to a destination (default is manifest type of source, with fallbacks)`) flags.VarP(commonFlag.NewOptionalStringValue(&opts.format), "format", "f", `MANIFEST TYPE (oci, v2s1, or v2s2) to use when syncing image(s) to a destination (default is manifest type of source, with fallbacks)`)
flags.StringVarP(&opts.source, "src", "s", "", "SOURCE transport type") flags.StringVarP(&opts.source, "src", "s", "", "SOURCE transport type")
flags.StringVarP(&opts.destination, "dest", "d", "", "DESTINATION transport type") flags.StringVarP(&opts.destination, "dest", "d", "", "DESTINATION transport type")
flags.BoolVar(&opts.scoped, "scoped", false, "Images at DESTINATION are prefix using the full source image path as scope") flags.BoolVar(&opts.scoped, "scoped", false, "Images at DESTINATION are prefix using the full source image path as scope")
@ -545,8 +546,8 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
} }
var manifestType string var manifestType string
if opts.format.present { if opts.format.Present() {
manifestType, err = parseManifestFormat(opts.format.value) manifestType, err = parseManifestFormat(opts.format.Value())
if err != nil { if err != nil {
return err return err
} }

View File

@ -7,6 +7,7 @@ import (
"os" "os"
"strings" "strings"
commonFlag "github.com/containers/common/pkg/flag"
"github.com/containers/common/pkg/retry" "github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/manifest" "github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/compression" "github.com/containers/image/v5/pkg/compression"
@ -45,7 +46,7 @@ func commandAction(handler func(args []string, stdout io.Writer) error) func(cmd
// whether or not the value actually ends up being used. // whether or not the value actually ends up being used.
// DO NOT ADD ANY NEW USES OF THIS; just call dockerImageFlags with an appropriate, possibly empty, flagPrefix. // DO NOT ADD ANY NEW USES OF THIS; just call dockerImageFlags with an appropriate, possibly empty, flagPrefix.
type deprecatedTLSVerifyOption struct { type deprecatedTLSVerifyOption struct {
tlsVerify optionalBool // FIXME FIXME: Warn if this is used, or even if it is ignored. tlsVerify commonFlag.OptionalBool // FIXME FIXME: Warn if this is used, or even if it is ignored.
} }
// warnIfUsed warns if tlsVerify was set by the user, and suggests alternatives (which should // warnIfUsed warns if tlsVerify was set by the user, and suggests alternatives (which should
@ -53,7 +54,7 @@ type deprecatedTLSVerifyOption struct {
// Every user should call this as part of handling the CLI, whether or not the value actually // Every user should call this as part of handling the CLI, whether or not the value actually
// ends up being used. // ends up being used.
func (opts *deprecatedTLSVerifyOption) warnIfUsed(alternatives []string) { func (opts *deprecatedTLSVerifyOption) warnIfUsed(alternatives []string) {
if opts.tlsVerify.present { if opts.tlsVerify.Present() {
logrus.Warnf("'--tls-verify' is deprecated, instead use: %s", strings.Join(alternatives, ", ")) logrus.Warnf("'--tls-verify' is deprecated, instead use: %s", strings.Join(alternatives, ", "))
} }
} }
@ -63,7 +64,7 @@ func (opts *deprecatedTLSVerifyOption) warnIfUsed(alternatives []string) {
func deprecatedTLSVerifyFlags() (pflag.FlagSet, *deprecatedTLSVerifyOption) { func deprecatedTLSVerifyFlags() (pflag.FlagSet, *deprecatedTLSVerifyOption) {
opts := deprecatedTLSVerifyOption{} opts := deprecatedTLSVerifyOption{}
fs := pflag.FlagSet{} fs := pflag.FlagSet{}
flag := optionalBoolFlag(&fs, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the container registry") flag := commonFlag.OptionalBoolFlag(&fs, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the container registry")
flag.Hidden = true flag.Hidden = true
return fs, &opts return fs, &opts
} }
@ -89,13 +90,13 @@ type dockerImageOptions struct {
global *globalOptions // May be shared across several imageOptions instances. global *globalOptions // May be shared across several imageOptions instances.
shared *sharedImageOptions // May be shared across several imageOptions instances. shared *sharedImageOptions // May be shared across several imageOptions instances.
deprecatedTLSVerify *deprecatedTLSVerifyOption // May be shared across several imageOptions instances, or nil. deprecatedTLSVerify *deprecatedTLSVerifyOption // May be shared across several imageOptions instances, or nil.
authFilePath optionalString // Path to a */containers/auth.json (prefixed version to override shared image option). authFilePath commonFlag.OptionalString // Path to a */containers/auth.json (prefixed version to override shared image option).
credsOption optionalString // username[:password] for accessing a registry credsOption commonFlag.OptionalString // username[:password] for accessing a registry
userName optionalString // username for accessing a registry userName commonFlag.OptionalString // username for accessing a registry
password optionalString // password for accessing a registry password commonFlag.OptionalString // password for accessing a registry
registryToken optionalString // token to be used directly as a Bearer token when accessing the registry registryToken commonFlag.OptionalString // token to be used directly as a Bearer token when accessing the registry
dockerCertPath string // A directory using Docker-like *.{crt,cert,key} files for connecting to a registry or a daemon dockerCertPath string // A directory using Docker-like *.{crt,cert,key} files for connecting to a registry or a daemon
tlsVerify optionalBool // Require HTTPS and verify certificates (for docker: and docker-daemon:) tlsVerify commonFlag.OptionalBool // Require HTTPS and verify certificates (for docker: and docker-daemon:)
noCreds bool // Access the registry anonymously noCreds bool // Access the registry anonymously
} }
@ -121,20 +122,20 @@ func dockerImageFlags(global *globalOptions, shared *sharedImageOptions, depreca
fs := pflag.FlagSet{} fs := pflag.FlagSet{}
if flagPrefix != "" { if flagPrefix != "" {
// the non-prefixed flag is handled by a shared flag. // the non-prefixed flag is handled by a shared flag.
fs.Var(newOptionalStringValue(&flags.authFilePath), flagPrefix+"authfile", "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json") fs.Var(commonFlag.NewOptionalStringValue(&flags.authFilePath), flagPrefix+"authfile", "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json")
} }
fs.Var(newOptionalStringValue(&flags.credsOption), flagPrefix+"creds", "Use `USERNAME[:PASSWORD]` for accessing the registry") fs.Var(commonFlag.NewOptionalStringValue(&flags.credsOption), flagPrefix+"creds", "Use `USERNAME[:PASSWORD]` for accessing the registry")
fs.Var(newOptionalStringValue(&flags.userName), flagPrefix+"username", "Username for accessing the registry") fs.Var(commonFlag.NewOptionalStringValue(&flags.userName), flagPrefix+"username", "Username for accessing the registry")
fs.Var(newOptionalStringValue(&flags.password), flagPrefix+"password", "Password for accessing the registry") fs.Var(commonFlag.NewOptionalStringValue(&flags.password), flagPrefix+"password", "Password for accessing the registry")
if credsOptionAlias != "" { if credsOptionAlias != "" {
// This is horribly ugly, but we need to support the old option forms of (skopeo copy) for compatibility. // This is horribly ugly, but we need to support the old option forms of (skopeo copy) for compatibility.
// Don't add any more cases like this. // Don't add any more cases like this.
f := fs.VarPF(newOptionalStringValue(&flags.credsOption), credsOptionAlias, "", "Use `USERNAME[:PASSWORD]` for accessing the registry") f := fs.VarPF(commonFlag.NewOptionalStringValue(&flags.credsOption), credsOptionAlias, "", "Use `USERNAME[:PASSWORD]` for accessing the registry")
f.Hidden = true f.Hidden = true
} }
fs.Var(newOptionalStringValue(&flags.registryToken), flagPrefix+"registry-token", "Provide a Bearer token for accessing the registry") fs.Var(commonFlag.NewOptionalStringValue(&flags.registryToken), flagPrefix+"registry-token", "Provide a Bearer token for accessing the registry")
fs.StringVar(&flags.dockerCertPath, flagPrefix+"cert-dir", "", "use certificates at `PATH` (*.crt, *.cert, *.key) to connect to the registry or daemon") fs.StringVar(&flags.dockerCertPath, flagPrefix+"cert-dir", "", "use certificates at `PATH` (*.crt, *.cert, *.key) to connect to the registry or daemon")
optionalBoolFlag(&fs, &flags.tlsVerify, flagPrefix+"tls-verify", "require HTTPS and verify certificates when talking to the container registry or daemon") commonFlag.OptionalBoolFlag(&fs, &flags.tlsVerify, flagPrefix+"tls-verify", "require HTTPS and verify certificates when talking to the container registry or daemon")
fs.BoolVar(&flags.noCreds, flagPrefix+"no-creds", false, "Access the registry anonymously") fs.BoolVar(&flags.noCreds, flagPrefix+"no-creds", false, "Access the registry anonymously")
return fs, &flags return fs, &flags
} }
@ -168,49 +169,49 @@ func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
ctx.AuthFilePath = opts.shared.authFilePath ctx.AuthFilePath = opts.shared.authFilePath
ctx.DockerDaemonHost = opts.dockerDaemonHost ctx.DockerDaemonHost = opts.dockerDaemonHost
ctx.DockerDaemonCertPath = opts.dockerCertPath ctx.DockerDaemonCertPath = opts.dockerCertPath
if opts.dockerImageOptions.authFilePath.present { if opts.dockerImageOptions.authFilePath.Present() {
ctx.AuthFilePath = opts.dockerImageOptions.authFilePath.value ctx.AuthFilePath = opts.dockerImageOptions.authFilePath.Value()
} }
if opts.deprecatedTLSVerify != nil && opts.deprecatedTLSVerify.tlsVerify.present { if opts.deprecatedTLSVerify != nil && opts.deprecatedTLSVerify.tlsVerify.Present() {
// If both this deprecated option and a non-deprecated option is present, we use the latter value. // If both this deprecated option and a non-deprecated option is present, we use the latter value.
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.deprecatedTLSVerify.tlsVerify.value) ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.deprecatedTLSVerify.tlsVerify.Value())
} }
if opts.tlsVerify.present { if opts.tlsVerify.Present() {
ctx.DockerDaemonInsecureSkipTLSVerify = !opts.tlsVerify.value ctx.DockerDaemonInsecureSkipTLSVerify = !opts.tlsVerify.Value()
} }
if opts.tlsVerify.present { if opts.tlsVerify.Present() {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value) ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.Value())
} }
if opts.credsOption.present && opts.noCreds { if opts.credsOption.Present() && opts.noCreds {
return nil, errors.New("creds and no-creds cannot be specified at the same time") return nil, errors.New("creds and no-creds cannot be specified at the same time")
} }
if opts.userName.present && opts.noCreds { if opts.userName.Present() && opts.noCreds {
return nil, errors.New("username and no-creds cannot be specified at the same time") return nil, errors.New("username and no-creds cannot be specified at the same time")
} }
if opts.credsOption.present && opts.userName.present { if opts.credsOption.Present() && opts.userName.Present() {
return nil, errors.New("creds and username cannot be specified at the same time") return nil, errors.New("creds and username cannot be specified at the same time")
} }
// if any of username or password is present, then both are expected to be present // if any of username or password is present, then both are expected to be present
if opts.userName.present != opts.password.present { if opts.userName.Present() != opts.password.Present() {
if opts.userName.present { if opts.userName.Present() {
return nil, errors.New("password must be specified when username is specified") return nil, errors.New("password must be specified when username is specified")
} }
return nil, errors.New("username must be specified when password is specified") return nil, errors.New("username must be specified when password is specified")
} }
if opts.credsOption.present { if opts.credsOption.Present() {
var err error var err error
ctx.DockerAuthConfig, err = getDockerAuth(opts.credsOption.value) ctx.DockerAuthConfig, err = getDockerAuth(opts.credsOption.Value())
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else if opts.userName.present { } else if opts.userName.Present() {
ctx.DockerAuthConfig = &types.DockerAuthConfig{ ctx.DockerAuthConfig = &types.DockerAuthConfig{
Username: opts.userName.value, Username: opts.userName.Value(),
Password: opts.password.value, Password: opts.password.Value(),
} }
} }
if opts.registryToken.present { if opts.registryToken.Present() {
ctx.DockerBearerRegistryToken = opts.registryToken.value ctx.DockerBearerRegistryToken = opts.registryToken.Value()
} }
if opts.noCreds { if opts.noCreds {
ctx.DockerAuthConfig = &types.DockerAuthConfig{} ctx.DockerAuthConfig = &types.DockerAuthConfig{}
@ -222,12 +223,12 @@ func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
// imageDestOptions is a superset of imageOptions specialized for image destinations. // imageDestOptions is a superset of imageOptions specialized for image destinations.
type imageDestOptions struct { type imageDestOptions struct {
*imageOptions *imageOptions
dirForceCompression bool // Compress layers when saving to the dir: transport dirForceCompression bool // Compress layers when saving to the dir: transport
dirForceDecompression bool // Decompress layers when saving to the dir: transport dirForceDecompression bool // Decompress layers when saving to the dir: transport
ociAcceptUncompressedLayers bool // Whether to accept uncompressed layers in the oci: transport ociAcceptUncompressedLayers bool // Whether to accept uncompressed layers in the oci: transport
compressionFormat string // Format to use for the compression compressionFormat string // Format to use for the compression
compressionLevel optionalInt // Level to use for the compression compressionLevel commonFlag.OptionalInt // Level to use for the compression
precomputeDigests bool // Precompute digests to dedup layers when saving to the docker: transport precomputeDigests bool // Precompute digests to dedup layers when saving to the docker: transport
} }
// imageDestFlags prepares a collection of CLI flags writing into imageDestOptions, and the managed imageDestOptions structure. // imageDestFlags prepares a collection of CLI flags writing into imageDestOptions, and the managed imageDestOptions structure.
@ -240,7 +241,7 @@ func imageDestFlags(global *globalOptions, shared *sharedImageOptions, deprecate
fs.BoolVar(&opts.dirForceDecompression, flagPrefix+"decompress", false, "Decompress tarball image layers when saving to directory using the 'dir' transport. (default is same compression type as source)") fs.BoolVar(&opts.dirForceDecompression, flagPrefix+"decompress", false, "Decompress tarball image layers when saving to directory using the 'dir' transport. (default is same compression type as source)")
fs.BoolVar(&opts.ociAcceptUncompressedLayers, flagPrefix+"oci-accept-uncompressed-layers", false, "Allow uncompressed image layers when saving to an OCI image using the 'oci' transport. (default is to compress things that aren't compressed)") fs.BoolVar(&opts.ociAcceptUncompressedLayers, flagPrefix+"oci-accept-uncompressed-layers", false, "Allow uncompressed image layers when saving to an OCI image using the 'oci' transport. (default is to compress things that aren't compressed)")
fs.StringVar(&opts.compressionFormat, flagPrefix+"compress-format", "", "`FORMAT` to use for the compression") fs.StringVar(&opts.compressionFormat, flagPrefix+"compress-format", "", "`FORMAT` to use for the compression")
fs.Var(newOptionalIntValue(&opts.compressionLevel), flagPrefix+"compress-level", "`LEVEL` to use for the compression") fs.Var(commonFlag.NewOptionalIntValue(&opts.compressionLevel), flagPrefix+"compress-level", "`LEVEL` to use for the compression")
fs.BoolVar(&opts.precomputeDigests, flagPrefix+"precompute-digests", false, "Precompute digests to prevent uploading layers already on the registry using the 'docker' transport.") fs.BoolVar(&opts.precomputeDigests, flagPrefix+"precompute-digests", false, "Precompute digests to prevent uploading layers already on the registry using the 'docker' transport.")
return fs, &opts return fs, &opts
} }
@ -263,8 +264,9 @@ func (opts *imageDestOptions) newSystemContext() (*types.SystemContext, error) {
} }
ctx.CompressionFormat = &cf ctx.CompressionFormat = &cf
} }
if opts.compressionLevel.present { if opts.compressionLevel.Present() {
ctx.CompressionLevel = &opts.compressionLevel.value value := opts.compressionLevel.Value()
ctx.CompressionLevel = &value
} }
ctx.DockerRegistryPushPrecomputeDigests = opts.precomputeDigests ctx.DockerRegistryPushPrecomputeDigests = opts.precomputeDigests
return ctx, err return ctx, err

4
go.mod
View File

@ -3,11 +3,11 @@ module github.com/containers/skopeo
go 1.12 go 1.12
require ( require (
github.com/containers/common v0.46.0 github.com/containers/common v0.46.1-0.20211026130826-7abfd453c86f
github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f
github.com/containers/ocicrypt v1.1.2 github.com/containers/ocicrypt v1.1.2
github.com/containers/storage v1.37.0 github.com/containers/storage v1.37.0
github.com/docker/docker v20.10.9+incompatible github.com/docker/docker v20.10.10+incompatible
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.2-0.20210819154149-5ad6f50d6283 github.com/opencontainers/image-spec v1.0.2-0.20210819154149-5ad6f50d6283

24
go.sum
View File

@ -74,7 +74,7 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.22 h1:CulZ3GW8sNJExknToo+RWD+U+6ZM5kkNfuxywSDPd08= github.com/Microsoft/hcsshim v0.8.22 h1:CulZ3GW8sNJExknToo+RWD+U+6ZM5kkNfuxywSDPd08=
github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0= github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0=
@ -174,6 +174,7 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo
github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
github.com/containerd/containerd v1.5.4/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw=
github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM= github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM=
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@ -203,7 +204,6 @@ github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJ
github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/stargz-snapshotter/estargz v0.8.0/go.mod h1:mwIwuwb+D8FX2t45Trwi0hmWmZm5VW7zPP/rekwhWQU=
github.com/containerd/stargz-snapshotter/estargz v0.9.0 h1:PkB6BSTfOKX23erT2GkoUKkJEcXfNcyKskIViK770v8= github.com/containerd/stargz-snapshotter/estargz v0.9.0 h1:PkB6BSTfOKX23erT2GkoUKkJEcXfNcyKskIViK770v8=
github.com/containerd/stargz-snapshotter/estargz v0.9.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0= github.com/containerd/stargz-snapshotter/estargz v0.9.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
@ -225,9 +225,9 @@ github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
github.com/containers/common v0.46.0 h1:95zB7kYBQJW+aK5xxZnaobCwoPyYOf85Y0yUx0E5aRg= github.com/containers/common v0.46.1-0.20211026130826-7abfd453c86f h1:jFFIV8QvsPgwkJHh3tjfREFRwSeMq5M8lt8vklkZaOk=
github.com/containers/common v0.46.0/go.mod h1:zxv7KjdYddSGoWuLUVp6eSb++Ow1zmSMB2jwxuNB4cU= github.com/containers/common v0.46.1-0.20211026130826-7abfd453c86f/go.mod h1:pVvmLTLCOZE300e4rex/QDmpnRmEM/5aZ/YfCkkjgZo=
github.com/containers/image/v5 v5.16.0/go.mod h1:XgTpfAPLRGOd1XYyCU5cISFr777bLmOerCSpt/v7+Q4= github.com/containers/image/v5 v5.16.1/go.mod h1:mCvIFdzyyP1B0NBcZ80OIuaYqFn/OpFpaOMOMn1kU2M=
github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f h1:gqeQG8jumo9u6TmyUPrSCuflSjkQX+zFa5bRJAZYz2g= github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f h1:gqeQG8jumo9u6TmyUPrSCuflSjkQX+zFa5bRJAZYz2g=
github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f/go.mod h1:ERFkrXC5lLXov65ia/NiKBKfEeHgiItB9bQz6fReQ7g= github.com/containers/image/v5 v5.16.2-0.20211021181114-25411654075f/go.mod h1:ERFkrXC5lLXov65ia/NiKBKfEeHgiItB9bQz6fReQ7g=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE= github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
@ -237,8 +237,6 @@ github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgU
github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
github.com/containers/ocicrypt v1.1.2 h1:Ez+GAMP/4GLix5Ywo/fL7O0nY771gsBIigiqUm1aXz0= github.com/containers/ocicrypt v1.1.2 h1:Ez+GAMP/4GLix5Ywo/fL7O0nY771gsBIigiqUm1aXz0=
github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
github.com/containers/storage v1.35.0/go.mod h1:qzYhasQP2/V9D9XdO+vRwkHBhsBO0oznMLzzRDQ8s20=
github.com/containers/storage v1.36.0/go.mod h1:vbd3SKVQNHdmU5qQI6hTEcKPxnZkGqydG4f6uwrI5a8=
github.com/containers/storage v1.37.0 h1:HVhDsur6sx889ZIZ1d1kEiOzv3gsr5q0diX2VZmOdSg= github.com/containers/storage v1.37.0 h1:HVhDsur6sx889ZIZ1d1kEiOzv3gsr5q0diX2VZmOdSg=
github.com/containers/storage v1.37.0/go.mod h1:kqeJeS0b7DO2ZT1nVWs0XufrmPFbgV3c+Q/45RlH6r4= github.com/containers/storage v1.37.0/go.mod h1:kqeJeS0b7DO2ZT1nVWs0XufrmPFbgV3c+Q/45RlH6r4=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@ -281,8 +279,9 @@ github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.9+incompatible h1:JlsVnETOjM2RLQa0Cc1XCIspUdXW3Zenq9P54uXBm6k=
github.com/docker/docker v20.10.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.10+incompatible h1:GKkP0T7U4ks6X3lmmHKC2QDprnpRJor2Z5a8m62R9ZM=
github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o=
github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
@ -395,7 +394,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -513,8 +511,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
@ -606,8 +602,9 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -647,7 +644,6 @@ github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pK
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/opencontainers/selinux v1.8.4/go.mod h1:HTvjPFoGMbpQsG886e3lQwnsRWtE4TC1OF3OUvG9FAo=
github.com/opencontainers/selinux v1.8.5/go.mod h1:HTvjPFoGMbpQsG886e3lQwnsRWtE4TC1OF3OUvG9FAo= github.com/opencontainers/selinux v1.8.5/go.mod h1:HTvjPFoGMbpQsG886e3lQwnsRWtE4TC1OF3OUvG9FAo=
github.com/opencontainers/selinux v1.9.1 h1:b4VPEF3O5JLZgdTDBmGepaaIbAo0GqoF6EBRq5f/g3Y= github.com/opencontainers/selinux v1.9.1 h1:b4VPEF3O5JLZgdTDBmGepaaIbAo0GqoF6EBRq5f/g3Y=
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
@ -786,7 +782,6 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
github.com/vbauerster/mpb/v7 v7.1.3/go.mod h1:X5GlohZw2fIpypMXWaKart+HGSAjpz49skxkDk+ZL7c=
github.com/vbauerster/mpb/v7 v7.1.5 h1:vtUEUfQHmNeJETyF4AcRCOV6RC4wqFwNORy52UMXPbQ= github.com/vbauerster/mpb/v7 v7.1.5 h1:vtUEUfQHmNeJETyF4AcRCOV6RC4wqFwNORy52UMXPbQ=
github.com/vbauerster/mpb/v7 v7.1.5/go.mod h1:4M8+qAoQqV60WDNktBM5k05i1iTrXE7rjKOHEVkVlec= github.com/vbauerster/mpb/v7 v7.1.5/go.mod h1:4M8+qAoQqV60WDNktBM5k05i1iTrXE7rjKOHEVkVlec=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
@ -1052,7 +1047,6 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef h1:fPxZ3Umkct3LZ8gK9nbk+DWDJ9fstZa2grBn+lWVKPs= golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef h1:fPxZ3Umkct3LZ8gK9nbk+DWDJ9fstZa2grBn+lWVKPs=

View File

@ -1,4 +1,4 @@
package main package flag
import ( import (
"strconv" "strconv"
@ -6,19 +6,31 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
// optionalBool is a boolean with a separate presence flag. // OptionalBool is a boolean with a separate presence flag and value.
type optionalBool struct { type OptionalBool struct {
present bool present bool
value bool value bool
} }
// Present returns the bool's presence flag.
func (ob *OptionalBool) Present() bool {
return ob.present
}
// Present returns the bool's value. Should only be used if Present() is true.
func (ob *OptionalBool) Value() bool {
return ob.value
}
// optionalBool is a cli.Generic == flag.Value implementation equivalent to // optionalBool is a cli.Generic == flag.Value implementation equivalent to
// the one underlying flag.Bool, except that it records whether the flag has been set. // the one underlying flag.Bool, except that it records whether the flag has been set.
// This is distinct from optionalBool to (pretend to) force callers to use // This is distinct from optionalBool to (pretend to) force callers to use
// optionalBoolFlag // optionalBoolFlag
type optionalBoolValue optionalBool type optionalBoolValue OptionalBool
func optionalBoolFlag(fs *pflag.FlagSet, p *optionalBool, name, usage string) *pflag.Flag { // OptionalBoolFlag creates new flag for an optional in the specified flag with
// the specified name and usage.
func OptionalBoolFlag(fs *pflag.FlagSet, p *OptionalBool, name, usage string) *pflag.Flag {
flag := fs.VarPF(internalNewOptionalBoolValue(p), name, "", usage) flag := fs.VarPF(internalNewOptionalBoolValue(p), name, "", usage)
flag.NoOptDefVal = "true" flag.NoOptDefVal = "true"
flag.DefValue = "false" flag.DefValue = "false"
@ -27,11 +39,12 @@ func optionalBoolFlag(fs *pflag.FlagSet, p *optionalBool, name, usage string) *p
// WARNING: Do not directly use this method to define optionalBool flag. // WARNING: Do not directly use this method to define optionalBool flag.
// Caller should use optionalBoolFlag // Caller should use optionalBoolFlag
func internalNewOptionalBoolValue(p *optionalBool) pflag.Value { func internalNewOptionalBoolValue(p *OptionalBool) pflag.Value {
p.present = false p.present = false
return (*optionalBoolValue)(p) return (*optionalBoolValue)(p)
} }
// Set parses the string to a bool and sets it.
func (ob *optionalBoolValue) Set(s string) error { func (ob *optionalBoolValue) Set(s string) error {
v, err := strconv.ParseBool(s) v, err := strconv.ParseBool(s)
if err != nil { if err != nil {
@ -42,6 +55,7 @@ func (ob *optionalBoolValue) Set(s string) error {
return nil return nil
} }
// String returns the string representation of the string.
func (ob *optionalBoolValue) String() string { func (ob *optionalBoolValue) String() string {
if !ob.present { if !ob.present {
return "" // This is, sadly, not round-trip safe: --flag is interpreted as --flag=true return "" // This is, sadly, not round-trip safe: --flag is interpreted as --flag=true
@ -49,37 +63,52 @@ func (ob *optionalBoolValue) String() string {
return strconv.FormatBool(ob.value) return strconv.FormatBool(ob.value)
} }
// Type returns the type.
func (ob *optionalBoolValue) Type() string { func (ob *optionalBoolValue) Type() string {
return "bool" return "bool"
} }
// IsBoolFlag indicates that it's a bool flag.
func (ob *optionalBoolValue) IsBoolFlag() bool { func (ob *optionalBoolValue) IsBoolFlag() bool {
return true return true
} }
// optionalString is a string with a separate presence flag. // OptionalString is a string with a separate presence flag.
type optionalString struct { type OptionalString struct {
present bool present bool
value string value string
} }
// Present returns the strings's presence flag.
func (os *OptionalString) Present() bool {
return os.present
}
// Present returns the string's value. Should only be used if Present() is true.
func (os *OptionalString) Value() string {
return os.value
}
// optionalString is a cli.Generic == flag.Value implementation equivalent to // optionalString is a cli.Generic == flag.Value implementation equivalent to
// the one underlying flag.String, except that it records whether the flag has been set. // the one underlying flag.String, except that it records whether the flag has been set.
// This is distinct from optionalString to (pretend to) force callers to use // This is distinct from optionalString to (pretend to) force callers to use
// newoptionalString // newoptionalString
type optionalStringValue optionalString type optionalStringValue OptionalString
func newOptionalStringValue(p *optionalString) pflag.Value { // NewOptionalStringValue returns a pflag.Value fo the string.
func NewOptionalStringValue(p *OptionalString) pflag.Value {
p.present = false p.present = false
return (*optionalStringValue)(p) return (*optionalStringValue)(p)
} }
// Set sets the string.
func (ob *optionalStringValue) Set(s string) error { func (ob *optionalStringValue) Set(s string) error {
ob.value = s ob.value = s
ob.present = true ob.present = true
return nil return nil
} }
// String returns the string if present.
func (ob *optionalStringValue) String() string { func (ob *optionalStringValue) String() string {
if !ob.present { if !ob.present {
return "" // This is, sadly, not round-trip safe: --flag= is interpreted as {present:true, value:""} return "" // This is, sadly, not round-trip safe: --flag= is interpreted as {present:true, value:""}
@ -87,27 +116,40 @@ func (ob *optionalStringValue) String() string {
return ob.value return ob.value
} }
// Type returns the string type.
func (ob *optionalStringValue) Type() string { func (ob *optionalStringValue) Type() string {
return "string" return "string"
} }
// optionalInt is a int with a separate presence flag. // OptionalInt is a int with a separate presence flag.
type optionalInt struct { type OptionalInt struct {
present bool present bool
value int value int
} }
// Present returns the int's presence flag.
func (oi *OptionalInt) Present() bool {
return oi.present
}
// Present returns the int's value. Should only be used if Present() is true.
func (oi *OptionalInt) Value() int {
return oi.value
}
// optionalInt is a cli.Generic == flag.Value implementation equivalent to // optionalInt is a cli.Generic == flag.Value implementation equivalent to
// the one underlying flag.Int, except that it records whether the flag has been set. // the one underlying flag.Int, except that it records whether the flag has been set.
// This is distinct from optionalInt to (pretend to) force callers to use // This is distinct from optionalInt to (pretend to) force callers to use
// newoptionalIntValue // newoptionalIntValue
type optionalIntValue optionalInt type optionalIntValue OptionalInt
func newOptionalIntValue(p *optionalInt) pflag.Value { // NewOptionalIntValue returns the pflag.Value of the int.
func NewOptionalIntValue(p *OptionalInt) pflag.Value {
p.present = false p.present = false
return (*optionalIntValue)(p) return (*optionalIntValue)(p)
} }
// Set parses the string to an int and sets it.
func (ob *optionalIntValue) Set(s string) error { func (ob *optionalIntValue) Set(s string) error {
v, err := strconv.ParseInt(s, 0, strconv.IntSize) v, err := strconv.ParseInt(s, 0, strconv.IntSize)
if err != nil { if err != nil {
@ -118,6 +160,7 @@ func (ob *optionalIntValue) Set(s string) error {
return nil return nil
} }
// String returns the string representation of the int.
func (ob *optionalIntValue) String() string { func (ob *optionalIntValue) String() string {
if !ob.present { if !ob.present {
return "" // If the value is not present, just return an empty string, any other value wouldn't make sense. return "" // If the value is not present, just return an empty string, any other value wouldn't make sense.
@ -125,6 +168,7 @@ func (ob *optionalIntValue) String() string {
return strconv.Itoa(int(ob.value)) return strconv.Itoa(int(ob.value))
} }
// Type returns the int's type.
func (ob *optionalIntValue) Type() string { func (ob *optionalIntValue) Type() string {
return "int" return "int"
} }

View File

@ -30,7 +30,7 @@ func RetryIfNecessary(ctx context.Context, operation func() error, retryOptions
if retryOptions.Delay != 0 { if retryOptions.Delay != 0 {
delay = retryOptions.Delay delay = retryOptions.Delay
} }
logrus.Warnf("failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, retryOptions.MaxRetry, err) logrus.Warnf("Failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, retryOptions.MaxRetry, err)
select { select {
case <-time.After(delay): case <-time.After(delay):
break break

5
vendor/modules.txt vendored
View File

@ -45,10 +45,11 @@ github.com/containerd/containerd/platforms
# github.com/containerd/stargz-snapshotter/estargz v0.9.0 # github.com/containerd/stargz-snapshotter/estargz v0.9.0
github.com/containerd/stargz-snapshotter/estargz github.com/containerd/stargz-snapshotter/estargz
github.com/containerd/stargz-snapshotter/estargz/errorutil github.com/containerd/stargz-snapshotter/estargz/errorutil
# github.com/containers/common v0.46.0 # github.com/containers/common v0.46.1-0.20211026130826-7abfd453c86f
github.com/containers/common/pkg/auth github.com/containers/common/pkg/auth
github.com/containers/common/pkg/capabilities github.com/containers/common/pkg/capabilities
github.com/containers/common/pkg/completion github.com/containers/common/pkg/completion
github.com/containers/common/pkg/flag
github.com/containers/common/pkg/report github.com/containers/common/pkg/report
github.com/containers/common/pkg/report/camelcase github.com/containers/common/pkg/report/camelcase
github.com/containers/common/pkg/retry github.com/containers/common/pkg/retry
@ -176,7 +177,7 @@ github.com/docker/distribution/registry/client/auth/challenge
github.com/docker/distribution/registry/client/transport github.com/docker/distribution/registry/client/transport
github.com/docker/distribution/registry/storage/cache github.com/docker/distribution/registry/storage/cache
github.com/docker/distribution/registry/storage/cache/memory github.com/docker/distribution/registry/storage/cache/memory
# github.com/docker/docker v20.10.9+incompatible # github.com/docker/docker v20.10.10+incompatible
github.com/docker/docker/api github.com/docker/docker/api
github.com/docker/docker/api/types github.com/docker/docker/api/types
github.com/docker/docker/api/types/blkiodev github.com/docker/docker/api/types/blkiodev