From 79db99c8bfdf3ab1be2e9f8d2184df032a02c239 Mon Sep 17 00:00:00 2001 From: Emily McMullan Date: Wed, 9 Aug 2023 10:27:46 -0400 Subject: [PATCH] :sparkles: Use Cobra for cli (#274) Signed-off-by: Emily McMullan --- cmd/analyzer/main.go | 95 ++++++++++++++++++++++++++++---------------- cmd/dep/main.go | 45 ++++++++++++++------- go.mod | 7 +++- go.sum | 8 ++++ 4 files changed, 104 insertions(+), 51 deletions(-) diff --git a/cmd/analyzer/main.go b/cmd/analyzer/main.go index 284050fe..eeefee6b 100644 --- a/cmd/analyzer/main.go +++ b/cmd/analyzer/main.go @@ -16,7 +16,7 @@ import ( "github.com/konveyor/analyzer-lsp/provider/lib" "github.com/konveyor/analyzer-lsp/tracing" "github.com/sirupsen/logrus" - flag "github.com/spf13/pflag" + "github.com/spf13/cobra" "gopkg.in/yaml.v2" ) @@ -25,25 +25,50 @@ const ( ) var ( - settingsFile = flag.String("provider-settings", "provider_settings.json", "path to the provider settings") - rulesFile = flag.StringArray("rules", []string{"rule-example.yaml"}, "filename or directory containing rule files") - outputViolations = flag.String("output-file", "output.yaml", "filepath to to store rule violations") - errorOnViolations = flag.Bool("error-on-violation", false, "exit with 3 if any violation are found will also print violations to console") - labelSelector = flag.String("label-selector", "", "an expression to select rules based on labels") - depLabelSelector = flag.String("dep-label-selector", "", "an expression to select dependencies based on labels. This will filter out the violations from these dependencies as well these dependencies when matching dependency conditions.") - logLevel = flag.Int("verbose", 9, "level for logging output") - enableJaeger = flag.Bool("enable-jaeger", false, "enable tracer exports to jaeger endpoint") - jaegerEndpoint = flag.String("jaeger-endpoint", "http://localhost:14268/api/traces", "jaeger endpoint to collect tracing data") - limitIncidents = flag.Int("limit-incidents", 1500, "Set this to the limit incidents that a given rule can give, zero means no limit") - limitCodeSnips = flag.Int("limit-code-snips", 20, "limit the number code snippets that are retrieved for a file while evaluating a rule, 0 means no limit") - analysisMode = flag.String("analysis-mode", "", "select one of full or source-only to tell the providers what to analyize. This can be given on a per provider setting, but this flag will override") - noDependencyRules = flag.Bool("no-dependency-rules", false, "Disable dependency analysis rules") + settingsFile string + rulesFile []string + outputViolations string + errorOnViolations bool + labelSelector string + depLabelSelector string + logLevel int + enableJaeger bool + jaegerEndpoint string + limitIncidents int + limitCodeSnips int + analysisMode string + noDependencyRules bool + + rootCmd = &cobra.Command{ + Use: "analyze", + Short: "Tool for working with analyzer-lsp", + Run: func(c *cobra.Command, args []string) {}, + } ) +func init() { + rootCmd.Flags().StringVar(&settingsFile, "settings-file", "provider_settings.json", "path to the provider settings") + rootCmd.Flags().StringArrayVar(&rulesFile, "rules-file", []string{"rule-example.yaml"}, "filename or directory containing rule files") + rootCmd.Flags().StringVar(&outputViolations, "output-file", "output.yaml", "filepath to to store rule violations") + rootCmd.Flags().BoolVar(&errorOnViolations, "error-on-violation", false, "exit with 3 if any violation are found will also print violations to console") + rootCmd.Flags().StringVar(&labelSelector, "label-selector", "", "an expression to select rules based on labels") + rootCmd.Flags().StringVar(&depLabelSelector, "dep-label-selector", "", "an expression to select dependencies based on labels. This will filter out the violations from these dependencies as well these dependencies when matching dependency conditions") + rootCmd.Flags().IntVar(&logLevel, "verbose", 9, "level for logging output") + rootCmd.Flags().BoolVar(&enableJaeger, "enable-jaeger", false, "enable tracer exports to jaeger endpoint") + rootCmd.Flags().StringVar(&jaegerEndpoint, "jaeger-endpoint", "http://localhost:14268/api/traces", "jaeger endpoint to collect tracing data") + rootCmd.Flags().IntVar(&limitIncidents, "limit-incidents", 1500, "Set this to the limit incidents that a given rule can give, zero means no limit") + rootCmd.Flags().IntVar(&limitCodeSnips, "limit-code-snips", 20, "limit the number code snippets that are retrieved for a file while evaluating a rule, 0 means no limit") + rootCmd.Flags().StringVar(&analysisMode, "analysis-mode", "", "select one of full or source-only to tell the providers what to analyize. This can be given on a per provider setting, but this flag will override") + rootCmd.Flags().BoolVar(&noDependencyRules, "no-dependency-rules", false, "Disable dependency analysis rules") +} + func main() { + if err := rootCmd.Execute(); err != nil { + println(err.Error()) + } + // This will globally prevent the yaml library from auto-wrapping lines at 80 characters yaml.FutureLineWrap() - flag.Parse() err := validateFlags() if err != nil { @@ -55,7 +80,7 @@ func main() { logrusLog.SetOutput(os.Stdout) logrusLog.SetFormatter(&logrus.TextFormatter{}) // need to do research on mapping in logrusr to level here TODO - logrusLog.SetLevel(logrus.Level(*logLevel)) + logrusLog.SetLevel(logrus.Level(logLevel)) log := logrusr.New(logrusLog) @@ -63,8 +88,8 @@ func main() { defer cancelFunc() selectors := []engine.RuleSelector{} - if labelSelector != nil && *labelSelector != "" { - selector, err := labels.NewLabelSelector[*engine.RuleMeta](*labelSelector) + if labelSelector != "" { + selector, err := labels.NewLabelSelector[*engine.RuleMeta](labelSelector) if err != nil { log.Error(err, "failed to create label selector from expression", "selector", labelSelector) os.Exit(1) @@ -73,8 +98,8 @@ func main() { } var dependencyLabelSelector *labels.LabelSelector[*konveyor.Dep] - if depLabelSelector != nil && *depLabelSelector != "" { - dependencyLabelSelector, err = labels.NewLabelSelector[*konveyor.Dep](*depLabelSelector) + if depLabelSelector != "" { + dependencyLabelSelector, err = labels.NewLabelSelector[*konveyor.Dep](depLabelSelector) if err != nil { log.Error(err, "failed to create label selector from expression", "selector", labelSelector) os.Exit(1) @@ -82,8 +107,8 @@ func main() { } tracerOptions := tracing.Options{ - EnableJaeger: *enableJaeger, - JaegerEndpoint: *jaegerEndpoint, + EnableJaeger: enableJaeger, + JaegerEndpoint: jaegerEndpoint, } tp, err := tracing.InitTracerProvider(log, tracerOptions) if err != nil { @@ -97,7 +122,7 @@ func main() { defer span.End() // Get the configs - configs, err := provider.GetConfig(*settingsFile) + configs, err := provider.GetConfig(settingsFile) if err != nil { log.Error(err, "unable to get configuration") os.Exit(1) @@ -107,18 +132,18 @@ func main() { eng := engine.CreateRuleEngine(ctx, 10, log, - engine.WithIncidentLimit(*limitIncidents), - engine.WithCodeSnipLimit(*limitCodeSnips), + engine.WithIncidentLimit(limitIncidents), + engine.WithCodeSnipLimit(limitCodeSnips), ) providers := map[string]provider.InternalProviderClient{} for _, config := range configs { // IF analsyis mode is set from the CLI, then we will override this for each init config - if *analysisMode != "" { + if analysisMode != "" { inits := []provider.InitConfig{} for _, i := range config.InitConfig { - i.AnalysisMode = provider.AnalysisMode(*analysisMode) + i.AnalysisMode = provider.AnalysisMode(analysisMode) inits = append(inits, i) } config.InitConfig = inits @@ -140,12 +165,12 @@ func main() { parser := parser.RuleParser{ ProviderNameToClient: providers, Log: log.WithName("parser"), - NoDependencyRules: *noDependencyRules, + NoDependencyRules: noDependencyRules, DepLabelSelector: dependencyLabelSelector, } ruleSets := []engine.RuleSet{} needProviders := map[string]provider.InternalProviderClient{} - for _, f := range *rulesFile { + for _, f := range rulesFile { internRuleSet, internNeedProviders, err := parser.LoadRules(f) if err != nil { log.WithValues("fileName", f).Error(err, "unable to parse all the rules for ruleset") @@ -177,28 +202,28 @@ func main() { // Write results out to CLI b, _ := yaml.Marshal(rulesets) - if *errorOnViolations && len(rulesets) != 0 { + if errorOnViolations && len(rulesets) != 0 { fmt.Printf("%s", string(b)) os.Exit(EXIT_ON_ERROR_CODE) } - os.WriteFile(*outputViolations, b, 0644) + os.WriteFile(outputViolations, b, 0644) } func validateFlags() error { - _, err := os.Stat(*settingsFile) + _, err := os.Stat(settingsFile) if err != nil { return fmt.Errorf("unable to find provider settings file") } - for _, f := range *rulesFile { + for _, f := range rulesFile { _, err = os.Stat(f) if err != nil { return fmt.Errorf("unable to find rule path or file") } } - m := provider.AnalysisMode(strings.ToLower(*analysisMode)) - if *analysisMode != "" && !(m == provider.FullAnalysisMode || m == provider.SourceOnlyAnalysisMode) { + m := provider.AnalysisMode(strings.ToLower(analysisMode)) + if analysisMode != "" && !(m == provider.FullAnalysisMode || m == provider.SourceOnlyAnalysisMode) { return fmt.Errorf("must select one of %s or %s for analysis mode", provider.FullAnalysisMode, provider.SourceOnlyAnalysisMode) } diff --git a/cmd/dep/main.go b/cmd/dep/main.go index 8e6e30f5..c49fb01b 100644 --- a/cmd/dep/main.go +++ b/cmd/dep/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "flag" "fmt" "os" "sort" @@ -13,24 +12,40 @@ import ( "github.com/konveyor/analyzer-lsp/provider" "github.com/konveyor/analyzer-lsp/provider/lib" "github.com/sirupsen/logrus" + "github.com/spf13/cobra" "gopkg.in/yaml.v2" ) var ( - providerSettings = flag.String("provider-settings", "provider_settings.json", "path to provider settings file") - treeOutput = flag.Bool("tree", false, "output dependencies as a tree") - outputFile = flag.String("output-file", "output.yaml", "path to output file") - depLabelSelector = flag.String("dep-label-selector", "", "an expression to select dependencies based on labels provided by the provider") + providerSettings string + treeOutput bool + outputFile string + depLabelSelector string + + rootCmd = &cobra.Command{ + Use: "analyze", + Short: "Tool for working with analyzer-lsp", + Run: func(c *cobra.Command, args []string) {}, + } ) +func init() { + rootCmd.Flags().StringVar(&providerSettings, "provider-settings", "provider_settings.json", "path to the provider settings") + rootCmd.Flags().BoolVar(&treeOutput, "tree", false, "output dependencies as a tree") + rootCmd.Flags().StringVar(&outputFile, "output-file", "output.yaml", "path to output file") + rootCmd.Flags().StringVar(&depLabelSelector, "dep-label-selector", "", "an expression to select dependencies based on labels provided by the provider") +} + func main() { + if err := rootCmd.Execute(); err != nil { + println(err.Error()) + } + logrusLog := logrus.New() logrusLog.SetOutput(os.Stdout) logrusLog.SetFormatter(&logrus.TextFormatter{}) log := logrusr.New(logrusLog) - flag.Parse() - err := validateFlags() if err != nil { log.Error(err, "failed to validate input flags") @@ -43,7 +58,7 @@ func main() { providers := map[string]provider.Client{} // Get the configs - configs, err := provider.GetConfig(*providerSettings) + configs, err := provider.GetConfig(providerSettings) if err != nil { log.Error(err, "unable to get configuration") os.Exit(1) @@ -78,7 +93,7 @@ func main() { continue } - if *treeOutput { + if treeOutput { deps, err := prov.GetDependenciesDAG() if err != nil { log.Error(err, "failed to get list of dependencies for provider", "provider", name) @@ -99,8 +114,8 @@ func main() { } for u, ds := range deps { newDeps := ds - if depLabelSelector != nil && *depLabelSelector != "" { - l, err := labels.NewLabelSelector[*konveyor.Dep](*depLabelSelector) + if depLabelSelector != "" { + l, err := labels.NewLabelSelector[*konveyor.Dep](depLabelSelector) if err != nil { panic(err) } @@ -124,7 +139,7 @@ func main() { } var b []byte - if *treeOutput { + if treeOutput { b, err = yaml.Marshal(depsTree) if err != nil { log.Error(err, "failed to marshal dependency data as yaml") @@ -149,15 +164,15 @@ func main() { fmt.Printf("%s", string(b)) - err = os.WriteFile(*outputFile, b, 0644) + err = os.WriteFile(outputFile, b, 0644) if err != nil { - log.Error(err, "failed to write dependencies to output file", "file", *outputFile) + log.Error(err, "failed to write dependencies to output file", "file", outputFile) os.Exit(1) } } func validateFlags() error { - _, err := os.Stat(*providerSettings) + _, err := os.Stat(providerSettings) if err != nil { return fmt.Errorf("unable to find provider settings file") } diff --git a/go.mod b/go.mod index 9661eb6d..b6a21e3c 100644 --- a/go.mod +++ b/go.mod @@ -19,9 +19,14 @@ require ( gopkg.in/yaml.v2 v2.4.0 ) +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.7.0 // indirect +) + require ( github.com/antchfx/xpath v1.2.4 - github.com/cbroglie/mustache v1.4.0 + github.com/cbroglie/mustache v1.3.0 github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/swag v0.19.5 // indirect diff --git a/go.sum b/go.sum index 56f95620..bdbe5411 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,11 @@ github.com/antchfx/xpath v1.2.4 h1:dW1HB/JxKvGtJ9WyVGJ0sIoEcqftV3SqIstujI+B9XY= github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/bombsimon/logrusr/v3 v3.0.0 h1:tcAoLfuAhKP9npBxWzSdpsvKPQt1XV02nSf2lZA82TQ= github.com/bombsimon/logrusr/v3 v3.0.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco= +github.com/cbroglie/mustache v1.3.0 h1:sj24GVYl8G7MH4b3zaROGsZnF8X79JqtjMx8/6H/nXM= +github.com/cbroglie/mustache v1.3.0/go.mod h1:w58RIHjw/L7DPyRX2CcCTduNmcP1dvztaHP72ciSfh0= github.com/cbroglie/mustache v1.4.0 h1:Azg0dVhxTml5me+7PsZ7WPrQq1Gkf3WApcHMjMprYoU= github.com/cbroglie/mustache v1.4.0/go.mod h1:SS1FTIghy0sjse4DUVGV1k/40B1qE1XkD9DtDsHo9iM= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -38,6 +41,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc= github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -54,10 +59,13 @@ github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1H github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=