github.com/w3security/vervet/v5@v5.3.1-0.20230618081846-5bd9b5d799dc/internal/cmd/cmd.go (about)

     1  // Package cmd provides subcommands for the vervet CLI.
     2  package cmd
     3  
     4  import (
     5  	"context"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/manifoldco/promptui"
    14  	"github.com/urfave/cli/v2"
    15  )
    16  
    17  //go:generate ../../scripts/genversion.bash
    18  
    19  // VervetParams contains configuration parameters for the Vervet CLI application.
    20  type VervetParams struct {
    21  	Stdin  io.ReadCloser
    22  	Stdout io.WriteCloser
    23  	Stderr io.WriteCloser
    24  	Prompt VervetPrompt
    25  }
    26  
    27  // VervetApp contains the cli Application.
    28  type VervetApp struct {
    29  	App    *cli.App
    30  	Params VervetParams
    31  }
    32  
    33  // VervetPrompt defines the interface for interactive prompts in vervet.
    34  type VervetPrompt interface {
    35  	Confirm(label string) (bool, error)                  // Confirm y/n an action
    36  	Entry(label string) (string, error)                  // Gather a freeform entry in response to a question
    37  	Select(label string, items []string) (string, error) // Select from a limited number of entries
    38  }
    39  
    40  type runKey string
    41  
    42  var vervetKey = runKey("vervet")
    43  
    44  func contextWithApp(ctx context.Context, v *VervetApp) context.Context {
    45  	return context.WithValue(ctx, vervetKey, v)
    46  }
    47  
    48  // Run runs the cli.App with the Vervet config params.
    49  func (v *VervetApp) Run(args []string) error {
    50  	ctx := contextWithApp(context.Background(), v)
    51  	return v.App.RunContext(ctx, args)
    52  }
    53  
    54  // NewApp returns a new VervetApp with the provided params.
    55  func NewApp(app *cli.App, vp VervetParams) *VervetApp {
    56  	app.Reader = vp.Stdin
    57  	app.Writer = vp.Stdout
    58  	app.ErrWriter = vp.Stderr
    59  	return &VervetApp{
    60  		App:    app,
    61  		Params: vp,
    62  	}
    63  }
    64  
    65  var CLIApp = cli.App{
    66  	Name:    "vervet",
    67  	Usage:   "OpenAPI resource versioning tool",
    68  	Version: "develop", // Set in init created with go generate.
    69  	Flags: []cli.Flag{
    70  		&cli.BoolFlag{
    71  			Name:  "debug",
    72  			Usage: "Turn on debug logging",
    73  		},
    74  	},
    75  	Commands: []*cli.Command{
    76  		&BackstageCommand,
    77  		&BuildCommand,
    78  		&FilterCommand,
    79  		&GenerateCommand,
    80  		&LintCommand,
    81  		&LocalizeCommand,
    82  		&ResourceCommand,
    83  		&ResolveCommand,
    84  	},
    85  }
    86  
    87  // Prompt is the default interactive prompt for vervet.
    88  type Prompt struct{}
    89  
    90  // Confirm implements VervetPrompt.Confirm.
    91  func (p Prompt) Confirm(label string) (bool, error) {
    92  	prompt := promptui.Prompt{
    93  		Label:   fmt.Sprintf("%v (y/N)?", label),
    94  		Default: "N",
    95  		Validate: func(input string) error {
    96  			input = strings.ToLower(input)
    97  			if input != "n" && input != "y" {
    98  				return errors.New("you must pick y or n")
    99  			}
   100  			return nil
   101  		},
   102  	}
   103  	result, err := prompt.Run()
   104  	if err != nil {
   105  		return false, err
   106  	}
   107  	return (result == "y"), nil
   108  }
   109  
   110  // Entry implements VervetPrompt.Entry.
   111  func (p Prompt) Entry(label string) (string, error) {
   112  	prompt := promptui.Prompt{
   113  		Label: label,
   114  		Validate: func(result string) error {
   115  			if result == "" {
   116  				return errors.New("you must provide a non-empty response")
   117  			}
   118  			return nil
   119  		},
   120  	}
   121  	result, err := prompt.Run()
   122  	if err != nil {
   123  		return "", err
   124  	}
   125  	return result, nil
   126  }
   127  
   128  // Select implements VervetPrompt.Select.
   129  func (p Prompt) Select(label string, items []string) (string, error) {
   130  	prompt := promptui.Select{
   131  		Label: label,
   132  		Items: items,
   133  	}
   134  	_, result, err := prompt.Run()
   135  	if err != nil {
   136  		return "", err
   137  	}
   138  	return result, nil
   139  }
   140  
   141  // Vervet is the vervet application with the CLI application.
   142  var Vervet = NewApp(&CLIApp, VervetParams{
   143  	Stdin:  os.Stdin,
   144  	Stdout: os.Stdout,
   145  	Stderr: os.Stderr,
   146  	Prompt: Prompt{},
   147  })
   148  
   149  func absPath(path string) (string, error) {
   150  	if path == "" {
   151  		return "", fmt.Errorf("path missing or empty")
   152  	}
   153  	return filepath.Abs(path)
   154  }
   155  
   156  func projectConfig(ctx *cli.Context) (string, string, error) {
   157  	var projectDir, configFile string
   158  	var err error
   159  	if cf := ctx.String("config"); cf != "" {
   160  		configFile, err = filepath.Abs(cf)
   161  		if err != nil {
   162  			return "", "", err
   163  		}
   164  		projectDir = filepath.Dir(configFile)
   165  	} else {
   166  		configFile = filepath.Join(projectDir, ".vervet.yaml")
   167  		projectDir, err = os.Getwd()
   168  		if err != nil {
   169  			return "", "", err
   170  		}
   171  	}
   172  	return projectDir, configFile, nil
   173  }