// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main import ( "fmt" "log" "os" "path/filepath" "runtime" "strings" ) var ( gopath []*pkgroot imports []string defaultRoot *pkgroot // default root for remote packages ) // set up gopath: parse and validate GOROOT and GOPATH variables func init() { root := runtime.GOROOT() p, err := newPkgroot(root) if err != nil { log.Fatalf("Invalid GOROOT %q: %v", root, err) } p.goroot = true gopath = []*pkgroot{p} for _, p := range filepath.SplitList(os.Getenv("GOPATH")) { if p == "" { continue } r, err := newPkgroot(p) if err != nil { log.Printf("Invalid GOPATH %q: %v", p, err) continue } gopath = append(gopath, r) imports = append(imports, r.pkgDir()) // select first GOPATH entry as default if defaultRoot == nil { defaultRoot = r } } // use GOROOT if no valid GOPATH specified if defaultRoot == nil { defaultRoot = gopath[0] } } type pkgroot struct { path string goroot bool // TODO(adg): remove this once Go tree re-organized } func newPkgroot(p string) (*pkgroot, os.Error) { if !filepath.IsAbs(p) { return nil, os.NewError("must be absolute") } ep, err := filepath.EvalSymlinks(p) if err != nil { return nil, err } return &pkgroot{path: ep}, nil } func (r *pkgroot) srcDir() string { if r.goroot { return filepath.Join(r.path, "src", "pkg") } return filepath.Join(r.path, "src") } func (r *pkgroot) pkgDir() string { goos, goarch := runtime.GOOS, runtime.GOARCH if e := os.Getenv("GOOS"); e != "" { goos = e } if e := os.Getenv("GOARCH"); e != "" { goarch = e } return filepath.Join(r.path, "pkg", goos+"_"+goarch) } func (r *pkgroot) binDir() string { return filepath.Join(r.path, "bin") } func (r *pkgroot) hasSrcDir(name string) bool { fi, err := os.Stat(filepath.Join(r.srcDir(), name)) if err != nil { return false } return fi.IsDirectory() } func (r *pkgroot) hasPkg(name string) bool { fi, err := os.Stat(filepath.Join(r.pkgDir(), name+".a")) if err != nil { return false } return fi.IsRegular() // TODO(adg): check object version is consistent } var ErrPackageNotFound = os.NewError("package could not be found locally") // findPackageRoot takes an import or filesystem path and returns the // root where the package source should be and the package import path. func findPackageRoot(path string) (root *pkgroot, pkg string, err os.Error) { if isLocalPath(path) { if path, err = filepath.Abs(path); err != nil { return } for _, r := range gopath { rpath := r.srcDir() + string(filepath.Separator) if !strings.HasPrefix(path, rpath) { continue } root = r pkg = path[len(rpath):] return } err = fmt.Errorf("path %q not inside a GOPATH", path) return } root = defaultRoot pkg = path for _, r := range gopath { if r.hasSrcDir(path) { root = r return } } err = ErrPackageNotFound return } // Is this a local path? /foo ./foo ../foo . .. func isLocalPath(s string) bool { const sep = string(filepath.Separator) return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".." }