customflags.go 3.57 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.

17
package utils
18

19
import (
20 21 22 23 24 25 26 27
	"flag"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"github.com/codegangsta/cli"
28 29 30 31 32 33
)

// Custom type which is registered in the flags library which cli uses for
// argument parsing. This allows us to expand Value to an absolute path when
// the argument is parsed
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 43
	self.Value = expandPath(value)
	return nil
44 45 46 47 48
}

// Custom cli.Flag type which expand the received string to an absolute path.
// e.g. ~/.ethereum -> /home/username/.ethereum
type DirectoryFlag struct {
49 50 51 52 53
	cli.GenericFlag
	Name   string
	Value  DirectoryString
	Usage  string
	EnvVar string
54 55 56
}

func (self DirectoryFlag) String() string {
57 58
	var fmtString string
	fmtString = "%s %v\t%v"
59

60 61 62 63 64
	if len(self.Value.Value) > 0 {
		fmtString = "%s \"%v\"\t%v"
	} else {
		fmtString = "%s %v\t%v"
	}
65

66
	return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage))
67 68 69
}

func eachName(longName string, fn func(string)) {
70 71 72 73 74
	parts := strings.Split(longName, ",")
	for _, name := range parts {
		name = strings.Trim(name, " ")
		fn(name)
	}
75
}
76

77 78 79
// called by cli library, grabs variable from environment (if in env)
// and adds variable to flag set for parsing.
func (self DirectoryFlag) Apply(set *flag.FlagSet) {
80 81 82 83 84 85 86 87 88 89 90
	if self.EnvVar != "" {
		for _, envVar := range strings.Split(self.EnvVar, ",") {
			envVar = strings.TrimSpace(envVar)
			if envVal := os.Getenv(envVar); envVal != "" {
				self.Value.Value = envVal
				break
			}
		}
	}

	eachName(self.Name, func(name string) {
91
		set.Var(&self.Value, self.Name, self.Usage)
92
	})
93 94 95
}

func prefixFor(name string) (prefix string) {
96 97 98 99 100
	if len(name) == 1 {
		prefix = "-"
	} else {
		prefix = "--"
	}
101

102
	return
103 104 105
}

func prefixedNames(fullName string) (prefixed string) {
106 107 108 109 110 111 112 113 114
	parts := strings.Split(fullName, ",")
	for i, name := range parts {
		name = strings.Trim(name, " ")
		prefixed += prefixFor(name) + name
		if i < len(parts)-1 {
			prefixed += ", "
		}
	}
	return
115 116 117
}

func withEnvHint(envVar, str string) string {
118 119 120 121 122
	envText := ""
	if envVar != "" {
		envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
	}
	return str + envText
123 124 125
}

func (self DirectoryFlag) getName() string {
126
	return self.Name
127 128 129
}

func (self *DirectoryFlag) Set(value string) {
130
	self.Value.Value = value
131 132 133 134 135 136 137 138
}

// Expands a file path
// 1. replace tilde with users home dir
// 2. expands embedded environment variables
// 3. cleans the path, e.g. /a/b/../c -> /a/c
// Note, it has limitations, e.g. ~someuser/tmp will not be expanded
func expandPath(p string) string {
139 140 141 142 143 144 145 146 147
	if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
		if user, err := user.Current(); err == nil {
			if err == nil {
				p = strings.Replace(p, "~", user.HomeDir, 1)
			}
		}
	}

	return filepath.Clean(os.ExpandEnv(p))
148
}