| // Copyright 2018 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 packages |
| |
| import ( |
| "encoding/json" |
| "path/filepath" |
| |
| "golang.org/x/tools/internal/gocommand" |
| ) |
| |
| // determineRootDirs returns a mapping from absolute directories that could |
| // contain code to their corresponding import path prefixes. |
| func (state *golistState) determineRootDirs() (map[string]string, error) { |
| env, err := state.getEnv() |
| if err != nil { |
| return nil, err |
| } |
| if env["GOMOD"] != "" { |
| state.rootsOnce.Do(func() { |
| state.rootDirs, state.rootDirsError = state.determineRootDirsModules() |
| }) |
| } else { |
| state.rootsOnce.Do(func() { |
| state.rootDirs, state.rootDirsError = state.determineRootDirsGOPATH() |
| }) |
| } |
| return state.rootDirs, state.rootDirsError |
| } |
| |
| func (state *golistState) determineRootDirsModules() (map[string]string, error) { |
| // List all of the modules--the first will be the directory for the main |
| // module. Any replaced modules will also need to be treated as roots. |
| // Editing files in the module cache isn't a great idea, so we don't |
| // plan to ever support that. |
| out, err := state.invokeGo("list", "-m", "-json", "all") |
| if err != nil { |
| // 'go list all' will fail if we're outside of a module and |
| // GO111MODULE=on. Try falling back without 'all'. |
| var innerErr error |
| out, innerErr = state.invokeGo("list", "-m", "-json") |
| if innerErr != nil { |
| return nil, err |
| } |
| } |
| roots := map[string]string{} |
| modules := map[string]string{} |
| var i int |
| for dec := json.NewDecoder(out); dec.More(); { |
| mod := new(gocommand.ModuleJSON) |
| if err := dec.Decode(mod); err != nil { |
| return nil, err |
| } |
| if mod.Dir != "" && mod.Path != "" { |
| // This is a valid module; add it to the map. |
| absDir, err := filepath.Abs(mod.Dir) |
| if err != nil { |
| return nil, err |
| } |
| modules[absDir] = mod.Path |
| // The first result is the main module. |
| if i == 0 || mod.Replace != nil && mod.Replace.Path != "" { |
| roots[absDir] = mod.Path |
| } |
| } |
| i++ |
| } |
| return roots, nil |
| } |
| |
| func (state *golistState) determineRootDirsGOPATH() (map[string]string, error) { |
| m := map[string]string{} |
| for _, dir := range filepath.SplitList(state.mustGetEnv()["GOPATH"]) { |
| absDir, err := filepath.Abs(dir) |
| if err != nil { |
| return nil, err |
| } |
| m[filepath.Join(absDir, "src")] = "" |
| } |
| return m, nil |
| } |