tools/go/packages/loader_fallback.go

131 lines
3.4 KiB
Go

// 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.
// TODO(matloob): Delete this file once Go 1.12 is released.
// This file provides backwards compatibility support for
// loading for versions of Go earlier than 1.10.4. This support is meant to
// assist with migration to the Package API until there's
// widespread adoption of these newer Go versions.
// This support will be removed once Go 1.12 is released
// in Q1 2019.
// The support is incomplete. These are some of the missing
// features:
// - the Tests option has no behavior, and test packages are
// never returned.
// - Package.OtherFiles are always missing even if the package
// contains non-go sources.
package packages
import (
"fmt"
"go/build"
"strings"
legacy "golang.org/x/tools/go/loader"
"golang.org/x/tools/imports"
)
func loaderFallback(dir string, env []string, patterns []string) ([]*Package, error) {
cfg := legacy.Config{}
cfg.Cwd = dir
cfg.AllowErrors = true
cfg.FromArgs(patterns, false) // test packages are not supported
// Set build ctx
buildCtx := build.Default
for _, ev := range env {
sp := strings.Split(ev, "=")
if len(sp) != 2 {
continue
}
evar, val := sp[0], sp[1]
switch evar {
case "GOPATH":
buildCtx.GOPATH = val
case "GOROOT":
buildCtx.GOROOT = val
case "GOARCH":
buildCtx.GOARCH = val
case "GOOS":
buildCtx.GOOS = val
}
}
cfg.Build = &buildCtx
lprog, err := cfg.Load()
if err != nil {
if err.Error() == "no initial packages were loaded" {
return nil, fmt.Errorf("packages not found") // Return same error as golist-based code
}
return nil, fmt.Errorf("failed to load packages with legacy loader: %v", err)
}
allpkgs := make(map[string]*loaderPackage)
initial := make(map[*legacy.PackageInfo]bool)
for _, lpkg := range lprog.InitialPackages() {
initial[lpkg] = true
}
for _, lpkg := range lprog.AllPackages {
id := lpkg.Pkg.Path()
var goFiles []string
for _, f := range lpkg.Files {
goFiles = append(goFiles, lprog.Fset.File(f.Pos()).Name())
}
pkgimports := make(map[string]string)
for _, imppkg := range lpkg.Pkg.Imports() {
// TODO(matloob): Is the import path of a package always VendorlessPath(path)?
pkgimports[imports.VendorlessPath(imppkg.Path())] = imppkg.Path()
}
allpkgs[id] = &loaderPackage{
raw: &rawPackage{
ID: id,
Name: lpkg.Pkg.Name(),
Imports: pkgimports,
GoFiles: goFiles,
DepOnly: !initial[lpkg],
},
Package: &Package{
ID: id,
Name: lpkg.Pkg.Name(),
GoFiles: goFiles,
Fset: lprog.Fset,
Syntax: lpkg.Files,
Errors: lpkg.Errors,
Types: lpkg.Pkg,
TypesInfo: &lpkg.Info,
IllTyped: !lpkg.TransitivelyErrorFree,
OtherFiles: nil, // Never set for the fallback, because we can't extract from loader.
},
}
}
// Do a second pass to populate imports.
for _, pkg := range allpkgs {
pkg.Imports = make(map[string]*Package)
for imppath, impid := range pkg.raw.Imports {
target, ok := allpkgs[impid]
if !ok {
// return nil, fmt.Errorf("could not load package: %v", impid)
continue
}
pkg.Imports[imppath] = target.Package
}
}
// Grab the initial set of packages.
var packages []*Package
for _, lpkg := range lprog.InitialPackages() {
packages = append(packages, allpkgs[lpkg.Pkg.Path()].Package)
}
return packages, nil
}