github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/cmd/geth/flagdir.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "flag" 21 "fmt" 22 "os" 23 "os/user" 24 "path" 25 "strings" 26 27 "gopkg.in/urfave/cli.v1" 28 ) 29 30 // Custom type which is registered in the flags library which cli uses for 31 // argument parsing. This allows us to expand Value to an absolute path when 32 // the argument is parsed 33 type DirectoryString struct { 34 Value string 35 } 36 37 func (self *DirectoryString) String() string { 38 return self.Value 39 } 40 41 func (self *DirectoryString) Set(value string) error { 42 self.Value = expandPath(value) 43 return nil 44 } 45 46 // Custom cli.Flag type which expand the received string to an absolute path. 47 // e.g. ~/.ethereum -> /home/username/.ethereum 48 type DirectoryFlag struct { 49 cli.GenericFlag 50 Name string 51 Value DirectoryString 52 Usage string 53 EnvVar string 54 } 55 56 func (self DirectoryFlag) String() string { 57 var fmtString string 58 fmtString = "%s %v\t%v" 59 60 if len(self.Value.Value) > 0 { 61 fmtString = "%s \"%v\"\t%v" 62 } else { 63 fmtString = "%s %v\t%v" 64 } 65 66 return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage)) 67 } 68 69 func eachName(s string, fn func(string)) { 70 f := func(r rune) bool { return r == ',' || r == ' ' } 71 72 for _, name := range strings.FieldsFunc(s, f) { 73 fn(name) 74 } 75 } 76 77 // called by cli library, grabs variable from environment (if in env) 78 // and adds variable to flag set for parsing. 79 func (self DirectoryFlag) Apply(set *flag.FlagSet) { 80 if self.EnvVar != "" { 81 for _, envVar := range strings.Split(self.EnvVar, ",") { 82 envVar = strings.TrimSpace(envVar) 83 if envVal := os.Getenv(envVar); envVal != "" { 84 self.Value.Value = envVal 85 break 86 } 87 } 88 } 89 90 eachName(self.Name, func(name string) { 91 set.Var(&self.Value, name, self.Usage) 92 }) 93 } 94 95 func prefixFor(name string) (prefix string) { 96 if len(name) == 1 { 97 prefix = "-" 98 } else { 99 prefix = "--" 100 } 101 102 return 103 } 104 105 func prefixedNames(fullName string) (prefixed string) { 106 parts := strings.Split(fullName, ",") 107 for i, name := range parts { 108 name = strings.Trim(name, " ") 109 prefixed += prefixFor(name) + name 110 if i < len(parts)-1 { 111 prefixed += ", " 112 } 113 } 114 return 115 } 116 117 func withEnvHint(envVar, str string) string { 118 envText := "" 119 if envVar != "" { 120 envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $")) 121 } 122 return str + envText 123 } 124 125 func (self *DirectoryFlag) Set(value string) { 126 self.Value.Value = value 127 } 128 129 // Expands a file path 130 // 1. replace tilde with users home dir 131 // 2. expands embedded environment variables 132 // 3. cleans the path, e.g. /a/b/../c -> /a/c 133 // Note, it has limitations, e.g. ~someuser/tmp will not be expanded 134 func expandPath(p string) string { 135 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 136 if user, err := user.Current(); err == nil { 137 p = user.HomeDir + p[1:] 138 } 139 } 140 return path.Clean(os.ExpandEnv(p)) 141 }