Migrate --authfile to sharedImageOptions

This introduces YET ANOTHER *Options structure, only to share this
option between copy source and destination.  (We do need to do this,
because the libraries, rightly, refuse to work with source and
destination declaring its own versino of the --authfile flag.)

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač
2018-07-18 00:24:55 +02:00
parent 444b90a9cf
commit 6ef45e5cf1
6 changed files with 52 additions and 39 deletions

View File

@@ -42,8 +42,9 @@ type copyOptions struct {
}
func copyCmd(global *globalOptions) cli.Command {
srcFlags, srcOpts := imageFlags(global, "src-", "screds")
destFlags, destOpts := imageDestFlags(global, "dest-", "dcreds")
sharedFlags, sharedOpts := sharedImageFlags()
srcFlags, srcOpts := imageFlags(global, sharedOpts, "src-", "screds")
destFlags, destOpts := imageDestFlags(global, sharedOpts, "dest-", "dcreds")
opts := copyOptions{global: global,
srcImage: srcOpts,
destImage: destOpts,
@@ -64,16 +65,12 @@ func copyCmd(global *globalOptions) cli.Command {
ArgsUsage: "SOURCE-IMAGE DESTINATION-IMAGE",
Action: opts.run,
// FIXME: Do we need to namespace the GPG aspect?
Flags: append(append([]cli.Flag{
Flags: append(append(append([]cli.Flag{
cli.StringSliceFlag{
Name: "additional-tag",
Usage: "additional tags (supports docker-archive)",
Value: &opts.additionalTags, // Surprisingly StringSliceFlag does not support Destination:, but modifies Value: in place.
},
cli.StringFlag{
Name: "authfile",
Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
},
cli.BoolFlag{
Name: "remove-signatures",
Usage: "Do not copy signatures from SOURCE-IMAGE",
@@ -89,7 +86,7 @@ func copyCmd(global *globalOptions) cli.Command {
Usage: "`MANIFEST TYPE` (oci, v2s1, or v2s2) to use when saving image to directory using the 'dir:' transport (default is manifest type of source)",
Value: newOptionalStringValue(&opts.format),
},
}, srcFlags...), destFlags...),
}, sharedFlags...), srcFlags...), destFlags...),
}
}

View File

@@ -16,7 +16,8 @@ type deleteOptions struct {
}
func deleteCmd(global *globalOptions) cli.Command {
imageFlags, imageOpts := imageFlags(global, "", "")
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
opts := deleteOptions{
global: global,
image: imageOpts,
@@ -34,12 +35,7 @@ func deleteCmd(global *globalOptions) cli.Command {
`, strings.Join(transports.ListNames(), ", ")),
ArgsUsage: "IMAGE-NAME",
Action: opts.run,
Flags: append([]cli.Flag{
cli.StringFlag{
Name: "authfile",
Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
},
}, imageFlags...),
Flags: append(sharedFlags, imageFlags...),
}
}

View File

@@ -36,7 +36,8 @@ type inspectOptions struct {
}
func inspectCmd(global *globalOptions) cli.Command {
imageFlags, imageOpts := imageFlags(global, "", "")
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
opts := inspectOptions{
global: global,
image: imageOpts,
@@ -53,17 +54,13 @@ func inspectCmd(global *globalOptions) cli.Command {
See skopeo(1) section "IMAGE NAMES" for the expected format
`, strings.Join(transports.ListNames(), ", ")),
ArgsUsage: "IMAGE-NAME",
Flags: append([]cli.Flag{
cli.StringFlag{
Name: "authfile",
Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
},
Flags: append(append([]cli.Flag{
cli.BoolFlag{
Name: "raw",
Usage: "output raw manifest",
Destination: &opts.raw,
},
}, imageFlags...),
}, sharedFlags...), imageFlags...),
Action: opts.run,
}
}

View File

@@ -21,7 +21,8 @@ type layersOptions struct {
}
func layersCmd(global *globalOptions) cli.Command {
imageFlags, imageOpts := imageFlags(global, "", "")
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
opts := layersOptions{
global: global,
image: imageOpts,
@@ -32,7 +33,7 @@ func layersCmd(global *globalOptions) cli.Command {
ArgsUsage: "IMAGE-NAME [LAYER...]",
Hidden: true,
Action: opts.run,
Flags: imageFlags,
Flags: append(sharedFlags, imageFlags...),
}
}

View File

@@ -10,22 +10,42 @@ import (
"github.com/urfave/cli"
)
// sharedImageOptions collects CLI flags which are image-related, but do not change across images.
// This really should be a part of globalOptions, but that would break existing users of (skopeo copy --authfile=).
type sharedImageOptions struct {
authFilePath string // Path to a */containers/auth.json
}
// imageFlags prepares a collection of CLI flags writing into sharedImageOptions, and the managed sharedImageOptions structure.
func sharedImageFlags() ([]cli.Flag, *sharedImageOptions) {
opts := sharedImageOptions{}
return []cli.Flag{
cli.StringFlag{
Name: "authfile",
Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
Destination: &opts.authFilePath,
},
}, &opts
}
// imageOptions collects CLI flags which are the same across subcommands, but may be different for each image
// (e.g. may differ between the source and destination of a copy)
type imageOptions struct {
global *globalOptions // May be shared across several imageOptions instances.
flagPrefix string // FIXME: Drop this eventually.
credsOption optionalString // username[:password] for accessing a registry
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:)
sharedBlobDir string // A directory to use for OCI blobs, shared across repositories
dockerDaemonHost string // docker-daemon: host to connect to
global *globalOptions // May be shared across several imageOptions instances.
shared *sharedImageOptions // May be shared across several imageOptions instances.
flagPrefix string // FIXME: Drop this eventually.
credsOption optionalString // username[:password] for accessing a registry
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:)
sharedBlobDir string // A directory to use for OCI blobs, shared across repositories
dockerDaemonHost string // docker-daemon: host to connect to
}
// imageFlags prepares a collection of CLI flags writing into imageOptions, and the managed imageOptions structure.
func imageFlags(global *globalOptions, flagPrefix, credsOptionAlias string) ([]cli.Flag, *imageOptions) {
func imageFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) ([]cli.Flag, *imageOptions) {
opts := imageOptions{
global: global,
shared: shared,
flagPrefix: flagPrefix,
}
@@ -74,7 +94,7 @@ func contextFromImageOptions(c *cli.Context, opts *imageOptions) (*types.SystemC
OSChoice: opts.global.overrideOS,
DockerCertPath: opts.dockerCertPath,
OCISharedBlobDirPath: opts.sharedBlobDir,
AuthFilePath: c.String("authfile"),
AuthFilePath: opts.shared.authFilePath,
DockerDaemonHost: opts.dockerDaemonHost,
DockerDaemonCertPath: opts.dockerCertPath,
}
@@ -106,8 +126,8 @@ type imageDestOptions struct {
}
// imageDestFlags prepares a collection of CLI flags writing into imageDestOptions, and the managed imageDestOptions structure.
func imageDestFlags(global *globalOptions, flagPrefix, credsOptionAlias string) ([]cli.Flag, *imageDestOptions) {
genericFlags, genericOptions := imageFlags(global, flagPrefix, credsOptionAlias)
func imageDestFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) ([]cli.Flag, *imageDestOptions) {
genericFlags, genericOptions := imageFlags(global, shared, flagPrefix, credsOptionAlias)
opts := imageDestOptions{imageOptions: genericOptions}
return append(genericFlags, []cli.Flag{

View File

@@ -35,7 +35,8 @@ func fakeImageContext(t *testing.T, cmdName string, flagPrefix string, globalFla
cmd := app.Command(cmdName)
require.NotNil(t, cmd)
imageFlags, imageOpts := imageFlags(globalOpts, flagPrefix, "")
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(globalOpts, sharedOpts, flagPrefix, "")
appliedFlags := map[string]struct{}{}
// Ugly: cmd.Flags includes imageFlags as well. For now, we need cmd.Flags to apply here
// to be able to test the non-Destination: flags, but we must not apply the same flag name twice.
@@ -46,7 +47,7 @@ func fakeImageContext(t *testing.T, cmdName string, flagPrefix string, globalFla
return strings.Split(f.GetName(), ",")[0]
}
flagSet := flag.NewFlagSet(cmd.Name, flag.ContinueOnError)
for _, f := range imageFlags {
for _, f := range append(sharedFlags, imageFlags...) {
f.Apply(flagSet)
appliedFlags[firstName(f)] = struct{}{}
}
@@ -145,7 +146,8 @@ func fakeImageDestContext(t *testing.T, cmdName string, flagPrefix string, globa
cmd := app.Command(cmdName)
require.NotNil(t, cmd)
imageFlags, imageOpts := imageDestFlags(globalOpts, flagPrefix, "")
sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageDestFlags(globalOpts, sharedOpts, flagPrefix, "")
appliedFlags := map[string]struct{}{}
// Ugly: cmd.Flags includes imageFlags as well. For now, we need cmd.Flags to apply here
// to be able to test the non-Destination: flags, but we must not apply the same flag name twice.
@@ -156,7 +158,7 @@ func fakeImageDestContext(t *testing.T, cmdName string, flagPrefix string, globa
return strings.Split(f.GetName(), ",")[0]
}
flagSet := flag.NewFlagSet(cmd.Name, flag.ContinueOnError)
for _, f := range imageFlags {
for _, f := range append(sharedFlags, imageFlags...) {
f.Apply(flagSet)
appliedFlags[firstName(f)] = struct{}{}
}