github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/cmd/root.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/mattn/go-isatty"
     9  	"github.com/spf13/cobra"
    10  	"github.com/spf13/viper"
    11  	filehelpers "github.com/turbot/go-kit/files"
    12  	"github.com/turbot/steampipe/pkg/constants"
    13  	"github.com/turbot/steampipe/pkg/error_helpers"
    14  	"github.com/turbot/steampipe/pkg/filepaths"
    15  	"github.com/turbot/steampipe/pkg/statushooks"
    16  	"github.com/turbot/steampipe/pkg/utils"
    17  	"github.com/turbot/steampipe/pkg/version"
    18  )
    19  
    20  var exitCode int
    21  
    22  // rootCmd represents the base command when called without any subcommands
    23  var rootCmd = &cobra.Command{
    24  	Use:     "steampipe [--version] [--help] COMMAND [args]",
    25  	Version: version.SteampipeVersion.String(),
    26  	Short:   "Query cloud resources using SQL",
    27  	Long: `Steampipe: select * from cloud;
    28  
    29  Dynamically query APIs, code and more with SQL.
    30  Zero-ETL from 140+ data sources.
    31  	
    32  Common commands:
    33  	
    34    # Interactive SQL query console
    35    steampipe query
    36  	
    37    # Install a plugin from the hub - https://hub.steampipe.io
    38    steampipe plugin install aws
    39  
    40    # Execute a defined SQL query
    41    steampipe query "select * from aws_s3_bucket"
    42  
    43    # Get help for a command
    44    steampipe help query
    45  	
    46  Documentation: https://steampipe.io/docs
    47   `,
    48  }
    49  
    50  func InitCmd() {
    51  	utils.LogTime("cmd.root.InitCmd start")
    52  	defer utils.LogTime("cmd.root.InitCmd end")
    53  
    54  	defaultInstallDir, err := filehelpers.Tildefy(filepaths.DefaultInstallDir)
    55  	error_helpers.FailOnError(err)
    56  	rootCmd.SetVersionTemplate(fmt.Sprintf("Steampipe v%s\n", version.SteampipeVersion.String()))
    57  
    58  	// global flags
    59  	rootCmd.PersistentFlags().String(constants.ArgWorkspaceProfile, "default", "The workspace profile to use") // workspace profile profile is a global flag since install-dir(global) can be set through the workspace profile
    60  	rootCmd.PersistentFlags().String(constants.ArgInstallDir, defaultInstallDir, "Path to the Config Directory")
    61  	rootCmd.PersistentFlags().Bool(constants.ArgSchemaComments, true, "Include schema comments when importing connection schemas")
    62  
    63  	error_helpers.FailOnError(viper.BindPFlag(constants.ArgInstallDir, rootCmd.PersistentFlags().Lookup(constants.ArgInstallDir)))
    64  	error_helpers.FailOnError(viper.BindPFlag(constants.ArgWorkspaceProfile, rootCmd.PersistentFlags().Lookup(constants.ArgWorkspaceProfile)))
    65  	error_helpers.FailOnError(viper.BindPFlag(constants.ArgSchemaComments, rootCmd.PersistentFlags().Lookup(constants.ArgSchemaComments)))
    66  
    67  	AddCommands()
    68  
    69  	// disable auto completion generation, since we don't want to support
    70  	// powershell yet - and there's no way to disable powershell in the default generator
    71  	rootCmd.CompletionOptions.DisableDefaultCmd = true
    72  	rootCmd.Flags().BoolP(constants.ArgHelp, "h", false, "Help for steampipe")
    73  	rootCmd.Flags().BoolP(constants.ArgVersion, "v", false, "Version for steampipe")
    74  
    75  	hideRootFlags(constants.ArgSchemaComments)
    76  
    77  	// tell OS to reclaim memory immediately
    78  	os.Setenv("GODEBUG", "madvdontneed=1")
    79  
    80  }
    81  
    82  func hideRootFlags(flags ...string) {
    83  	for _, flag := range flags {
    84  		rootCmd.Flag(flag).Hidden = true
    85  	}
    86  }
    87  
    88  func AddCommands() {
    89  	// explicitly initialise commands here rather than in init functions to allow us to handle errors from the config load
    90  	rootCmd.AddCommand(
    91  		pluginCmd(),
    92  		queryCmd(),
    93  		checkCmd(),
    94  		serviceCmd(),
    95  		modCmd(),
    96  		generateCompletionScriptsCmd(),
    97  		pluginManagerCmd(),
    98  		dashboardCmd(),
    99  		variableCmd(),
   100  		loginCmd(),
   101  	)
   102  }
   103  
   104  func Execute() int {
   105  	utils.LogTime("cmd.root.Execute start")
   106  	defer utils.LogTime("cmd.root.Execute end")
   107  
   108  	ctx := createRootContext()
   109  
   110  	rootCmd.ExecuteContext(ctx)
   111  	return exitCode
   112  }
   113  
   114  // create the root context - add a status renderer
   115  func createRootContext() context.Context {
   116  	statusRenderer := statushooks.NullHooks
   117  	// if the client is a TTY, inject a status spinner
   118  	if isatty.IsTerminal(os.Stdout.Fd()) {
   119  		statusRenderer = statushooks.NewStatusSpinnerHook()
   120  	}
   121  
   122  	ctx := statushooks.AddStatusHooksToContext(context.Background(), statusRenderer)
   123  	return ctx
   124  }