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 }