func Execute() {
	if err := RootCmd.Execute(); err != nil {
		log.Error(err)
		log.Error("Lift aborted")
		os.Exit(-1)
	}
}
Execute adds all child commands to the root command and sets flags appropriately.
This is called by main.main(). It only needs to happen once to the rootCmd.
package cmd
import (
	"fmt"
	"os"
	"strings"
	"github.com/bjwschaap/alpine-lift/pkg/lift"
	homedir "github.com/mitchellh/go-homedir"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)
var (
	RootCmd = &cobra.Command{
		Use:     "lift",
		Version: fmt.Sprintf("%s-%s (built by %s on %s)", version, gitTag, buildUser, buildDate),
		Short:   "A cloud-init alternative for Alpine Linux",
		Long:    `Lift performs initial OS configuration on first boot.`,
		Run: func(cmd *cobra.Command, args []string) {
			if viper.GetBool("debug") {
				log.SetLevel(log.DebugLevel)
			}
			if viper.GetBool("no-color") {
				logFormat = log.TextFormatter{
					ForceColors:     false,
					DisableColors:   true,
					FullTimestamp:   true,
					TimestampFormat: "2006-01-02T15:04:05.999999999",
				}
			}
			if viper.GetBool("json") {
				log.SetFormatter(&log.JSONFormatter{})
			}
			headers := make(map[string][]string)
			for _, h := range viper.GetStringSlice("request-headers") {
				words := strings.SplitN(h, ":", 2)
				key := strings.TrimSpace(words[0])
				value := strings.TrimSpace(words[1])
				if key == "" || value == "" {
					log.Errorf("Invalid request header: %s", h)
					log.Error("Lift aborted")
					os.Exit(1)
				}
				headers[key] = append(headers[key], value)
			}
			lift, err := lift.New(viper.GetString("alpine-data-url"), headers)
			if err != nil {
				log.Error(err)
				log.Error("Lift aborted")
				os.Exit(1)
			}
			if err = lift.Start(); err != nil {
				log.Error(err)
				log.Error("Lift aborted")
				os.Exit(1)
			}
		},
	}
	logFormat = log.TextFormatter{
		ForceColors:     true,
		DisableColors:   false,
		FullTimestamp:   true,
		TimestampFormat: "2006-01-02T15:04:05.999999999",
	}
	cfgFile string
	dataURL string
	headers []string
	debug   bool
	json    bool
	nocolor bool
)
func init() {
	log.SetOutput(os.Stdout)
	log.SetFormatter(&logFormat)
	log.SetLevel(log.InfoLevel)
	cobra.OnInitialize(initConfig)
	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (e.g. $HOME/.lift)")
	RootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "enable debug logging")
	RootCmd.PersistentFlags().BoolVar(&nocolor, "no-color", false, "disable colors in logging")
	RootCmd.PersistentFlags().BoolVarP(&json, "json", "j", false, "Log output in JSON format")
	RootCmd.PersistentFlags().StringVarP(&dataURL, "alpine-data-url", "s", "", "URL to download alpine-data")
	RootCmd.PersistentFlags().StringArrayVarP(&headers, "request-header", "H", nil, "HTTP header(s) to include in request, akin to curl's -H")
	_ = viper.BindPFlag("debug", RootCmd.PersistentFlags().Lookup("debug"))
	_ = viper.BindPFlag("alpine-data-url", RootCmd.PersistentFlags().Lookup("alpine-data-url"))
	_ = viper.BindPFlag("request-header", RootCmd.PersistentFlags().Lookup("request-header"))
	_ = viper.BindPFlag("json", RootCmd.PersistentFlags().Lookup("json"))
	_ = viper.BindPFlag("no-color", RootCmd.PersistentFlags().Lookup("no-color"))
}
func initConfig() {
	viper.SetEnvPrefix("lift")
	viper.AutomaticEnv()
	if cfgFile != "" {
		viper.SetConfigFile(cfgFile)
	} else {
		home, err := homedir.Dir()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		viper.AddConfigPath("/etc/lift/")
		viper.AddConfigPath(fmt.Sprintf("%s/.lift/", home))
		viper.AddConfigPath(".")
		viper.SetConfigName("config")
	}
	if err := viper.ReadInConfig(); err != nil {
	}
}