github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/cmdconfig/builder.go (about)

     1  package cmdconfig
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  
     7  	"github.com/spf13/cobra"
     8  	"github.com/spf13/pflag"
     9  	"github.com/spf13/viper"
    10  	"github.com/turbot/steampipe/pkg/constants"
    11  	"github.com/turbot/steampipe/pkg/error_helpers"
    12  	"github.com/turbot/steampipe/pkg/utils"
    13  )
    14  
    15  type CmdBuilder struct {
    16  	cmd      *cobra.Command
    17  	bindings map[string]*pflag.Flag
    18  }
    19  
    20  // OnCmd starts a config builder wrapping over the provided *cobra.Command
    21  func OnCmd(cmd *cobra.Command) *CmdBuilder {
    22  	cfg := new(CmdBuilder)
    23  	cfg.cmd = cmd
    24  	cfg.bindings = map[string]*pflag.Flag{}
    25  
    26  	// we will wrap over these two function - need references to call them
    27  	originalPreRun := cfg.cmd.PreRun
    28  	cfg.cmd.PreRun = func(cmd *cobra.Command, args []string) {
    29  		utils.LogTime(fmt.Sprintf("cmd.%s.PreRun start", cmd.CommandPath()))
    30  		defer utils.LogTime(fmt.Sprintf("cmd.%s.PreRun end", cmd.CommandPath()))
    31  		// bind flags
    32  		for flagName, flag := range cfg.bindings {
    33  			if flag == nil {
    34  				// we can panic here since this is bootstrap code and not execution path specific
    35  				panic(fmt.Sprintf("flag for %s cannot be nil", flagName))
    36  			}
    37  			//nolint:golint,errcheck // nil check above
    38  			viper.GetViper().BindPFlag(flagName, flag)
    39  		}
    40  
    41  		// now that we have done all the flag bindings, run the global pre run
    42  		// this will load up and populate the global config, init the logger and
    43  		// also run the daily task runner
    44  		preRunHook(cmd, args)
    45  
    46  		// run the original PreRun
    47  		if originalPreRun != nil {
    48  			originalPreRun(cmd, args)
    49  		}
    50  	}
    51  
    52  	originalPostRun := cfg.cmd.PostRun
    53  	cfg.cmd.PostRun = func(cmd *cobra.Command, args []string) {
    54  		utils.LogTime(fmt.Sprintf("cmd.%s.PostRun start", cmd.CommandPath()))
    55  		defer utils.LogTime(fmt.Sprintf("cmd.%s.PostRun end", cmd.CommandPath()))
    56  		// run the original PostRun
    57  		if originalPostRun != nil {
    58  			originalPostRun(cmd, args)
    59  		}
    60  
    61  		// run the post run
    62  		postRunHook(cmd, args)
    63  	}
    64  
    65  	// wrap over the original Run function
    66  	originalRun := cfg.cmd.Run
    67  	cfg.cmd.Run = func(cmd *cobra.Command, args []string) {
    68  		utils.LogTime(fmt.Sprintf("cmd.%s.Run start", cmd.CommandPath()))
    69  		defer utils.LogTime(fmt.Sprintf("cmd.%s.Run end", cmd.CommandPath()))
    70  
    71  		// run the original Run
    72  		if originalRun != nil {
    73  			originalRun(cmd, args)
    74  		}
    75  	}
    76  
    77  	return cfg
    78  }
    79  
    80  // AddStringFlag is a helper function to add a string flag to a command
    81  func (c *CmdBuilder) AddStringFlag(name string, defaultValue string, desc string, opts ...FlagOption) *CmdBuilder {
    82  	c.cmd.Flags().String(name, defaultValue, desc)
    83  	c.bindings[name] = c.cmd.Flags().Lookup(name)
    84  	for _, o := range opts {
    85  		o(c.cmd, name, name)
    86  	}
    87  
    88  	return c
    89  }
    90  
    91  // AddIntFlag is a helper function to add an integer flag to a command
    92  func (c *CmdBuilder) AddIntFlag(name string, defaultValue int, desc string, opts ...FlagOption) *CmdBuilder {
    93  	c.cmd.Flags().Int(name, defaultValue, desc)
    94  	c.bindings[name] = c.cmd.Flags().Lookup(name)
    95  	for _, o := range opts {
    96  		o(c.cmd, name, name)
    97  	}
    98  	return c
    99  }
   100  
   101  // AddBoolFlag ia s helper function to add a boolean flag to a command
   102  func (c *CmdBuilder) AddBoolFlag(name string, defaultValue bool, desc string, opts ...FlagOption) *CmdBuilder {
   103  	c.cmd.Flags().Bool(name, defaultValue, desc)
   104  	c.bindings[name] = c.cmd.Flags().Lookup(name)
   105  	for _, o := range opts {
   106  		o(c.cmd, name, name)
   107  	}
   108  	return c
   109  }
   110  
   111  // AddCloudFlags is helper function to add the cloud flags to a command
   112  func (c *CmdBuilder) AddCloudFlags() *CmdBuilder {
   113  	return c.
   114  		AddStringFlag(constants.ArgPipesHost, constants.DefaultPipesHost, "Turbot Pipes host").
   115  		AddStringFlag(constants.ArgPipesToken, "", "Turbot Pipes authentication token").
   116  		AddStringFlag(constants.ArgCloudHost, constants.DefaultPipesHost, "Turbot Pipes host", FlagOptions.Deprecated(constants.ArgPipesHost)).
   117  		AddStringFlag(constants.ArgCloudToken, "", "Turbot Pipes authentication token", FlagOptions.Deprecated(constants.ArgPipesToken))
   118  }
   119  
   120  // AddWorkspaceDatabaseFlag is helper function to add the workspace-databse flag to a command
   121  func (c *CmdBuilder) AddWorkspaceDatabaseFlag() *CmdBuilder {
   122  	return c.
   123  		AddStringFlag(constants.ArgWorkspaceDatabase, constants.DefaultWorkspaceDatabase, "Turbot Pipes workspace database")
   124  }
   125  
   126  // AddModLocationFlag is helper function to add the mod-location flag to a command
   127  func (c *CmdBuilder) AddModLocationFlag() *CmdBuilder {
   128  	cwd, err := os.Getwd()
   129  	error_helpers.FailOnError(err)
   130  	return c.
   131  		AddStringFlag(constants.ArgModLocation, cwd, "Path to the workspace working directory")
   132  }
   133  
   134  // AddStringSliceFlag is a helper function to add a flag that accepts an array of strings
   135  func (c *CmdBuilder) AddStringSliceFlag(name string, defaultValue []string, desc string, opts ...FlagOption) *CmdBuilder {
   136  	c.cmd.Flags().StringSlice(name, defaultValue, desc)
   137  	c.bindings[name] = c.cmd.Flags().Lookup(name)
   138  	for _, o := range opts {
   139  		o(c.cmd, name, name)
   140  	}
   141  	return c
   142  }
   143  
   144  // AddStringArrayFlag is a helper function to add a flag that accepts an array of strings
   145  func (c *CmdBuilder) AddStringArrayFlag(name string, defaultValue []string, desc string, opts ...FlagOption) *CmdBuilder {
   146  	c.cmd.Flags().StringArray(name, defaultValue, desc)
   147  	c.bindings[name] = c.cmd.Flags().Lookup(name)
   148  	for _, o := range opts {
   149  		o(c.cmd, name, name)
   150  	}
   151  	return c
   152  }
   153  
   154  // AddStringMapStringFlag is a helper function to add a flag that accepts a map of strings
   155  func (c *CmdBuilder) AddStringMapStringFlag(name string, defaultValue map[string]string, desc string, opts ...FlagOption) *CmdBuilder {
   156  	c.cmd.Flags().StringToString(name, defaultValue, desc)
   157  	c.bindings[name] = c.cmd.Flags().Lookup(name)
   158  	for _, o := range opts {
   159  		o(c.cmd, name, name)
   160  	}
   161  	return c
   162  }
   163  
   164  func (c *CmdBuilder) AddVarFlag(value pflag.Value, name string, usage string, opts ...FlagOption) *CmdBuilder {
   165  	c.cmd.Flags().Var(value, name, usage)
   166  
   167  	c.bindings[name] = c.cmd.Flags().Lookup(name)
   168  	for _, o := range opts {
   169  		o(c.cmd, name, name)
   170  	}
   171  
   172  	//
   173  	return c
   174  }