OSDN Git Service

add package
[bytom/vapor.git] / vendor / github.com / mitchellh / go-homedir / homedir.go
1 package homedir
2
3 import (
4         "bytes"
5         "errors"
6         "os"
7         "os/exec"
8         "path/filepath"
9         "runtime"
10         "strconv"
11         "strings"
12         "sync"
13 )
14
15 // DisableCache will disable caching of the home directory. Caching is enabled
16 // by default.
17 var DisableCache bool
18
19 var homedirCache string
20 var cacheLock sync.RWMutex
21
22 // Dir returns the home directory for the executing user.
23 //
24 // This uses an OS-specific method for discovering the home directory.
25 // An error is returned if a home directory cannot be detected.
26 func Dir() (string, error) {
27         if !DisableCache {
28                 cacheLock.RLock()
29                 cached := homedirCache
30                 cacheLock.RUnlock()
31                 if cached != "" {
32                         return cached, nil
33                 }
34         }
35
36         cacheLock.Lock()
37         defer cacheLock.Unlock()
38
39         var result string
40         var err error
41         if runtime.GOOS == "windows" {
42                 result, err = dirWindows()
43         } else {
44                 // Unix-like system, so just assume Unix
45                 result, err = dirUnix()
46         }
47
48         if err != nil {
49                 return "", err
50         }
51         homedirCache = result
52         return result, nil
53 }
54
55 // Expand expands the path to include the home directory if the path
56 // is prefixed with `~`. If it isn't prefixed with `~`, the path is
57 // returned as-is.
58 func Expand(path string) (string, error) {
59         if len(path) == 0 {
60                 return path, nil
61         }
62
63         if path[0] != '~' {
64                 return path, nil
65         }
66
67         if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
68                 return "", errors.New("cannot expand user-specific home dir")
69         }
70
71         dir, err := Dir()
72         if err != nil {
73                 return "", err
74         }
75
76         return filepath.Join(dir, path[1:]), nil
77 }
78
79 // Reset clears the cache, forcing the next call to Dir to re-detect
80 // the home directory. This generally never has to be called, but can be
81 // useful in tests if you're modifying the home directory via the HOME
82 // env var or something.
83 func Reset() {
84         cacheLock.Lock()
85         defer cacheLock.Unlock()
86         homedirCache = ""
87 }
88
89 func dirUnix() (string, error) {
90         homeEnv := "HOME"
91         if runtime.GOOS == "plan9" {
92                 // On plan9, env vars are lowercase.
93                 homeEnv = "home"
94         }
95
96         // First prefer the HOME environmental variable
97         if home := os.Getenv(homeEnv); home != "" {
98                 return home, nil
99         }
100
101         var stdout bytes.Buffer
102
103         // If that fails, try OS specific commands
104         if runtime.GOOS == "darwin" {
105                 cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`)
106                 cmd.Stdout = &stdout
107                 if err := cmd.Run(); err == nil {
108                         result := strings.TrimSpace(stdout.String())
109                         if result != "" {
110                                 return result, nil
111                         }
112                 }
113         } else {
114                 cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
115                 cmd.Stdout = &stdout
116                 if err := cmd.Run(); err != nil {
117                         // If the error is ErrNotFound, we ignore it. Otherwise, return it.
118                         if err != exec.ErrNotFound {
119                                 return "", err
120                         }
121                 } else {
122                         if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
123                                 // username:password:uid:gid:gecos:home:shell
124                                 passwdParts := strings.SplitN(passwd, ":", 7)
125                                 if len(passwdParts) > 5 {
126                                         return passwdParts[5], nil
127                                 }
128                         }
129                 }
130         }
131
132         // If all else fails, try the shell
133         stdout.Reset()
134         cmd := exec.Command("sh", "-c", "cd && pwd")
135         cmd.Stdout = &stdout
136         if err := cmd.Run(); err != nil {
137                 return "", err
138         }
139
140         result := strings.TrimSpace(stdout.String())
141         if result == "" {
142                 return "", errors.New("blank output when reading home directory")
143         }
144
145         return result, nil
146 }
147
148 func dirWindows() (string, error) {
149         // First prefer the HOME environmental variable
150         if home := os.Getenv("HOME"); home != "" {
151                 return home, nil
152         }
153
154         // Prefer standard environment variable USERPROFILE
155         if home := os.Getenv("USERPROFILE"); home != "" {
156                 return home, nil
157         }
158
159         drive := os.Getenv("HOMEDRIVE")
160         path := os.Getenv("HOMEPATH")
161         home := drive + path
162         if drive == "" || path == "" {
163                 return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank")
164         }
165
166         return home, nil
167 }