github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/cmd/apply.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/qri-io/dataset"
    11  	"github.com/qri-io/ioes"
    12  	"github.com/qri-io/qri/lib"
    13  	"github.com/qri-io/qri/repo"
    14  	"github.com/spf13/cobra"
    15  )
    16  
    17  // NewApplyCommand creates a new `qri apply` cobra command for applying transformations
    18  func NewApplyCommand(f Factory, ioStreams ioes.IOStreams) *cobra.Command {
    19  	o := &ApplyOptions{IOStreams: ioStreams}
    20  	cmd := &cobra.Command{
    21  		Use:   "apply",
    22  		Short: "apply a transform to a dataset",
    23  		Long: `Apply runs a transform script. The result of the transform is displayed after
    24  the command completes.
    25  
    26  The apply command itself does not commit results to the repository. Use
    27  the --apply flag on the save command to commit results from transforms.`,
    28  		Example: ` # Apply a transform and display the output:
    29   $ qri apply --file transform.star
    30  
    31   # Apply a transform using an existing dataset version:
    32   $ qri apply --file transform.star me/my_dataset`,
    33  		Annotations: map[string]string{
    34  			"group": "dataset",
    35  		},
    36  		RunE: func(cmd *cobra.Command, args []string) error {
    37  			if err := o.Complete(f, args); err != nil {
    38  				return err
    39  			}
    40  			return o.Run()
    41  		},
    42  	}
    43  
    44  	cmd.Flags().StringVar(&o.FilePath, "file", "", "path of transform script file")
    45  	cmd.MarkFlagRequired("file")
    46  	cmd.Flags().StringSliceVar(&o.Secrets, "secrets", nil, "transform secrets as comma separated key,value,key,value,... sequence")
    47  	cmd.Flags().BoolVar(&o.Quiet, "quiet", false, "whether to suppress output from the application")
    48  
    49  	return cmd
    50  }
    51  
    52  // ApplyOptions encapsulates state for the apply command
    53  type ApplyOptions struct {
    54  	ioes.IOStreams
    55  
    56  	Instance *lib.Instance
    57  
    58  	Refs     *RefSelect
    59  	FilePath string
    60  	Quiet    bool
    61  	Secrets  []string
    62  }
    63  
    64  // Complete adds any missing configuration that can only be added just before calling Run
    65  func (o *ApplyOptions) Complete(f Factory, args []string) (err error) {
    66  	if o.Instance, err = f.Instance(); err != nil {
    67  		return err
    68  	}
    69  	if o.Refs, err = GetCurrentRefSelect(f, args, -1); err != nil {
    70  		// This error will be handled during validation
    71  		if err != repo.ErrEmptyRef {
    72  			return err
    73  		}
    74  		err = nil
    75  	}
    76  	o.FilePath, err = filepath.Abs(o.FilePath)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	return nil
    81  }
    82  
    83  // Run executes the apply command
    84  func (o *ApplyOptions) Run() (err error) {
    85  
    86  	if !strings.HasSuffix(o.FilePath, ".star") {
    87  		return errors.New("only transform scripts are supported by --file")
    88  	}
    89  
    90  	ctx := context.TODO()
    91  	inst := o.Instance
    92  
    93  	tf := dataset.Transform{
    94  		ScriptPath: o.FilePath,
    95  	}
    96  
    97  	if len(o.Secrets) > 0 {
    98  		tf.Secrets, err = parseSecrets(o.Secrets...)
    99  		if err != nil {
   100  			return err
   101  		}
   102  	}
   103  
   104  	params := lib.ApplyParams{
   105  		Ref:          o.Refs.Ref(),
   106  		Transform:    &tf,
   107  		ScriptOutput: o.Out,
   108  		Wait:         true,
   109  	}
   110  
   111  	terminalWidth, terminalHeight := sizeOfTerminal()
   112  	if terminalWidth > 0 && terminalHeight > 0 {
   113  		params.OutputWidth = terminalWidth
   114  		params.OutputHeight = terminalHeight
   115  	}
   116  
   117  	res, err := inst.Automation().Apply(ctx, &params)
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	if !o.Quiet {
   123  		data, err := json.MarshalIndent(res.Data, "", " ")
   124  		if err != nil {
   125  			return err
   126  		}
   127  		printSuccess(o.Out, string(data))
   128  	}
   129  	return nil
   130  }