-
Notifications
You must be signed in to change notification settings - Fork 0
/
gopath.go
131 lines (115 loc) · 2.42 KB
/
gopath.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"syscall"
)
const Usage = "This program is not meant to be called directly," +
" please see the README for usage.\n"
var configPath = []string{
"$XDG_CONFIG_HOME/gopathrc",
"$HOME/.config/gopathrc",
"$HOME/.gopathrc",
}
type config struct {
Command map[string]string `json:"command"`
}
func setPath() error {
p, err := filepath.Abs(".")
if err != nil {
return err
}
for p != "/" {
fis, err := ioutil.ReadDir(p)
if err != nil {
return err
}
for _, fi := range fis {
if ((fi.Mode()&os.ModeDir != 0) || (fi.Mode()&os.ModeSymlink != 0)) &&
fi.Name() == "src" {
return os.Setenv("GOPATH", p)
}
}
p = filepath.Dir(p)
}
return errors.New("unable to guess GOPATH")
}
func parseConfig() *config {
var data []byte
for _, fname := range configPath {
f, err := os.Open(os.ExpandEnv(fname))
if err != nil {
continue
}
data, err = ioutil.ReadAll(f)
f.Close()
if err == nil {
break
}
}
c := &config{}
json.Unmarshal(data, c)
// make a little user friendly
if c.Command == nil {
c.Command = make(map[string]string)
c.Command["go"] = "/usr/bin/go"
}
return c
}
func main() {
// find the original binary.
args := os.Args
if filepath.Base(args[0]) == "gopath" {
if len(args) == 1 || args[1][0] == '-' {
fmt.Fprintf(os.Stderr, Usage)
os.Exit(0)
}
args = args[1:]
}
cfg := parseConfig()
cmd := filepath.Base(args[0])
bin, ok := cfg.Command[cmd]
if !ok {
bin, _ = exec.LookPath(cmd + ".bin")
}
if bin == "" {
fmt.Fprintf(os.Stderr, "gopath: cannot find executable \"%s\" in path\n", args[0])
os.Exit(1)
}
// set GOPATH if we cannot find it in environment.
if os.Getenv("GOPATH") == "" {
err := setPath()
// make some noise to let caller know the underlying work, for debug purpose.
if len(args) == 1 {
if err != nil {
fmt.Fprintf(os.Stderr, "gopath: %s\n", err)
} else {
fmt.Fprintf(os.Stderr, "goapth: GOPATH set to %s\n", os.Getenv("GOPATH"))
}
}
}
c := exec.Cmd{
Path: bin,
Args: args,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
err := c.Run()
if err == nil {
os.Exit(0)
}
if ee, ok := err.(*exec.ExitError); ok {
if ws, ok := ee.Sys().(syscall.WaitStatus); ok {
os.Exit(ws.ExitStatus())
}
}
fmt.Fprintf(os.Stderr, "gopath: error when calling original binary(%s): %s\n",
bin, err)
os.Exit(1)
}