customflags.go 3.6 KB

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