customflags.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package utils
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. "os/user"
  7. "path/filepath"
  8. "strings"
  9. "github.com/codegangsta/cli"
  10. )
  11. // Custom type which is registered in the flags library which cli uses for
  12. // argument parsing. This allows us to expand Value to an absolute path when
  13. // the argument is parsed
  14. type DirectoryString struct {
  15. Value string
  16. }
  17. func (self DirectoryString) String() string {
  18. return self.Value
  19. }
  20. func (self DirectoryString) Set(value string) error {
  21. self.Value = expandPath(value)
  22. return nil
  23. }
  24. // Custom cli.Flag type which expand the received string to an absolute path.
  25. // e.g. ~/.ethereum -> /home/username/.ethereum
  26. type DirectoryFlag struct {
  27. cli.GenericFlag
  28. Name string
  29. Value DirectoryString
  30. Usage string
  31. EnvVar string
  32. }
  33. func (self DirectoryFlag) String() string {
  34. var fmtString string
  35. fmtString = "%s %v\t%v"
  36. if len(self.Value.Value) > 0 {
  37. fmtString = "%s \"%v\"\t%v"
  38. } else {
  39. fmtString = "%s %v\t%v"
  40. }
  41. return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage))
  42. }
  43. func eachName(longName string, fn func(string)) {
  44. parts := strings.Split(longName, ",")
  45. for _, name := range parts {
  46. name = strings.Trim(name, " ")
  47. fn(name)
  48. }
  49. }
  50. // called by cli library, grabs variable from environment (if in env)
  51. // and adds variable to flag set for parsing.
  52. func (self DirectoryFlag) Apply(set *flag.FlagSet) {
  53. if self.EnvVar != "" {
  54. for _, envVar := range strings.Split(self.EnvVar, ",") {
  55. envVar = strings.TrimSpace(envVar)
  56. if envVal := os.Getenv(envVar); envVal != "" {
  57. self.Value.Value = envVal
  58. break
  59. }
  60. }
  61. }
  62. eachName(self.Name, func(name string) {
  63. set.Var(self.Value, self.Name, "a: "+self.Usage)
  64. })
  65. }
  66. func prefixFor(name string) (prefix string) {
  67. if len(name) == 1 {
  68. prefix = "-"
  69. } else {
  70. prefix = "--"
  71. }
  72. return
  73. }
  74. func prefixedNames(fullName string) (prefixed string) {
  75. parts := strings.Split(fullName, ",")
  76. for i, name := range parts {
  77. name = strings.Trim(name, " ")
  78. prefixed += prefixFor(name) + name
  79. if i < len(parts)-1 {
  80. prefixed += ", "
  81. }
  82. }
  83. return
  84. }
  85. func withEnvHint(envVar, str string) string {
  86. envText := ""
  87. if envVar != "" {
  88. envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
  89. }
  90. return str + envText
  91. }
  92. func (self DirectoryFlag) getName() string {
  93. return self.Name
  94. }
  95. func (self *DirectoryFlag) Set(value string) {
  96. self.Value.Value = value
  97. }
  98. // Expands a file path
  99. // 1. replace tilde with users home dir
  100. // 2. expands embedded environment variables
  101. // 3. cleans the path, e.g. /a/b/../c -> /a/c
  102. // Note, it has limitations, e.g. ~someuser/tmp will not be expanded
  103. func expandPath(p string) string {
  104. if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
  105. if user, err := user.Current(); err == nil {
  106. if err == nil {
  107. p = strings.Replace(p, "~", user.HomeDir, 1)
  108. }
  109. }
  110. }
  111. return filepath.Clean(os.ExpandEnv(p))
  112. }