diff --git a/README.rst b/README.rst index 1dac53e93..b78b334ac 100644 --- a/README.rst +++ b/README.rst @@ -336,6 +336,11 @@ The following flags are accepted: | See `Predefined plugins`_ for available options; commonly used options include | | ``@io_bazel_rules_go//proto:gofast_grpc`` and ``@io_bazel_rules_go//proto:gogofaster_grpc``. | +--------------------------------------------------------------+----------------------------------------+ +| :flag:`-go_naming_convention` | | ++--------------------------------------------------------------+----------------------------------------+ +| Controls the names of generated Go targets. Equivalent to the | +| # gazelle:go_naming_convention directive. | ++--------------------------------------------------------------+----------------------------------------+ | :flag:`-go_prefix example.com/repo` | | +--------------------------------------------------------------+----------------------------------------+ | A prefix of import paths for libraries in the repository that corresponds to | @@ -575,6 +580,22 @@ The following directives are recognized: | ``@io_bazel_rules_go//proto:gofast_grpc`` and | | ``@io_bazel_rules_go//proto:gogofaster_grpc``. | +---------------------------------------------------+----------------------------------------+ +| :direc:`# gazelle:go_naming_convention` | n/a | ++---------------------------------------------------+----------------------------------------+ +| Controls the names of generated Go targets. By default, library targets are named | +| `go_default_library` and test targets `go_default_test`. | +| Valid values are: | +| * ``go_default_library``: Library targets are named ``go_default_library``, test targets | +| are named ``go_default_test``. | +| * ``import``: Library and test targets are named after the last segment of their import | +| path. | +| For example, ``example.repo/foo`` is named ``foo``, and the test target is ``foo_test``. | +| Major version suffixes like ``/v2`` are dropped. | +| For a main package with a binary ``foobin``, the names are instead ``foobin_lib`` and | +| ``foobin_test``. | +| * ``import_alias``: Same as ``import``, but an ``alias`` target is generated named | +| ``go_default_library`` to ensure backwards compatibility. | ++---------------------------------------------------+----------------------------------------+ | :direc:`# gazelle:go_proto_compilers` | ``@io_bazel_rules_go//proto:go_proto`` | +---------------------------------------------------+----------------------------------------+ | The protocol buffers compiler(s) to use for building go bindings. | diff --git a/cmd/gazelle/fix-update.go b/cmd/gazelle/fix-update.go index fa57d313e..a8a43a265 100644 --- a/cmd/gazelle/fix-update.go +++ b/cmd/gazelle/fix-update.go @@ -147,12 +147,15 @@ func (ucr *updateConfigurer) CheckFlags(fs *flag.FlagSet, c *config.Config) erro GoPrefix: imp, }) } + goRepos := make(map[string]repo.Repo) for _, r := range c.Repos { if r.Kind() == "go_repository" { - uc.repos = append(uc.repos, repo.Repo{ - Name: r.Name(), - GoPrefix: r.AttrString("importpath"), - }) + gr := repo.Repo{ + Name: r.Name(), + GoPrefix: r.AttrString("importpath"), + } + uc.repos = append(uc.repos, gr) + goRepos[r.Name()] = gr } } diff --git a/internal/go_repository.bzl b/internal/go_repository.bzl index 51a7317df..a8d947a67 100644 --- a/internal/go_repository.bzl +++ b/internal/go_repository.bzl @@ -191,7 +191,6 @@ go_repository = repository_rule( attrs = { # Fundamental attributes of a go repository "importpath": attr.string(mandatory = True), - # Attributes for a repository that should be checked out from VCS "commit": attr.string(), "tag": attr.string(), @@ -235,6 +234,14 @@ go_repository = repository_rule( "off", ], ), + "build_naming_convention": attr.string( + values = [ + "", + "go_default_library", + "import", + "import_alias", + ], + ), "build_tags": attr.string_list(), "build_file_proto_mode": attr.string( values = [ diff --git a/language/go/config.go b/language/go/config.go index d157d3391..3b0c5f458 100644 --- a/language/go/config.go +++ b/language/go/config.go @@ -77,6 +77,9 @@ type goConfig struct { // goGenerateProto indicates whether to generate go_proto_library goGenerateProto bool + // goNamingConvention controls the name of generated targets + goNamingConvention namingConvention + // goProtoCompilers is the protocol buffers compiler(s) to use for go code. goProtoCompilers []string @@ -104,6 +107,10 @@ type goConfig struct { // resolved differently (also depending on goRepositoryMode). moduleMode bool + // map between external repo names and their `build_naming_convention` + // attribute. + repoNamingConvention map[string]namingConvention + // submodules is a list of modules which have the current module's path // as a prefix of their own path. This affects visibility attributes // in internal packages. @@ -171,6 +178,15 @@ func (gc *goConfig) setBuildTags(tags string) error { return nil } +func (gc *goConfig) setNamingConvention(s string) error { + if nc, err := namingConventionFromString(s); err == nil { + gc.goNamingConvention = nc + return nil + } else { + return err + } +} + func getProtoMode(c *config.Config) proto.Mode { if gc := getGoConfig(c); !gc.goGenerateProto { return proto.DisableMode @@ -236,6 +252,59 @@ func (f tagsFlag) String() string { return "" } +type namingConventionFlag func(string) error + +func (f namingConventionFlag) Set(value string) error { + return f(value) +} + +func (f namingConventionFlag) String() string { + return "" +} + +// namingConvention determines how go targets are named. +type namingConvention int + +const ( + // 'go_default_library' and 'go_default_test' + goDefaultLibraryNamingConvention = iota + + // For an import path that ends with foo, the go_library rules target is + // named 'foo', the go_test is named 'foo_test'. + // For a main package, the go_binary takes the 'foo' name, the library + // is named 'foo_lib', and the go_test is named 'foo_test'. + importNamingConvention + + // Same as importNamingConvention, but generate alias rules for libraries that have + // the legacy 'go_default_library' name. + importAliasNamingConvention +) + +func (nc namingConvention) String() string { + switch nc { + case goDefaultLibraryNamingConvention: + return "go_default_library" + case importNamingConvention: + return "import" + case importAliasNamingConvention: + return "import_alias" + } + return "" +} + +func namingConventionFromString(s string) (namingConvention, error) { + switch s { + case "go_default_library": + return goDefaultLibraryNamingConvention, nil + case "import": + return importNamingConvention, nil + case "import_alias": + return importAliasNamingConvention, nil + default: + return goDefaultLibraryNamingConvention, fmt.Errorf("unknown naming convention %q", s) + } +} + type moduleRepo struct { repoName, modulePath string } @@ -249,6 +318,7 @@ func (*goLang) KnownDirectives() []string { "build_tags", "go_generate_proto", "go_grpc_compilers", + "go_naming_convention", "go_proto_compilers", "go_visibility", "importmap_prefix", @@ -290,6 +360,10 @@ func (*goLang) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config) { "go_repository_module_mode", false, "set when gazelle is invoked by go_repository in module mode") + fs.Var( + namingConventionFlag(gc.setNamingConvention), + "go_naming_convention", + "controls generated library names. One of (go_default_library, import, import_alias)") case "update-repos": fs.Var(&gzflag.AllowedStringFlag{Value: &gc.buildExternalAttr, Allowed: validBuildExternalAttr}, @@ -372,6 +446,17 @@ Update io_bazel_rules_go to a newer version in your WORKSPACE file.` log.Printf("Found RULES_GO_VERSION %s. Minimum compatible version is %s.\n%s", gc.rulesGoVersion, minimumRulesGoVersion, message) } } + repoNamingConvention := map[string]namingConvention{} + for _, repo := range c.Repos { + if repo.Kind() == "go_repository" { + if nc, err := namingConventionFromString(repo.AttrString("build_naming_convention")); err == nil { + repoNamingConvention[repo.Name()] = nc + } else { + log.Printf("%v\n", err) + } + } + } + gc.repoNamingConvention = repoNamingConvention } if !gc.moduleMode { @@ -408,12 +493,15 @@ Update io_bazel_rules_go to a newer version in your WORKSPACE file.` gc.preprocessTags() gc.setBuildTags(d.Value) case "go_generate_proto": - if goGenerateProto, err := strconv.ParseBool(d.Value); err == nil { gc.goGenerateProto = goGenerateProto } else { log.Printf("parsing go_generate_proto: %v", err) } + case "go_naming_convention": + if err := gc.setNamingConvention(d.Value); err != nil { + log.Print(err) + } case "go_grpc_compilers": // Special syntax (empty value) to reset directive. if d.Value == "" { diff --git a/language/go/config_test.go b/language/go/config_test.go index d2a2aba4d..2196077fd 100644 --- a/language/go/config_test.go +++ b/language/go/config_test.go @@ -64,6 +64,7 @@ func TestCommandLine(t *testing.T) { t, "-build_tags=foo,bar", "-go_prefix=example.com/repo", + "-go_naming_convention=import_alias", "-external=vendored", "-repo_root=.") gc := getGoConfig(c) @@ -78,6 +79,9 @@ func TestCommandLine(t *testing.T) { if gc.depMode != vendorMode { t.Errorf("got dep mode %v; want %v", gc.depMode, vendorMode) } + if gc.goNamingConvention != importAliasNamingConvention { + t.Errorf("got naming convention %v; want %v", gc.goNamingConvention, importAliasNamingConvention) + } } func TestDirectives(t *testing.T) { diff --git a/language/go/fix.go b/language/go/fix.go index 88d99963e..b721cc842 100644 --- a/language/go/fix.go +++ b/language/go/fix.go @@ -30,10 +30,125 @@ func (_ *goLang) Fix(c *config.Config, f *rule.File) { flattenSrcs(c, f) squashCgoLibrary(c, f) squashXtest(c, f) + migrateNamingConvention(c, f) removeLegacyProto(c, f) removeLegacyGazelle(c, f) } +// migrateNamingConvention renames rules according to go_naming_convention directives. +func migrateNamingConvention(c *config.Config, f *rule.File) { + nc := getGoConfig(c).goNamingConvention + + binName := binName(f) + importPath := importPath(f) + libName := libNameByConvention(nc, binName, importPath) + testName := testNameByConvention(nc, binName, importPath) + var migrateLibName, migrateTestName string + switch nc { + case goDefaultLibraryNamingConvention: + migrateLibName = libNameByConvention(importNamingConvention, binName, importPath) + migrateTestName = testNameByConvention(importNamingConvention, binName, importPath) + case importNamingConvention, importAliasNamingConvention: + migrateLibName = defaultLibName + migrateTestName = defaultTestName + default: + return + } + + for _, r := range f.Rules { + switch r.Kind() { + case "go_binary": + replaceInListAttr(r, "embed", ":"+migrateLibName, ":"+libName) + case "go_library": + if r.Name() == migrateLibName { + r.SetName(libName) + } + case "go_test": + if r.Name() == migrateTestName { + r.SetName(testName) + replaceInListAttr(r, "embed", ":"+migrateLibName, ":"+libName) + } + } + } + + // Alias migration + if binName == "" { + var ar *rule.Rule + var lib *rule.Rule + for _, r := range f.Rules { + if r.Kind() == "alias" && r.Name() == defaultLibName { + ar = r + } else if r.Kind() == "go_library" && r.Name() == libName { + lib = r + } + } + if nc == importAliasNamingConvention { + if ar == nil && lib != nil { + r := rule.NewRule("alias", defaultLibName) + r.SetAttr("actual", ":"+lib.Name()) + visibility := lib.Attr("visibility") + if visibility != nil { + r.SetAttr("visibility", visibility) + } + r.Insert(f) + } + } else { + if ar != nil { + ar.Delete() + } + } + } +} + +// binName returns the name of a go_binary rule if one can be found. +func binName(f *rule.File) string { + for _, r := range f.Rules { + if r.Kind() == "go_binary" { + return r.Name() + } + } + return "" +} + +// import path returns the existing import path from the first encountered Go rule with the attribute set. +func importPath(f *rule.File) string { + for _, r := range f.Rules { + switch r.Kind() { + case "go_binary", "go_library", "go_test": + if ip, ok := r.Attr("importpath").(*bzl.StringExpr); ok && ip.Value != "" { + return ip.Value + } + } + } + return f.Pkg +} + +func replaceInListAttr(r *rule.Rule, attr, old, new string) { + a := r.Attr(attr) + oldAttr, ok := a.(*bzl.ListExpr) + if !ok { + r.SetAttr(attr, []string{new}) + return + } + var shouldAdd = true + var items []bzl.Expr + for _, v := range oldAttr.List { + str, ok := v.(*bzl.StringExpr) + if !ok || str.Value != old { + items = append(items, v) + } + if ok && str.Value == new { + shouldAdd = false + } + } + if shouldAdd { + items = append(items, &bzl.StringExpr{Value: new}) + } + newAttr := *oldAttr + newAttr.List = items + r.SetAttr(attr, &newAttr) +} + // migrateLibraryEmbed converts "library" attributes to "embed" attributes, // preserving comments. This only applies to Go rules, and only if there is // no keep comment on "library" and no existing "embed" attribute. @@ -72,6 +187,9 @@ func migrateGrpcCompilers(c *config.Config, f *rule.File) { // MergeFile will remove unused values and attributes later. func squashCgoLibrary(c *config.Config, f *rule.File) { // Find the default cgo_library and go_library rules. + binName := binName(f) + importPath := importPath(f) + libName := libNameByConvention(getGoConfig(c).goNamingConvention, binName, importPath) var cgoLibrary, goLibrary *rule.Rule for _, r := range f.Rules { if r.Kind() == "cgo_library" && r.Name() == "cgo_default_library" && !r.ShouldKeep() { @@ -82,7 +200,7 @@ func squashCgoLibrary(c *config.Config, f *rule.File) { cgoLibrary = r continue } - if r.Kind() == "go_library" && r.Name() == defaultLibName { + if r.Kind() == "go_library" && r.Name() == libName { if goLibrary != nil { log.Printf("%s: when fixing existing file, multiple go_library rules with default name referencing cgo_library found", f.Path) } @@ -99,9 +217,10 @@ func squashCgoLibrary(c *config.Config, f *rule.File) { return } + // If there wasn't an existing library to squash into, we'll have to guess at its name. if goLibrary == nil { cgoLibrary.SetKind("go_library") - cgoLibrary.SetName(defaultLibName) + cgoLibrary.SetName(libName) cgoLibrary.SetAttr("cgo", true) return } @@ -121,12 +240,15 @@ func squashCgoLibrary(c *config.Config, f *rule.File) { // renaming the old rule). func squashXtest(c *config.Config, f *rule.File) { // Search for internal and external tests. + binName := binName(f) + importPath := importPath(f) + testName := testNameByConvention(getGoConfig(c).goNamingConvention, binName, importPath) var itest, xtest *rule.Rule for _, r := range f.Rules { if r.Kind() != "go_test" { continue } - if r.Name() == defaultTestName { + if r.Name() == testName { itest = r } else if r.Name() == "go_default_xtest" { xtest = r @@ -138,16 +260,16 @@ func squashXtest(c *config.Config, f *rule.File) { } if !c.ShouldFix { if itest == nil { - log.Printf("%s: go_default_xtest is no longer necessary. Run 'gazelle fix' to rename to go_default_test.", f.Path) + log.Printf("%s: go_default_xtest is no longer necessary. Run 'gazelle fix' to rename to %s.", f.Path, testName) } else { - log.Printf("%s: go_default_xtest is no longer necessary. Run 'gazelle fix' to squash with go_default_test.", f.Path) + log.Printf("%s: go_default_xtest is no longer necessary. Run 'gazelle fix' to squash with %s.", f.Path, testName) } return } // If there was no internal test, we can just rename the external test. if itest == nil { - xtest.SetName(defaultTestName) + xtest.SetName(testName) return } diff --git a/language/go/fix_test.go b/language/go/fix_test.go index 44109ffa8..218db27a8 100644 --- a/language/go/fix_test.go +++ b/language/go/fix_test.go @@ -16,6 +16,7 @@ limitations under the License. package golang import ( + "fmt" "path/filepath" "testing" @@ -24,13 +25,452 @@ import ( ) type fixTestCase struct { - desc, old, want string + desc, old, want string + namingConvention namingConvention } func TestFixFile(t *testing.T) { for _, tc := range []fixTestCase{ - // migrateLibraryEmbed tests + // migrateNamingConvention tests { + desc: "go_naming_convention=go_default_library -> import for lib", + namingConvention: importNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + }, { + desc: "go_naming_convention=go_default_library -> import for bin", + namingConvention: importNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_binary( + name = "foo", + embed = [":go_default_library"], +) + +go_library( + name = "go_default_library", + importpath = "foo", + srcs = ["foo.go"], +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_binary( + name = "foo", + embed = [":foo_lib"], +) + +go_library( + name = "foo_lib", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo_lib"], +) +`, + }, { + desc: "go_naming_convention=import -> go_default_library for lib", + namingConvention: goDefaultLibraryNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + }, { + desc: "go_naming_convention=import -> go_default_library for bin", + namingConvention: goDefaultLibraryNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_binary( + name = "foo", + embed = [":foo_lib"], +) + +go_library( + name = "foo_lib", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo_lib"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_binary( + name = "foo", + embed = [":go_default_library"], +) + +go_library( + name = "go_default_library", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + }, { + desc: "go_naming_convention=go_default_library -> import_alias for lib", + namingConvention: importAliasNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["foo.go"], + importpath = "foo", + visibility = ["//visibility:private"], +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", + visibility = ["//visibility:private"], +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) + +alias( + name = "go_default_library", + actual = ":foo", + visibility = ["//visibility:private"], +) +`, + }, { + desc: "go_naming_convention=import_alias -> go_default_library for lib", + namingConvention: goDefaultLibraryNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +alias( + name = "go_default_library", + actual = ":foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + }, { + desc: "go_naming_convention=go_default_library -> import_alias for bin", + namingConvention: importAliasNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_binary( + name = "foo", + embed = [":go_default_library"], +) + +go_library( + name = "go_default_library", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_binary( + name = "foo", + embed = [":foo_lib"], +) + +go_library( + name = "foo_lib", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo_lib"], +) +`, + }, { + desc: "go_naming_convention=import -> import_alias for lib", + namingConvention: importAliasNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) + +alias( + name = "go_default_library", + actual = ":foo", +) +`, + }, { + desc: "go_naming_convention import_alias -> import for lib", + namingConvention: importNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +alias( + name = "go_default_library", + actual = ":foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + }, { + desc: "go_naming_convention=import -> import for lib", + namingConvention: importNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + }, { + desc: "go_naming_convention go_default_library -> go_default_library for lib", + namingConvention: goDefaultLibraryNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["foo.go"], + importpath = "foo", + visibility = ["//visibility:private"], +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["foo.go"], + importpath = "foo", + visibility = ["//visibility:private"], +) + +go_test( + name = "go_default_test", + srcs = ["foo_test.go"], + embed = [":go_default_library"], +) +`, + }, { + desc: "go_naming_convention=import_alias -> import_alias for lib", + namingConvention: importAliasNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +alias( + name = "go_default_library", + actual = ":foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "foo", + srcs = ["foo.go"], + importpath = "foo", +) + +alias( + name = "go_default_library", + actual = ":foo", +) + +go_test( + name = "foo_test", + srcs = ["foo_test.go"], + embed = [":foo"], +) +`, + }, { + // migrateLibraryEmbed tests desc: "library migrated to embed", old: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") @@ -304,6 +744,66 @@ go_library( ) # after go_library # after cgo_library +`, + }, { + desc: "cgo_library merged with go_library go_naming_convention=import", + namingConvention: importNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_library") + +# before go_library +go_library( + name = "foo", + srcs = ["pure.go"], + deps = ["pure_deps"], + data = ["pure_data"], + importpath = "foo", + gc_goopts = ["pure_gc_goopts"], + library = ":cgo_default_library", + cgo = False, +) +# after go_library + +# before cgo_library +cgo_library( + name = "cgo_default_library", + srcs = ["cgo.go"], + deps = ["cgo_deps"], + data = ["cgo_data"], + gc_goopts = ["cgo_gc_goopts"], + copts = ["copts"], + cdeps = ["cdeps"], +) +# after cgo_library +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_library") + +# before go_library +# before cgo_library +go_library( + name = "foo", + srcs = [ + "cgo.go", + "pure.go", + ], + cdeps = ["cdeps"], + cgo = True, + copts = ["copts"], + data = [ + "cgo_data", + "pure_data", + ], + gc_goopts = [ + "cgo_gc_goopts", + "pure_gc_goopts", + ], + importpath = "foo", + deps = [ + "cgo_deps", + "pure_deps", + ], +) +# after go_library +# after cgo_library `, }, // squashXtest tests @@ -361,6 +861,69 @@ go_test( ":x_dep", ], ) +`, + }, + { + desc: "rename xtest go_naming_convention=import", + namingConvention: importNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_test") +go_test( + name = "go_default_xtest", + srcs = ["x_test.go"], + importpath = "foo", +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "foo_test", + srcs = ["x_test.go"], + importpath = "foo", +) +`, + }, + { + desc: "squash xtest go_naming_convention=import", + namingConvention: importNamingConvention, + old: `load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "foo_test", + srcs = ["i_test.go"], + deps = [ + ":i_dep", + ":shared_dep", + ], + importpath = "foo", + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_xtest", + srcs = ["x_test.go"], + deps = [ + ":x_dep", + ":shared_dep", + ], + visibility = ["//visibility:public"], +) +`, + want: `load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "foo_test", + srcs = [ + "i_test.go", + "x_test.go", + ], + importpath = "foo", + visibility = ["//visibility:public"], + deps = [ + ":i_dep", + ":shared_dep", + ":x_dep", + ], +) `, }, // removeLegacyProto tests @@ -408,7 +971,8 @@ go_proto_library(name = "foo_proto") } { t.Run(tc.desc, func(t *testing.T) { testFix(t, tc, func(f *rule.File) { - c, langs, _ := testConfig(t) + c, langs, _ := testConfig(t, + fmt.Sprintf("-go_naming_convention=%s", tc.namingConvention)) c.ShouldFix = true for _, lang := range langs { lang.Fix(c, f) diff --git a/language/go/generate.go b/language/go/generate.go index 71a25b3d2..cb58ab61f 100644 --- a/language/go/generate.go +++ b/language/go/generate.go @@ -255,15 +255,19 @@ func (gl *goLang) GenerateRules(args language.GenerateArgs) language.GenerateRes _, rs := g.generateProto(pcMode, pkg.proto, pkg.importPath) rules = append(rules, rs...) } - lib := g.generateLib(pkg, protoEmbed) + binName := pathtools.RelBaseName(pkg.rel, getGoConfig(g.c).prefix, g.c.RepoRoot) + lib := g.generateLib(pkg, binName, protoEmbed) var libName string if !lib.IsEmpty(goKinds[lib.Kind()]) { libName = lib.Name() } rules = append(rules, lib) + if getGoConfig(c).goNamingConvention == importAliasNamingConvention && !pkg.isCommand() && libName != "" { + rules = append(rules, g.generateImportAlias(pkg, libName)) + } rules = append(rules, - g.generateBin(pkg, libName), - g.generateTest(pkg, libName)) + g.generateBin(pkg, binName, libName), + g.generateTest(pkg, binName, libName)) } for _, r := range rules { @@ -442,8 +446,13 @@ func (g *generator) generateProto(mode proto.Mode, target protoTarget, importPat return goProtoName, []*rule.Rule{goProtoLibrary} } -func (g *generator) generateLib(pkg *goPackage, embed string) *rule.Rule { - goLibrary := rule.NewRule("go_library", defaultLibName) +func (g *generator) generateLib(pkg *goPackage, binName, embed string) *rule.Rule { + var bn string + if pkg.isCommand() { + bn = binName + } + name := libNameByConvention(getGoConfig(g.c).goNamingConvention, bn, pkg.name) + goLibrary := rule.NewRule("go_library", name) if !pkg.library.sources.hasGo() && embed == "" { return goLibrary // empty } @@ -459,9 +468,8 @@ func (g *generator) generateLib(pkg *goPackage, embed string) *rule.Rule { return goLibrary } -func (g *generator) generateBin(pkg *goPackage, library string) *rule.Rule { - name := pathtools.RelBaseName(pkg.rel, getGoConfig(g.c).prefix, g.c.RepoRoot) - goBinary := rule.NewRule("go_binary", name) +func (g *generator) generateBin(pkg *goPackage, binName, library string) *rule.Rule { + goBinary := rule.NewRule("go_binary", binName) if !pkg.isCommand() || pkg.binary.sources.isEmpty() && library == "" { return goBinary // empty } @@ -470,8 +478,13 @@ func (g *generator) generateBin(pkg *goPackage, library string) *rule.Rule { return goBinary } -func (g *generator) generateTest(pkg *goPackage, library string) *rule.Rule { - goTest := rule.NewRule("go_test", defaultTestName) +func (g *generator) generateTest(pkg *goPackage, binName, library string) *rule.Rule { + var bn string + if pkg.isCommand() { + bn = binName + } + name := testNameByConvention(getGoConfig(g.c).goNamingConvention, bn, pkg.name) + goTest := rule.NewRule("go_test", name) if !pkg.test.sources.hasGo() { return goTest // empty } @@ -482,6 +495,13 @@ func (g *generator) generateTest(pkg *goPackage, library string) *rule.Rule { return goTest } +func (g *generator) generateImportAlias(pkg *goPackage, library string) *rule.Rule { + alias := rule.NewRule("alias", defaultLibName) + alias.SetAttr("actual", ":"+library) + alias.SetAttr("visibility", g.commonVisibility(pkg.importPath)) + return alias +} + func (g *generator) setCommonAttrs(r *rule.Rule, pkgRel string, visibility []string, target goTarget, embed string) { if !target.sources.isEmpty() { r.SetAttr("srcs", target.sources.buildFlat()) diff --git a/language/go/package.go b/language/go/package.go index 0f47b0f9a..6aa932eb7 100644 --- a/language/go/package.go +++ b/language/go/package.go @@ -79,6 +79,9 @@ const ( platformSet ) +// Matches a package version, eg. the end segment of 'example.com/foo/v1' +var pkgVersionRe = regexp.MustCompile("^v[0-9]+$") + // addFile adds the file described by "info" to a target in the package "p" if // the file is buildable. // @@ -166,6 +169,49 @@ func (pkg *goPackage) inferImportPath(c *config.Config) error { return nil } +// Returns a a suitable go_library name based on the dir. +// Major version suffixes (eg. "v1") are dropped. +func libNameFromDir(dir string) string { + i := strings.LastIndexAny(dir, "/\\") + if i < 0 { + return dir + } + name := dir[i+1:] + if pkgVersionRe.MatchString(name) { + dir := dir[:i] + i = strings.LastIndexAny(dir, "/\\") + if i >= 0 { + name = dir[i+1:] + } + } + return name +} + +// libNameByConvention returns a suitable lib name based on go_naming_convention +// If go_default_library, "go_default_library" is returned. +// Else if this is a 'main' package, 'foo_lib' is returned, where 'foo' is the name of the go_binary rule. +// Else it is a regular package, the last segment of the importpath is returned. Major version suffixes (eg. "v1") are dropped. +func libNameByConvention(nc namingConvention, binName, imp string) string { + if nc == goDefaultLibraryNamingConvention { + return defaultLibName + } + if binName != "" { + return binName + "_lib" + } + return libNameFromDir(imp) +} + +// testNameByConvention works like libNameByConvention, but always appends '_test'. +func testNameByConvention(nc namingConvention, binName, imp string) string { + if nc == goDefaultLibraryNamingConvention { + return defaultTestName + } + if binName != "" { + return binName + "_test" + } + return libNameFromDir(imp) + "_test" +} + func InferImportPath(c *config.Config, rel string) string { gc := getGoConfig(c) if rel == gc.prefixRel { diff --git a/language/go/resolve.go b/language/go/resolve.go index 86bb040e8..18f99f933 100644 --- a/language/go/resolve.go +++ b/language/go/resolve.go @@ -183,14 +183,15 @@ func ResolveGo(c *config.Config, ix *resolve.RuleIndex, rc *repo.RemoteCache, im // current repo if pathtools.HasPrefix(imp, gc.prefix) { pkg := path.Join(gc.prefixRel, pathtools.TrimPrefix(imp, gc.prefix)) - return label.New("", pkg, defaultLibName), nil + libName := libNameByConvention(gc.goNamingConvention, "", imp) + return label.New("", pkg, libName), nil } } if gc.depMode == externalMode { - return resolveExternal(gc.moduleMode, rc, imp) + return resolveExternal(c, rc, imp) } else { - return resolveVendored(rc, imp) + return resolveVendored(gc, imp) } } @@ -255,7 +256,7 @@ func resolveWithIndexGo(ix *resolve.RuleIndex, imp string, from label.Label) (la var modMajorRex = regexp.MustCompile(`/v\d+(?:/|$)`) -func resolveExternal(moduleMode bool, rc *repo.RemoteCache, imp string) (label.Label, error) { +func resolveExternal(c *config.Config, rc *repo.RemoteCache, imp string) (label.Label, error) { // If we're in module mode, use "go list" to find the module path and // repository name. Otherwise, use special cases (for github.com, golang.org) // or send a GET with ?go-get=1 to find the root. If the path contains @@ -264,6 +265,8 @@ func resolveExternal(moduleMode bool, rc *repo.RemoteCache, imp string) (label.L // Eventually module mode will be the only mode. But for now, it's expensive // and not the common case, especially when known repositories aren't // listed in WORKSPACE (which is currently the case within go_repository). + gc := getGoConfig(c) + moduleMode := gc.moduleMode if !moduleMode { moduleMode = pathWithoutSemver(imp) != "" } @@ -288,11 +291,23 @@ func resolveExternal(moduleMode bool, rc *repo.RemoteCache, imp string) (label.L pkg = pathtools.TrimPrefix(impWithoutSemver, prefix) } - return label.New(repo, pkg, defaultLibName), nil + // Determine what naming convention is used by the go_repository rule. + // If none is specified with "build_naming_convention", the either naming convention + // can be used, so we'll default to whatever's used in the current workspace to avoid churn. + nc := gc.goNamingConvention + if gc.repoNamingConvention != nil { + if rnc, ok := gc.repoNamingConvention[repo]; ok { + nc = rnc + } + } + + name := libNameByConvention(nc, "", imp) + return label.New(repo, pkg, name), nil } -func resolveVendored(rc *repo.RemoteCache, imp string) (label.Label, error) { - return label.New("", path.Join("vendor", imp), defaultLibName), nil +func resolveVendored(gc *goConfig, imp string) (label.Label, error) { + name := libNameByConvention(gc.goNamingConvention, "", imp) + return label.New("", path.Join("vendor", imp), name), nil } func resolveProto(c *config.Config, ix *resolve.RuleIndex, rc *repo.RemoteCache, imp string, from label.Label) (label.Label, error) { @@ -331,7 +346,8 @@ func resolveProto(c *config.Config, ix *resolve.RuleIndex, rc *repo.RemoteCache, if from.Pkg == "vendor" || strings.HasPrefix(from.Pkg, "vendor/") { rel = path.Join("vendor", rel) } - return label.New("", rel, defaultLibName), nil + libName := libNameByConvention(getGoConfig(c).goNamingConvention, "", imp) + return label.New("", rel, libName), nil } // wellKnownProtos is the set of proto sets for which we don't need to add diff --git a/language/go/resolve_test.go b/language/go/resolve_test.go index 667da7e53..143cb6eb2 100644 --- a/language/go/resolve_test.go +++ b/language/go/resolve_test.go @@ -35,11 +35,12 @@ func TestResolveGo(t *testing.T) { rel, content string } type testCase struct { - desc string - index []buildFile - old buildFile - want string - skipIndex bool + desc string + index []buildFile + old buildFile + want string + skipIndex bool + namingConvention namingConvention } for _, tc := range []testCase{ { @@ -533,6 +534,21 @@ go_binary( name = "bin", deps = ["//vendor/example.com/outside/prefix:go_default_library"], ) +`, + }, { + desc: "vendor with go_naming_convention=import", + namingConvention: importNamingConvention, + old: buildFile{content: ` +go_binary( + name = "bin", + _imports = ["example.com/outside/prefix"], +) +`}, + want: ` +go_binary( + name = "bin", + deps = ["//vendor/example.com/outside/prefix"], +) `, }, { desc: "test_and_library_not_indexed", @@ -919,6 +935,7 @@ go_proto_library( c, langs, cexts := testConfig( t, "-go_prefix=example.com/repo/resolve", + fmt.Sprintf("-go_naming_convention=%s", tc.namingConvention), "-external=vendored", fmt.Sprintf("-index=%v", !tc.skipIndex)) mrslv := make(mapResolver) for _, lang := range langs { @@ -1064,6 +1081,8 @@ func TestResolveExternal(t *testing.T) { desc, importpath string repos []repo.Repo moduleMode bool + namingConvention namingConvention + repoNamingConvention map[string]namingConvention want string }{ { @@ -1074,6 +1093,16 @@ func TestResolveExternal(t *testing.T) { desc: "sub", importpath: "example.com/repo/lib", want: "@com_example_repo//lib:go_default_library", + }, { + desc: "top go_naming_convention=import", + namingConvention: importNamingConvention, + importpath: "example.com/repo", + want: "@com_example_repo//:repo", + }, { + desc: "sub go_naming_convention=import", + namingConvention: importNamingConvention, + importpath: "example.com/repo/lib", + want: "@com_example_repo//lib", }, { desc: "custom_repo", repos: []repo.Repo{{ @@ -1082,6 +1111,17 @@ func TestResolveExternal(t *testing.T) { }}, importpath: "example.com/repo/lib", want: "@custom_repo_name//lib:go_default_library", + }, { + desc: "custom_repo go_naming_convention=import", + repos: []repo.Repo{{ + Name: "custom_repo_name", + GoPrefix: "example.com/repo", + }}, + repoNamingConvention: map[string]namingConvention{ + "custom_repo_name": importNamingConvention, + }, + importpath: "example.com/repo/lib", + want: "@custom_repo_name//lib", }, { desc: "qualified", importpath: "example.com/repo.git/lib", @@ -1139,6 +1179,8 @@ func TestResolveExternal(t *testing.T) { } { t.Run(tc.desc, func(t *testing.T) { gc.moduleMode = tc.moduleMode + gc.goNamingConvention = tc.namingConvention + gc.repoNamingConvention = tc.repoNamingConvention rc := testRemoteCache(tc.repos) r := rule.NewRule("go_library", "x") imports := rule.PlatformStrings{Generic: []string{tc.importpath}} diff --git a/language/go/testdata/naming_convention/import/bin/BUILD.old b/language/go/testdata/naming_convention/import/bin/BUILD.old new file mode 100644 index 000000000..9ded1d54c --- /dev/null +++ b/language/go/testdata/naming_convention/import/bin/BUILD.old @@ -0,0 +1 @@ +# gazelle:go_naming_convention import \ No newline at end of file diff --git a/language/go/testdata/naming_convention/import/bin/BUILD.want b/language/go/testdata/naming_convention/import/bin/BUILD.want new file mode 100644 index 000000000..361b8e8a6 --- /dev/null +++ b/language/go/testdata/naming_convention/import/bin/BUILD.want @@ -0,0 +1,29 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") + +go_library( + name = "bin_lib", + srcs = [ + "lib.go", + "main.go", + ], + _gazelle_imports = [ + "example.com/repo/naming_convention/import/bin", + "fmt", + ], + importpath = "example.com/repo/naming_convention/import/bin", + visibility = ["//visibility:private"], +) + +go_binary( + name = "bin", + _gazelle_imports = [], + embed = [":bin_lib"], + visibility = ["//visibility:public"], +) + +go_test( + name = "bin_test", + srcs = ["bin_test.go"], + _gazelle_imports = ["testing"], + embed = [":bin_lib"], +) diff --git a/language/go/testdata/naming_convention/import/bin/bin_test.go b/language/go/testdata/naming_convention/import/bin/bin_test.go new file mode 100644 index 000000000..233090048 --- /dev/null +++ b/language/go/testdata/naming_convention/import/bin/bin_test.go @@ -0,0 +1,26 @@ +/* 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 main + +import ( + "testing" +) + +func TestAnswer(t *testing.T) { + if got, want := Answer(), 42; got != want { + t.Errorf("Answer() = %d; want %d", got, want) + } +} diff --git a/language/go/testdata/naming_convention/import/bin/lib.go b/language/go/testdata/naming_convention/import/bin/lib.go new file mode 100644 index 000000000..c9bdde1c2 --- /dev/null +++ b/language/go/testdata/naming_convention/import/bin/lib.go @@ -0,0 +1,21 @@ +/* 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 main + +// Answer returns the ultimate answer to life, the universe and everything. +func Answer() int { + return 42 +} diff --git a/language/go/testdata/naming_convention/import/bin/main.go b/language/go/testdata/naming_convention/import/bin/main.go new file mode 100644 index 000000000..a535e5a57 --- /dev/null +++ b/language/go/testdata/naming_convention/import/bin/main.go @@ -0,0 +1,25 @@ +/* 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 main + +import ( + "fmt" + "example.com/repo/naming_convention/import/bin" +) + +func main() { + fmt.Printf("Answer: %d", bin.Answer()) +} diff --git a/language/go/testdata/naming_convention/import/lib/BUILD.old b/language/go/testdata/naming_convention/import/lib/BUILD.old new file mode 100644 index 000000000..9ded1d54c --- /dev/null +++ b/language/go/testdata/naming_convention/import/lib/BUILD.old @@ -0,0 +1 @@ +# gazelle:go_naming_convention import \ No newline at end of file diff --git a/language/go/testdata/naming_convention/import/lib/BUILD.want b/language/go/testdata/naming_convention/import/lib/BUILD.want new file mode 100644 index 000000000..a9a7c5534 --- /dev/null +++ b/language/go/testdata/naming_convention/import/lib/BUILD.want @@ -0,0 +1,16 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "lib", + srcs = ["lib.go"], + _gazelle_imports = [], + importpath = "example.com/repo/naming_convention/import/lib", + visibility = ["//visibility:public"], +) + +go_test( + name = "lib_test", + srcs = ["lib_test.go"], + _gazelle_imports = ["testing"], + embed = [":lib"], +) diff --git a/language/go/testdata/naming_convention/import/lib/lib.go b/language/go/testdata/naming_convention/import/lib/lib.go new file mode 100644 index 000000000..9c41e7826 --- /dev/null +++ b/language/go/testdata/naming_convention/import/lib/lib.go @@ -0,0 +1,21 @@ +/* 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 lib + +// Answer returns the ultimate answer to life, the universe and everything. +func Answer() int { + return 42 +} diff --git a/language/go/testdata/naming_convention/import/lib/lib_test.go b/language/go/testdata/naming_convention/import/lib/lib_test.go new file mode 100644 index 000000000..d88361f18 --- /dev/null +++ b/language/go/testdata/naming_convention/import/lib/lib_test.go @@ -0,0 +1,26 @@ +/* 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 lib + +import ( + "testing" +) + +func TestAnswer(t *testing.T) { + if got, want := Answer(), 42; got != want { + t.Errorf("Answer() = %d; want %d", got, want) + } +} diff --git a/language/go/testdata/naming_convention/import_alias/bin/BUILD.old b/language/go/testdata/naming_convention/import_alias/bin/BUILD.old new file mode 100644 index 000000000..9ded1d54c --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/bin/BUILD.old @@ -0,0 +1 @@ +# gazelle:go_naming_convention import \ No newline at end of file diff --git a/language/go/testdata/naming_convention/import_alias/bin/BUILD.want b/language/go/testdata/naming_convention/import_alias/bin/BUILD.want new file mode 100644 index 000000000..2623e9a76 --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/bin/BUILD.want @@ -0,0 +1,29 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") + +go_library( + name = "bin_lib", + srcs = [ + "lib.go", + "main.go", + ], + _gazelle_imports = [ + "example.com/repo/naming_convention/import_alias/bin", + "fmt", + ], + importpath = "example.com/repo/naming_convention/import_alias/bin", + visibility = ["//visibility:private"], +) + +go_binary( + name = "bin", + _gazelle_imports = [], + embed = [":bin_lib"], + visibility = ["//visibility:public"], +) + +go_test( + name = "bin_test", + srcs = ["bin_test.go"], + _gazelle_imports = ["testing"], + embed = [":bin_lib"], +) diff --git a/language/go/testdata/naming_convention/import_alias/bin/bin_test.go b/language/go/testdata/naming_convention/import_alias/bin/bin_test.go new file mode 100644 index 000000000..233090048 --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/bin/bin_test.go @@ -0,0 +1,26 @@ +/* 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 main + +import ( + "testing" +) + +func TestAnswer(t *testing.T) { + if got, want := Answer(), 42; got != want { + t.Errorf("Answer() = %d; want %d", got, want) + } +} diff --git a/language/go/testdata/naming_convention/import_alias/bin/lib.go b/language/go/testdata/naming_convention/import_alias/bin/lib.go new file mode 100644 index 000000000..c9bdde1c2 --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/bin/lib.go @@ -0,0 +1,21 @@ +/* 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 main + +// Answer returns the ultimate answer to life, the universe and everything. +func Answer() int { + return 42 +} diff --git a/language/go/testdata/naming_convention/import_alias/bin/main.go b/language/go/testdata/naming_convention/import_alias/bin/main.go new file mode 100644 index 000000000..d1f370bb3 --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/bin/main.go @@ -0,0 +1,25 @@ +/* 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 main + +import ( + "fmt" + "example.com/repo/naming_convention/import_alias/bin" +) + +func main() { + fmt.Printf("Answer: %d", bin.Answer()) +} diff --git a/language/go/testdata/naming_convention/import_alias/lib/BUILD.old b/language/go/testdata/naming_convention/import_alias/lib/BUILD.old new file mode 100644 index 000000000..388f23013 --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/lib/BUILD.old @@ -0,0 +1 @@ +# gazelle:go_naming_convention import_alias \ No newline at end of file diff --git a/language/go/testdata/naming_convention/import_alias/lib/BUILD.want b/language/go/testdata/naming_convention/import_alias/lib/BUILD.want new file mode 100644 index 000000000..64074ff2c --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/lib/BUILD.want @@ -0,0 +1,22 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "lib", + srcs = ["lib.go"], + _gazelle_imports = [], + importpath = "example.com/repo/naming_convention/import_alias/lib", + visibility = ["//visibility:public"], +) + +alias( + name = "go_default_library", + actual = ":lib", + visibility = ["//visibility:public"], +) + +go_test( + name = "lib_test", + srcs = ["lib_test.go"], + _gazelle_imports = ["testing"], + embed = [":lib"], +) diff --git a/language/go/testdata/naming_convention/import_alias/lib/lib.go b/language/go/testdata/naming_convention/import_alias/lib/lib.go new file mode 100644 index 000000000..9c41e7826 --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/lib/lib.go @@ -0,0 +1,21 @@ +/* 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 lib + +// Answer returns the ultimate answer to life, the universe and everything. +func Answer() int { + return 42 +} diff --git a/language/go/testdata/naming_convention/import_alias/lib/lib_test.go b/language/go/testdata/naming_convention/import_alias/lib/lib_test.go new file mode 100644 index 000000000..d88361f18 --- /dev/null +++ b/language/go/testdata/naming_convention/import_alias/lib/lib_test.go @@ -0,0 +1,26 @@ +/* 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 lib + +import ( + "testing" +) + +func TestAnswer(t *testing.T) { + if got, want := Answer(), 42; got != want { + t.Errorf("Answer() = %d; want %d", got, want) + } +} diff --git a/language/go/testdata/naming_convention/versions/v2/BUILD.old b/language/go/testdata/naming_convention/versions/v2/BUILD.old new file mode 100644 index 000000000..9ded1d54c --- /dev/null +++ b/language/go/testdata/naming_convention/versions/v2/BUILD.old @@ -0,0 +1 @@ +# gazelle:go_naming_convention import \ No newline at end of file diff --git a/language/go/testdata/naming_convention/versions/v2/BUILD.want b/language/go/testdata/naming_convention/versions/v2/BUILD.want new file mode 100644 index 000000000..181bc08a7 --- /dev/null +++ b/language/go/testdata/naming_convention/versions/v2/BUILD.want @@ -0,0 +1,16 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "versions", + srcs = ["lib.go"], + _gazelle_imports = [], + importpath = "example.com/repo/naming_convention/versions/v2", + visibility = ["//visibility:public"], +) + +go_test( + name = "versions_test", + srcs = ["lib_test.go"], + _gazelle_imports = ["testing"], + embed = [":versions"], +) diff --git a/language/go/testdata/naming_convention/versions/v2/lib.go b/language/go/testdata/naming_convention/versions/v2/lib.go new file mode 100644 index 000000000..d2a5305f4 --- /dev/null +++ b/language/go/testdata/naming_convention/versions/v2/lib.go @@ -0,0 +1,21 @@ +/* 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 versions + +// Answer returns the ultimate answer to life, the universe and everything. +func Answer() int { + return 42 +} diff --git a/language/go/testdata/naming_convention/versions/v2/lib_test.go b/language/go/testdata/naming_convention/versions/v2/lib_test.go new file mode 100644 index 000000000..aead926f1 --- /dev/null +++ b/language/go/testdata/naming_convention/versions/v2/lib_test.go @@ -0,0 +1,26 @@ +/* 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 versions + +import ( + "testing" +) + +func TestAnswer(t *testing.T) { + if got, want := Answer(), 42; got != want { + t.Errorf("Answer() = %d; want %d", got, want) + } +} diff --git a/repository.rst b/repository.rst index 4fd1b7895..c4572a87b 100644 --- a/repository.rst +++ b/repository.rst @@ -143,6 +143,14 @@ returned by ``go env GOPATH``. | A value for ``sum`` may be found in the ``go.sum`` file or by running | | ``go mod download -json @``. | +--------------------------------+----------------------+---------------------------------------------------------------+ +| :param:`build_naming_convention` | :type:`string` | :value:`""` | ++--------------------------------+----------------------+---------------------------------------------------------------+ +| Sets the library naming convention to use when resolving dependencies against this external | +| repository. If unset, the convention from the external workspace is used. | +| Legal values are ``go_default_library``, ``import``, and ``import_alias``. | +| | +| See ``-go_naming_convention`` for more information. | ++--------------------------------+----------------------+---------------------------------------------------------------+ | :param:`replace` | :type:`string` | :value:`""` | +--------------------------------+----------------------+---------------------------------------------------------------+ | A replacement for the module named by ``importpath``. The module named by |