Skip to content

Commit

Permalink
Add 'go_naming_convention' support.
Browse files Browse the repository at this point in the history
Add directive 'go_naming_convention' to control the name of
generated Go rules.

go_default_library: Legacy behaviour.
import: Name targets after their import path.
import_alias: Same as import, but generate alias targets to
  maintain backwards compatibility with go_default_library.

We also add a `build_naming_convention` attribute to
`go_repository` rules, allowing per-external control over
the naming convention.

gazelle fix is augmented to migrate between the different
styles, both forwards and backwards.

FIXES=bazel-contrib#5
  • Loading branch information
tomlu committed Jun 7, 2020
1 parent be9c2a8 commit 4b04eb2
Show file tree
Hide file tree
Showing 37 changed files with 1,359 additions and 38 deletions.
17 changes: 17 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ 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` | |
+--------------------------------------------------------------+----------------------------------------+
| Command line flag for the ``go_naming_convention`` directive. |
+--------------------------------------------------------------+----------------------------------------+
| :flag:`-go_prefix example.com/repo` | |
+--------------------------------------------------------------+----------------------------------------+
| A prefix of import paths for libraries in the repository that corresponds to |
Expand Down Expand Up @@ -575,6 +579,19 @@ 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. 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.|
| Eg. ``example.repo/foo`` is named ``foo``, and the test target is ``foo_test``. |
| Major version suffixes (eg. ``v1``) 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. |
Expand Down
11 changes: 7 additions & 4 deletions cmd/gazelle/fix-update.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,13 @@ func (ucr *updateConfigurer) CheckFlags(fs *flag.FlagSet, c *config.Config) erro
}
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"),
BuildNamingConvention: r.AttrString("build_naming_convention"),
}
uc.repos = append(uc.repos, gr)
c.GoRepos[r.Name()] = gr
}
}

Expand Down
1 change: 1 addition & 0 deletions config/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//internal/wspace:go_default_library",
"//repo:go_default_library",
"//rule:go_default_library",
],
)
Expand Down
4 changes: 4 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"strings"

"github.com/bazelbuild/bazel-gazelle/internal/wspace"
"github.com/bazelbuild/bazel-gazelle/repo"
"github.com/bazelbuild/bazel-gazelle/rule"
)

Expand Down Expand Up @@ -85,6 +86,9 @@ type Config struct {
// generation and dependency resolution.
Repos []*rule.Rule

// go_repository rules, mapped by name.
GoRepos map[string]repo.Repo

// Langs is a list of language names which Gazelle should process.
// An empty list means "all languages".
Langs []string
Expand Down
8 changes: 8 additions & 0 deletions internal/go_repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ go_repository = repository_rule(
attrs = {
# Fundamental attributes of a go repository
"importpath": attr.string(mandatory = True),
"build_naming_convention": attr.string(
values = [
"",
"go_default_library",
"import",
"import_alias",
],
),

# Attributes for a repository that should be checked out from VCS
"commit": attr.string(),
Expand Down
75 changes: 74 additions & 1 deletion language/go/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -171,6 +174,15 @@ func (gc *goConfig) setBuildTags(tags string) error {
return nil
}

func (gc *goConfig) setNamingConvention(s string) error {
if nc, ok := namingConventionFromString(s); ok {
gc.goNamingConvention = nc
return nil
} else {
return fmt.Errorf("unknown go_naming_convention %q", s)
}
}

func getProtoMode(c *config.Config) proto.Mode {
if gc := getGoConfig(c); !gc.goGenerateProto {
return proto.DisableMode
Expand Down Expand Up @@ -236,6 +248,59 @@ func (f tagsFlag) String() string {
return ""
}

type goNamingConventionFlag func(string) error

func (f goNamingConventionFlag) Set(value string) error {
return f(value)
}

func (f goNamingConventionFlag) String() string {
return ""
}

// namingConvention determines how go targets are named.
type namingConvention int

const (
// 'go_default_library', 'go_default_test', and TODO(tomlu)
goDefaultLibraryNC = 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'.
importNC

// Same as importNC, but generate alias rules for libraries that have
// the legacy 'go_default_library' name.
importAliasNC
)

func (nc namingConvention) String() string {
switch nc {
case goDefaultLibraryNC:
return "go_default_library"
case importNC:
return "import"
case importAliasNC:
return "import_alias"
}
return ""
}

func namingConventionFromString(s string) (namingConvention, bool) {
switch s {
case "go_default_library":
return goDefaultLibraryNC, true
case "import":
return importNC, true
case "import_alias":
return importAliasNC, true
default:
return goDefaultLibraryNC, false
}
}

type moduleRepo struct {
repoName, modulePath string
}
Expand All @@ -249,6 +314,7 @@ func (*goLang) KnownDirectives() []string {
"build_tags",
"go_generate_proto",
"go_grpc_compilers",
"go_naming_convention",
"go_proto_compilers",
"go_visibility",
"importmap_prefix",
Expand Down Expand Up @@ -290,6 +356,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(
goNamingConventionFlag(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},
Expand Down Expand Up @@ -408,12 +478,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 == "" {
Expand Down
4 changes: 4 additions & 0 deletions language/go/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 != importAliasNC {
t.Errorf("got naming convention %v; want %v", gc.goNamingConvention, importAliasNC)
}
}

func TestDirectives(t *testing.T) {
Expand Down
Loading

0 comments on commit 4b04eb2

Please sign in to comment.