github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/internal/commands/image/render.go (about)

     1  package image
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  
     8  	"github.com/deislabs/cnab-go/action"
     9  	"github.com/deislabs/cnab-go/driver"
    10  	"github.com/docker/app/internal"
    11  	bdl "github.com/docker/app/internal/bundle"
    12  	"github.com/docker/app/internal/cliopts"
    13  	"github.com/docker/app/internal/cnab"
    14  	"github.com/docker/app/internal/packager"
    15  	appstore "github.com/docker/app/internal/store"
    16  	"github.com/docker/cli/cli"
    17  	"github.com/docker/cli/cli/command"
    18  	"github.com/docker/cli/cli/config"
    19  	"github.com/pkg/errors"
    20  	"github.com/spf13/cobra"
    21  )
    22  
    23  type renderOptions struct {
    24  	cliopts.ParametersOptions
    25  	formatDriver string
    26  	renderOutput string
    27  }
    28  
    29  func renderCmd(dockerCli command.Cli, installerContext *cliopts.InstallerContextOptions) *cobra.Command {
    30  	var opts renderOptions
    31  	cmd := &cobra.Command{
    32  		Use:     "render [OPTIONS] APP_IMAGE",
    33  		Short:   "Render the Compose file for an App image",
    34  		Example: `$ docker app render myrepo/myapp:1.0.0 --set key=value --parameters-file myparam.yml`,
    35  		Args:    cli.ExactArgs(1),
    36  		Hidden:  true,
    37  		RunE: func(cmd *cobra.Command, args []string) error {
    38  			return runRender(dockerCli, args[0], opts, installerContext)
    39  		},
    40  	}
    41  	opts.ParametersOptions.AddFlags(cmd.Flags())
    42  	cmd.Flags().StringVarP(&opts.renderOutput, "output", "o", "-", "Output file")
    43  	cmd.Flags().StringVar(&opts.formatDriver, "formatter", "yaml", "Configure the output format (yaml|json)")
    44  
    45  	return cmd
    46  }
    47  
    48  func runRender(dockerCli command.Cli, appname string, opts renderOptions, installerContext *cliopts.InstallerContextOptions) error {
    49  	var w io.Writer = os.Stdout
    50  	if opts.renderOutput != "-" {
    51  		f, err := os.Create(opts.renderOutput)
    52  		if err != nil {
    53  			return err
    54  		}
    55  		defer f.Close()
    56  		w = f
    57  	}
    58  
    59  	s, err := appstore.NewApplicationStore(config.Dir())
    60  	if err != nil {
    61  		return err
    62  	}
    63  	imageStore, err := s.ImageStore()
    64  	if err != nil {
    65  		return err
    66  	}
    67  	img, ref, err := cnab.GetBundle(dockerCli, imageStore, appname)
    68  	if err != nil {
    69  		return errors.Wrapf(err, "could not render %q: no such App image", appname)
    70  	}
    71  	if err := packager.CheckAppVersion(dockerCli.Err(), img.Bundle); err != nil {
    72  		return err
    73  	}
    74  	installation, err := appstore.NewInstallation("custom-action", ref.String(), img)
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	if err := bdl.MergeBundleParameters(installation,
    80  		bdl.WithFileParameters(opts.ParametersFiles),
    81  		bdl.WithCommandLineParameters(opts.Overrides),
    82  	); err != nil {
    83  		return err
    84  	}
    85  
    86  	defer muteDockerCli(dockerCli)()
    87  	driverImpl, errBuf, err := cnab.SetupDriver(installation, dockerCli, installerContext, w)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	action := &action.RunCustom{
    92  		Action: internal.ActionRenderName,
    93  		Driver: driverImpl,
    94  	}
    95  	installation.Parameters[internal.ParameterRenderFormatName] = opts.formatDriver
    96  
    97  	cfgFunc := func(op *driver.Operation) error {
    98  		op.Out = w
    99  		return nil
   100  	}
   101  
   102  	if err := action.Run(&installation.Claim, nil, cfgFunc, cnab.WithRelocationMap(installation)); err != nil {
   103  		return fmt.Errorf("render failed: %s\n%s", err, errBuf)
   104  	}
   105  	return nil
   106  }