-
Notifications
You must be signed in to change notification settings - Fork 45
/
root.go
150 lines (126 loc) · 4.46 KB
/
root.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package cmd
import (
"fmt"
"os"
"strings"
"github.com/devops-works/binenv/internal/app"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
const (
// The environment variable prefix of all environment variables bound to our command line flags.
envPrefix = "BINENV"
)
// RootCmd returns the root cobra command
func RootCmd() *cobra.Command {
var (
bindir, linkdir, cachedir, confdir string
global, verbose bool
)
a, err := app.New()
if err != nil {
panic(err)
}
rootCmd := &cobra.Command{
Use: "binenv",
Short: "Install binary distributions easily",
Long: `binenv lets you install binary-distributed applications
(e.g. terraform, kubectl, ...) easily and switch between any version.
If your directory has a '.binenv.lock', proper versions will always be
selected.`,
SilenceUsage: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
err := initializeConfig(cmd.Root())
a.SetVerbose(verbose)
// Set defaults or explicitely set directories
a.SetBinDir(bindir)
a.SetLinkDir(linkdir)
a.SetConfigDir(confdir)
a.SetCacheDir(cachedir)
// Apply dir changes for global mode
a.SetGlobal(global)
// If some directories have been set explicitely, overwrite them
// otherwise we keep preceding setting
if cmd.Root().PersistentFlags().Lookup("bindir").Changed {
a.SetBinDir(bindir)
}
// if options has been changed by flag or env, we apply it
// otherwise we keep preceding setting
if cmd.Root().PersistentFlags().Lookup("linkdir").Changed {
a.SetLinkDir(linkdir)
}
// if options has been changed by flag or env, we apply it
// otherwise we keep preceding setting
if cmd.Root().PersistentFlags().Lookup("confdir").Changed {
a.SetConfigDir(confdir)
}
// if options has been changed by flag or env, we apply it
// otherwise we keep preceding setting
if cmd.Root().PersistentFlags().Lookup("cachedir").Changed {
a.SetCacheDir(cachedir)
}
a.Init()
if err != nil {
fmt.Printf("got error %v\n", err)
panic(err)
}
return err
},
Run: func(cmd *cobra.Command, args []string) {
if !strings.HasSuffix(os.Args[0], "binenv") {
a.Execute(os.Args)
}
},
}
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose operation [BINENV_VERBOSE]")
rootCmd.PersistentFlags().BoolVarP(&global, "global", "g", false, "global mode [BINENV_GLOBAL]")
rootCmd.PersistentFlags().StringVarP(&bindir, "bindir", "B", app.GetDefaultBinDir(), "binaries directory [BINENV_BINDIR]")
rootCmd.PersistentFlags().StringVarP(&linkdir, "linkdir", "L", app.GetDefaultLinkDir(), "link directory [BINENV_LINKDIR]")
rootCmd.PersistentFlags().StringVarP(&cachedir, "cachedir", "K", app.GetDefaultCacheDir(), "cache directory [BINENV_CACHEDIR]")
rootCmd.PersistentFlags().StringVarP(&confdir, "confdir", "C", app.GetDefaultConfDir(), "distributions configuration directory [BINENV_CONFDIR]")
rootCmd.AddCommand(
completionCmd(),
expandCmd(a),
installCmd(a),
localCmd(a),
searchCmd(a),
uninstallCmd(a),
updateCmd(a),
versionCmd(),
versionsCmd(a),
upgradeCmd(a),
)
return rootCmd
}
func initializeConfig(cmd *cobra.Command) error {
v := viper.New()
// When we bind flags to environment variables expect that the
// environment variables are prefixed, e.g. a flag like --number
// binds to an environment variable STING_NUMBER. This helps
// avoid conflicts.
v.SetEnvPrefix("BINENV")
// Bind to environment variables
// Works great for simple config names, but needs help for names
// like --favorite-color which we fix in the bindFlags function
v.AutomaticEnv()
// Bind the current command's flags to viper
bindFlags(cmd, v)
return nil
}
// Bind each cobra flag to its associated viper configuration (config file and environment variable)
func bindFlags(cmd *cobra.Command, v *viper.Viper) {
cmd.PersistentFlags().VisitAll(func(f *pflag.Flag) {
// Environment variables can't have dashes in them, so bind them to their equivalent
// keys with underscores, e.g. --favorite-color to STING_FAVORITE_COLOR
if strings.Contains(f.Name, "-") {
envVarSuffix := strings.ToUpper(strings.ReplaceAll(f.Name, "-", "_"))
v.BindEnv(f.Name, fmt.Sprintf("%s_%s", envPrefix, envVarSuffix))
}
// Apply the viper config value to the flag when the flag is not set and viper has a value
if !f.Changed && v.IsSet(f.Name) {
val := v.Get(f.Name)
cmd.PersistentFlags().Set(f.Name, fmt.Sprintf("%v", val))
}
})
}