Use the *Options structures for command-specific options

Use Destionation: &opts.flag in the flag definition
instead of c.String("flag-name") and the like in the hadler and
matching only by strings.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač 2018-07-07 02:33:47 +02:00
parent 59117e6e3d
commit 485a7aa330
3 changed files with 39 additions and 32 deletions

View File

@ -32,6 +32,10 @@ func contextsFromGlobalOptions(c *cli.Context) (*types.SystemContext, *types.Sys
} }
type copyOptions struct { type copyOptions struct {
additionalTags cli.StringSlice // 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
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
format optionalString // Force conversion of the image to a specified format
} }
func copyCmd() cli.Command { func copyCmd() cli.Command {
@ -55,18 +59,21 @@ func copyCmd() cli.Command {
cli.StringSliceFlag{ cli.StringSliceFlag{
Name: "additional-tag", Name: "additional-tag",
Usage: "additional tags (supports docker-archive)", Usage: "additional tags (supports docker-archive)",
Value: &opts.additionalTags, // Surprisingly StringSliceFlag does not support Destination:, but modifies Value: in place.
}, },
cli.StringFlag{ cli.StringFlag{
Name: "authfile", Name: "authfile",
Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json", Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "remove-signatures", Name: "remove-signatures",
Usage: "Do not copy signatures from SOURCE-IMAGE", Usage: "Do not copy signatures from SOURCE-IMAGE",
Destination: &opts.removeSignatures,
}, },
cli.StringFlag{ cli.StringFlag{
Name: "sign-by", Name: "sign-by",
Usage: "Sign the image using a GPG key with the specified `FINGERPRINT`", Usage: "Sign the image using a GPG key with the specified `FINGERPRINT`",
Destination: &opts.signByFingerprint,
}, },
cli.StringFlag{ cli.StringFlag{
Name: "src-creds, screds", Name: "src-creds, screds",
@ -111,9 +118,10 @@ func copyCmd() cli.Command {
Value: "", Value: "",
Usage: "`DIRECTORY` to use to store retrieved blobs (OCI layout destinations only)", Usage: "`DIRECTORY` to use to store retrieved blobs (OCI layout destinations only)",
}, },
cli.StringFlag{ cli.GenericFlag{
Name: "format, f", Name: "format, f",
Usage: "`MANIFEST TYPE` (oci, v2s1, or v2s2) to use when saving image to directory using the 'dir:' transport (default is manifest type of source)", 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),
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "dest-compress", Name: "dest-compress",
@ -153,8 +161,6 @@ func (opts *copyOptions) run(c *cli.Context) error {
if err != nil { if err != nil {
return fmt.Errorf("Invalid destination name %s: %v", c.Args()[1], err) return fmt.Errorf("Invalid destination name %s: %v", c.Args()[1], err)
} }
signBy := c.String("sign-by")
removeSignatures := c.Bool("remove-signatures")
sourceCtx, destinationCtx, err := contextsFromGlobalOptions(c) sourceCtx, destinationCtx, err := contextsFromGlobalOptions(c)
if err != nil { if err != nil {
@ -162,8 +168,8 @@ func (opts *copyOptions) run(c *cli.Context) error {
} }
var manifestType string var manifestType string
if c.IsSet("format") { if opts.format.present {
switch c.String("format") { switch opts.format.value {
case "oci": case "oci":
manifestType = imgspecv1.MediaTypeImageManifest manifestType = imgspecv1.MediaTypeImageManifest
case "v2s1": case "v2s1":
@ -171,30 +177,28 @@ func (opts *copyOptions) run(c *cli.Context) error {
case "v2s2": case "v2s2":
manifestType = manifest.DockerV2Schema2MediaType manifestType = manifest.DockerV2Schema2MediaType
default: default:
return fmt.Errorf("unknown format %q. Choose one of the supported formats: 'oci', 'v2s1', or 'v2s2'", c.String("format")) return fmt.Errorf("unknown format %q. Choose one of the supported formats: 'oci', 'v2s1', or 'v2s2'", opts.format.value)
} }
} }
if c.IsSet("additional-tag") { for _, image := range opts.additionalTags {
for _, image := range c.StringSlice("additional-tag") { ref, err := reference.ParseNormalizedNamed(image)
ref, err := reference.ParseNormalizedNamed(image) if err != nil {
if err != nil { return fmt.Errorf("error parsing additional-tag '%s': %v", image, err)
return fmt.Errorf("error parsing additional-tag '%s': %v", image, err)
}
namedTagged, isNamedTagged := ref.(reference.NamedTagged)
if !isNamedTagged {
return fmt.Errorf("additional-tag '%s' must be a tagged reference", image)
}
destinationCtx.DockerArchiveAdditionalTags = append(destinationCtx.DockerArchiveAdditionalTags, namedTagged)
} }
namedTagged, isNamedTagged := ref.(reference.NamedTagged)
if !isNamedTagged {
return fmt.Errorf("additional-tag '%s' must be a tagged reference", image)
}
destinationCtx.DockerArchiveAdditionalTags = append(destinationCtx.DockerArchiveAdditionalTags, namedTagged)
} }
ctx, cancel := commandTimeoutContextFromGlobalOptions(c) ctx, cancel := commandTimeoutContextFromGlobalOptions(c)
defer cancel() defer cancel()
_, err = copy.Image(ctx, policyContext, destRef, srcRef, &copy.Options{ _, err = copy.Image(ctx, policyContext, destRef, srcRef, &copy.Options{
RemoveSignatures: removeSignatures, RemoveSignatures: opts.removeSignatures,
SignBy: signBy, SignBy: opts.signByFingerprint,
ReportWriter: os.Stdout, ReportWriter: os.Stdout,
SourceCtx: sourceCtx, SourceCtx: sourceCtx,
DestinationCtx: destinationCtx, DestinationCtx: destinationCtx,

View File

@ -30,6 +30,7 @@ type inspectOutput struct {
} }
type inspectOptions struct { type inspectOptions struct {
raw bool // Output the raw manifest instead of parsing information about the image
} }
func inspectCmd() cli.Command { func inspectCmd() cli.Command {
@ -61,8 +62,9 @@ func inspectCmd() cli.Command {
Usage: "require HTTPS and verify certificates when talking to container registries (defaults to true)", Usage: "require HTTPS and verify certificates when talking to container registries (defaults to true)",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "raw", Name: "raw",
Usage: "output raw manifest", Usage: "output raw manifest",
Destination: &opts.raw,
}, },
cli.StringFlag{ cli.StringFlag{
Name: "creds", Name: "creds",
@ -93,7 +95,7 @@ func (opts *inspectOptions) run(c *cli.Context) (retErr error) {
if err != nil { if err != nil {
return err return err
} }
if c.Bool("raw") { if opts.raw {
_, err := c.App.Writer.Write(rawManifest) _, err := c.App.Writer.Write(rawManifest)
if err != nil { if err != nil {
return fmt.Errorf("Error writing manifest to standard output: %v", err) return fmt.Errorf("Error writing manifest to standard output: %v", err)

View File

@ -11,6 +11,7 @@ import (
) )
type standaloneSignOptions struct { type standaloneSignOptions struct {
output string // Output file path
} }
func standaloneSignCmd() cli.Command { func standaloneSignCmd() cli.Command {
@ -22,16 +23,16 @@ func standaloneSignCmd() cli.Command {
Action: opts.run, Action: opts.run,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "output, o", Name: "output, o",
Usage: "output the signature to `SIGNATURE`", Usage: "output the signature to `SIGNATURE`",
Destination: &opts.output,
}, },
}, },
} }
} }
func (opts *standaloneSignOptions) run(c *cli.Context) error { func (opts *standaloneSignOptions) run(c *cli.Context) error {
outputFile := c.String("output") if len(c.Args()) != 3 || opts.output == "" {
if len(c.Args()) != 3 || outputFile == "" {
return errors.New("Usage: skopeo standalone-sign manifest docker-reference key-fingerprint -o signature") return errors.New("Usage: skopeo standalone-sign manifest docker-reference key-fingerprint -o signature")
} }
manifestPath := c.Args()[0] manifestPath := c.Args()[0]
@ -53,8 +54,8 @@ func (opts *standaloneSignOptions) run(c *cli.Context) error {
return fmt.Errorf("Error creating signature: %v", err) return fmt.Errorf("Error creating signature: %v", err)
} }
if err := ioutil.WriteFile(outputFile, signature, 0644); err != nil { if err := ioutil.WriteFile(opts.output, signature, 0644); err != nil {
return fmt.Errorf("Error writing signature to %s: %v", outputFile, err) return fmt.Errorf("Error writing signature to %s: %v", opts.output, err)
} }
return nil return nil
} }