github.com/VMitov/casper@v0.4.0/cmd/casper/flags.go (about) 1 package main 2 3 import ( 4 "flag" 5 "net/url" 6 "path/filepath" 7 "strings" 8 "syscall" 9 10 "github.com/pkg/errors" 11 cli "gopkg.in/urfave/cli.v2" 12 "gopkg.in/urfave/cli.v2/altsrc" 13 ) 14 15 // sourcesSliceFlag is the flag type that wraps cli.sourcesSliceFlag to allow 16 // for other values to be specified 17 type sourcesSliceFlag struct { 18 *cli.StringSliceFlag 19 set *flag.FlagSet 20 } 21 22 // newSourcesSliceFlag creates a new StringSliceFlag 23 func newSourcesSliceFlag(fl *cli.StringSliceFlag) *sourcesSliceFlag { 24 return &sourcesSliceFlag{StringSliceFlag: fl, set: nil} 25 } 26 27 // Apply saves the flagSet for later usage calls, then calls the 28 // wrapped StringSliceFlag.Apply 29 func (f *sourcesSliceFlag) Apply(set *flag.FlagSet) { 30 f.set = set 31 f.StringSliceFlag.Apply(set) 32 } 33 34 // ApplyWithError saves the flagSet for later usage calls, then calls the 35 // wrapped StringSliceFlag.ApplyWithError 36 func (f *sourcesSliceFlag) ApplyWithError(set *flag.FlagSet) error { 37 f.set = set 38 return f.StringSliceFlag.ApplyWithError(set) 39 } 40 41 // ApplyInputSourceValue applies a StringSlice value to the flagSet if required 42 func (f *sourcesSliceFlag) ApplyInputSourceValue(context *cli.Context, isc altsrc.InputSourceContext) error { 43 if f.set != nil { 44 if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVars) { 45 value, err := isc.StringSlice(f.StringSliceFlag.Name) 46 if err != nil { 47 return err 48 } 49 50 dir, err := getConfigDir(context) 51 if err != nil { 52 return err 53 } 54 55 value, err = fixPathsForSources(dir, value) 56 if err != nil { 57 return err 58 } 59 60 if value != nil { 61 sliceValue := *(cli.NewStringSlice(value...)) 62 for _, name := range f.Names() { 63 underlyingFlag := f.set.Lookup(name) 64 if underlyingFlag != nil { 65 underlyingFlag.Value = &sliceValue 66 } 67 } 68 } 69 } 70 } 71 return nil 72 } 73 74 func getConfigDir(context *cli.Context) (string, error) { 75 configPath := context.String(configFlag) 76 inputSourcePath, err := filepath.Abs(configPath) 77 if err != nil { 78 return "", errors.Wrapf(err, "resolving absolute path for config %v failed", configPath) 79 } 80 81 return filepath.Dir(inputSourcePath), nil 82 } 83 84 func fixPathsForSources(dir string, value []string) ([]string, error) { 85 for i, v := range value { 86 fixed, err := fixPathsForSource(dir, v) 87 if err != nil { 88 return value, err 89 } 90 if fixed != v { 91 value[i] = fixed 92 } 93 } 94 return value, nil 95 } 96 97 func fixPathsForSource(dir, value string) (string, error) { 98 u, err := url.Parse(value) 99 if err != nil { 100 return "", errors.Wrapf(err, "parsing source %v failed", value) 101 } 102 103 if u.Scheme == "file" { 104 fixed, err := fixPathsForFileSource(dir, u) 105 if err != nil { 106 return "", errors.Wrapf(err, "converting file source path %v to absolute failed", u) 107 } 108 109 return fixed, nil 110 } 111 112 return value, nil 113 } 114 115 func fixPathsForFileSource(dir string, u *url.URL) (string, error) { 116 path := u.Host + u.Path 117 if strings.HasPrefix(path, "/") { 118 return u.String(), nil 119 } 120 121 var err error 122 u.Path, err = url.PathUnescape(filepath.Join(dir, path)) 123 if err != nil { 124 return "", err 125 } 126 127 u.Host = "" 128 return u.String(), nil 129 } 130 131 func isEnvVarSet(envVars []string) bool { 132 for _, envVar := range envVars { 133 if _, ok := syscall.Getenv(envVar); ok { 134 // TODO: Can't use this for bools as 135 // set means that it was true or false based on 136 // Bool flag type, should work for other types 137 return true 138 } 139 } 140 141 return false 142 }