Create Gazelle language for Starlark (#251)
This commit is contained in:
parent
b10f2cb0fc
commit
d35e8d7bc6
15
BUILD
15
BUILD
|
@ -4,6 +4,11 @@ licenses(["notice"])
|
|||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
# gazelle:exclude internal_deps.bzl
|
||||
# gazelle:exclude internal_setup.bzl
|
||||
# buildifier: disable=skylark-comment
|
||||
# gazelle:exclude skylark_library.bzl
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
filegroup(
|
||||
|
@ -45,6 +50,16 @@ bzl_library(
|
|||
srcs = ["bzl_library.bzl"],
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "version",
|
||||
srcs = ["version.bzl"],
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "workspace",
|
||||
srcs = ["workspace.bzl"],
|
||||
)
|
||||
|
||||
# The files needed for distribution.
|
||||
# TODO(aiuto): We should strip this from the release, but there is no
|
||||
# capability now to generate BUILD.foo from BUILD and have it appear in the
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
* @c-parsons @laurentlb @jin @aiuto
|
||||
distribution/ @aiuto @fwe
|
||||
rules/ @juliexxia
|
||||
gazelle/ @achew22 @jayconrod
|
||||
|
|
27
WORKSPACE
27
WORKSPACE
|
@ -10,14 +10,20 @@ maybe(
|
|||
url = "https://github.com/bazelbuild/bazel-federation/releases/download/0.0.1/bazel_federation-0.0.1.tar.gz",
|
||||
)
|
||||
|
||||
load("@bazel_federation//:repositories.bzl", "bazel_skylib_deps")
|
||||
load("@bazel_federation//:repositories.bzl", "bazel_skylib_deps", "rules_go")
|
||||
|
||||
bazel_skylib_deps()
|
||||
|
||||
rules_go()
|
||||
|
||||
load("@bazel_federation//setup:bazel_skylib.bzl", "bazel_skylib_setup")
|
||||
|
||||
bazel_skylib_setup()
|
||||
|
||||
load("@bazel_federation//setup:rules_go.bzl", "rules_go_setup")
|
||||
|
||||
rules_go_setup()
|
||||
|
||||
# Below this line is for documentation generation only,
|
||||
# and should thus not be included by dependencies on
|
||||
# bazel-skylib.
|
||||
|
@ -40,3 +46,22 @@ maybe(
|
|||
"https://github.com/bazelbuild/rules_cc/archive/cb2dfba6746bfa3c3705185981f3109f0ae1b893.zip",
|
||||
],
|
||||
)
|
||||
|
||||
# Provide a repository hint for Gazelle to inform it that the go package
|
||||
# github.com/bazelbuild/rules_go is available from io_bazel_rules_go and it
|
||||
# doesn't need to duplicatively fetch it.
|
||||
# gazelle:repository go_repository name=io_bazel_rules_go importpath=github.com/bazelbuild/rules_go
|
||||
http_archive(
|
||||
name = "bazel_gazelle",
|
||||
sha256 = "bfd86b3cbe855d6c16c6fce60d76bd51f5c8dbc9cfcaef7a2bb5c1aafd0710e8",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.0/bazel-gazelle-v0.21.0.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.0/bazel-gazelle-v0.21.0.tar.gz",
|
||||
],
|
||||
)
|
||||
# Another Gazelle repository hint.
|
||||
# gazelle:repository go_repository name=bazel_gazelle importpath=github.com/bazelbuild/bazel-gazelle/testtools
|
||||
|
||||
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
|
||||
|
||||
gazelle_dependencies()
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary")
|
||||
|
||||
# gazelle:exclude testdata
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["gazelle.go"],
|
||||
importpath = "github.com/bazelbuild/bazel-skylib/gazelle",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"@bazel_gazelle//config:go_default_library",
|
||||
"@bazel_gazelle//label:go_default_library",
|
||||
"@bazel_gazelle//language:go_default_library",
|
||||
"@bazel_gazelle//pathtools:go_default_library",
|
||||
"@bazel_gazelle//repo:go_default_library",
|
||||
"@bazel_gazelle//resolve:go_default_library",
|
||||
"@bazel_gazelle//rule:go_default_library",
|
||||
"@com_github_bazelbuild_buildtools//build:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["gazelle_test.go"],
|
||||
data = [
|
||||
":gazelle-skylib",
|
||||
] + glob([
|
||||
"testdata/**",
|
||||
]),
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"@bazel_gazelle//testtools:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
# This gazelle binary is used exclusively for testing the gazelle language
|
||||
# extension and thus only has the skylib language installed.
|
||||
gazelle_binary(
|
||||
name = "gazelle-skylib",
|
||||
languages = [":go_default_library"],
|
||||
visibility = [
|
||||
# Also make the binary available in the root of the repo for use, but
|
||||
# not externally.
|
||||
"//:__pkg__",
|
||||
],
|
||||
)
|
||||
|
||||
gazelle(
|
||||
name = "gazelle",
|
||||
gazelle = "//gazelle:gazelle-skylib",
|
||||
)
|
|
@ -0,0 +1,13 @@
|
|||
# Gazelle
|
||||
|
||||
Gazelle is a `BUILD` file generator for Bazel. This directory contains a
|
||||
language extension for the Gazelle generator that allows it to automatically
|
||||
parse valid `bzl_library` targets for all `.bzl` files in a repo in which it
|
||||
runs. It will additionally include a `deps` entry tracking every `.bzl` that is
|
||||
`load`ed into the primary file.
|
||||
|
||||
This can be used, for example, to generate
|
||||
[`stardoc`](https://github.com/bazelbuild/stardoc) documentation for your
|
||||
`.bzl` files, both simplify the task of and improve the quality of
|
||||
documentation.
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
/* Copyright 2020 The Bazel Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package gazelle generates a `bzl_library` target for every `.bzl` file in
|
||||
// each package.
|
||||
//
|
||||
// The `bzl_library` rule is provided by
|
||||
// https://github.com/bazelbuild/bazel-skylib.
|
||||
//
|
||||
// This extension is experimental and subject to change. It is not included
|
||||
// in the default Gazelle binary.
|
||||
package gazelle
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/bazelbuild/bazel-gazelle/config"
|
||||
"github.com/bazelbuild/bazel-gazelle/label"
|
||||
"github.com/bazelbuild/bazel-gazelle/language"
|
||||
"github.com/bazelbuild/bazel-gazelle/pathtools"
|
||||
"github.com/bazelbuild/bazel-gazelle/repo"
|
||||
"github.com/bazelbuild/bazel-gazelle/resolve"
|
||||
"github.com/bazelbuild/bazel-gazelle/rule"
|
||||
|
||||
"github.com/bazelbuild/buildtools/build"
|
||||
)
|
||||
|
||||
const languageName = "starlark"
|
||||
const fileType = ".bzl"
|
||||
|
||||
var ignoreSuffix = suffixes{
|
||||
"_tests.bzl",
|
||||
"_test.bzl",
|
||||
}
|
||||
|
||||
type suffixes []string
|
||||
|
||||
func (s suffixes) Matches(test string) bool {
|
||||
for _, v := range s {
|
||||
if strings.HasSuffix(test, v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type bzlLibraryLang struct{}
|
||||
|
||||
// NewLanguage is called by Gazelle to install this language extension in a binary.
|
||||
func NewLanguage() language.Language {
|
||||
return &bzlLibraryLang{}
|
||||
}
|
||||
|
||||
// Name returns the name of the language. This should be a prefix of the
|
||||
// kinds of rules generated by the language, e.g., "go" for the Go extension
|
||||
// since it generates "go_library" rules.
|
||||
func (*bzlLibraryLang) Name() string { return languageName }
|
||||
|
||||
// The following methods are implemented to satisfy the
|
||||
// https://pkg.go.dev/github.com/bazelbuild/bazel-gazelle/resolve?tab=doc#Resolver
|
||||
// interface, but are otherwise unused.
|
||||
func (*bzlLibraryLang) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config) {}
|
||||
func (*bzlLibraryLang) CheckFlags(fs *flag.FlagSet, c *config.Config) error { return nil }
|
||||
func (*bzlLibraryLang) KnownDirectives() []string { return nil }
|
||||
func (*bzlLibraryLang) Configure(c *config.Config, rel string, f *rule.File) {}
|
||||
|
||||
// Kinds returns a map of maps rule names (kinds) and information on how to
|
||||
// match and merge attributes that may be found in rules of those kinds. All
|
||||
// kinds of rules generated for this language may be found here.
|
||||
func (*bzlLibraryLang) Kinds() map[string]rule.KindInfo {
|
||||
return kinds
|
||||
}
|
||||
|
||||
// Loads returns .bzl files and symbols they define. Every rule generated by
|
||||
// GenerateRules, now or in the past, should be loadable from one of these
|
||||
// files.
|
||||
func (*bzlLibraryLang) Loads() []rule.LoadInfo {
|
||||
return []rule.LoadInfo{{
|
||||
Name: "@bazel_skylib//:bzl_library.bzl",
|
||||
Symbols: []string{"bzl_library"},
|
||||
}}
|
||||
}
|
||||
|
||||
// Fix repairs deprecated usage of language-specific rules in f. This is
|
||||
// called before the file is indexed. Unless c.ShouldFix is true, fixes
|
||||
// that delete or rename rules should not be performed.
|
||||
func (*bzlLibraryLang) Fix(c *config.Config, f *rule.File) {}
|
||||
|
||||
// Imports returns a list of ImportSpecs that can be used to import the rule
|
||||
// r. This is used to populate RuleIndex.
|
||||
//
|
||||
// If nil is returned, the rule will not be indexed. If any non-nil slice is
|
||||
// returned, including an empty slice, the rule will be indexed.
|
||||
func (b *bzlLibraryLang) Imports(c *config.Config, r *rule.Rule, f *rule.File) []resolve.ImportSpec {
|
||||
srcs := r.AttrStrings("srcs")
|
||||
imports := make([]resolve.ImportSpec, len(srcs))
|
||||
|
||||
for _, src := range srcs {
|
||||
spec := resolve.ImportSpec{
|
||||
// Lang is the language in which the import string appears (this should
|
||||
// match Resolver.Name).
|
||||
Lang: languageName,
|
||||
// Imp is an import string for the library.
|
||||
Imp: fmt.Sprintf("//%s:%s", f.Pkg, src),
|
||||
}
|
||||
|
||||
imports = append(imports, spec)
|
||||
}
|
||||
|
||||
return imports
|
||||
}
|
||||
|
||||
// Embeds returns a list of labels of rules that the given rule embeds. If
|
||||
// a rule is embedded by another importable rule of the same language, only
|
||||
// the embedding rule will be indexed. The embedding rule will inherit
|
||||
// the imports of the embedded rule.
|
||||
// Since SkyLark doesn't support embedding this should always return nil.
|
||||
func (*bzlLibraryLang) Embeds(r *rule.Rule, from label.Label) []label.Label { return nil }
|
||||
|
||||
// Resolve translates imported libraries for a given rule into Bazel
|
||||
// dependencies. Information about imported libraries is returned for each
|
||||
// rule generated by language.GenerateRules in
|
||||
// language.GenerateResult.Imports. Resolve generates a "deps" attribute (or
|
||||
// the appropriate language-specific equivalent) for each import according to
|
||||
// language-specific rules and heuristics.
|
||||
func (*bzlLibraryLang) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.RemoteCache, r *rule.Rule, importsRaw interface{}, from label.Label) {
|
||||
imports := importsRaw.([]string)
|
||||
|
||||
r.DelAttr("deps")
|
||||
|
||||
if len(imports) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
deps := make([]string, 0, len(imports))
|
||||
for _, imp := range imports {
|
||||
if strings.HasPrefix(imp, "@") || !c.IndexLibraries {
|
||||
// This is a dependency that is external to the current repo, or indexing
|
||||
// is disabled so take a guess at what hte target name should be.
|
||||
deps = append(deps, strings.TrimSuffix(imp, fileType))
|
||||
} else {
|
||||
res := resolve.ImportSpec{
|
||||
Lang: languageName,
|
||||
Imp: imp,
|
||||
}
|
||||
matches := ix.FindRulesByImport(res, languageName)
|
||||
|
||||
if len(matches) == 0 {
|
||||
log.Printf("%s: %q was not found in dependency index. Skipping. This may result in an incomplete deps section and require manual BUILD file intervention.\n", from.String(), imp)
|
||||
}
|
||||
|
||||
for _, m := range matches {
|
||||
deps = append(deps, m.Label.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(deps)
|
||||
if len(deps) > 0 {
|
||||
r.SetAttr("deps", deps)
|
||||
}
|
||||
}
|
||||
|
||||
var kinds = map[string]rule.KindInfo{
|
||||
"bzl_library": {
|
||||
NonEmptyAttrs: map[string]bool{"srcs": true, "deps": true},
|
||||
MergeableAttrs: map[string]bool{"srcs": true},
|
||||
},
|
||||
}
|
||||
|
||||
// GenerateRules extracts build metadata from source files in a directory.
|
||||
// GenerateRules is called in each directory where an update is requested
|
||||
// in depth-first post-order.
|
||||
//
|
||||
// args contains the arguments for GenerateRules. This is passed as a
|
||||
// struct to avoid breaking implementations in the future when new
|
||||
// fields are added.
|
||||
//
|
||||
// A GenerateResult struct is returned. Optional fields may be added to this
|
||||
// type in the future.
|
||||
//
|
||||
// Any non-fatal errors this function encounters should be logged using
|
||||
// log.Print.
|
||||
func (*bzlLibraryLang) GenerateRules(args language.GenerateArgs) language.GenerateResult {
|
||||
var rules []*rule.Rule
|
||||
var imports []interface{}
|
||||
for _, f := range append(args.RegularFiles, args.GenFiles...) {
|
||||
if !isBzlSourceFile(f) {
|
||||
continue
|
||||
}
|
||||
name := strings.TrimSuffix(f, fileType)
|
||||
r := rule.NewRule("bzl_library", name)
|
||||
|
||||
r.SetAttr("srcs", []string{f})
|
||||
|
||||
if args.File == nil || !args.File.HasDefaultVisibility() {
|
||||
inPrivateDir := pathtools.Index(args.Rel, "private") >= 0
|
||||
if !inPrivateDir {
|
||||
r.SetAttr("visibility", []string{"//visibility:public"})
|
||||
}
|
||||
}
|
||||
|
||||
fullPath := filepath.Join(args.Dir, f)
|
||||
loads, err := getBzlFileLoads(fullPath)
|
||||
if err != nil {
|
||||
log.Printf("%s: contains syntax errors: %v", fullPath, err)
|
||||
// Don't `continue` since it is reasonable to create a target even
|
||||
// without deps.
|
||||
}
|
||||
|
||||
rules = append(rules, r)
|
||||
imports = append(imports, loads)
|
||||
}
|
||||
|
||||
return language.GenerateResult{
|
||||
Gen: rules,
|
||||
Imports: imports,
|
||||
Empty: generateEmpty(args),
|
||||
}
|
||||
}
|
||||
|
||||
func getBzlFileLoads(path string) ([]string, error) {
|
||||
f, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ioutil.ReadFile(%q) error: %v", path, err)
|
||||
}
|
||||
ast, err := build.ParseBuild(path, f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("build.Parse(%q) error: %v", f, err)
|
||||
}
|
||||
|
||||
var loads []string
|
||||
build.WalkOnce(ast, func(expr *build.Expr) {
|
||||
n := *expr
|
||||
if l, ok := n.(*build.LoadStmt); ok {
|
||||
loads = append(loads, l.Module.Value)
|
||||
}
|
||||
})
|
||||
sort.Strings(loads)
|
||||
|
||||
return loads, nil
|
||||
}
|
||||
|
||||
func isBzlSourceFile(f string) bool {
|
||||
return strings.HasSuffix(f, fileType) && !ignoreSuffix.Matches(f)
|
||||
}
|
||||
|
||||
// generateEmpty generates the list of rules that don't need to exist in the
|
||||
// BUILD file any more.
|
||||
// For each bzl_library rule in args.File that only has srcs that aren't in
|
||||
// args.RegularFiles or args.GenFiles, add a bzl_library with no srcs or deps.
|
||||
// That will let Gazelle delete bzl_library rules after the corresponding .bzl
|
||||
// files are deleted.
|
||||
func generateEmpty(args language.GenerateArgs) []*rule.Rule {
|
||||
var ret []*rule.Rule
|
||||
if args.File == nil {
|
||||
return ret
|
||||
}
|
||||
for _, r := range args.File.Rules {
|
||||
if r.Kind() != "bzl_library" {
|
||||
continue
|
||||
}
|
||||
name := r.AttrString("name")
|
||||
|
||||
exists := make(map[string]bool)
|
||||
for _, f := range args.RegularFiles {
|
||||
exists[f] = true
|
||||
}
|
||||
for _, f := range args.GenFiles {
|
||||
exists[f] = true
|
||||
}
|
||||
for _, r := range args.File.Rules {
|
||||
srcsExist := false
|
||||
for _, f := range r.AttrStrings("srcs") {
|
||||
if exists[f] {
|
||||
srcsExist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !srcsExist {
|
||||
ret = append(ret, rule.NewRule("bzl_library", name))
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type srcsList []string
|
||||
|
||||
func (s srcsList) Contains(m string) bool {
|
||||
for _, e := range s {
|
||||
if e == m {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
package gazelle
|
||||
|
||||
/* Copyright 2020 The Bazel Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/bazel-gazelle/testtools"
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
)
|
||||
|
||||
var gazellePath = findGazelle()
|
||||
|
||||
const testDataPath = "gazelle/testdata/"
|
||||
|
||||
// TestGazelleBinary runs a gazelle binary with starlib installed on each
|
||||
// directory in `testdata/*`. Please see `testdata/README.md` for more
|
||||
// information on each test.
|
||||
func TestGazelleBinary(t *testing.T) {
|
||||
tests := map[string][]bazel.RunfileEntry{}
|
||||
|
||||
files, err := bazel.ListRunfiles()
|
||||
if err != nil {
|
||||
t.Fatalf("bazel.ListRunfiles() error: %v", err)
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.HasPrefix(f.ShortPath, testDataPath) {
|
||||
relativePath := strings.TrimPrefix(f.ShortPath, testDataPath)
|
||||
parts := strings.SplitN(relativePath, "/", 2)
|
||||
if len(parts) < 2 {
|
||||
// This file is not a part of a testcase since it must be in a dir that
|
||||
// is the test case and then have a path inside of that.
|
||||
continue
|
||||
}
|
||||
|
||||
tests[parts[0]] = append(tests[parts[0]], f)
|
||||
}
|
||||
}
|
||||
|
||||
for testName, files := range tests {
|
||||
testPath(t, testName, files)
|
||||
}
|
||||
}
|
||||
|
||||
func testPath(t *testing.T, name string, files []bazel.RunfileEntry) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var inputs []testtools.FileSpec
|
||||
var goldens []testtools.FileSpec
|
||||
|
||||
for _, f := range files {
|
||||
path := f.Path
|
||||
trim := testDataPath + name + "/"
|
||||
shortPath := strings.TrimPrefix(f.ShortPath, trim)
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
t.Fatalf("os.Stat(%q) error: %v", path, err)
|
||||
}
|
||||
|
||||
// Skip dirs.
|
||||
if info.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Errorf("ioutil.ReadFile(%q) error: %v", path, err)
|
||||
}
|
||||
|
||||
// Now trim the common prefix off.
|
||||
if strings.HasSuffix(shortPath, ".in") {
|
||||
inputs = append(inputs, testtools.FileSpec{
|
||||
Path: strings.TrimSuffix(shortPath, ".in"),
|
||||
Content: string(content),
|
||||
})
|
||||
} else if strings.HasSuffix(shortPath, ".out") {
|
||||
goldens = append(goldens, testtools.FileSpec{
|
||||
Path: strings.TrimSuffix(shortPath, ".out"),
|
||||
Content: string(content),
|
||||
})
|
||||
} else {
|
||||
inputs = append(inputs, testtools.FileSpec{
|
||||
Path: shortPath,
|
||||
Content: string(content),
|
||||
})
|
||||
goldens = append(goldens, testtools.FileSpec{
|
||||
Path: shortPath,
|
||||
Content: string(content),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
dir, cleanup := testtools.CreateFiles(t, inputs)
|
||||
defer cleanup()
|
||||
|
||||
cmd := exec.Command(gazellePath, "-build_file_name=BUILD")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Dir = dir
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testtools.CheckFiles(t, dir, goldens)
|
||||
if t.Failed() {
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Logf("%q exists", path)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func findGazelle() string {
|
||||
gazellePath, ok := bazel.FindBinary("gazelle", "gazelle-skylib")
|
||||
if !ok {
|
||||
panic("could not find gazelle binary")
|
||||
}
|
||||
return gazellePath
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
# Gazelle test cases
|
||||
|
||||
This directory contains a suite of test cases for the Skylark language plugin
|
||||
for Gazelle.
|
||||
|
||||
Please note that there are no `BUILD` or `BUILD.bazel` files in subdirs, insted
|
||||
there are `BUILD.in` and `BUILD.out` describing what the `BUILD` should look
|
||||
like initially and what the `BUILD` file should look like after the run. These
|
||||
names are special because they are not recognized by Bazel as a proper `BUILD`
|
||||
file, and therefore are included in the data dependency by the recursive data
|
||||
glob in `//gazelle:go_default_test`. If you would like to include any extremely
|
||||
complicated tests that contain proper `BUILD` files you will need to manually
|
||||
add them to the `//gazelle:go_default_test` target's `data` section.
|
||||
|
||||
## `simple`
|
||||
|
||||
Simple is a base test case that was used to validate the parser.
|
||||
|
||||
## `nobuildfiles`
|
||||
|
||||
A test just like `simple` that has no `BUILD` files at the beginning.
|
||||
|
||||
## `import`
|
||||
|
||||
Import is a test case that imports a `.bzl` from the same directory.
|
||||
|
||||
## `multidir`
|
||||
|
||||
Multidir is a test that has a `.bzl` that imports from a different dirrectory.
|
||||
|
||||
## `tests`
|
||||
|
||||
Using the skylib as an example, this test has `.bzl` files that end in
|
||||
`_tests.bzl` which are `load`ed into `BUILD` files and never imported by
|
||||
another repo.
|
||||
|
||||
## `private`
|
||||
|
||||
Using the skylib as an example, this test has `.bzl` files that live in a
|
||||
directory called `private` which is used to indicate that they are repo private.
|
||||
Note that this is distict from the expectations of go's `internal` where the
|
||||
relative position in the hierarchy determines the visibility.
|
||||
|
||||
## `defaultvisibility`
|
||||
|
||||
If the package declares a `default_visibility` the generated `bzl_library`
|
||||
should not set its own `visibility`.
|
||||
|
||||
## `external`
|
||||
|
||||
This test demonstrates that if you load from another repo, it is able to
|
||||
generate a `deps` entry for the dependency.
|
||||
|
||||
## `empty`
|
||||
|
||||
Gazelle has the ability to remove old and unused targets. Test that.
|
|
@ -0,0 +1,8 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//nested/dir:bar"],
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
Doc string
|
||||
"""
|
||||
|
||||
load("//nested/dir:bar.bzl", "func")
|
||||
|
||||
func()
|
|
@ -0,0 +1 @@
|
|||
package(default_visibility = ["//:__pkg__"])
|
|
@ -0,0 +1,8 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
package(default_visibility = ["//:__pkg__"])
|
||||
|
||||
bzl_library(
|
||||
name = "bar",
|
||||
srcs = ["bar.bzl"],
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
"""
|
||||
Doc string
|
||||
"""
|
||||
|
||||
def asdf():
|
||||
pass
|
|
@ -0,0 +1,13 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "weirdly_named_target_that_will_be_removed",
|
||||
srcs = ["nonexistant.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "weirdly_named_target_that_will_be_renamed",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
# Some comment to be preserved
|
||||
|
||||
filegroup(
|
||||
name = "allfiles",
|
||||
srcs = glob(["**"]),
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
# Some comment to be preserved
|
||||
|
||||
filegroup(
|
||||
name = "allfiles",
|
||||
srcs = glob(["**"]),
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@external_repo//path/to:file"],
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
Test sample code.
|
||||
"""
|
||||
|
||||
load("@external_repo//path/to:file.bzl", "func")
|
||||
|
||||
func()
|
|
@ -0,0 +1,14 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "bar",
|
||||
srcs = ["bar.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//:bar"],
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
"""
|
||||
Doc string
|
||||
"""
|
||||
|
||||
def func():
|
||||
pass
|
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
Doc string
|
||||
"""
|
||||
|
||||
load("//:bar.bzl", "func")
|
||||
|
||||
func()
|
|
@ -0,0 +1,8 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//nested/dir:bar"],
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
Doc string
|
||||
"""
|
||||
|
||||
load("//nested/dir:bar.bzl", "func")
|
||||
|
||||
func()
|
|
@ -0,0 +1,7 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "bar",
|
||||
srcs = ["bar.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
"""
|
||||
Doc string
|
||||
"""
|
||||
|
||||
def func():
|
||||
pass
|
|
@ -0,0 +1,7 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//private:bar"],
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
Test sample code.
|
||||
"""
|
||||
|
||||
load("//private:bar.bzl", "func")
|
||||
|
||||
func()
|
|
@ -0,0 +1,6 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
bzl_library(
|
||||
name = "bar",
|
||||
srcs = ["bar.bzl"],
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
"""
|
||||
Test sample code.
|
||||
"""
|
||||
|
||||
def func():
|
||||
pass
|
|
@ -0,0 +1,6 @@
|
|||
# Some comment to be preserved
|
||||
|
||||
filegroup(
|
||||
name = "allfiles",
|
||||
srcs = glob(["**"]),
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
# Some comment to be preserved
|
||||
|
||||
filegroup(
|
||||
name = "allfiles",
|
||||
srcs = glob(["**"]),
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
# Some comment to be preserved
|
||||
|
||||
filegroup(
|
||||
name = "allfiles",
|
||||
srcs = glob(["**"]),
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
|
||||
|
||||
# Some comment to be preserved
|
||||
|
||||
filegroup(
|
||||
name = "allfiles",
|
||||
srcs = glob(["**"]),
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "foo",
|
||||
srcs = ["foo.bzl"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -93,3 +93,8 @@ filegroup(
|
|||
"//distribution:__pkg__",
|
||||
],
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "old_sets",
|
||||
srcs = ["old_sets.bzl"],
|
||||
)
|
||||
|
|
|
@ -81,3 +81,8 @@ exports_files(
|
|||
glob(["*.bzl"]),
|
||||
visibility = ["//:__subpackages__"],
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "select_file",
|
||||
srcs = ["select_file.bzl"],
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue