2020-12-09 15:31:34 +00:00
package cmd
import (
"os"
"strings"
"github.com/sirupsen/logrus"
2021-12-06 13:29:39 +00:00
"github.com/snyk/driftctl/build"
"github.com/snyk/driftctl/pkg"
"github.com/snyk/driftctl/sentry"
2020-12-09 15:31:34 +00:00
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
var usageTemplate = ` Usage : { { . UseLine } } { { if . HasAvailableSubCommands } }
COMMANDS : { { range . Commands } } { { if . IsAvailableCommand } }
{ { rpad . Name 24 } } { { . Short } } { { end } } { { end } } { { end } } { { if . HasAvailableLocalFlags } }
FLAGS :
{ { . LocalFlags . FlagUsages | trimTrailingWhitespaces } } { { end } } { { if . HasAvailableInheritedFlags } }
INHERITED FLAGS :
{ { . InheritedFlags . FlagUsages | trimTrailingWhitespaces } } { { end } } { { if . HasAvailableSubCommands } }
LEARN MORE :
Use "{{.CommandPath}} <command> --help" for more information about a command { { end } }
`
var versionTemplate = ` {{ printf "%s\n" .Version }} `
type DriftctlCmd struct {
cobra . Command
build build . BuildInterface
}
func NewDriftctlCmd ( build build . BuildInterface ) * DriftctlCmd {
cmd := & DriftctlCmd {
cobra . Command {
Use : "driftctl <command> [flags]" ,
Short : "Driftctl CLI" ,
PersistentPreRunE : func ( cmd * cobra . Command , args [ ] string ) error {
2021-01-04 17:28:40 +00:00
err := bindEnvToFlags ( cmd )
if err != nil {
return err
}
return handleReporting ( cmd )
2020-12-09 15:31:34 +00:00
} ,
Long : "Detect, track and alert on infrastructure drift." ,
SilenceErrors : true ,
2021-01-27 18:12:25 +00:00
SilenceUsage : true ,
2020-12-09 15:31:34 +00:00
} ,
build ,
}
cmd . SetVersionTemplate ( versionTemplate )
cmd . AddCommand ( NewVersionCmd ( ) )
2021-01-20 13:04:33 +00:00
cmd . AddCommand ( NewCompletionCmd ( ) )
2020-12-09 15:31:34 +00:00
cmd . SetUsageTemplate ( usageTemplate )
cmd . PersistentFlags ( ) . BoolP ( "help" , "h" , false , "Display help for command" )
2021-11-25 14:07:50 +00:00
if cmd . build . IsUsageReportingEnabled ( ) {
cmd . PersistentFlags ( ) . BoolP ( "no-version-check" , "" , false , "Disable the version check" )
cmd . PersistentFlags ( ) . BoolP ( "disable-telemetry" , "" , false , "Disable telemetry" )
}
2021-04-12 19:05:08 +00:00
cmd . PersistentFlags ( ) . BoolP ( "send-crash-report" , "" , false , "Enable error reporting. Crash data will be sent to us via Sentry.\nWARNING: may leak sensitive data (please read the documentation for more details)\nThis flag should be used only if an error occurs during execution" )
2020-12-09 15:31:34 +00:00
2021-09-30 13:32:08 +00:00
cmd . AddCommand ( NewScanCmd ( & pkg . ScanOptions { } ) )
2022-03-04 09:20:24 +00:00
cmd . AddCommand ( NewFmtCmd ( & pkg . FmtOptions { } ) )
2021-05-04 15:08:54 +00:00
cmd . AddCommand ( NewGenDriftIgnoreCmd ( ) )
2020-12-09 15:31:34 +00:00
return cmd
}
func contains ( args [ ] string , cmd string ) bool {
for _ , arg := range args {
if arg == cmd {
return true
}
}
return false
}
func ( driftctlCmd DriftctlCmd ) ShouldCheckVersion ( ) bool {
2021-01-29 09:15:31 +00:00
_ , noVersionCheckEnv := os . LookupEnv ( "DCTL_NO_VERSION_CHECK" )
2020-12-09 15:31:34 +00:00
noVersionCheckVal := contains ( os . Args [ 1 : ] , "--no-version-check" )
hasVersionCmd := contains ( os . Args [ 1 : ] , "version" )
2021-01-20 13:04:33 +00:00
hasCompletionCmd := contains ( os . Args [ 1 : ] , "completion" )
2020-12-09 15:31:34 +00:00
isHelp := contains ( os . Args [ 1 : ] , "help" ) || contains ( os . Args [ 1 : ] , "--help" ) || contains ( os . Args [ 1 : ] , "-h" )
2021-11-25 14:07:50 +00:00
return driftctlCmd . build . IsRelease ( ) && driftctlCmd . build . IsUsageReportingEnabled ( ) && ! hasVersionCmd && ! hasCompletionCmd && ! noVersionCheckVal && ! isHelp && ! noVersionCheckEnv
2020-12-09 15:31:34 +00:00
}
2021-01-04 17:28:40 +00:00
func IsReportingEnabled ( cmd * cobra . Command ) bool {
2021-04-12 16:21:16 +00:00
enableReporting , err := cmd . Flags ( ) . GetBool ( "send-crash-report" )
2021-01-04 17:28:40 +00:00
if err != nil {
return false
}
return enableReporting
}
func handleReporting ( cmd * cobra . Command ) error {
if IsReportingEnabled ( cmd ) {
2021-02-09 19:03:35 +00:00
return sentry . Initialize ( )
2021-01-04 17:28:40 +00:00
}
return nil
}
2020-12-09 15:31:34 +00:00
// Iterate over command flags
// If the command flag is not manually set (f.Changed) we override its value
// from the according env value
func bindEnvToFlags ( cmd * cobra . Command ) error {
var err error
cmd . Flags ( ) . VisitAll ( func ( f * pflag . Flag ) {
if err != nil {
return
}
2020-12-17 10:10:33 +00:00
// Ignore some global flags
// no-version-check is ignored because we don't use cmd flags to retrieve flag in version check function
// as we check version before cmd, we use os.Args
if f . Name == "help" || f . Name == "no-version-check" {
return
}
2020-12-09 15:31:34 +00:00
envKey := strings . ReplaceAll ( f . Name , "-" , "_" )
// Apply the viper config value to the flag when the flag is not set and viper has a value
// Allow flags precedence over env variables
if ! f . Changed && viper . IsSet ( envKey ) {
envVal := viper . GetString ( envKey )
2020-12-17 10:10:33 +00:00
err = cmd . Flags ( ) . Set ( f . Name , envVal )
2020-12-09 15:31:34 +00:00
if err != nil {
return
}
logrus . WithFields ( logrus . Fields {
"env" : envKey ,
"flag" : f . Name ,
"value" : envVal ,
} ) . Debug ( "Bound environment variable to flag" )
}
} )
return err
}