OSDN Git Service

libgo: Update to weekly.2011-12-02.
[pf3gnuchains/gcc-fork.git] / libgo / go / go / build / path.go
1 // Copyright 2011 The Go Authors.  All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package build
6
7 import (
8         "errors"
9         "fmt"
10         "log"
11         "os"
12         "path/filepath"
13         "runtime"
14 )
15
16 // Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
17 var Path []*Tree
18
19 // Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
20 type Tree struct {
21         Path   string
22         Goroot bool
23 }
24
25 func newTree(p string) (*Tree, error) {
26         if !filepath.IsAbs(p) {
27                 return nil, errors.New("must be absolute")
28         }
29         ep, err := filepath.EvalSymlinks(p)
30         if err != nil {
31                 return nil, err
32         }
33         return &Tree{Path: ep}, nil
34 }
35
36 // SrcDir returns the tree's package source directory.
37 func (t *Tree) SrcDir() string {
38         if t.Goroot {
39                 return filepath.Join(t.Path, "src", "pkg")
40         }
41         return filepath.Join(t.Path, "src")
42 }
43
44 // PkgDir returns the tree's package object directory.
45 func (t *Tree) PkgDir() string {
46         goos, goarch := runtime.GOOS, runtime.GOARCH
47         if e := os.Getenv("GOOS"); e != "" {
48                 goos = e
49         }
50         if e := os.Getenv("GOARCH"); e != "" {
51                 goarch = e
52         }
53         return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
54 }
55
56 // BinDir returns the tree's binary executable directory.
57 func (t *Tree) BinDir() string {
58         if t.Goroot {
59                 if gobin := os.Getenv("GOBIN"); gobin != "" {
60                         return gobin
61                 }
62         }
63         return filepath.Join(t.Path, "bin")
64 }
65
66 // HasSrc returns whether the given package's
67 // source can be found inside this Tree.
68 func (t *Tree) HasSrc(pkg string) bool {
69         fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
70         if err != nil {
71                 return false
72         }
73         return fi.IsDir()
74 }
75
76 // HasPkg returns whether the given package's
77 // object file can be found inside this Tree.
78 func (t *Tree) HasPkg(pkg string) bool {
79         fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
80         if err != nil {
81                 return false
82         }
83         return !fi.IsDir()
84         // TODO(adg): check object version is consistent
85 }
86
87 var (
88         ErrNotFound     = errors.New("go/build: package could not be found locally")
89         ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
90 )
91
92 // FindTree takes an import or filesystem path and returns the
93 // tree where the package source should be and the package import path.
94 func FindTree(path string) (tree *Tree, pkg string, err error) {
95         if isLocalPath(path) {
96                 if path, err = filepath.Abs(path); err != nil {
97                         return
98                 }
99                 if path, err = filepath.EvalSymlinks(path); err != nil {
100                         return
101                 }
102                 for _, t := range Path {
103                         tpath := t.SrcDir() + string(filepath.Separator)
104                         if !filepath.HasPrefix(path, tpath) {
105                                 continue
106                         }
107                         tree = t
108                         pkg = path[len(tpath):]
109                         return
110                 }
111                 err = fmt.Errorf("path %q not inside a GOPATH", path)
112                 return
113         }
114         tree = defaultTree
115         pkg = path
116         for _, t := range Path {
117                 if t.HasSrc(pkg) {
118                         tree = t
119                         return
120                 }
121         }
122         if tree == nil {
123                 err = ErrTreeNotFound
124         } else {
125                 err = ErrNotFound
126         }
127         return
128 }
129
130 // isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
131 // Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
132 func isLocalPath(s string) bool {
133         const sep = string(filepath.Separator)
134         return s == "." || s == ".." ||
135                 filepath.HasPrefix(s, sep) ||
136                 filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
137                 filepath.VolumeName(s) != ""
138 }
139
140 var (
141         // argument lists used by the build's gc and ld methods
142         gcImportArgs []string
143         ldImportArgs []string
144
145         // default tree for remote packages
146         defaultTree *Tree
147 )
148
149 // set up Path: parse and validate GOROOT and GOPATH variables
150 func init() {
151         root := runtime.GOROOT()
152         t, err := newTree(root)
153         if err != nil {
154                 log.Printf("go/build: invalid GOROOT %q: %v", root, err)
155         } else {
156                 t.Goroot = true
157                 Path = []*Tree{t}
158         }
159
160         for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
161                 if p == "" {
162                         continue
163                 }
164                 t, err := newTree(p)
165                 if err != nil {
166                         log.Printf("go/build: invalid GOPATH %q: %v", p, err)
167                         continue
168                 }
169                 Path = append(Path, t)
170                 gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
171                 ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())
172
173                 // select first GOPATH entry as default
174                 if defaultTree == nil {
175                         defaultTree = t
176                 }
177         }
178
179         // use GOROOT if no valid GOPATH specified
180         if defaultTree == nil && len(Path) > 0 {
181                 defaultTree = Path[0]
182         }
183 }