From 4213c203626a3f57e99eb178cfdd3e753ad34687 Mon Sep 17 00:00:00 2001 From: Andrew Z Allen Date: Tue, 26 May 2020 23:36:33 -0600 Subject: [PATCH 1/9] Create Gazelle language for Starlark --- BUILD | 25 ++ WORKSPACE | 35 +++ gazelle/BUILD | 51 ++++ gazelle/README.md | 13 + gazelle/gazelle.go | 263 ++++++++++++++++++ gazelle/gazelle_test.go | 129 +++++++++ gazelle/testdata/README.md | 52 ++++ gazelle/testdata/defaultvisibility/BUILD.in | 0 gazelle/testdata/defaultvisibility/BUILD.out | 6 + gazelle/testdata/defaultvisibility/WORKSPACE | 0 gazelle/testdata/defaultvisibility/foo.bzl | 1 + .../defaultvisibility/nested/dir/BUILD.in | 1 + .../defaultvisibility/nested/dir/BUILD.out | 7 + .../defaultvisibility/nested/dir/bar.bzl | 2 + gazelle/testdata/external/BUILD.in | 6 + gazelle/testdata/external/BUILD.out | 13 + gazelle/testdata/external/WORKSPACE | 0 gazelle/testdata/external/foo.bzl | 1 + gazelle/testdata/import/BUILD.in | 0 gazelle/testdata/import/BUILD.out | 12 + gazelle/testdata/import/WORKSPACE | 0 gazelle/testdata/import/bar.bzl | 2 + gazelle/testdata/import/foo.bzl | 1 + gazelle/testdata/multidir/BUILD.in | 0 gazelle/testdata/multidir/BUILD.out | 6 + gazelle/testdata/multidir/WORKSPACE | 0 gazelle/testdata/multidir/foo.bzl | 1 + .../testdata/multidir/nested/dir/BUILD.out | 6 + gazelle/testdata/multidir/nested/dir/bar.bzl | 2 + gazelle/testdata/nobuildfiles/BUILD.out | 5 + gazelle/testdata/nobuildfiles/WORKSPACE | 0 gazelle/testdata/nobuildfiles/foo.bzl | 0 gazelle/testdata/private/BUILD.in | 0 gazelle/testdata/private/BUILD.out | 6 + gazelle/testdata/private/WORKSPACE | 0 gazelle/testdata/private/foo.bzl | 1 + .../testdata/private/nested/private/BUILD.out | 5 + .../testdata/private/nested/private/bar.bzl | 2 + gazelle/testdata/simple/BUILD.in | 6 + gazelle/testdata/simple/BUILD.out | 12 + gazelle/testdata/simple/WORKSPACE | 0 gazelle/testdata/simple/foo.bzl | 0 gazelle/testdata/tests/BUILD.in | 6 + gazelle/testdata/tests/BUILD.out | 12 + gazelle/testdata/tests/WORKSPACE | 0 gazelle/testdata/tests/foo.bzl | 0 gazelle/testdata/tests/foo_tests.bzl | 0 lib/BUILD | 5 + rules/BUILD | 5 + 49 files changed, 700 insertions(+) create mode 100644 gazelle/BUILD create mode 100644 gazelle/README.md create mode 100644 gazelle/gazelle.go create mode 100644 gazelle/gazelle_test.go create mode 100644 gazelle/testdata/README.md create mode 100644 gazelle/testdata/defaultvisibility/BUILD.in create mode 100644 gazelle/testdata/defaultvisibility/BUILD.out create mode 100644 gazelle/testdata/defaultvisibility/WORKSPACE create mode 100644 gazelle/testdata/defaultvisibility/foo.bzl create mode 100644 gazelle/testdata/defaultvisibility/nested/dir/BUILD.in create mode 100644 gazelle/testdata/defaultvisibility/nested/dir/BUILD.out create mode 100644 gazelle/testdata/defaultvisibility/nested/dir/bar.bzl create mode 100644 gazelle/testdata/external/BUILD.in create mode 100644 gazelle/testdata/external/BUILD.out create mode 100644 gazelle/testdata/external/WORKSPACE create mode 100644 gazelle/testdata/external/foo.bzl create mode 100644 gazelle/testdata/import/BUILD.in create mode 100644 gazelle/testdata/import/BUILD.out create mode 100644 gazelle/testdata/import/WORKSPACE create mode 100644 gazelle/testdata/import/bar.bzl create mode 100644 gazelle/testdata/import/foo.bzl create mode 100644 gazelle/testdata/multidir/BUILD.in create mode 100644 gazelle/testdata/multidir/BUILD.out create mode 100644 gazelle/testdata/multidir/WORKSPACE create mode 100644 gazelle/testdata/multidir/foo.bzl create mode 100644 gazelle/testdata/multidir/nested/dir/BUILD.out create mode 100644 gazelle/testdata/multidir/nested/dir/bar.bzl create mode 100644 gazelle/testdata/nobuildfiles/BUILD.out create mode 100644 gazelle/testdata/nobuildfiles/WORKSPACE create mode 100644 gazelle/testdata/nobuildfiles/foo.bzl create mode 100644 gazelle/testdata/private/BUILD.in create mode 100644 gazelle/testdata/private/BUILD.out create mode 100644 gazelle/testdata/private/WORKSPACE create mode 100644 gazelle/testdata/private/foo.bzl create mode 100644 gazelle/testdata/private/nested/private/BUILD.out create mode 100644 gazelle/testdata/private/nested/private/bar.bzl create mode 100644 gazelle/testdata/simple/BUILD.in create mode 100644 gazelle/testdata/simple/BUILD.out create mode 100644 gazelle/testdata/simple/WORKSPACE create mode 100644 gazelle/testdata/simple/foo.bzl create mode 100644 gazelle/testdata/tests/BUILD.in create mode 100644 gazelle/testdata/tests/BUILD.out create mode 100644 gazelle/testdata/tests/WORKSPACE create mode 100644 gazelle/testdata/tests/foo.bzl create mode 100644 gazelle/testdata/tests/foo_tests.bzl diff --git a/BUILD b/BUILD index c0ccdcd6..ec378c67 100644 --- a/BUILD +++ b/BUILD @@ -4,6 +4,10 @@ licenses(["notice"]) package(default_visibility = ["//visibility:public"]) +# gazelle:exclude internal_deps.bzl +# gazelle:exclude internal_setup.bzl +# gazelle:exclude skylark_library.bzl + exports_files(["LICENSE"]) filegroup( @@ -45,6 +49,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 @@ -69,3 +83,14 @@ filegroup( "//rules:bins", ], ) + +# Below this line is for development purposes only and should thus not be +# included by dependencies on bazel-skylib nor packaged in the distribution +# release. + +load("@bazel_gazelle//:def.bzl", "gazelle") + +gazelle( + name = "gazelle", + gazelle = "//gazelle:gazelle-skylib", +) diff --git a/WORKSPACE b/WORKSPACE index a6581ec6..cefdfa0a 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -40,3 +40,38 @@ maybe( "https://github.com/bazelbuild/rules_cc/archive/cb2dfba6746bfa3c3705185981f3109f0ae1b893.zip", ], ) + +# Below are dependencies for the generator. + +load("@bazel_federation//:repositories.bzl", "rules_go") + +rules_go() +# 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 + +load("@bazel_federation//setup:rules_go.bzl", "rules_go_setup") + +rules_go_setup() + +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", "go_repository") + +gazelle_dependencies() + +go_repository( + name = "net_starlark_go", + commit = "0aa95694c76801c1528349fb86033b9098d634fc", + importpath = "go.starlark.net", +) diff --git a/gazelle/BUILD b/gazelle/BUILD new file mode 100644 index 00000000..ca23dcf3 --- /dev/null +++ b/gazelle/BUILD @@ -0,0 +1,51 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@bazel_gazelle//:def.bzl", "DEFAULT_LANGUAGES", "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//repo:go_default_library", + "@bazel_gazelle//resolve:go_default_library", + "@bazel_gazelle//rule:go_default_library", + "@net_starlark_go//syntax: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"], + msan = "off", + pure = "off", + race = "off", + static = "off", + visibility = [ + # Also make the binary available in the root of the repo for use, but + # not externally. + "//:__pkg__", + ], +) diff --git a/gazelle/README.md b/gazelle/README.md new file mode 100644 index 00000000..8b7cb7b9 --- /dev/null +++ b/gazelle/README.md @@ -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. + diff --git a/gazelle/gazelle.go b/gazelle/gazelle.go new file mode 100644 index 00000000..9b302008 --- /dev/null +++ b/gazelle/gazelle.go @@ -0,0 +1,263 @@ +/* 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" + "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/repo" + "github.com/bazelbuild/bazel-gazelle/resolve" + "github.com/bazelbuild/bazel-gazelle/rule" + + "go.starlark.net/syntax" +) + +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 nil } + +// 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, "@") { + // This is a dependency that is external to the current repo. + deps = append(deps, strings.TrimSuffix(imp, fileType)) + } else { + res := resolve.ImportSpec{ + Lang: languageName, + Imp: imp, + } + matches := ix.FindRulesByImport(res, languageName) + fmt.Printf("ix: %v\n", ix) + + if len(matches) == 0 { + fmt.Printf("Didn't find match for %q\n", 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) { + if ignoreSuffix.Matches(f) { + continue + } + if strings.HasSuffix(f, fileType) { + name := strings.TrimSuffix(f, fileType) + r := rule.NewRule("bzl_library", name) + + r.SetAttr("srcs", []string{f}) + + if args.File == nil || !args.File.HasDefaultVisibility() { + var inPrivateDir bool + for _, d := range strings.Split(args.Dir, string(filepath.Separator)) { + if d == "private" { + inPrivateDir = true + } + } + if !inPrivateDir { + r.SetAttr("visibility", []string{"//visibility:public"}) + } + } + + fullPath := filepath.Join(args.Dir, f) + loads, err := getBzlFileLoads(fullPath) + if err != nil { + fmt.Printf("Error getting getBzlFileLoads(%q, %q): %v", args.Dir, f, err) + // Don't `continue` since it is reasonable to create a target even without deps. + } + fmt.Printf("loads: %v\n", loads) + + rules = append(rules, r) + imports = append(imports, loads) + } + } + return language.GenerateResult{ + Gen: rules, + Imports: imports, + } +} + +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 := syntax.Parse(path, f, 0644) + if err != nil { + return nil, fmt.Errorf("syntax.Parse(%q) error: %v", f, err) + } + + var loads []string + syntax.Walk(ast, func(n syntax.Node) bool { + if l, ok := n.(*syntax.LoadStmt); ok { + val, ok := l.Module.Value.(string) + if !ok { + fmt.Printf("The load statement at %s:%s is not a simple string. Therefore, bazel targets can not be generated automatically for it.", path, l.Module.TokenPos) + return true + } + loads = append(loads, val) + } + return true + }) + sort.Strings(loads) + + return loads, nil +} diff --git a/gazelle/gazelle_test.go b/gazelle/gazelle_test.go new file mode 100644 index 00000000..b4ced390 --- /dev/null +++ b/gazelle/gazelle_test.go @@ -0,0 +1,129 @@ +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 base = "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) { + ds, err := ioutil.ReadDir(base) + if err != nil { + t.Errorf("ioutil.ReadDir(%q) error: %v", base, err) + } + for _, d := range ds { + if d.IsDir() { + t.Run(d.Name(), testPath(d.Name())) + } + } +} + +func testPath(dir string) func(t *testing.T) { + return func(t *testing.T) { + var inputs []testtools.FileSpec + var goldens []testtools.FileSpec + + if err := filepath.Walk(filepath.Join(base, dir), func(path string, info os.FileInfo, err error) error { + // If you were called with an error, don't try to recover, just fail. + if err != nil { + return err + } + + // Skip dirs. + if info.IsDir() { + return nil + } + + content, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + // Now trim the common prefix off. + newPath := strings.TrimPrefix(path, filepath.Join(base, dir)+"/") + + if strings.HasSuffix(newPath, ".in") { + inputs = append(inputs, testtools.FileSpec{ + Path: strings.TrimSuffix(newPath, ".in"), + Content: string(content), + }) + } else if strings.HasSuffix(newPath, ".out") { + goldens = append(goldens, testtools.FileSpec{ + Path: strings.TrimSuffix(newPath, ".out"), + Content: string(content), + }) + } else { + inputs = append(inputs, testtools.FileSpec{ + Path: newPath, + Content: string(content), + }) + goldens = append(goldens, testtools.FileSpec{ + Path: newPath, + Content: string(content), + }) + } + + return nil + }); err != nil { + t.Errorf("filepath.Walk(%q) error: %v", filepath.Join(base, dir), err) + } + + 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 +} diff --git a/gazelle/testdata/README.md b/gazelle/testdata/README.md new file mode 100644 index 00000000..66790434 --- /dev/null +++ b/gazelle/testdata/README.md @@ -0,0 +1,52 @@ +# 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. diff --git a/gazelle/testdata/defaultvisibility/BUILD.in b/gazelle/testdata/defaultvisibility/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/defaultvisibility/BUILD.out b/gazelle/testdata/defaultvisibility/BUILD.out new file mode 100644 index 00000000..7e210739 --- /dev/null +++ b/gazelle/testdata/defaultvisibility/BUILD.out @@ -0,0 +1,6 @@ +bzl_library( + name = "foo", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], + deps = ["//nested/dir:bar"], +) diff --git a/gazelle/testdata/defaultvisibility/WORKSPACE b/gazelle/testdata/defaultvisibility/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/defaultvisibility/foo.bzl b/gazelle/testdata/defaultvisibility/foo.bzl new file mode 100644 index 00000000..ef1b937b --- /dev/null +++ b/gazelle/testdata/defaultvisibility/foo.bzl @@ -0,0 +1 @@ +load("//nested/dir:bar.bzl", "asdf") diff --git a/gazelle/testdata/defaultvisibility/nested/dir/BUILD.in b/gazelle/testdata/defaultvisibility/nested/dir/BUILD.in new file mode 100644 index 00000000..830932af --- /dev/null +++ b/gazelle/testdata/defaultvisibility/nested/dir/BUILD.in @@ -0,0 +1 @@ +package(default_visibility = ["//:__pkg__"]) diff --git a/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out b/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out new file mode 100644 index 00000000..771dfb62 --- /dev/null +++ b/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out @@ -0,0 +1,7 @@ +package(default_visibility = ["//:__pkg__"]) + +bzl_library( + name = "bar", + srcs = ["bar.bzl"], +) + diff --git a/gazelle/testdata/defaultvisibility/nested/dir/bar.bzl b/gazelle/testdata/defaultvisibility/nested/dir/bar.bzl new file mode 100644 index 00000000..3268d8d0 --- /dev/null +++ b/gazelle/testdata/defaultvisibility/nested/dir/bar.bzl @@ -0,0 +1,2 @@ +def asdf(): + pass diff --git a/gazelle/testdata/external/BUILD.in b/gazelle/testdata/external/BUILD.in new file mode 100644 index 00000000..e267b5a1 --- /dev/null +++ b/gazelle/testdata/external/BUILD.in @@ -0,0 +1,6 @@ +# Some comment to be preserved + +filegroup( + name = "allfiles", + srcs = glob(["**"]), +) diff --git a/gazelle/testdata/external/BUILD.out b/gazelle/testdata/external/BUILD.out new file mode 100644 index 00000000..f586c430 --- /dev/null +++ b/gazelle/testdata/external/BUILD.out @@ -0,0 +1,13 @@ +# 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"], +) diff --git a/gazelle/testdata/external/WORKSPACE b/gazelle/testdata/external/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/external/foo.bzl b/gazelle/testdata/external/foo.bzl new file mode 100644 index 00000000..43bec45b --- /dev/null +++ b/gazelle/testdata/external/foo.bzl @@ -0,0 +1 @@ +load("@external_repo//path/to:file.bzl", "func") diff --git a/gazelle/testdata/import/BUILD.in b/gazelle/testdata/import/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/import/BUILD.out b/gazelle/testdata/import/BUILD.out new file mode 100644 index 00000000..dd5822d9 --- /dev/null +++ b/gazelle/testdata/import/BUILD.out @@ -0,0 +1,12 @@ +bzl_library( + name = "bar", + srcs = ["bar.bzl"], + visibility = ["//visibility:public"], +) + +bzl_library( + name = "foo", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], + deps = ["//:bar"], +) diff --git a/gazelle/testdata/import/WORKSPACE b/gazelle/testdata/import/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/import/bar.bzl b/gazelle/testdata/import/bar.bzl new file mode 100644 index 00000000..3268d8d0 --- /dev/null +++ b/gazelle/testdata/import/bar.bzl @@ -0,0 +1,2 @@ +def asdf(): + pass diff --git a/gazelle/testdata/import/foo.bzl b/gazelle/testdata/import/foo.bzl new file mode 100644 index 00000000..e7c55148 --- /dev/null +++ b/gazelle/testdata/import/foo.bzl @@ -0,0 +1 @@ +load("//:bar.bzl", "asdf") diff --git a/gazelle/testdata/multidir/BUILD.in b/gazelle/testdata/multidir/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/multidir/BUILD.out b/gazelle/testdata/multidir/BUILD.out new file mode 100644 index 00000000..7e210739 --- /dev/null +++ b/gazelle/testdata/multidir/BUILD.out @@ -0,0 +1,6 @@ +bzl_library( + name = "foo", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], + deps = ["//nested/dir:bar"], +) diff --git a/gazelle/testdata/multidir/WORKSPACE b/gazelle/testdata/multidir/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/multidir/foo.bzl b/gazelle/testdata/multidir/foo.bzl new file mode 100644 index 00000000..ef1b937b --- /dev/null +++ b/gazelle/testdata/multidir/foo.bzl @@ -0,0 +1 @@ +load("//nested/dir:bar.bzl", "asdf") diff --git a/gazelle/testdata/multidir/nested/dir/BUILD.out b/gazelle/testdata/multidir/nested/dir/BUILD.out new file mode 100644 index 00000000..6477e60c --- /dev/null +++ b/gazelle/testdata/multidir/nested/dir/BUILD.out @@ -0,0 +1,6 @@ +bzl_library( + name = "bar", + srcs = ["bar.bzl"], + visibility = ["//visibility:public"], +) + diff --git a/gazelle/testdata/multidir/nested/dir/bar.bzl b/gazelle/testdata/multidir/nested/dir/bar.bzl new file mode 100644 index 00000000..3268d8d0 --- /dev/null +++ b/gazelle/testdata/multidir/nested/dir/bar.bzl @@ -0,0 +1,2 @@ +def asdf(): + pass diff --git a/gazelle/testdata/nobuildfiles/BUILD.out b/gazelle/testdata/nobuildfiles/BUILD.out new file mode 100644 index 00000000..2d2a8f9e --- /dev/null +++ b/gazelle/testdata/nobuildfiles/BUILD.out @@ -0,0 +1,5 @@ +bzl_library( + name = "foo", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], +) diff --git a/gazelle/testdata/nobuildfiles/WORKSPACE b/gazelle/testdata/nobuildfiles/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/nobuildfiles/foo.bzl b/gazelle/testdata/nobuildfiles/foo.bzl new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/private/BUILD.in b/gazelle/testdata/private/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/private/BUILD.out b/gazelle/testdata/private/BUILD.out new file mode 100644 index 00000000..05d739f4 --- /dev/null +++ b/gazelle/testdata/private/BUILD.out @@ -0,0 +1,6 @@ +bzl_library( + name = "foo", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], + deps = ["//nested/private:bar"], +) diff --git a/gazelle/testdata/private/WORKSPACE b/gazelle/testdata/private/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/private/foo.bzl b/gazelle/testdata/private/foo.bzl new file mode 100644 index 00000000..599e8e2b --- /dev/null +++ b/gazelle/testdata/private/foo.bzl @@ -0,0 +1 @@ +load("//nested/private:bar.bzl", "asdf") diff --git a/gazelle/testdata/private/nested/private/BUILD.out b/gazelle/testdata/private/nested/private/BUILD.out new file mode 100644 index 00000000..04dba8d5 --- /dev/null +++ b/gazelle/testdata/private/nested/private/BUILD.out @@ -0,0 +1,5 @@ +bzl_library( + name = "bar", + srcs = ["bar.bzl"], +) + diff --git a/gazelle/testdata/private/nested/private/bar.bzl b/gazelle/testdata/private/nested/private/bar.bzl new file mode 100644 index 00000000..3268d8d0 --- /dev/null +++ b/gazelle/testdata/private/nested/private/bar.bzl @@ -0,0 +1,2 @@ +def asdf(): + pass diff --git a/gazelle/testdata/simple/BUILD.in b/gazelle/testdata/simple/BUILD.in new file mode 100644 index 00000000..e267b5a1 --- /dev/null +++ b/gazelle/testdata/simple/BUILD.in @@ -0,0 +1,6 @@ +# Some comment to be preserved + +filegroup( + name = "allfiles", + srcs = glob(["**"]), +) diff --git a/gazelle/testdata/simple/BUILD.out b/gazelle/testdata/simple/BUILD.out new file mode 100644 index 00000000..3e57f6ab --- /dev/null +++ b/gazelle/testdata/simple/BUILD.out @@ -0,0 +1,12 @@ +# Some comment to be preserved + +filegroup( + name = "allfiles", + srcs = glob(["**"]), +) + +bzl_library( + name = "foo", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], +) diff --git a/gazelle/testdata/simple/WORKSPACE b/gazelle/testdata/simple/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/simple/foo.bzl b/gazelle/testdata/simple/foo.bzl new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/tests/BUILD.in b/gazelle/testdata/tests/BUILD.in new file mode 100644 index 00000000..e267b5a1 --- /dev/null +++ b/gazelle/testdata/tests/BUILD.in @@ -0,0 +1,6 @@ +# Some comment to be preserved + +filegroup( + name = "allfiles", + srcs = glob(["**"]), +) diff --git a/gazelle/testdata/tests/BUILD.out b/gazelle/testdata/tests/BUILD.out new file mode 100644 index 00000000..3e57f6ab --- /dev/null +++ b/gazelle/testdata/tests/BUILD.out @@ -0,0 +1,12 @@ +# Some comment to be preserved + +filegroup( + name = "allfiles", + srcs = glob(["**"]), +) + +bzl_library( + name = "foo", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], +) diff --git a/gazelle/testdata/tests/WORKSPACE b/gazelle/testdata/tests/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/tests/foo.bzl b/gazelle/testdata/tests/foo.bzl new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/tests/foo_tests.bzl b/gazelle/testdata/tests/foo_tests.bzl new file mode 100644 index 00000000..e69de29b diff --git a/lib/BUILD b/lib/BUILD index c959bcc1..d17caa57 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -93,3 +93,8 @@ filegroup( "//distribution:__pkg__", ], ) + +bzl_library( + name = "old_sets", + srcs = ["old_sets.bzl"], +) diff --git a/rules/BUILD b/rules/BUILD index 9c6c047c..bad361b8 100644 --- a/rules/BUILD +++ b/rules/BUILD @@ -81,3 +81,8 @@ exports_files( glob(["*.bzl"]), visibility = ["//:__subpackages__"], ) + +bzl_library( + name = "select_file", + srcs = ["select_file.bzl"], +) From 1a355d66697d0fb904e2494f4390b580980a74f1 Mon Sep 17 00:00:00 2001 From: Andrew Z Allen Date: Fri, 29 May 2020 17:42:42 -0600 Subject: [PATCH 2/9] Respond to reviewer comments --- BUILD | 3 +- WORKSPACE | 6 ---- gazelle/BUILD | 4 +-- gazelle/gazelle.go | 29 ++++++++----------- gazelle/testdata/defaultvisibility/foo.bzl | 8 ++++- .../defaultvisibility/nested/dir/BUILD.out | 1 - .../defaultvisibility/nested/dir/bar.bzl | 4 +++ gazelle/testdata/external/foo.bzl | 6 ++++ gazelle/testdata/import/bar.bzl | 6 +++- gazelle/testdata/import/foo.bzl | 8 ++++- gazelle/testdata/multidir/foo.bzl | 8 ++++- .../testdata/multidir/nested/dir/BUILD.out | 1 - gazelle/testdata/multidir/nested/dir/bar.bzl | 6 +++- gazelle/testdata/private/foo.bzl | 8 ++++- .../testdata/private/nested/private/BUILD.out | 1 - .../testdata/private/nested/private/bar.bzl | 6 +++- 16 files changed, 68 insertions(+), 37 deletions(-) diff --git a/BUILD b/BUILD index ec378c67..1201291f 100644 --- a/BUILD +++ b/BUILD @@ -1,4 +1,5 @@ load("//:bzl_library.bzl", "bzl_library") +load("@bazel_gazelle//:def.bzl", "gazelle") licenses(["notice"]) @@ -88,8 +89,6 @@ filegroup( # included by dependencies on bazel-skylib nor packaged in the distribution # release. -load("@bazel_gazelle//:def.bzl", "gazelle") - gazelle( name = "gazelle", gazelle = "//gazelle:gazelle-skylib", diff --git a/WORKSPACE b/WORKSPACE index cefdfa0a..803e3696 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -69,9 +69,3 @@ http_archive( load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") gazelle_dependencies() - -go_repository( - name = "net_starlark_go", - commit = "0aa95694c76801c1528349fb86033b9098d634fc", - importpath = "go.starlark.net", -) diff --git a/gazelle/BUILD b/gazelle/BUILD index ca23dcf3..bb6d605c 100644 --- a/gazelle/BUILD +++ b/gazelle/BUILD @@ -1,5 +1,5 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") -load("@bazel_gazelle//:def.bzl", "DEFAULT_LANGUAGES", "gazelle_binary") +load("@bazel_gazelle//:def.bzl", "gazelle_binary") # gazelle:exclude testdata @@ -15,7 +15,7 @@ go_library( "@bazel_gazelle//repo:go_default_library", "@bazel_gazelle//resolve:go_default_library", "@bazel_gazelle//rule:go_default_library", - "@net_starlark_go//syntax:go_default_library", + "@com_github_bazelbuild_buildtools//build:go_default_library", ], ) diff --git a/gazelle/gazelle.go b/gazelle/gazelle.go index 9b302008..c114c9ac 100644 --- a/gazelle/gazelle.go +++ b/gazelle/gazelle.go @@ -27,6 +27,7 @@ import ( "flag" "fmt" "io/ioutil" + "log" "path/filepath" "sort" "strings" @@ -38,7 +39,7 @@ import ( "github.com/bazelbuild/bazel-gazelle/resolve" "github.com/bazelbuild/bazel-gazelle/rule" - "go.starlark.net/syntax" + "github.com/bazelbuild/buildtools/build" ) const languageName = "starlark" @@ -154,10 +155,9 @@ func (*bzlLibraryLang) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo Imp: imp, } matches := ix.FindRulesByImport(res, languageName) - fmt.Printf("ix: %v\n", ix) if len(matches) == 0 { - fmt.Printf("Didn't find match for %q\n", imp) + 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 { @@ -220,10 +220,10 @@ func (*bzlLibraryLang) GenerateRules(args language.GenerateArgs) language.Genera fullPath := filepath.Join(args.Dir, f) loads, err := getBzlFileLoads(fullPath) if err != nil { - fmt.Printf("Error getting getBzlFileLoads(%q, %q): %v", args.Dir, f, err) - // Don't `continue` since it is reasonable to create a target even without deps. + log.Printf("%s: contains symtax errors: %v", fullPath, err) + // Don't `continue` since it is reasonable to create a target even + // without deps. } - fmt.Printf("loads: %v\n", loads) rules = append(rules, r) imports = append(imports, loads) @@ -240,22 +240,17 @@ func getBzlFileLoads(path string) ([]string, error) { if err != nil { return nil, fmt.Errorf("ioutil.ReadFile(%q) error: %v", path, err) } - ast, err := syntax.Parse(path, f, 0644) + ast, err := build.ParseBuild(path, f) if err != nil { - return nil, fmt.Errorf("syntax.Parse(%q) error: %v", f, err) + return nil, fmt.Errorf("build.Parse(%q) error: %v", f, err) } var loads []string - syntax.Walk(ast, func(n syntax.Node) bool { - if l, ok := n.(*syntax.LoadStmt); ok { - val, ok := l.Module.Value.(string) - if !ok { - fmt.Printf("The load statement at %s:%s is not a simple string. Therefore, bazel targets can not be generated automatically for it.", path, l.Module.TokenPos) - return true - } - loads = append(loads, val) + build.WalkOnce(ast, func(expr *build.Expr) { + n := *expr + if l, ok := n.(*build.LoadStmt); ok { + loads = append(loads, l.Module.Value) } - return true }) sort.Strings(loads) diff --git a/gazelle/testdata/defaultvisibility/foo.bzl b/gazelle/testdata/defaultvisibility/foo.bzl index ef1b937b..1191303a 100644 --- a/gazelle/testdata/defaultvisibility/foo.bzl +++ b/gazelle/testdata/defaultvisibility/foo.bzl @@ -1 +1,7 @@ -load("//nested/dir:bar.bzl", "asdf") +""" +Doc string +""" + +load("//nested/dir:bar.bzl", "func") + +func() diff --git a/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out b/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out index 771dfb62..15633a9f 100644 --- a/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out +++ b/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out @@ -4,4 +4,3 @@ bzl_library( name = "bar", srcs = ["bar.bzl"], ) - diff --git a/gazelle/testdata/defaultvisibility/nested/dir/bar.bzl b/gazelle/testdata/defaultvisibility/nested/dir/bar.bzl index 3268d8d0..8ab1fcb5 100644 --- a/gazelle/testdata/defaultvisibility/nested/dir/bar.bzl +++ b/gazelle/testdata/defaultvisibility/nested/dir/bar.bzl @@ -1,2 +1,6 @@ +""" +Doc string +""" + def asdf(): pass diff --git a/gazelle/testdata/external/foo.bzl b/gazelle/testdata/external/foo.bzl index 43bec45b..ad548a58 100644 --- a/gazelle/testdata/external/foo.bzl +++ b/gazelle/testdata/external/foo.bzl @@ -1 +1,7 @@ +""" +Test sample code. +""" + load("@external_repo//path/to:file.bzl", "func") + +func() diff --git a/gazelle/testdata/import/bar.bzl b/gazelle/testdata/import/bar.bzl index 3268d8d0..7ffea515 100644 --- a/gazelle/testdata/import/bar.bzl +++ b/gazelle/testdata/import/bar.bzl @@ -1,2 +1,6 @@ -def asdf(): +""" +Doc string +""" + +def func(): pass diff --git a/gazelle/testdata/import/foo.bzl b/gazelle/testdata/import/foo.bzl index e7c55148..eb8d33c6 100644 --- a/gazelle/testdata/import/foo.bzl +++ b/gazelle/testdata/import/foo.bzl @@ -1 +1,7 @@ -load("//:bar.bzl", "asdf") +""" +Doc string +""" + +load("//:bar.bzl", "func") + +func() diff --git a/gazelle/testdata/multidir/foo.bzl b/gazelle/testdata/multidir/foo.bzl index ef1b937b..1191303a 100644 --- a/gazelle/testdata/multidir/foo.bzl +++ b/gazelle/testdata/multidir/foo.bzl @@ -1 +1,7 @@ -load("//nested/dir:bar.bzl", "asdf") +""" +Doc string +""" + +load("//nested/dir:bar.bzl", "func") + +func() diff --git a/gazelle/testdata/multidir/nested/dir/BUILD.out b/gazelle/testdata/multidir/nested/dir/BUILD.out index 6477e60c..a575eba2 100644 --- a/gazelle/testdata/multidir/nested/dir/BUILD.out +++ b/gazelle/testdata/multidir/nested/dir/BUILD.out @@ -3,4 +3,3 @@ bzl_library( srcs = ["bar.bzl"], visibility = ["//visibility:public"], ) - diff --git a/gazelle/testdata/multidir/nested/dir/bar.bzl b/gazelle/testdata/multidir/nested/dir/bar.bzl index 3268d8d0..7ffea515 100644 --- a/gazelle/testdata/multidir/nested/dir/bar.bzl +++ b/gazelle/testdata/multidir/nested/dir/bar.bzl @@ -1,2 +1,6 @@ -def asdf(): +""" +Doc string +""" + +def func(): pass diff --git a/gazelle/testdata/private/foo.bzl b/gazelle/testdata/private/foo.bzl index 599e8e2b..bf33a05c 100644 --- a/gazelle/testdata/private/foo.bzl +++ b/gazelle/testdata/private/foo.bzl @@ -1 +1,7 @@ -load("//nested/private:bar.bzl", "asdf") +""" +Test sample code. +""" + +load("//nested/private:bar.bzl", "func") + +func() diff --git a/gazelle/testdata/private/nested/private/BUILD.out b/gazelle/testdata/private/nested/private/BUILD.out index 04dba8d5..2c7085ab 100644 --- a/gazelle/testdata/private/nested/private/BUILD.out +++ b/gazelle/testdata/private/nested/private/BUILD.out @@ -2,4 +2,3 @@ bzl_library( name = "bar", srcs = ["bar.bzl"], ) - diff --git a/gazelle/testdata/private/nested/private/bar.bzl b/gazelle/testdata/private/nested/private/bar.bzl index 3268d8d0..c8a48713 100644 --- a/gazelle/testdata/private/nested/private/bar.bzl +++ b/gazelle/testdata/private/nested/private/bar.bzl @@ -1,2 +1,6 @@ -def asdf(): +""" +Test sample code. +""" + +def func(): pass From 3cab68cc604a83673356346c20c82169413f0c73 Mon Sep 17 00:00:00 2001 From: Andrew Allen Date: Tue, 9 Jun 2020 19:37:16 +0000 Subject: [PATCH 3/9] More reviewer comments --- BUILD | 10 --- CODEOWNERS | 1 + WORKSPACE | 2 +- gazelle/BUILD | 12 +-- gazelle/gazelle.go | 80 +++++++++++++++---- gazelle/testdata/README.md | 4 + gazelle/testdata/defaultvisibility/BUILD.out | 2 + .../defaultvisibility/nested/dir/BUILD.out | 2 + gazelle/testdata/empty/BUILD.in | 7 ++ gazelle/testdata/empty/BUILD.out | 7 ++ gazelle/testdata/empty/WORKSPACE | 0 gazelle/testdata/empty/foo.bzl | 0 gazelle/testdata/external/BUILD.in | 2 + gazelle/testdata/external/BUILD.out | 2 + gazelle/testdata/import/BUILD.out | 2 + gazelle/testdata/multidir/BUILD.out | 2 + .../testdata/multidir/nested/dir/BUILD.out | 2 + gazelle/testdata/nobuildfiles/BUILD.out | 2 + gazelle/testdata/private/BUILD.out | 2 + .../testdata/private/nested/private/BUILD.out | 2 + gazelle/testdata/simple/BUILD.out | 2 + gazelle/testdata/tests/BUILD.out | 2 + 22 files changed, 116 insertions(+), 31 deletions(-) create mode 100644 gazelle/testdata/empty/BUILD.in create mode 100644 gazelle/testdata/empty/BUILD.out create mode 100644 gazelle/testdata/empty/WORKSPACE create mode 100644 gazelle/testdata/empty/foo.bzl diff --git a/BUILD b/BUILD index 1201291f..ad1dbfb8 100644 --- a/BUILD +++ b/BUILD @@ -1,5 +1,4 @@ load("//:bzl_library.bzl", "bzl_library") -load("@bazel_gazelle//:def.bzl", "gazelle") licenses(["notice"]) @@ -84,12 +83,3 @@ filegroup( "//rules:bins", ], ) - -# Below this line is for development purposes only and should thus not be -# included by dependencies on bazel-skylib nor packaged in the distribution -# release. - -gazelle( - name = "gazelle", - gazelle = "//gazelle:gazelle-skylib", -) diff --git a/CODEOWNERS b/CODEOWNERS index 2b22b23a..07b74fad 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,4 @@ * @c-parsons @laurentlb @jin @aiuto distribution/ @aiuto @fwe rules/ @juliexxia +gazelle/ @achew22 @jayconrod diff --git a/WORKSPACE b/WORKSPACE index 803e3696..c5a2130d 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -66,6 +66,6 @@ http_archive( # 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", "go_repository") +load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") gazelle_dependencies() diff --git a/gazelle/BUILD b/gazelle/BUILD index bb6d605c..d20212cb 100644 --- a/gazelle/BUILD +++ b/gazelle/BUILD @@ -1,5 +1,5 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") -load("@bazel_gazelle//:def.bzl", "gazelle_binary") +load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary") # gazelle:exclude testdata @@ -12,6 +12,7 @@ go_library( "@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", @@ -39,13 +40,14 @@ go_test( gazelle_binary( name = "gazelle-skylib", languages = [":go_default_library"], - msan = "off", - pure = "off", - race = "off", - static = "off", 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", +) diff --git a/gazelle/gazelle.go b/gazelle/gazelle.go index c114c9ac..ec3edc6e 100644 --- a/gazelle/gazelle.go +++ b/gazelle/gazelle.go @@ -35,6 +35,7 @@ import ( "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" @@ -91,7 +92,12 @@ func (*bzlLibraryLang) Kinds() map[string]rule.KindInfo { // 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 nil } +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 @@ -146,8 +152,9 @@ func (*bzlLibraryLang) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo deps := make([]string, 0, len(imports)) for _, imp := range imports { - if strings.HasPrefix(imp, "@") { - // This is a dependency that is external to the current repo. + 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{ @@ -195,23 +202,15 @@ var kinds = map[string]rule.KindInfo{ func (*bzlLibraryLang) GenerateRules(args language.GenerateArgs) language.GenerateResult { var rules []*rule.Rule var imports []interface{} - for _, f := range append(args.RegularFiles) { - if ignoreSuffix.Matches(f) { - continue - } - if strings.HasSuffix(f, fileType) { + for _, f := range append(args.RegularFiles, args.GenFiles...) { + if isBzlSourceFile(f) { name := strings.TrimSuffix(f, fileType) r := rule.NewRule("bzl_library", name) r.SetAttr("srcs", []string{f}) if args.File == nil || !args.File.HasDefaultVisibility() { - var inPrivateDir bool - for _, d := range strings.Split(args.Dir, string(filepath.Separator)) { - if d == "private" { - inPrivateDir = true - } - } + inPrivateDir := pathtools.Index(args.Rel, "private") >= 0 if !inPrivateDir { r.SetAttr("visibility", []string{"//visibility:public"}) } @@ -220,7 +219,7 @@ func (*bzlLibraryLang) GenerateRules(args language.GenerateArgs) language.Genera fullPath := filepath.Join(args.Dir, f) loads, err := getBzlFileLoads(fullPath) if err != nil { - log.Printf("%s: contains symtax errors: %v", fullPath, err) + log.Printf("%s: contains syntax errors: %v", fullPath, err) // Don't `continue` since it is reasonable to create a target even // without deps. } @@ -229,9 +228,11 @@ func (*bzlLibraryLang) GenerateRules(args language.GenerateArgs) language.Genera imports = append(imports, loads) } } + return language.GenerateResult{ Gen: rules, Imports: imports, + Empty: generateEmpty(args), } } @@ -256,3 +257,52 @@ func getBzlFileLoads(path string) ([]string, error) { 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") + srcs := srcsList(r.AttrStrings("srcs")) + + for _, f := range args.RegularFiles { + if srcs.Contains(f) { + continue + } + } + for _, f := range args.GenFiles { + if srcs.Contains(f) { + continue + } + } + + 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 +} diff --git a/gazelle/testdata/README.md b/gazelle/testdata/README.md index 66790434..a6a36031 100644 --- a/gazelle/testdata/README.md +++ b/gazelle/testdata/README.md @@ -50,3 +50,7 @@ should not set its own `visibility`. 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. diff --git a/gazelle/testdata/defaultvisibility/BUILD.out b/gazelle/testdata/defaultvisibility/BUILD.out index 7e210739..44c1495e 100644 --- a/gazelle/testdata/defaultvisibility/BUILD.out +++ b/gazelle/testdata/defaultvisibility/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + bzl_library( name = "foo", srcs = ["foo.bzl"], diff --git a/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out b/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out index 15633a9f..8394b9c8 100644 --- a/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out +++ b/gazelle/testdata/defaultvisibility/nested/dir/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + package(default_visibility = ["//:__pkg__"]) bzl_library( diff --git a/gazelle/testdata/empty/BUILD.in b/gazelle/testdata/empty/BUILD.in new file mode 100644 index 00000000..80690c9e --- /dev/null +++ b/gazelle/testdata/empty/BUILD.in @@ -0,0 +1,7 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +bzl_library( + name = "weirdly_named_target_that_will_be_renamed", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], +) diff --git a/gazelle/testdata/empty/BUILD.out b/gazelle/testdata/empty/BUILD.out new file mode 100644 index 00000000..ac0e990f --- /dev/null +++ b/gazelle/testdata/empty/BUILD.out @@ -0,0 +1,7 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +bzl_library( + name = "foo", + srcs = ["foo.bzl"], + visibility = ["//visibility:public"], +) diff --git a/gazelle/testdata/empty/WORKSPACE b/gazelle/testdata/empty/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/empty/foo.bzl b/gazelle/testdata/empty/foo.bzl new file mode 100644 index 00000000..e69de29b diff --git a/gazelle/testdata/external/BUILD.in b/gazelle/testdata/external/BUILD.in index e267b5a1..e7bc836e 100644 --- a/gazelle/testdata/external/BUILD.in +++ b/gazelle/testdata/external/BUILD.in @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + # Some comment to be preserved filegroup( diff --git a/gazelle/testdata/external/BUILD.out b/gazelle/testdata/external/BUILD.out index f586c430..c70685fe 100644 --- a/gazelle/testdata/external/BUILD.out +++ b/gazelle/testdata/external/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + # Some comment to be preserved filegroup( diff --git a/gazelle/testdata/import/BUILD.out b/gazelle/testdata/import/BUILD.out index dd5822d9..a19a11aa 100644 --- a/gazelle/testdata/import/BUILD.out +++ b/gazelle/testdata/import/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + bzl_library( name = "bar", srcs = ["bar.bzl"], diff --git a/gazelle/testdata/multidir/BUILD.out b/gazelle/testdata/multidir/BUILD.out index 7e210739..44c1495e 100644 --- a/gazelle/testdata/multidir/BUILD.out +++ b/gazelle/testdata/multidir/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + bzl_library( name = "foo", srcs = ["foo.bzl"], diff --git a/gazelle/testdata/multidir/nested/dir/BUILD.out b/gazelle/testdata/multidir/nested/dir/BUILD.out index a575eba2..07ec8ce6 100644 --- a/gazelle/testdata/multidir/nested/dir/BUILD.out +++ b/gazelle/testdata/multidir/nested/dir/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + bzl_library( name = "bar", srcs = ["bar.bzl"], diff --git a/gazelle/testdata/nobuildfiles/BUILD.out b/gazelle/testdata/nobuildfiles/BUILD.out index 2d2a8f9e..ac0e990f 100644 --- a/gazelle/testdata/nobuildfiles/BUILD.out +++ b/gazelle/testdata/nobuildfiles/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + bzl_library( name = "foo", srcs = ["foo.bzl"], diff --git a/gazelle/testdata/private/BUILD.out b/gazelle/testdata/private/BUILD.out index 05d739f4..5709f874 100644 --- a/gazelle/testdata/private/BUILD.out +++ b/gazelle/testdata/private/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + bzl_library( name = "foo", srcs = ["foo.bzl"], diff --git a/gazelle/testdata/private/nested/private/BUILD.out b/gazelle/testdata/private/nested/private/BUILD.out index 2c7085ab..eb2e935d 100644 --- a/gazelle/testdata/private/nested/private/BUILD.out +++ b/gazelle/testdata/private/nested/private/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + bzl_library( name = "bar", srcs = ["bar.bzl"], diff --git a/gazelle/testdata/simple/BUILD.out b/gazelle/testdata/simple/BUILD.out index 3e57f6ab..3c71d561 100644 --- a/gazelle/testdata/simple/BUILD.out +++ b/gazelle/testdata/simple/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + # Some comment to be preserved filegroup( diff --git a/gazelle/testdata/tests/BUILD.out b/gazelle/testdata/tests/BUILD.out index 3e57f6ab..3c71d561 100644 --- a/gazelle/testdata/tests/BUILD.out +++ b/gazelle/testdata/tests/BUILD.out @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + # Some comment to be preserved filegroup( From 79fe22a4fa0f5ffc8da387aa8a1f083d018e3f15 Mon Sep 17 00:00:00 2001 From: Andrew Allen Date: Tue, 9 Jun 2020 19:42:21 +0000 Subject: [PATCH 4/9] Fixup for windows --- gazelle/gazelle_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gazelle/gazelle_test.go b/gazelle/gazelle_test.go index b4ced390..e980ce2c 100644 --- a/gazelle/gazelle_test.go +++ b/gazelle/gazelle_test.go @@ -35,7 +35,11 @@ const base = "testdata" // directory in `testdata/*`. Please see `testdata/README.md` for more // information on each test. func TestGazelleBinary(t *testing.T) { - ds, err := ioutil.ReadDir(base) + testdata, err := bazel.Runfile(base) + if err != nil { + t.Errorf("bazel.Runfile(%q) error: %v", base, err) + } + ds, err := ioutil.ReadDir(testdata) if err != nil { t.Errorf("ioutil.ReadDir(%q) error: %v", base, err) } From a7de5f3f54b48ea2ff9dba6b8794162810bb628a Mon Sep 17 00:00:00 2001 From: Andrew Allen Date: Tue, 9 Jun 2020 19:49:03 +0000 Subject: [PATCH 5/9] Fixup some lint errors --- WORKSPACE | 18 +++++++----------- gazelle/gazelle_test.go | 12 ++++++------ gazelle/testdata/private/BUILD.out | 2 +- gazelle/testdata/private/foo.bzl | 2 +- .../private/{nested => }/private/BUILD.out | 0 .../private/{nested => }/private/bar.bzl | 0 6 files changed, 15 insertions(+), 19 deletions(-) rename gazelle/testdata/private/{nested => }/private/BUILD.out (100%) rename gazelle/testdata/private/{nested => }/private/bar.bzl (100%) diff --git a/WORKSPACE b/WORKSPACE index c5a2130d..c79cb22b 100644 --- a/WORKSPACE +++ b/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. @@ -41,20 +47,10 @@ maybe( ], ) -# Below are dependencies for the generator. - -load("@bazel_federation//:repositories.bzl", "rules_go") - -rules_go() # 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 - -load("@bazel_federation//setup:rules_go.bzl", "rules_go_setup") - -rules_go_setup() - http_archive( name = "bazel_gazelle", sha256 = "bfd86b3cbe855d6c16c6fce60d76bd51f5c8dbc9cfcaef7a2bb5c1aafd0710e8", diff --git a/gazelle/gazelle_test.go b/gazelle/gazelle_test.go index e980ce2c..f3f63145 100644 --- a/gazelle/gazelle_test.go +++ b/gazelle/gazelle_test.go @@ -29,7 +29,7 @@ import ( var gazellePath = findGazelle() -const base = "testdata" +const base = "gazelle/testdata" // TestGazelleBinary runs a gazelle binary with starlib installed on each // directory in `testdata/*`. Please see `testdata/README.md` for more @@ -45,17 +45,17 @@ func TestGazelleBinary(t *testing.T) { } for _, d := range ds { if d.IsDir() { - t.Run(d.Name(), testPath(d.Name())) + t.Run(d.Name(), testPath(testdata, d.Name())) } } } -func testPath(dir string) func(t *testing.T) { +func testPath(testdata string, dir string) func(t *testing.T) { return func(t *testing.T) { var inputs []testtools.FileSpec var goldens []testtools.FileSpec - if err := filepath.Walk(filepath.Join(base, dir), func(path string, info os.FileInfo, err error) error { + if err := filepath.Walk(filepath.Join(testdata, dir), func(path string, info os.FileInfo, err error) error { // If you were called with an error, don't try to recover, just fail. if err != nil { return err @@ -72,7 +72,7 @@ func testPath(dir string) func(t *testing.T) { } // Now trim the common prefix off. - newPath := strings.TrimPrefix(path, filepath.Join(base, dir)+"/") + newPath := strings.TrimPrefix(path, filepath.Join(testdata, dir)+"/") if strings.HasSuffix(newPath, ".in") { inputs = append(inputs, testtools.FileSpec{ @@ -97,7 +97,7 @@ func testPath(dir string) func(t *testing.T) { return nil }); err != nil { - t.Errorf("filepath.Walk(%q) error: %v", filepath.Join(base, dir), err) + t.Errorf("filepath.Walk(%q) error: %v", filepath.Join(testdata, dir), err) } dir, cleanup := testtools.CreateFiles(t, inputs) diff --git a/gazelle/testdata/private/BUILD.out b/gazelle/testdata/private/BUILD.out index 5709f874..e65b00f8 100644 --- a/gazelle/testdata/private/BUILD.out +++ b/gazelle/testdata/private/BUILD.out @@ -4,5 +4,5 @@ bzl_library( name = "foo", srcs = ["foo.bzl"], visibility = ["//visibility:public"], - deps = ["//nested/private:bar"], + deps = ["//private:bar"], ) diff --git a/gazelle/testdata/private/foo.bzl b/gazelle/testdata/private/foo.bzl index bf33a05c..7e1dcd1f 100644 --- a/gazelle/testdata/private/foo.bzl +++ b/gazelle/testdata/private/foo.bzl @@ -2,6 +2,6 @@ Test sample code. """ -load("//nested/private:bar.bzl", "func") +load("//private:bar.bzl", "func") func() diff --git a/gazelle/testdata/private/nested/private/BUILD.out b/gazelle/testdata/private/private/BUILD.out similarity index 100% rename from gazelle/testdata/private/nested/private/BUILD.out rename to gazelle/testdata/private/private/BUILD.out diff --git a/gazelle/testdata/private/nested/private/bar.bzl b/gazelle/testdata/private/private/bar.bzl similarity index 100% rename from gazelle/testdata/private/nested/private/bar.bzl rename to gazelle/testdata/private/private/bar.bzl From 990d75932a3b53dc6586d4b2cdad379d1ba29b5f Mon Sep 17 00:00:00 2001 From: Andrew Allen Date: Tue, 9 Jun 2020 19:57:04 +0000 Subject: [PATCH 6/9] Make error output better --- gazelle/gazelle_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gazelle/gazelle_test.go b/gazelle/gazelle_test.go index f3f63145..bb501be6 100644 --- a/gazelle/gazelle_test.go +++ b/gazelle/gazelle_test.go @@ -41,7 +41,7 @@ func TestGazelleBinary(t *testing.T) { } ds, err := ioutil.ReadDir(testdata) if err != nil { - t.Errorf("ioutil.ReadDir(%q) error: %v", base, err) + t.Errorf("ioutil.ReadDir(%q) error: %v", testdata, err) } for _, d := range ds { if d.IsDir() { From 760a9dc8e3ba113d0664313faa510572e883029f Mon Sep 17 00:00:00 2001 From: Andrew Allen Date: Tue, 9 Jun 2020 20:06:08 +0000 Subject: [PATCH 7/9] Try another way of doing runfiles This might make windows work? --- gazelle/gazelle_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gazelle/gazelle_test.go b/gazelle/gazelle_test.go index bb501be6..73d5ee33 100644 --- a/gazelle/gazelle_test.go +++ b/gazelle/gazelle_test.go @@ -29,19 +29,18 @@ import ( var gazellePath = findGazelle() -const base = "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) { - testdata, err := bazel.Runfile(base) + runfilesPath, err := bazel.RunfilesPath() if err != nil { - t.Errorf("bazel.Runfile(%q) error: %v", base, err) + t.Fatalf("bazel.RunfilesPath() error: %v", err) } + testdata := filepath.Join(runfilesPath, "gazelle", "testdata") ds, err := ioutil.ReadDir(testdata) if err != nil { - t.Errorf("ioutil.ReadDir(%q) error: %v", testdata, err) + t.Fatalf("ioutil.ReadDir(%q) error: %v", testdata, err) } for _, d := range ds { if d.IsDir() { From a1575d87a35b49c633780cd0085eb3579b12d522 Mon Sep 17 00:00:00 2001 From: Andrew Allen Date: Tue, 9 Jun 2020 20:24:28 +0000 Subject: [PATCH 8/9] One more try for windows --- gazelle/gazelle.go | 61 ++++++++++++++++------------- gazelle/gazelle_test.go | 68 ++++++++++++++++++--------------- gazelle/testdata/empty/BUILD.in | 6 +++ 3 files changed, 78 insertions(+), 57 deletions(-) diff --git a/gazelle/gazelle.go b/gazelle/gazelle.go index ec3edc6e..b45ef3d8 100644 --- a/gazelle/gazelle.go +++ b/gazelle/gazelle.go @@ -203,30 +203,31 @@ func (*bzlLibraryLang) GenerateRules(args language.GenerateArgs) language.Genera var rules []*rule.Rule var imports []interface{} for _, f := range append(args.RegularFiles, args.GenFiles...) { - if isBzlSourceFile(f) { - name := strings.TrimSuffix(f, fileType) - r := rule.NewRule("bzl_library", name) - - r.SetAttr("srcs", []string{f}) + if !isBzlSourceFile(f) { + continue + } + name := strings.TrimSuffix(f, fileType) + r := rule.NewRule("bzl_library", name) - if args.File == nil || !args.File.HasDefaultVisibility() { - inPrivateDir := pathtools.Index(args.Rel, "private") >= 0 - if !inPrivateDir { - r.SetAttr("visibility", []string{"//visibility:public"}) - } - } + r.SetAttr("srcs", []string{f}) - 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. + if args.File == nil || !args.File.HasDefaultVisibility() { + inPrivateDir := pathtools.Index(args.Rel, "private") >= 0 + if !inPrivateDir { + r.SetAttr("visibility", []string{"//visibility:public"}) } + } - rules = append(rules, r) - imports = append(imports, loads) + 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{ @@ -278,20 +279,26 @@ func generateEmpty(args language.GenerateArgs) []*rule.Rule { continue } name := r.AttrString("name") - srcs := srcsList(r.AttrStrings("srcs")) + exists := make(map[string]bool) for _, f := range args.RegularFiles { - if srcs.Contains(f) { - continue - } + exists[f] = true } for _, f := range args.GenFiles { - if srcs.Contains(f) { - continue + 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)) } } - - ret = append(ret, rule.NewRule("bzl_library", name)) } return ret } diff --git a/gazelle/gazelle_test.go b/gazelle/gazelle_test.go index 73d5ee33..a22f7f65 100644 --- a/gazelle/gazelle_test.go +++ b/gazelle/gazelle_test.go @@ -29,74 +29,82 @@ import ( 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) { - runfilesPath, err := bazel.RunfilesPath() - if err != nil { - t.Fatalf("bazel.RunfilesPath() error: %v", err) - } - testdata := filepath.Join(runfilesPath, "gazelle", "testdata") - ds, err := ioutil.ReadDir(testdata) + tests := map[string][]bazel.RunfileEntry{} + + files, err := bazel.ListRunfiles() if err != nil { - t.Fatalf("ioutil.ReadDir(%q) error: %v", testdata, err) + t.Fatalf("bazel.ListRunfiles() error: %v", err) } - for _, d := range ds { - if d.IsDir() { - t.Run(d.Name(), testPath(testdata, d.Name())) + 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(testdata string, dir string) func(t *testing.T) { - return func(t *testing.T) { +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 - if err := filepath.Walk(filepath.Join(testdata, dir), func(path string, info os.FileInfo, err error) error { - // If you were called with an error, don't try to recover, just fail. + for _, f := range files { + path := f.Path + trim := testDataPath + name + "/" + shortPath := strings.TrimPrefix(f.ShortPath, trim) + info, err := os.Stat(path) if err != nil { - return err + t.Fatalf("os.Stat(%q) error: %v", path, err) } // Skip dirs. if info.IsDir() { - return nil + continue } content, err := ioutil.ReadFile(path) if err != nil { - return err + t.Errorf("ioutil.ReadFile(%q) error: %v", path, err) } // Now trim the common prefix off. - newPath := strings.TrimPrefix(path, filepath.Join(testdata, dir)+"/") - - if strings.HasSuffix(newPath, ".in") { + if strings.HasSuffix(shortPath, ".in") { inputs = append(inputs, testtools.FileSpec{ - Path: strings.TrimSuffix(newPath, ".in"), + Path: strings.TrimSuffix(shortPath, ".in"), Content: string(content), }) - } else if strings.HasSuffix(newPath, ".out") { + } else if strings.HasSuffix(shortPath, ".out") { goldens = append(goldens, testtools.FileSpec{ - Path: strings.TrimSuffix(newPath, ".out"), + Path: strings.TrimSuffix(shortPath, ".out"), Content: string(content), }) } else { inputs = append(inputs, testtools.FileSpec{ - Path: newPath, + Path: shortPath, Content: string(content), }) goldens = append(goldens, testtools.FileSpec{ - Path: newPath, + Path: shortPath, Content: string(content), }) } - - return nil - }); err != nil { - t.Errorf("filepath.Walk(%q) error: %v", filepath.Join(testdata, dir), err) } dir, cleanup := testtools.CreateFiles(t, inputs) @@ -120,7 +128,7 @@ func testPath(testdata string, dir string) func(t *testing.T) { return nil }) } - } + }) } func findGazelle() string { diff --git a/gazelle/testdata/empty/BUILD.in b/gazelle/testdata/empty/BUILD.in index 80690c9e..e1e154cb 100644 --- a/gazelle/testdata/empty/BUILD.in +++ b/gazelle/testdata/empty/BUILD.in @@ -1,5 +1,11 @@ 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"], From 5da107a17525608134249f55901f972d651c3a9e Mon Sep 17 00:00:00 2001 From: Andrew Allen Date: Wed, 24 Jun 2020 22:44:30 +0000 Subject: [PATCH 9/9] Fix lint error --- BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILD b/BUILD index ad1dbfb8..bec32f56 100644 --- a/BUILD +++ b/BUILD @@ -6,6 +6,7 @@ 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"])