github.com/snyk/vervet/v6@v6.2.4/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 &LocalizeCommand, 81 &ResourceCommand, 82 &ResolveCommand, 83 }, 84 } 85 86 // Prompt is the default interactive prompt for vervet. 87 type Prompt struct{} 88 89 // Confirm implements VervetPrompt.Confirm. 90 func (p Prompt) Confirm(label string) (bool, error) { 91 prompt := promptui.Prompt{ 92 Label: fmt.Sprintf("%v (y/N)?", label), 93 Default: "N", 94 Validate: func(input string) error { 95 input = strings.ToLower(input) 96 if input != "n" && input != "y" { 97 return errors.New("you must pick y or n") 98 } 99 return nil 100 }, 101 } 102 result, err := prompt.Run() 103 if err != nil { 104 return false, err 105 } 106 return (result == "y"), nil 107 } 108 109 // Entry implements VervetPrompt.Entry. 110 func (p Prompt) Entry(label string) (string, error) { 111 prompt := promptui.Prompt{ 112 Label: label, 113 Validate: func(result string) error { 114 if result == "" { 115 return errors.New("you must provide a non-empty response") 116 } 117 return nil 118 }, 119 } 120 result, err := prompt.Run() 121 if err != nil { 122 return "", err 123 } 124 return result, nil 125 } 126 127 // Select implements VervetPrompt.Select. 128 func (p Prompt) Select(label string, items []string) (string, error) { 129 prompt := promptui.Select{ 130 Label: label, 131 Items: items, 132 } 133 _, result, err := prompt.Run() 134 if err != nil { 135 return "", err 136 } 137 return result, nil 138 } 139 140 // Vervet is the vervet application with the CLI application. 141 var Vervet = NewApp(&CLIApp, VervetParams{ 142 Stdin: os.Stdin, 143 Stdout: os.Stdout, 144 Stderr: os.Stderr, 145 Prompt: Prompt{}, 146 }) 147 148 func absPath(path string) (string, error) { 149 if path == "" { 150 return "", fmt.Errorf("path missing or empty") 151 } 152 return filepath.Abs(path) 153 } 154 155 func projectConfig(ctx *cli.Context) (string, string, error) { 156 var projectDir, configFile string 157 var err error 158 if cf := ctx.String("config"); cf != "" { 159 configFile, err = filepath.Abs(cf) 160 if err != nil { 161 return "", "", err 162 } 163 projectDir = filepath.Dir(configFile) 164 } else { 165 configFile = filepath.Join(projectDir, ".vervet.yaml") 166 projectDir, err = os.Getwd() 167 if err != nil { 168 return "", "", err 169 } 170 } 171 return projectDir, configFile, nil 172 }