Update to gazelle 0.12.0 and run hack/update-bazel.sh

This commit is contained in:
Jeff Grafton
2018-05-15 17:22:27 -07:00
parent e7f1eaf289
commit a725660640
855 changed files with 2949 additions and 6691 deletions

View File

@@ -12,16 +12,17 @@ go_library(
"update-repos.go",
"version.go",
],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/cmd/gazelle",
importpath = "github.com/bazelbuild/bazel-gazelle/cmd/gazelle",
visibility = ["//visibility:private"],
deps = [
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/config:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/generator:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/label:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/merger:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/packages:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/repos:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/resolve:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/rules:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/version:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/wspace:go_default_library",
"//vendor/github.com/bazelbuild/buildtools/build:go_default_library",

View File

@@ -26,12 +26,12 @@ import (
"strings"
"github.com/bazelbuild/bazel-gazelle/internal/config"
"github.com/bazelbuild/bazel-gazelle/internal/generator"
"github.com/bazelbuild/bazel-gazelle/internal/label"
"github.com/bazelbuild/bazel-gazelle/internal/merger"
"github.com/bazelbuild/bazel-gazelle/internal/packages"
"github.com/bazelbuild/bazel-gazelle/internal/repos"
"github.com/bazelbuild/bazel-gazelle/internal/resolve"
"github.com/bazelbuild/bazel-gazelle/internal/rules"
"github.com/bazelbuild/bazel-gazelle/internal/wspace"
bf "github.com/bazelbuild/buildtools/build"
)
@@ -107,13 +107,7 @@ func runFixUpdate(cmd command, args []string) error {
// Fix any problems in the file.
if file != nil {
file = merger.FixFileMinor(c, file)
fixedFile := merger.FixFile(c, file)
if cmd == fixCmd {
file = fixedFile
} else if fixedFile != file {
log.Printf("%s: warning: file contains rules whose structure is out of date. Consider running 'gazelle fix'.", file.Path)
}
merger.FixFile(c, file)
}
// If the file exists, but no Go code is present, create an empty package.
@@ -124,7 +118,7 @@ func runFixUpdate(cmd command, args []string) error {
// Generate new rules and merge them into the existing file (if present).
if pkg != nil {
g := rules.NewGenerator(c, l, file)
g := generator.NewGenerator(c, l, file)
rules, empty, err := g.GenerateRules(pkg)
if err != nil {
log.Print(err)
@@ -136,7 +130,7 @@ func runFixUpdate(cmd command, args []string) error {
Stmt: rules,
}
} else {
file, rules = merger.MergeFile(rules, empty, file, merger.PreResolveAttrs)
rules = merger.MergeFile(rules, empty, file, merger.PreResolveAttrs)
}
visits = append(visits, visitRecord{
pkgRel: rel,
@@ -162,13 +156,13 @@ func runFixUpdate(cmd command, args []string) error {
for j := range visits[i].rules {
visits[i].rules[j] = resolver.ResolveRule(visits[i].rules[j], visits[i].pkgRel)
}
visits[i].file, _ = merger.MergeFile(visits[i].rules, visits[i].empty, visits[i].file, merger.PostResolveAttrs)
merger.MergeFile(visits[i].rules, visits[i].empty, visits[i].file, merger.PostResolveAttrs)
}
// Emit merged files.
for _, v := range visits {
rules.SortLabels(v.file)
v.file = merger.FixLoads(v.file)
generator.SortLabels(v.file)
merger.FixLoads(v.file)
bf.Rewrite(v.file, nil) // have buildifier 'format' our rules.
path := v.file.Path
@@ -294,17 +288,21 @@ func newFixUpdateConfiguration(cmd command, args []string) (*updateConfig, error
uc.outSuffix = *outSuffix
workspacePath := filepath.Join(uc.c.RepoRoot, "WORKSPACE")
workspaceContent, err := ioutil.ReadFile(workspacePath)
if os.IsNotExist(err) {
workspaceContent = nil
} else if err != nil {
return nil, err
if workspaceContent, err := ioutil.ReadFile(workspacePath); err != nil {
if !os.IsNotExist(err) {
return nil, err
}
} else {
workspace, err := bf.Parse(workspacePath, workspaceContent)
if err != nil {
return nil, err
}
if err := fixWorkspace(uc, workspace); err != nil {
return nil, err
}
uc.c.RepoName = findWorkspaceName(workspace)
uc.repos = repos.ListRepositories(workspace)
}
workspace, err := bf.Parse(workspacePath, workspaceContent)
if err != nil {
return nil, err
}
uc.repos = repos.ListRepositories(workspace)
repoPrefixes := make(map[string]bool)
for _, r := range uc.repos {
repoPrefixes[r.GoPrefix] = true
@@ -324,7 +322,7 @@ func newFixUpdateConfiguration(cmd command, args []string) (*updateConfig, error
}
func fixUpdateUsage(fs *flag.FlagSet) {
fmt.Fprintln(os.Stderr, `usage: gazelle [fix|update] [flags...] [package-dirs...]
fmt.Fprint(os.Stderr, `usage: gazelle [fix|update] [flags...] [package-dirs...]
The update command creates new build files and update existing BUILD files
when needed.
@@ -347,6 +345,7 @@ subdirectories. All directories must be under the directory specified by
WORKSPACE file.
FLAGS:
`)
fs.PrintDefaults()
}
@@ -412,6 +411,42 @@ func loadGoPrefix(c *config.Config) (string, error) {
return "", fmt.Errorf("-go_prefix not set, and no # gazelle:prefix directive found in %s", f.Path)
}
func fixWorkspace(uc *updateConfig, workspace *bf.File) error {
if !uc.c.ShouldFix {
return nil
}
shouldFix := false
for _, d := range uc.c.Dirs {
if d == uc.c.RepoRoot {
shouldFix = true
}
}
if !shouldFix {
return nil
}
merger.FixWorkspace(workspace)
merger.FixLoads(workspace)
if err := merger.CheckGazelleLoaded(workspace); err != nil {
return err
}
return uc.emit(uc.c, workspace, workspace.Path)
}
func findWorkspaceName(f *bf.File) string {
for _, stmt := range f.Stmt {
call, ok := stmt.(*bf.CallExpr)
if !ok {
continue
}
rule := bf.Rule{Call: call}
if rule.Kind() == "workspace" {
return rule.Name()
}
}
return ""
}
func isDescendingDir(dir, root string) bool {
rel, err := filepath.Rel(root, dir)
if err != nil {

View File

@@ -30,7 +30,7 @@ import (
bf "github.com/bazelbuild/buildtools/build"
)
type updateReposFn func(c *updateReposConfiguration, oldFile *bf.File) (*bf.File, error)
type updateReposFn func(c *updateReposConfiguration, oldFile *bf.File) error
type updateReposConfiguration struct {
fn updateReposFn
@@ -50,18 +50,21 @@ func updateRepos(args []string) error {
if err != nil {
return fmt.Errorf("error reading %q: %v", workspacePath, err)
}
oldFile, err := bf.Parse(workspacePath, content)
f, err := bf.Parse(workspacePath, content)
if err != nil {
return fmt.Errorf("error parsing %q: %v", workspacePath, err)
}
merger.FixWorkspace(f)
mergedFile, err := c.fn(c, oldFile)
if err != nil {
if err := c.fn(c, f); err != nil {
return err
}
mergedFile = merger.FixLoads(mergedFile)
if err := ioutil.WriteFile(mergedFile.Path, bf.Format(mergedFile), 0666); err != nil {
return fmt.Errorf("error writing %q: %v", mergedFile.Path, err)
merger.FixLoads(f)
if err := merger.CheckGazelleLoaded(f); err != nil {
return err
}
if err := ioutil.WriteFile(f.Path, bf.Format(f), 0666); err != nil {
return fmt.Errorf("error writing %q: %v", f.Path, err)
}
return nil
}
@@ -115,7 +118,7 @@ func newUpdateReposConfiguration(args []string) (*updateReposConfiguration, erro
}
func updateReposUsage(fs *flag.FlagSet) {
fmt.Fprintln(os.Stderr, `usage:
fmt.Fprint(os.Stderr, `usage:
# Add/update repositories by import path
gazelle update-repos example.com/repo1 example.com/repo2
@@ -129,11 +132,12 @@ update-repos can also import repository rules from a vendoring tool's lock
file (currently only deps' Gopkg.lock is supported).
FLAGS:
`)
}
func updateImportPaths(c *updateReposConfiguration, oldFile *bf.File) (*bf.File, error) {
rs := repos.ListRepositories(oldFile)
func updateImportPaths(c *updateReposConfiguration, f *bf.File) error {
rs := repos.ListRepositories(f)
rc := repos.NewRemoteCache(rs)
genRules := make([]bf.Expr, len(c.importPaths))
@@ -158,19 +162,19 @@ func updateImportPaths(c *updateReposConfiguration, oldFile *bf.File) (*bf.File,
for _, err := range errs {
if err != nil {
return nil, err
return err
}
}
mergedFile, _ := merger.MergeFile(genRules, nil, oldFile, merger.RepoAttrs)
return mergedFile, nil
merger.MergeFile(genRules, nil, f, merger.RepoAttrs)
return nil
}
func importFromLockFile(c *updateReposConfiguration, oldFile *bf.File) (*bf.File, error) {
func importFromLockFile(c *updateReposConfiguration, f *bf.File) error {
genRules, err := repos.ImportRepoRules(c.lockFilename)
if err != nil {
return nil, err
return err
}
mergedFile, _ := merger.MergeFile(genRules, nil, oldFile, merger.RepoAttrs)
return mergedFile, nil
merger.MergeFile(genRules, nil, f, merger.RepoAttrs)
return nil
}

View File

@@ -26,7 +26,7 @@ import (
"github.com/bazelbuild/bazel-gazelle/internal/version"
)
var minimumRulesGoVersion = version.Version{0, 9, 0}
var minimumRulesGoVersion = version.Version{0, 11, 0}
// checkRulesGoVersion checks whether a compatible version of rules_go is
// being used in the workspace. A message will be logged if an incompatible

View File

@@ -8,6 +8,7 @@ go_library(
"directives.go",
"platform.go",
],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/config",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/config",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
deps = ["//vendor/github.com/bazelbuild/buildtools/build:go_default_library"],

View File

@@ -31,6 +31,9 @@ type Config struct {
// repository with all symlinks resolved.
RepoRoot string
// RepoName is the name of the repository.
RepoName string
// ValidBuildFileNames is a list of base names that are considered valid
// build files. Some repositories may have files named "BUILD" that are not
// used by Bazel and should be ignored. Must contain at least one string.
@@ -48,6 +51,16 @@ type Config struct {
// was set, relative to the repository root. "" for the repository root.
GoPrefixRel string
// GoImportMapPrefix is a string that should appear at the beginning of
// importmap attributes in go_library rules generated by Gazelle. These
// attributes are not generated when this is empty.
GoImportMapPrefix string
// GoImportMapPrefixRel is the slash-separated path to the directory where
// GoImportMapPrefix was set, relative to the repository root. "" for the
// repository root.
GoImportMapPrefixRel string
// ShouldFix determines whether Gazelle attempts to remove and replace
// usage of deprecated rules.
ShouldFix bool

View File

@@ -42,12 +42,14 @@ const (
// WellKnownTypesProtoRepo is the repository containing proto_library rules
// for the Well Known Types.
WellKnownTypesProtoRepo = "com_google_protobuf"
// WellKnownTypesGoProtoRepo is the repository containing go_library rules
// for the Well Known Types.
WellKnownTypesGoProtoRepo = "com_github_golang_protobuf"
// WellKnownTypeProtoPrefix is the proto import path prefix for the
// Well Known Types.
WellKnownTypesProtoPrefix = "google/protobuf"
// WellKnownTypesGoPrefix is the import path for the Go repository containing
// pre-generated code for the Well Known Types.
WellKnownTypesGoPrefix = "github.com/golang/protobuf"
// WellKnownTypesPkg is the package name for the predefined WKTs in rules_go.
WellKnownTypesPkg = "proto/wkt"
// GazelleImportsKey is an internal attribute that lists imported packages
// on generated rules. It is replaced with "deps" during import resolution.

View File

@@ -38,12 +38,14 @@ type Directive struct {
// Top-level directives apply to the whole package or build file. They must
// appear before the first statement.
var knownTopLevelDirectives = map[string]bool{
"build_file_name": true,
"build_tags": true,
"exclude": true,
"prefix": true,
"ignore": true,
"proto": true,
"build_file_name": true,
"build_tags": true,
"exclude": true,
"ignore": true,
"importmap_prefix": true,
"repo": true,
"prefix": true,
"proto": true,
}
// TODO(jayconrod): annotation directives will apply to an individual rule.
@@ -89,6 +91,9 @@ func ApplyDirectives(c *Config, directives []Directive, rel string) *Config {
didModify := false
for _, d := range directives {
switch d.Key {
case "build_file_name":
modified.ValidBuildFileNames = strings.Split(d.Value, ",")
didModify = true
case "build_tags":
if err := modified.SetBuildTags(d.Value); err != nil {
log.Print(err)
@@ -97,8 +102,13 @@ func ApplyDirectives(c *Config, directives []Directive, rel string) *Config {
modified.PreprocessTags()
didModify = true
}
case "build_file_name":
modified.ValidBuildFileNames = strings.Split(d.Value, ",")
case "importmap_prefix":
if err := CheckPrefix(d.Value); err != nil {
log.Print(err)
continue
}
modified.GoImportMapPrefix = d.Value
modified.GoImportMapPrefixRel = rel
didModify = true
case "prefix":
if err := CheckPrefix(d.Value); err != nil {

View File

@@ -8,12 +8,14 @@ go_library(
"generator.go",
"sort_labels.go",
],
importpath = "github.com/bazelbuild/bazel-gazelle/internal/rules",
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/generator",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/generator",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
deps = [
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/config:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/label:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/packages:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/pathtools:go_default_library",
"//vendor/github.com/bazelbuild/buildtools/build:go_default_library",
"//vendor/github.com/bazelbuild/buildtools/tables:go_default_library",
],

View File

@@ -13,7 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package rules
package generator
import (
"fmt"

View File

@@ -13,5 +13,5 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package rules provides Bazel rule generation for Go build targets.
package rules
// Package generator provides Bazel rule generation for Go build targets.
package generator

View File

@@ -13,7 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package rules
package generator
import (
"fmt"
@@ -24,6 +24,7 @@ import (
"github.com/bazelbuild/bazel-gazelle/internal/config"
"github.com/bazelbuild/bazel-gazelle/internal/label"
"github.com/bazelbuild/bazel-gazelle/internal/packages"
"github.com/bazelbuild/bazel-gazelle/internal/pathtools"
bf "github.com/bazelbuild/buildtools/build"
)
@@ -54,8 +55,7 @@ func (g *Generator) GenerateRules(pkg *packages.Package) (rules []bf.Expr, empty
rs = append(rs,
g.generateBin(pkg, libName),
g.generateTest(pkg, libName, false),
g.generateTest(pkg, "", true))
g.generateTest(pkg, libName))
for _, r := range rs {
if isEmpty(r) {
@@ -119,8 +119,8 @@ func (g *Generator) generateProto(pkg *packages.Package) (string, []bf.Expr) {
goProtoAttrs := []KeyValue{
{"name", goProtoName},
{"proto", ":" + protoName},
{"importpath", pkg.ImportPath},
}
goProtoAttrs = append(goProtoAttrs, g.importAttrs(pkg)...)
if pkg.Proto.HasServices {
goProtoAttrs = append(goProtoAttrs, KeyValue{"compilers", []string{"@io_bazel_rules_go//proto:go_grpc"}})
}
@@ -162,7 +162,7 @@ func (g *Generator) generateLib(pkg *packages.Package, goProtoName string) (stri
}
attrs := g.commonAttrs(pkg.Rel, name, visibility, pkg.Library)
attrs = append(attrs, KeyValue{"importpath", pkg.ImportPath})
attrs = append(attrs, g.importAttrs(pkg)...)
if goProtoName != "" {
attrs = append(attrs, KeyValue{"embed", []string{":" + goProtoName}})
}
@@ -199,16 +199,12 @@ func checkInternalVisibility(rel, visibility string) string {
return visibility
}
func (g *Generator) generateTest(pkg *packages.Package, library string, isXTest bool) bf.Expr {
name := g.l.TestLabel(pkg.Rel, isXTest).Name
target := pkg.Test
if isXTest {
target = pkg.XTest
}
if !target.HasGo() {
func (g *Generator) generateTest(pkg *packages.Package, library string) bf.Expr {
name := g.l.TestLabel(pkg.Rel).Name
if !pkg.Test.HasGo() {
return EmptyRule("go_test", name)
}
attrs := g.commonAttrs(pkg.Rel, name, "", target)
attrs := g.commonAttrs(pkg.Rel, name, "", pkg.Test)
if library != "" {
attrs = append(attrs, KeyValue{"embed", []string{":" + library}})
}
@@ -222,7 +218,7 @@ func (g *Generator) generateTest(pkg *packages.Package, library string, isXTest
func (g *Generator) commonAttrs(pkgRel, name, visibility string, target packages.GoTarget) []KeyValue {
attrs := []KeyValue{{"name", name}}
if !target.Sources.IsEmpty() {
attrs = append(attrs, KeyValue{"srcs", target.Sources})
attrs = append(attrs, KeyValue{"srcs", target.Sources.Flat()})
}
if target.Cgo {
attrs = append(attrs, KeyValue{"cgo", true})
@@ -243,6 +239,18 @@ func (g *Generator) commonAttrs(pkgRel, name, visibility string, target packages
return attrs
}
func (g *Generator) importAttrs(pkg *packages.Package) []KeyValue {
attrs := []KeyValue{{"importpath", pkg.ImportPath}}
if g.c.GoImportMapPrefix != "" {
fromPrefixRel := pathtools.TrimPrefix(pkg.Rel, g.c.GoImportMapPrefixRel)
importMap := path.Join(g.c.GoImportMapPrefix, fromPrefixRel)
if importMap != pkg.ImportPath {
attrs = append(attrs, KeyValue{"importmap", importMap})
}
}
return attrs
}
var (
// shortOptPrefixes are strings that come at the beginning of an option
// argument that includes a path, e.g., -Ifoo/bar.

View File

@@ -13,7 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package rules
package generator
import (
"sort"

View File

@@ -6,6 +6,7 @@ go_library(
"label.go",
"labeler.go",
],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/label",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/label",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
deps = [

View File

@@ -34,14 +34,8 @@ func (l *Labeler) LibraryLabel(rel string) Label {
return Label{Pkg: rel, Name: config.DefaultLibName}
}
func (l *Labeler) TestLabel(rel string, isXTest bool) Label {
var name string
if isXTest {
name = config.DefaultXTestName
} else {
name = config.DefaultTestName
}
return Label{Pkg: rel, Name: name}
func (l *Labeler) TestLabel(rel string) Label {
return Label{Pkg: rel, Name: config.DefaultTestName}
}
func (l *Labeler) BinaryLabel(rel string) Label {

View File

@@ -6,6 +6,7 @@ go_library(
"fix.go",
"merger.go",
],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/merger",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/merger",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
deps = [

View File

@@ -16,8 +16,11 @@ limitations under the License.
package merger
import (
"errors"
"fmt"
"log"
"sort"
"strings"
"github.com/bazelbuild/bazel-gazelle/internal/config"
bf "github.com/bazelbuild/buildtools/build"
@@ -28,14 +31,65 @@ import (
// dependency, that library depends on a proto in Bazel itself, which is
// a 95MB download. Not worth it.
// FixFile updates rules in oldFile that were generated by an older version of
// FixFile updates rules in f that were generated by an older version of
// Gazelle to a newer form that can be merged with freshly generated rules.
//
// FixLoads should be called after this, since it will fix load
// statements that may be broken by transformations applied by this function.
func FixFile(c *config.Config, oldFile *bf.File) *bf.File {
fixedFile := squashCgoLibrary(oldFile)
return removeLegacyProto(c, fixedFile)
// If c.ShouldFix is true, FixFile may perform potentially destructive
// transformations, such as squashing or deleting rules (e.g., cgo_library).
// If not, FixFile will perform a set of low-risk transformations (e.g., removing
// unused attributes) and will print a message about transformations it
// would have performed.
//
// FixLoads should be called after this, since it will fix load statements that
// may be broken by transformations applied by this function.
func FixFile(c *config.Config, f *bf.File) {
migrateLibraryEmbed(c, f)
migrateGrpcCompilers(c, f)
flattenSrcs(c, f)
squashCgoLibrary(c, f)
squashXtest(c, f)
removeLegacyProto(c, f)
}
// migrateLibraryEmbed converts "library" attributes to "embed" attributes,
// preserving comments. This only applies to Go rules, and only if there is
// no keep comment on "library" and no existing "embed" attribute.
func migrateLibraryEmbed(c *config.Config, f *bf.File) {
for _, stmt := range f.Stmt {
call, ok := stmt.(*bf.CallExpr)
if !ok || shouldKeep(stmt) {
continue
}
rule := bf.Rule{Call: call}
if !isGoRule(rule.Kind()) {
continue
}
libExpr := rule.Attr("library")
if libExpr == nil || shouldKeep(libExpr) || rule.Attr("embed") != nil {
continue
}
rule.DelAttr("library")
rule.SetAttr("embed", &bf.ListExpr{List: []bf.Expr{libExpr}})
}
}
// migrateGrpcCompilers converts "go_grpc_library" rules into "go_proto_library"
// rules with a "compilers" attribute.
func migrateGrpcCompilers(c *config.Config, f *bf.File) {
for _, stmt := range f.Stmt {
call, ok := stmt.(*bf.CallExpr)
if !ok {
continue
}
rule := bf.Rule{Call: call}
if rule.Kind() != "go_grpc_library" || shouldKeep(stmt) || rule.Attr("compilers") != nil {
continue
}
rule.SetKind("go_proto_library")
rule.SetAttr("compilers", &bf.ListExpr{
List: []bf.Expr{&bf.StringExpr{Value: config.GrpcCompilerLabel}},
})
}
}
// squashCgoLibrary removes cgo_library rules with the default name and
@@ -44,14 +98,13 @@ func FixFile(c *config.Config, oldFile *bf.File) *bf.File {
//
// Note that the library attribute is disregarded, so cgo_library and
// go_library attributes will be squashed even if the cgo_library was unlinked.
// MergeWithExisting will remove unused values and attributes later.
func squashCgoLibrary(oldFile *bf.File) *bf.File {
// MergeFile will remove unused values and attributes later.
func squashCgoLibrary(c *config.Config, f *bf.File) {
// Find the default cgo_library and go_library rules.
var cgoLibrary, goLibrary bf.Rule
cgoLibraryIndex := -1
goLibraryIndex := -1
for i, stmt := range oldFile.Stmt {
for i, stmt := range f.Stmt {
c, ok := stmt.(*bf.CallExpr)
if !ok {
continue
@@ -59,7 +112,7 @@ func squashCgoLibrary(oldFile *bf.File) *bf.File {
r := bf.Rule{Call: c}
if r.Kind() == "cgo_library" && r.Name() == config.DefaultCgoLibName && !shouldKeep(c) {
if cgoLibrary.Call != nil {
log.Printf("%s: when fixing existing file, multiple cgo_library rules with default name found", oldFile.Path)
log.Printf("%s: when fixing existing file, multiple cgo_library rules with default name found", f.Path)
continue
}
cgoLibrary = r
@@ -68,88 +121,169 @@ func squashCgoLibrary(oldFile *bf.File) *bf.File {
}
if r.Kind() == "go_library" && r.Name() == config.DefaultLibName {
if goLibrary.Call != nil {
log.Printf("%s: when fixing existing file, multiple go_library rules with default name referencing cgo_library found", oldFile.Path)
log.Printf("%s: when fixing existing file, multiple go_library rules with default name referencing cgo_library found", f.Path)
continue
}
goLibrary = r
goLibraryIndex = i
}
}
if cgoLibrary.Call == nil {
return oldFile
return
}
if !c.ShouldFix {
log.Printf("%s: cgo_library is deprecated. Run 'gazelle fix' to squash with go_library.", f.Path)
return
}
// If go_library has a '# keep' comment, just delete cgo_library.
if goLibrary.Call != nil && shouldKeep(goLibrary.Call) {
fixedFile := *oldFile
fixedFile.Stmt = append(fixedFile.Stmt[:cgoLibraryIndex], fixedFile.Stmt[cgoLibraryIndex+1:]...)
return &fixedFile
}
// Delete cgo_library.
f.Stmt = append(f.Stmt[:cgoLibraryIndex], f.Stmt[cgoLibraryIndex+1:]...)
// Copy the comments and attributes from cgo_library into go_library. If no
// go_library exists, create an empty one.
var fixedGoLibraryExpr bf.CallExpr
fixedGoLibrary := bf.Rule{Call: &fixedGoLibraryExpr}
if goLibrary.Call != nil && shouldKeep(goLibrary.Call) {
return
}
if goLibrary.Call == nil {
fixedGoLibrary.SetKind("go_library")
fixedGoLibrary.SetAttr("name", &bf.StringExpr{Value: config.DefaultLibName})
goLibrary.Call = &bf.CallExpr{}
goLibrary.SetKind("go_library")
goLibrary.SetAttr("name", &bf.StringExpr{Value: config.DefaultLibName})
if vis := cgoLibrary.Attr("visibility"); vis != nil {
fixedGoLibrary.SetAttr("visibility", vis)
goLibrary.SetAttr("visibility", vis)
}
} else {
fixedGoLibraryExpr = *goLibrary.Call
fixedGoLibraryExpr.List = append([]bf.Expr{}, goLibrary.Call.List...)
f.Stmt = append(f.Stmt, goLibrary.Call)
}
fixedGoLibrary.DelAttr("embed")
fixedGoLibrary.SetAttr("cgo", &bf.LiteralExpr{Token: "True"})
fixedGoLibraryExpr.Comments.Before = append(fixedGoLibraryExpr.Comments.Before, cgoLibrary.Call.Comments.Before...)
fixedGoLibraryExpr.Comments.Suffix = append(fixedGoLibraryExpr.Comments.Suffix, cgoLibrary.Call.Comments.Suffix...)
fixedGoLibraryExpr.Comments.After = append(fixedGoLibraryExpr.Comments.After, cgoLibrary.Call.Comments.After...)
goLibrary.DelAttr("embed")
goLibrary.SetAttr("cgo", &bf.LiteralExpr{Token: "True"})
goLibrary.Call.Comments.Before = append(goLibrary.Call.Comments.Before, cgoLibrary.Call.Comments.Before...)
goLibrary.Call.Comments.Suffix = append(goLibrary.Call.Comments.Suffix, cgoLibrary.Call.Comments.Suffix...)
goLibrary.Call.Comments.After = append(goLibrary.Call.Comments.After, cgoLibrary.Call.Comments.After...)
for _, key := range []string{"cdeps", "clinkopts", "copts", "data", "deps", "gc_goopts", "srcs"} {
goLibraryAttr := fixedGoLibrary.Attr(key)
goLibraryAttr := goLibrary.Attr(key)
cgoLibraryAttr := cgoLibrary.Attr(key)
if cgoLibraryAttr == nil {
continue
}
if fixedAttr, err := squashExpr(goLibraryAttr, cgoLibraryAttr); err == nil {
fixedGoLibrary.SetAttr(key, fixedAttr)
goLibrary.SetAttr(key, fixedAttr)
}
}
// Rebuild the file with the cgo_library removed and the go_library replaced.
// If the go_library didn't already exist, it will replace cgo_library.
fixedFile := *oldFile
if goLibrary.Call == nil {
fixedFile.Stmt = append([]bf.Expr{}, oldFile.Stmt...)
fixedFile.Stmt[cgoLibraryIndex] = &fixedGoLibraryExpr
} else {
fixedFile.Stmt = append(oldFile.Stmt[:cgoLibraryIndex], oldFile.Stmt[cgoLibraryIndex+1:]...)
if goLibraryIndex > cgoLibraryIndex {
goLibraryIndex--
}
fixedFile.Stmt[goLibraryIndex] = &fixedGoLibraryExpr
}
return &fixedFile
}
// squashExpr combines two expressions. Unlike mergeExpr, squashExpr does not
// discard information from an "old" expression. It does not sort or de-duplicate
// elements. Any non-scalar expressions that mergeExpr understands can be
// squashed.
func squashExpr(x, y bf.Expr) (bf.Expr, error) {
xExprs, err := extractPlatformStringsExprs(x)
// squashXtest removes go_test rules with the default external name and merges
// their attributes with a go_test rule with the default internal name. If
// no internal go_test rule exists, a new one will be created (effectively
// renaming the old rule).
func squashXtest(c *config.Config, f *bf.File) {
// Search for internal and external tests.
var itest, xtest bf.Rule
xtestIndex := -1
for i, stmt := range f.Stmt {
call, ok := stmt.(*bf.CallExpr)
if !ok {
continue
}
rule := bf.Rule{Call: call}
if rule.Kind() != "go_test" {
continue
}
if name := rule.Name(); name == config.DefaultTestName {
itest = rule
} else if name == config.DefaultXTestName {
xtest = rule
xtestIndex = i
}
}
if xtest.Call == nil || shouldKeep(xtest.Call) || (itest.Call != nil && shouldKeep(itest.Call)) {
return
}
if !c.ShouldFix {
if itest.Call == nil {
log.Printf("%s: go_default_xtest is no longer necessary. Run 'gazelle fix' to rename to go_default_test.", f.Path)
} else {
log.Printf("%s: go_default_xtest is no longer necessary. Run 'gazelle fix' to squash with go_default_test.", f.Path)
}
return
}
// If there was no internal test, we can just rename the external test.
if itest.Call == nil {
xtest.SetAttr("name", &bf.StringExpr{Value: config.DefaultTestName})
return
}
// Attempt to squash.
if err := squashRule(xtest.Call, itest.Call, f.Path); err != nil {
log.Print(err)
return
}
// Delete the external test.
f.Stmt = append(f.Stmt[:xtestIndex], f.Stmt[xtestIndex+1:]...)
// Copy comments and attributes from external test to internal test.
itest.Call.Comments.Before = append(itest.Call.Comments.Before, xtest.Call.Comments.Before...)
itest.Call.Comments.Suffix = append(itest.Call.Comments.Suffix, xtest.Call.Comments.Suffix...)
itest.Call.Comments.After = append(itest.Call.Comments.After, xtest.Call.Comments.After...)
}
// squashRule copies information in mergeable attributes from src into dst. This
// works similarly to mergeRule, but it doesn't discard information from dst. It
// detects duplicate elements, but it doesn't sort elements after squashing.
// If squashing fails because the expression is understood, an error is
// returned, and neither rule is modified.
func squashRule(src, dst *bf.CallExpr, filename string) error {
srcRule := bf.Rule{Call: src}
dstRule := bf.Rule{Call: dst}
kind := dstRule.Kind()
type squashedAttr struct {
key string
attr bf.Expr
}
var squashedAttrs []squashedAttr
for _, k := range srcRule.AttrKeys() {
srcExpr := srcRule.Attr(k)
dstExpr := dstRule.Attr(k)
if dstExpr == nil {
dstRule.SetAttr(k, srcExpr)
continue
}
if !PreResolveAttrs[kind][k] && !PostResolveAttrs[kind][k] {
// keep non-mergeable attributes in dst (e.g., name, visibility)
continue
}
squashedExpr, err := squashExpr(srcExpr, dstExpr)
if err != nil {
start, end := dstExpr.Span()
return fmt.Errorf("%s:%d.%d-%d.%d: could not squash expression", filename, start.Line, start.LineRune, end.Line, end.LineRune)
}
squashedAttrs = append(squashedAttrs, squashedAttr{key: k, attr: squashedExpr})
}
for _, a := range squashedAttrs {
dstRule.SetAttr(a.key, a.attr)
}
return nil
}
func squashExpr(src, dst bf.Expr) (bf.Expr, error) {
if shouldKeep(dst) {
return dst, nil
}
if isScalar(dst) {
// may lose src, but they should always be the same.
return dst, nil
}
srcExprs, err := extractPlatformStringsExprs(src)
if err != nil {
return nil, err
}
yExprs, err := extractPlatformStringsExprs(y)
dstExprs, err := extractPlatformStringsExprs(dst)
if err != nil {
return nil, err
}
squashedExprs, err := squashPlatformStringsExprs(xExprs, yExprs)
squashedExprs, err := squashPlatformStringsExprs(srcExprs, dstExprs)
if err != nil {
return nil, err
}
@@ -159,7 +293,9 @@ func squashExpr(x, y bf.Expr) (bf.Expr, error) {
func squashPlatformStringsExprs(x, y platformStringsExprs) (platformStringsExprs, error) {
var ps platformStringsExprs
var err error
ps.generic = squashList(x.generic, y.generic)
if ps.generic, err = squashList(x.generic, y.generic); err != nil {
return platformStringsExprs{}, err
}
if ps.os, err = squashDict(x.os, y.os); err != nil {
return platformStringsExprs{}, err
}
@@ -172,19 +308,34 @@ func squashPlatformStringsExprs(x, y platformStringsExprs) (platformStringsExprs
return ps, nil
}
func squashList(x, y *bf.ListExpr) *bf.ListExpr {
func squashList(x, y *bf.ListExpr) (*bf.ListExpr, error) {
if x == nil {
return y
return y, nil
}
if y == nil {
return x
return x, nil
}
squashed := *x
ls := makeListSquasher()
for _, e := range x.List {
s, ok := e.(*bf.StringExpr)
if !ok {
return nil, errors.New("could not squash non-string")
}
ls.add(s)
}
for _, e := range y.List {
s, ok := e.(*bf.StringExpr)
if !ok {
return nil, errors.New("could not squash non-string")
}
ls.add(s)
}
squashed := ls.list()
squashed.Comments.Before = append(x.Comments.Before, y.Comments.Before...)
squashed.Comments.Suffix = append(x.Comments.Suffix, y.Comments.Suffix...)
squashed.Comments.After = append(x.Comments.After, y.Comments.After...)
squashed.List = append(x.List, y.List...)
return &squashed
return squashed, nil
}
func squashDict(x, y *bf.DictExpr) (*bf.DictExpr, error) {
@@ -195,47 +346,62 @@ func squashDict(x, y *bf.DictExpr) (*bf.DictExpr, error) {
return x, nil
}
cases := make(map[string]*bf.KeyValueExpr)
addCase := func(e bf.Expr) error {
kv := e.(*bf.KeyValueExpr)
key, ok := kv.Key.(*bf.StringExpr)
if !ok {
return errors.New("could not squash non-string dict key")
}
if _, ok := kv.Value.(*bf.ListExpr); !ok {
return errors.New("could not squash non-list dict value")
}
if c, ok := cases[key.Value]; ok {
if sq, err := squashList(kv.Value.(*bf.ListExpr), c.Value.(*bf.ListExpr)); err != nil {
return err
} else {
c.Value = sq
}
} else {
kvCopy := *kv
cases[key.Value] = &kvCopy
}
return nil
}
for _, e := range x.List {
if err := addCase(e); err != nil {
return nil, err
}
}
for _, e := range y.List {
if err := addCase(e); err != nil {
return nil, err
}
}
keys := make([]string, 0, len(cases))
haveDefault := false
for k := range cases {
if k == "//conditions:default" {
haveDefault = true
continue
}
keys = append(keys, k)
}
sort.Strings(keys)
if haveDefault {
keys = append(keys, "//conditions:default") // must be last
}
squashed := *x
squashed.Comments.Before = append(x.Comments.Before, y.Comments.Before...)
squashed.Comments.Suffix = append(x.Comments.Suffix, y.Comments.Suffix...)
squashed.Comments.After = append(x.Comments.After, y.Comments.After...)
xCaseIndex := make(map[string]int)
for i, e := range x.List {
kv, ok := e.(*bf.KeyValueExpr)
if !ok {
continue
}
key, ok := kv.Key.(*bf.StringExpr)
if !ok {
continue
}
xCaseIndex[key.Value] = i
squashed.List = make([]bf.Expr, 0, len(cases))
for _, k := range keys {
squashed.List = append(squashed.List, cases[k])
}
for _, e := range y.List {
kv, ok := e.(*bf.KeyValueExpr)
if !ok {
squashed.List = append(squashed.List, e)
continue
}
key, ok := e.(*bf.StringExpr)
if !ok {
squashed.List = append(squashed.List, e)
continue
}
i, ok := xCaseIndex[key.Value]
if !ok {
squashed.List = append(squashed.List, e)
continue
}
squashedElem, err := squashExpr(x.List[i], kv.Value)
if err != nil {
return nil, err
}
x.List[i] = squashedElem
}
return &squashed, nil
}
@@ -244,17 +410,17 @@ func squashDict(x, y *bf.DictExpr) (*bf.DictExpr, error) {
// go_proto_library attributes which are no longer recognized. New rules
// are generated in place of the deleted rules, but attributes and comments
// are not migrated.
func removeLegacyProto(c *config.Config, oldFile *bf.File) *bf.File {
func removeLegacyProto(c *config.Config, f *bf.File) {
// Don't fix if the proto mode was set to something other than the default.
if c.ProtoMode != config.DefaultProtoMode {
return oldFile
return
}
// Scan for definitions to delete.
var deletedIndices []int
var protoIndices []int
shouldDeleteProtos := false
for i, stmt := range oldFile.Stmt {
for i, stmt := range f.Stmt {
c, ok := stmt.(*bf.CallExpr)
if !ok {
continue
@@ -283,7 +449,11 @@ func removeLegacyProto(c *config.Config, oldFile *bf.File) *bf.File {
}
}
if len(deletedIndices) == 0 {
return oldFile
return
}
if !c.ShouldFix {
log.Printf("%s: go_proto_library.bzl is deprecated. Run 'gazelle fix' to replace old rules.", f.Path)
return
}
// Rebuild the file without deleted statements. Only delete go_proto_library
@@ -292,124 +462,90 @@ func removeLegacyProto(c *config.Config, oldFile *bf.File) *bf.File {
deletedIndices = append(deletedIndices, protoIndices...)
sort.Ints(deletedIndices)
}
fixedFile := *oldFile
fixedFile.Stmt = deleteIndices(oldFile.Stmt, deletedIndices)
return &fixedFile
f.Stmt = deleteIndices(f.Stmt, deletedIndices)
}
// FixFileMinor updates rules in oldFile that were generated by an older version
// of Gazelle to a newer form that can be merged with freshly generated rules.
//
// FixFileMinor includes only small, low-risk fixes that can be applied in
// update mode. When both FixFileMinor and FixFile are called, FixFileMinor
// should be called first.
//
// FixLoads should be called after this, since it will fix load
// statements that may be broken by transformations applied by this function.
func FixFileMinor(c *config.Config, oldFile *bf.File) *bf.File {
fixedFile := migrateLibraryEmbed(c, oldFile)
fixedFile = migrateGrpcCompilers(c, fixedFile)
return removeBinaryImportPath(c, fixedFile)
}
// migrateLibraryEmbed converts "library" attributes to "embed" attributes,
// preserving comments. This only applies to Go rules, and only if there is
// no keep comment on "library" and no existing "embed" attribute.
func migrateLibraryEmbed(c *config.Config, oldFile *bf.File) *bf.File {
fixed := false
fixedFile := *oldFile
for i, stmt := range fixedFile.Stmt {
// flattenSrcs transforms srcs attributes structured as concatenations of
// lists and selects (generated from PlatformStrings; see
// extractPlatformStringsExprs for matching details) into a sorted,
// de-duplicated list. Comments are accumulated and de-duplicated across
// duplicate expressions.
func flattenSrcs(c *config.Config, f *bf.File) {
for _, stmt := range f.Stmt {
call, ok := stmt.(*bf.CallExpr)
if !ok {
continue
}
rule := bf.Rule{Call: call}
if kind := rule.Kind(); !isGoRule(kind) || shouldKeep(stmt) {
if !isGoRule(rule.Kind()) {
continue
}
libExpr := rule.Attr("library")
if libExpr == nil || shouldKeep(libExpr) || rule.Attr("embed") != nil {
oldSrcs := rule.Attr("srcs")
if oldSrcs == nil {
continue
}
fixedCall := *call
rule.Call = &fixedCall
rule.DelAttr("library")
rule.SetAttr("embed", &bf.ListExpr{List: []bf.Expr{libExpr}})
fixedFile.Stmt[i] = &fixedCall
fixed = true
flatSrcs := flattenSrcsExpr(oldSrcs)
rule.SetAttr("srcs", flatSrcs)
}
if !fixed {
return oldFile
}
return &fixedFile
}
// migrateGrpcCompilers converts "go_grpc_library" rules into "go_proto_library"
// rules with a "compilers" attribute.
func migrateGrpcCompilers(c *config.Config, oldFile *bf.File) *bf.File {
fixed := false
fixedFile := *oldFile
for i, stmt := range fixedFile.Stmt {
call, ok := stmt.(*bf.CallExpr)
func flattenSrcsExpr(oldSrcs bf.Expr) bf.Expr {
oldExprs, err := extractPlatformStringsExprs(oldSrcs)
if err != nil {
return oldSrcs
}
ls := makeListSquasher()
addElem := func(e bf.Expr) bool {
s, ok := e.(*bf.StringExpr)
if !ok {
continue
return false
}
rule := bf.Rule{Call: call}
if rule.Kind() != "go_grpc_library" || shouldKeep(stmt) || rule.Attr("compilers") != nil {
continue
}
fixedCall := *call
fixedCall.List = make([]bf.Expr, len(call.List))
copy(fixedCall.List, call.List)
rule.Call = &fixedCall
rule.SetKind("go_proto_library")
rule.SetAttr("compilers", &bf.ListExpr{
List: []bf.Expr{&bf.StringExpr{Value: config.GrpcCompilerLabel}},
})
fixedFile.Stmt[i] = &fixedCall
fixed = true
ls.add(s)
return true
}
if !fixed {
return oldFile
}
return &fixedFile
}
// removeBinaryImportPath removes "importpath" attributes from "go_binary"
// and "go_test" rules. These are now deprecated.
func removeBinaryImportPath(c *config.Config, oldFile *bf.File) *bf.File {
fixed := false
fixedFile := *oldFile
for i, stmt := range fixedFile.Stmt {
call, ok := stmt.(*bf.CallExpr)
addList := func(e bf.Expr) bool {
l, ok := e.(*bf.ListExpr)
if !ok {
continue
return false
}
rule := bf.Rule{Call: call}
if rule.Kind() != "go_binary" && rule.Kind() != "go_test" || rule.Attr("importpath") == nil {
continue
for _, elem := range l.List {
if !addElem(elem) {
return false
}
}
return true
}
addDict := func(d *bf.DictExpr) bool {
for _, kv := range d.List {
if !addList(kv.(*bf.KeyValueExpr).Value) {
return false
}
}
return true
}
fixedCall := *call
fixedCall.List = make([]bf.Expr, len(call.List))
copy(fixedCall.List, call.List)
rule.Call = &fixedCall
rule.DelAttr("importpath")
fixedFile.Stmt[i] = &fixedCall
fixed = true
if oldExprs.generic != nil {
if !addList(oldExprs.generic) {
return oldSrcs
}
}
if !fixed {
return oldFile
for _, d := range []*bf.DictExpr{oldExprs.os, oldExprs.arch, oldExprs.platform} {
if d == nil {
continue
}
if !addDict(d) {
return oldSrcs
}
}
return &fixedFile
return ls.list()
}
// FixLoads removes loads of unused go rules and adds loads of newly used rules.
// This should be called after FixFile and MergeWithExisting, since symbols
// This should be called after FixFile and MergeFile, since symbols
// may be introduced that aren't loaded.
func FixLoads(oldFile *bf.File) *bf.File {
func FixLoads(f *bf.File) {
// Make a list of load statements in the file. Keep track of loads of known
// files, since these may be changed. Keep track of known symbols loaded from
// unknown files; we will not add loads for these.
@@ -420,7 +556,7 @@ func FixLoads(oldFile *bf.File) *bf.File {
}
var loads []loadInfo
otherLoadedKinds := make(map[string]bool)
for i, stmt := range oldFile.Stmt {
for i, stmt := range f.Stmt {
c, ok := stmt.(*bf.CallExpr)
if !ok {
continue
@@ -459,7 +595,7 @@ func FixLoads(oldFile *bf.File) *bf.File {
// Make a map of all the symbols from known files used in this file.
usedKinds := make(map[string]map[string]bool)
for _, stmt := range oldFile.Stmt {
for _, stmt := range f.Stmt {
c, ok := stmt.(*bf.CallExpr)
if !ok {
continue
@@ -481,7 +617,11 @@ func FixLoads(oldFile *bf.File) *bf.File {
// Fix the load statements. The order is important, so we iterate over
// knownLoads instead of knownFiles.
changed := false
var newFirstLoads []*bf.CallExpr
type newLoad struct {
index int
load *bf.CallExpr
}
var newLoads []newLoad
for _, l := range knownLoads {
file := l.file
first := true
@@ -501,49 +641,63 @@ func FixLoads(oldFile *bf.File) *bf.File {
if first {
load := fixLoad(nil, file, usedKinds[file])
if load != nil {
newFirstLoads = append(newFirstLoads, load)
index := newLoadIndex(f.Stmt, l.after)
newLoads = append(newLoads, newLoad{index, load})
changed = true
}
}
}
if !changed {
return oldFile
return
}
sort.Slice(newLoads, func(i, j int) bool {
return newLoads[i].index < newLoads[j].index
})
// Rebuild the file.
fixedFile := *oldFile
fixedFile.Stmt = make([]bf.Expr, 0, len(oldFile.Stmt)+len(newFirstLoads))
for _, l := range newFirstLoads {
fixedFile.Stmt = append(fixedFile.Stmt, l)
}
// Rebuild the file. Insert new loads at appropriate indices, replace fixed
// loads, and drop deleted loads.
oldStmt := f.Stmt
f.Stmt = make([]bf.Expr, 0, len(oldStmt)+len(newLoads))
newLoadIndex := 0
loadIndex := 0
for i, stmt := range oldFile.Stmt {
for i, stmt := range oldStmt {
for newLoadIndex < len(newLoads) && i == newLoads[newLoadIndex].index {
f.Stmt = append(f.Stmt, newLoads[newLoadIndex].load)
newLoadIndex++
}
if loadIndex < len(loads) && i == loads[loadIndex].index {
if loads[loadIndex].fixed != nil {
fixedFile.Stmt = append(fixedFile.Stmt, loads[loadIndex].fixed)
f.Stmt = append(f.Stmt, loads[loadIndex].fixed)
}
loadIndex++
continue
}
fixedFile.Stmt = append(fixedFile.Stmt, stmt)
f.Stmt = append(f.Stmt, stmt)
}
return &fixedFile
}
// knownLoads is a list of files Gazelle will generate loads from and
// the symbols it knows about. All symbols Gazelle ever generated
// the symbols it knows about. All symbols Gazelle ever generated
// loads for are present, including symbols it no longer uses (e.g.,
// cgo_library). Manually loaded symbols (e.g., go_embed_data) are not
// included. The order of the files here will match the order of
// generated load statements. The symbols should be sorted
// lexicographically.
// included.
//
// Some symbols have a list of function calls that they should be loaded
// after. This is important for WORKSPACE, where function calls may
// introduce new repository names.
//
// The order of the files here will match the order of generated load
// statements. The symbols should be sorted lexicographically. If a
// symbol appears in more than one file (e.g., because it was moved),
// it will be loaded from the last file in this list.
var knownLoads = []struct {
file string
kinds []string
after []string
}{
{
"@io_bazel_rules_go//go:def.bzl",
[]string{
file: "@io_bazel_rules_go//go:def.bzl",
kinds: []string{
"cgo_library",
"go_binary",
"go_library",
@@ -552,11 +706,21 @@ var knownLoads = []struct {
"go_test",
},
}, {
"@io_bazel_rules_go//proto:def.bzl",
[]string{
file: "@io_bazel_rules_go//proto:def.bzl",
kinds: []string{
"go_grpc_library",
"go_proto_library",
},
}, {
file: "@bazel_gazelle//:deps.bzl",
kinds: []string{
"go_repository",
},
after: []string{
"go_rules_dependencies",
"go_register_toolchains",
"gazelle_dependencies",
},
},
}
@@ -642,6 +806,181 @@ func fixLoad(load *bf.CallExpr, file string, kinds map[string]bool) *bf.CallExpr
return &fixed
}
// newLoadIndex returns the index in stmts where a new load statement should
// be inserted. after is a list of function names that the load should not
// be inserted before.
func newLoadIndex(stmts []bf.Expr, after []string) int {
if len(after) == 0 {
return 0
}
index := 0
for i, stmt := range stmts {
call, ok := stmt.(*bf.CallExpr)
if !ok {
continue
}
x, ok := call.X.(*bf.LiteralExpr)
if !ok {
continue
}
for _, a := range after {
if x.Token == a {
index = i + 1
}
}
}
return index
}
// FixWorkspace updates rules in the WORKSPACE file f that were used with an
// older version of rules_go or gazelle.
func FixWorkspace(f *bf.File) {
removeLegacyGoRepository(f)
}
// CheckGazelleLoaded searches the given WORKSPACE file for a repository named
// "bazel_gazelle". If no such repository is found *and* the repo is not
// declared with a directive *and* at least one load statement mentions
// the repository, a descriptive error will be returned.
//
// This should be called after modifications have been made to WORKSPACE
// (i.e., after FixLoads) before writing it to disk.
func CheckGazelleLoaded(f *bf.File) error {
needGazelle := false
for _, stmt := range f.Stmt {
call, ok := stmt.(*bf.CallExpr)
if !ok {
continue
}
x, ok := call.X.(*bf.LiteralExpr)
if !ok {
continue
}
if x.Token == "load" {
if len(call.List) == 0 {
continue
}
if s, ok := call.List[0].(*bf.StringExpr); ok && strings.HasPrefix(s.Value, "@bazel_gazelle//") {
needGazelle = true
}
continue
}
rule := bf.Rule{Call: call}
if rule.Name() == "bazel_gazelle" {
return nil
}
}
if !needGazelle {
return nil
}
for _, d := range config.ParseDirectives(f) {
if d.Key != "repo" {
continue
}
if fs := strings.Fields(d.Value); len(fs) > 0 && fs[0] == "bazel_gazelle" {
return nil
}
}
return fmt.Errorf(`%s: error: bazel_gazelle is not declared in WORKSPACE.
Without this repository, Gazelle cannot safely modify the WORKSPACE file.
See the instructions at https://github.com/bazelbuild/bazel-gazelle.
If the bazel_gazelle is declared inside a macro, you can suppress this error
by adding a comment like this to WORKSPACE:
# gazelle:repo bazel_gazelle
`, f.Path)
}
// removeLegacyGoRepository removes loads of go_repository from
// @io_bazel_rules_go. FixLoads should be called after this; it will load from
// @bazel_gazelle.
func removeLegacyGoRepository(f *bf.File) {
var deletedStmtIndices []int
for stmtIndex, stmt := range f.Stmt {
call, ok := stmt.(*bf.CallExpr)
if !ok || len(call.List) < 1 {
continue
}
if x, ok := call.X.(*bf.LiteralExpr); !ok || x.Token != "load" {
continue
}
if path, ok := call.List[0].(*bf.StringExpr); !ok || path.Value != "@io_bazel_rules_go//go:def.bzl" {
continue
}
var deletedArgIndices []int
for argIndex, arg := range call.List {
str, ok := arg.(*bf.StringExpr)
if !ok {
continue
}
if str.Value == "go_repository" {
deletedArgIndices = append(deletedArgIndices, argIndex)
}
}
if len(call.List)-len(deletedArgIndices) == 1 {
deletedStmtIndices = append(deletedStmtIndices, stmtIndex)
} else {
call.List = deleteIndices(call.List, deletedArgIndices)
}
}
f.Stmt = deleteIndices(f.Stmt, deletedStmtIndices)
}
// listSquasher builds a sorted, deduplicated list of string expressions. If
// a string expression is added multiple times, comments are consolidated.
// The original expressions are not modified.
type listSquasher struct {
unique map[string]*bf.StringExpr
seenComments map[elemComment]bool
}
type elemComment struct {
elem, com string
}
func makeListSquasher() listSquasher {
return listSquasher{
unique: make(map[string]*bf.StringExpr),
seenComments: make(map[elemComment]bool),
}
}
func (ls *listSquasher) add(s *bf.StringExpr) {
sCopy, ok := ls.unique[s.Value]
if !ok {
// Make a copy of s. We may modify it when we consolidate comments from
// duplicate strings. We don't want to modify the original in case this
// function fails (due to a later failed pattern match).
sCopy = new(bf.StringExpr)
*sCopy = *s
sCopy.Comments.Before = make([]bf.Comment, 0, len(s.Comments.Before))
sCopy.Comments.Suffix = make([]bf.Comment, 0, len(s.Comments.Suffix))
ls.unique[s.Value] = sCopy
}
for _, c := range s.Comment().Before {
if key := (elemComment{s.Value, c.Token}); !ls.seenComments[key] {
sCopy.Comments.Before = append(sCopy.Comments.Before, c)
ls.seenComments[key] = true
}
}
for _, c := range s.Comment().Suffix {
if key := (elemComment{s.Value, c.Token}); !ls.seenComments[key] {
sCopy.Comments.Suffix = append(sCopy.Comments.Suffix, c)
ls.seenComments[key] = true
}
}
}
func (ls *listSquasher) list() *bf.ListExpr {
sortedExprs := make([]bf.Expr, 0, len(ls.unique))
for _, e := range ls.unique {
sortedExprs = append(sortedExprs, e)
}
sort.Slice(sortedExprs, func(i, j int) bool {
return sortedExprs[i].(*bf.StringExpr).Value < sortedExprs[j].(*bf.StringExpr).Value
})
return &bf.ListExpr{List: sortedExprs}
}
type byString []*bf.StringExpr
func (s byString) Len() int {

View File

@@ -83,6 +83,7 @@ func init() {
},
attrs: []string{
"importpath",
"importmap",
},
}, {
mergeableAttrs: PreResolveAttrs,
@@ -178,31 +179,28 @@ func init() {
}
}
// MergeFile merges the rules in genRules with matching rules in oldFile and
// MergeFile merges the rules in genRules with matching rules in f and
// adds unmatched rules to the end of the merged file. MergeFile also merges
// rules in empty with matching rules in oldFile and deletes rules that
// rules in empty with matching rules in f and deletes rules that
// are empty after merging. attrs is the set of attributes to merge. Attributes
// not in this set will be left alone if they already exist.
func MergeFile(genRules []bf.Expr, empty []bf.Expr, oldFile *bf.File, attrs MergeableAttrs) (mergedFile *bf.File, mergedRules []bf.Expr) {
func MergeFile(genRules []bf.Expr, empty []bf.Expr, f *bf.File, attrs MergeableAttrs) (mergedRules []bf.Expr) {
// Merge empty rules into the file and delete any rules which become empty.
mergedFile = new(bf.File)
*mergedFile = *oldFile
mergedFile.Stmt = append([]bf.Expr{}, oldFile.Stmt...)
var deletedIndices []int
for _, s := range empty {
emptyCall := s.(*bf.CallExpr)
if oldCall, i, _ := match(oldFile.Stmt, emptyCall); oldCall != nil {
mergedRule := mergeRule(emptyCall, oldCall, attrs, oldFile.Path)
if oldCall, i, _ := match(f.Stmt, emptyCall); oldCall != nil {
mergedRule := mergeRule(emptyCall, oldCall, attrs, f.Path)
if isRuleEmpty(mergedRule) {
deletedIndices = append(deletedIndices, i)
} else {
mergedFile.Stmt[i] = mergedRule
f.Stmt[i] = mergedRule
}
}
}
if len(deletedIndices) > 0 {
sort.Ints(deletedIndices)
mergedFile.Stmt = deleteIndices(mergedFile.Stmt, deletedIndices)
f.Stmt = deleteIndices(f.Stmt, deletedIndices)
}
// Match generated rules with existing rules in the file. Keep track of
@@ -212,7 +210,7 @@ func MergeFile(genRules []bf.Expr, empty []bf.Expr, oldFile *bf.File, attrs Merg
substitutions := make(map[string]string)
for i, s := range genRules {
genCall := s.(*bf.CallExpr)
oldCall, oldIndex, err := match(mergedFile.Stmt, genCall)
oldCall, oldIndex, err := match(f.Stmt, genCall)
if err != nil {
// TODO(jayconrod): add a verbose mode and log errors. They are too chatty
// to print by default.
@@ -245,16 +243,16 @@ func MergeFile(genRules []bf.Expr, empty []bf.Expr, oldFile *bf.File, attrs Merg
continue
}
if matchIndices[i] < 0 {
mergedFile.Stmt = append(mergedFile.Stmt, genRules[i])
f.Stmt = append(f.Stmt, genRules[i])
mergedRules = append(mergedRules, genRules[i])
} else {
mergedRule := mergeRule(genRules[i].(*bf.CallExpr), mergedFile.Stmt[matchIndices[i]].(*bf.CallExpr), attrs, oldFile.Path)
mergedFile.Stmt[matchIndices[i]] = mergedRule
mergedRule := mergeRule(genRules[i].(*bf.CallExpr), f.Stmt[matchIndices[i]].(*bf.CallExpr), attrs, f.Path)
f.Stmt[matchIndices[i]] = mergedRule
mergedRules = append(mergedRules, mergedRule)
}
}
return mergedFile, mergedRules
return mergedRules
}
// mergeRule combines information from gen and old and returns an updated rule.
@@ -829,7 +827,7 @@ func match(stmts []bf.Expr, x *bf.CallExpr) (*bf.CallExpr, int, error) {
return nameMatches[0].rule.Call, nameMatches[0].index, nil
}
if len(nameMatches) > 1 {
return nil, -1, fmt.Errorf("could not merge %s(%s): multiple rules have the same name", xname)
return nil, -1, fmt.Errorf("could not merge %s(%s): multiple rules have the same name", xkind, xname)
}
attrs := matchAttrs[xr.Kind()]
@@ -913,6 +911,9 @@ func stringValue(e bf.Expr) string {
// deleteIndices copies a list, dropping elements at deletedIndices.
// deletedIndices must be sorted.
func deleteIndices(stmt []bf.Expr, deletedIndices []int) []bf.Expr {
if len(deletedIndices) == 0 {
return stmt
}
kept := make([]bf.Expr, 0, len(stmt)-len(deletedIndices))
di := 0
for i, s := range stmt {

View File

@@ -10,6 +10,7 @@ go_library(
"package.go",
"walk.go",
],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/packages",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/packages",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
deps = [

View File

@@ -49,10 +49,6 @@ type fileInfo struct {
// ends with "_test.go". This is never true for non-Go files.
isTest bool
// isXTest is true for test Go files whose declared package name ends
// with "_test".
isXTest bool
// imports is a list of packages imported by a file. It does not include
// "C" or anything from the standard library.
imports []string

View File

@@ -49,7 +49,6 @@ func goFileInfo(c *config.Config, dir, rel, name string) fileInfo {
info.packageName = pf.Name.Name
if info.isTest && strings.HasSuffix(info.packageName, "_test") {
info.isXTest = true
info.packageName = info.packageName[:len(info.packageName)-len("_test")]
}

View File

@@ -45,8 +45,8 @@ type Package struct {
// ImportPath is the string used to import this package in Go.
ImportPath string
Library, Binary, Test, XTest GoTarget
Proto ProtoTarget
Library, Binary, Test GoTarget
Proto ProtoTarget
HasTestdata bool
}
@@ -129,6 +129,34 @@ func (ps *PlatformStrings) IsEmpty() bool {
return len(ps.Generic) == 0 && len(ps.OS) == 0 && len(ps.Arch) == 0 && len(ps.Platform) == 0
}
func (ps *PlatformStrings) Flat() []string {
unique := make(map[string]struct{})
for _, s := range ps.Generic {
unique[s] = struct{}{}
}
for _, ss := range ps.OS {
for _, s := range ss {
unique[s] = struct{}{}
}
}
for _, ss := range ps.Arch {
for _, s := range ss {
unique[s] = struct{}{}
}
}
for _, ss := range ps.Platform {
for _, s := range ss {
unique[s] = struct{}{}
}
}
flat := make([]string, 0, len(unique))
for s := range unique {
flat = append(flat, s)
}
sort.Strings(flat)
return flat
}
func (ps *PlatformStrings) firstGoFile() string {
for _, f := range ps.Generic {
if strings.HasSuffix(f, ".go") {
@@ -160,11 +188,11 @@ func (ps *PlatformStrings) firstGoFile() string {
}
type packageBuilder struct {
name, dir, rel string
library, binary, test, xtest goTargetBuilder
proto protoTargetBuilder
hasTestdata bool
importPath, importPathFile string
name, dir, rel string
library, binary, test goTargetBuilder
proto protoTargetBuilder
hasTestdata bool
importPath, importPathFile string
}
type goTargetBuilder struct {
@@ -212,11 +240,6 @@ func (pb *packageBuilder) addFile(c *config.Config, info fileInfo, cgo bool) err
!cgo && (info.category == cExt || info.category == csExt) ||
c.ProtoMode == config.DisableProtoMode && info.category == protoExt:
return nil
case info.isXTest:
if info.isCgo {
return fmt.Errorf("%s: use of cgo in test not supported", info.path)
}
pb.xtest.addFile(c, info)
case info.isTest:
if info.isCgo {
return fmt.Errorf("%s: use of cgo in test not supported", info.path)
@@ -258,7 +281,6 @@ func (pb *packageBuilder) firstGoFile() string {
pb.library.sources,
pb.binary.sources,
pb.test.sources,
pb.xtest.sources,
}
for _, sb := range goSrcs {
if sb.strs != nil {
@@ -297,7 +319,6 @@ func (pb *packageBuilder) build() *Package {
Library: pb.library.build(),
Binary: pb.binary.build(),
Test: pb.test.build(),
XTest: pb.xtest.build(),
Proto: pb.proto.build(),
HasTestdata: pb.hasTestdata,
}

View File

@@ -135,6 +135,8 @@ func Walk(c *config.Config, root string, f WalkFunc) {
cCopy := *c
cCopy.GoPrefix = ""
cCopy.GoPrefixRel = rel
cCopy.GoImportMapPrefix = path.Join(c.RepoName, rel)
cCopy.GoImportMapPrefixRel = rel
c = &cCopy
}
var directives []config.Directive

View File

@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["path.go"],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/pathtools",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/pathtools",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
)

View File

@@ -7,12 +7,13 @@ go_library(
"remote.go",
"repo.go",
],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/repos",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/repos",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
deps = [
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/generator:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/label:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/pathtools:go_default_library",
"//vendor/github.com/bazelbuild/bazel-gazelle/internal/rules:go_default_library",
"//vendor/github.com/bazelbuild/buildtools/build:go_default_library",
"//vendor/github.com/pelletier/go-toml:go_default_library",
"//vendor/golang.org/x/tools/go/vcs:go_default_library",

View File

@@ -22,7 +22,7 @@ import (
"sort"
"strings"
"github.com/bazelbuild/bazel-gazelle/internal/rules"
"github.com/bazelbuild/bazel-gazelle/internal/generator"
bf "github.com/bazelbuild/buildtools/build"
)
@@ -103,18 +103,18 @@ func getLockFileFormat(filename string) lockFileFormat {
// GenerateRule returns a repository rule for the given repository that can
// be written in a WORKSPACE file.
func GenerateRule(repo Repo) bf.Expr {
attrs := []rules.KeyValue{
attrs := []generator.KeyValue{
{Key: "name", Value: repo.Name},
{Key: "commit", Value: repo.Commit},
{Key: "importpath", Value: repo.GoPrefix},
}
if repo.Remote != "" {
attrs = append(attrs, rules.KeyValue{Key: "remote", Value: repo.Remote})
attrs = append(attrs, generator.KeyValue{Key: "remote", Value: repo.Remote})
}
if repo.VCS != "" {
attrs = append(attrs, rules.KeyValue{Key: "vcs", Value: repo.VCS})
attrs = append(attrs, generator.KeyValue{Key: "vcs", Value: repo.VCS})
}
return rules.NewRule("go_repository", attrs)
return generator.NewRule("go_repository", attrs)
}
// FindExternalRepo attempts to locate the directory where Bazel has fetched

View File

@@ -9,6 +9,7 @@ go_library(
"resolve_vendored.go",
"std_package_list.go",
],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/resolve",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/resolve",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
deps = [

View File

@@ -76,13 +76,16 @@ func (r *Resolver) ResolveRule(e bf.Expr, pkgRel string) bf.Expr {
from := label.New("", pkgRel, rule.Name())
var resolve func(imp string, from label.Label) (label.Label, error)
var embeds []label.Label
switch rule.Kind() {
case "go_library", "go_binary", "go_test":
resolve = r.resolveGo
embeds = getEmbedsGo(call, from)
case "proto_library":
resolve = r.resolveProto
case "go_proto_library", "go_grpc_library":
resolve = r.resolveGoProto
embeds = getEmbedsGo(call, from)
default:
return e
}
@@ -105,6 +108,11 @@ func (r *Resolver) ResolveRule(e bf.Expr, pkgRel string) bf.Expr {
return ""
}
}
for _, e := range embeds {
if label.Equal(e) {
return ""
}
}
label.Relative = label.Repo == "" && label.Pkg == pkgRel
return label.String()
})
@@ -226,6 +234,10 @@ func (r *Resolver) resolveGo(imp string, from label.Label) (label.Label, error)
return label.NoLabel, standardImportError{imp}
}
if l := resolveWellKnownGo(imp); !l.Equal(label.NoLabel) {
return l, nil
}
if l, err := r.ix.findLabelByImport(importSpec{config.GoLang, imp}, config.GoLang, from); err != nil {
if _, ok := err.(ruleNotFoundError); !ok {
return label.NoLabel, err
@@ -241,19 +253,13 @@ func (r *Resolver) resolveGo(imp string, from label.Label) (label.Label, error)
return r.external.resolve(imp)
}
const (
wellKnownPrefix = "google/protobuf/"
wellKnownGoProtoPkg = "ptypes"
descriptorPkg = "protoc-gen-go/descriptor"
)
// resolveProto resolves an import statement in a .proto file to a label
// for a proto_library rule.
func (r *Resolver) resolveProto(imp string, from label.Label) (label.Label, error) {
if !strings.HasSuffix(imp, ".proto") {
return label.NoLabel, fmt.Errorf("can't import non-proto: %q", imp)
}
if isWellKnown(imp) {
if isWellKnownProto(imp) {
name := path.Base(imp[:len(imp)-len(".proto")]) + "_proto"
return label.New(config.WellKnownTypesProtoRepo, "", name), nil
}
@@ -282,40 +288,8 @@ func (r *Resolver) resolveGoProto(imp string, from label.Label) (label.Label, er
}
stem := imp[:len(imp)-len(".proto")]
if isWellKnown(stem) {
// Well Known Type
base := path.Base(stem)
if base == "descriptor" {
switch r.c.DepMode {
case config.ExternalMode:
label := r.l.LibraryLabel(descriptorPkg)
if r.c.GoPrefix != config.WellKnownTypesGoPrefix {
label.Repo = config.WellKnownTypesGoProtoRepo
}
return label, nil
case config.VendorMode:
pkg := path.Join("vendor", config.WellKnownTypesGoPrefix, descriptorPkg)
label := r.l.LibraryLabel(pkg)
return label, nil
default:
log.Panicf("unknown external mode: %v", r.c.DepMode)
}
}
switch r.c.DepMode {
case config.ExternalMode:
pkg := path.Join(wellKnownGoProtoPkg, base)
label := r.l.LibraryLabel(pkg)
if r.c.GoPrefix != config.WellKnownTypesGoPrefix {
label.Repo = config.WellKnownTypesGoProtoRepo
}
return label, nil
case config.VendorMode:
pkg := path.Join("vendor", config.WellKnownTypesGoPrefix, wellKnownGoProtoPkg, base)
return r.l.LibraryLabel(pkg), nil
default:
log.Panicf("unknown external mode: %v", r.c.DepMode)
}
if isWellKnownProto(stem) {
return label.NoLabel, standardImportError{imp}
}
if l, err := r.ix.findLabelByImport(importSpec{config.ProtoLang, imp}, config.GoLang, from); err != nil {
@@ -340,11 +314,67 @@ func (r *Resolver) resolveGoProto(imp string, from label.Label) (label.Label, er
return r.l.LibraryLabel(rel), nil
}
func getEmbedsGo(call *bf.CallExpr, from label.Label) []label.Label {
rule := bf.Rule{Call: call}
embedStrings := rule.AttrStrings("embed")
embedLabels := make([]label.Label, 0, len(embedStrings))
for _, s := range embedStrings {
l, err := label.Parse(s)
if err != nil {
continue
}
l = l.Abs(from.Repo, from.Pkg)
embedLabels = append(embedLabels, l)
}
return embedLabels
}
// IsStandard returns whether a package is in the standard library.
func IsStandard(imp string) bool {
return stdPackages[imp]
}
func isWellKnown(imp string) bool {
return strings.HasPrefix(imp, wellKnownPrefix) && strings.TrimPrefix(imp, wellKnownPrefix) == path.Base(imp)
func isWellKnownProto(imp string) bool {
return pathtools.HasPrefix(imp, config.WellKnownTypesProtoPrefix) && pathtools.TrimPrefix(imp, config.WellKnownTypesProtoPrefix) == path.Base(imp)
}
func resolveWellKnownGo(imp string) label.Label {
// keep in sync with @io_bazel_rules_go//proto/wkt:well_known_types.bzl
// TODO(jayconrod): in well_known_types.bzl, write the import paths and
// targets in a public dict. Import it here, and use it to generate this code.
switch imp {
case "github.com/golang/protobuf/ptypes/any",
"github.com/golang/protobuf/ptypes/api",
"github.com/golang/protobuf/protoc-gen-go/descriptor",
"github.com/golang/protobuf/ptypes/duration",
"github.com/golang/protobuf/ptypes/empty",
"google.golang.org/genproto/protobuf/field_mask",
"google.golang.org/genproto/protobuf/source_context",
"github.com/golang/protobuf/ptypes/struct",
"github.com/golang/protobuf/ptypes/timestamp",
"github.com/golang/protobuf/ptypes/wrappers":
return label.Label{
Repo: config.RulesGoRepoName,
Pkg: config.WellKnownTypesPkg,
Name: path.Base(imp) + "_go_proto",
}
case "github.com/golang/protobuf/protoc-gen-go/plugin":
return label.Label{
Repo: config.RulesGoRepoName,
Pkg: config.WellKnownTypesPkg,
Name: "compiler_plugin_go_proto",
}
case "google.golang.org/genproto/protobuf/ptype":
return label.Label{
Repo: config.RulesGoRepoName,
Pkg: config.WellKnownTypesPkg,
Name: "type_go_proto",
}
}
return label.NoLabel
}
func isWellKnownGo(imp string) bool {
prefix := config.WellKnownTypesGoPrefix + "/ptypes/"
return strings.HasPrefix(imp, prefix) && strings.TrimPrefix(imp, prefix) == path.Base(imp)
}

View File

@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["version.go"],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/version",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/version",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
)

View File

@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["finder.go"],
importmap = "vendor/github.com/bazelbuild/bazel-gazelle/internal/wspace",
importpath = "github.com/bazelbuild/bazel-gazelle/internal/wspace",
visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"],
)

View File

@@ -12,6 +12,7 @@ go_library(
"syntax.go",
"walk.go",
],
importmap = "vendor/github.com/bazelbuild/buildtools/build",
importpath = "github.com/bazelbuild/buildtools/build",
visibility = ["//visibility:public"],
deps = ["//vendor/github.com/bazelbuild/buildtools/tables:go_default_library"],

View File

@@ -6,6 +6,7 @@ go_library(
"jsonparser.go",
"tables.go",
],
importmap = "vendor/github.com/bazelbuild/buildtools/tables",
importpath = "github.com/bazelbuild/buildtools/tables",
visibility = ["//visibility:public"],
)