diff --git a/README.md b/README.md
index 9e0a915361..096ad8973b 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,9 @@
Rules
+ - go_repositories
+ - go_repository
+ - new_go_repository
- go_prefix
- go_library
- cgo_library
@@ -120,6 +123,132 @@ and it should work.
These rules are not supported by Google's Go team.
+
+## go\_repositories
+
+```bzl
+go_repositories()
+```
+
+Instantiates external dependencies to Go toolchain in a WORKSPACE.
+All the other workspace rules and build rules assume that this rule is
+placed in the WORKSPACE.
+
+
+
+## go\_repository
+
+```bzl
+go_repository(name, importpath, commit, tag)
+```
+
+Fetches a remote repository of a Go project, expecting it contains `BUILD`
+files. It is an analogy to `git_repository` but it recognizes importpath
+redirection of Go.
+
+
+
+
+
+
+
+
+ Attributes |
+
+
+
+
+ name |
+
+ String, required
+ A unique name for this external dependency.
+ |
+
+
+ importpath |
+
+ String, required
+ An import path in Go, which corresponds to the root of the target
+ remote repository
+ |
+
+
+ commit |
+
+ String, coptional
+ The commit hash to checkout in the repository.
+ Note that one of either commit or tag must be defined.
+ |
+
+
+ tag |
+
+ String, coptional
+ The tag to checkout in the repository.
+ Note that one of either commit or tag must be defined.
+ |
+
+
+
+
+
+
+## new\_go\_repository
+
+```bzl
+new_go_repository(name, importpath, commit, tag)
+```
+
+Fetches a remote repository of a Go project and automatically generates
+`BUILD` files in it. It is an analogy to `new_git_repository` but it recognizes
+importpath redirection of Go.
+
+
+
+
+
+
+
+
+ Attributes |
+
+
+
+
+ name |
+
+ String, required
+ A unique name for this external dependency.
+ |
+
+
+ importpath |
+
+ String, required
+ An import path in Go, which corresponds to the root of the target
+ remote repository
+ |
+
+
+ commit |
+
+ String, coptional
+ The commit hash to checkout in the repository.
+ Note that one of either commit or tag must be defined.
+ |
+
+
+ tag |
+
+ String, coptional
+ The tag to checkout in the repository.
+ Note that one of either commit or tag must be defined.
+ |
+
+
+
+
+
## go\_prefix
diff --git a/WORKSPACE b/WORKSPACE
index b23e877310..3e36aa4a9e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,58 +1,16 @@
workspace(name = "io_bazel_rules_go")
-load("//go:def.bzl", "go_repositories")
+load("//go:def.bzl", "go_repositories", "go_internal_tools_deps", "new_go_repository")
go_repositories()
-GLOG_BUILD = """
-load("@//go:def.bzl", "go_prefix", "go_library")
-
-go_prefix("github.com/golang/glog")
-
-go_library(
- name = "go_default_library",
- srcs = [
- "glog.go",
- "glog_file.go",
- ],
- visibility = ["//visibility:public"],
-)
-"""
-
-new_git_repository(
+new_go_repository(
name = "com_github_golang_glog",
- build_file_content = GLOG_BUILD,
commit = "23def4e6c14b4da8ac2ed8007337bc5eb5007998",
- remote = "https://github.com/golang/glog.git",
-)
-
-git_repository(
- name = "io_bazel_buildifier",
- commit = "0ca1d7991357ae7a7555589af88930d82cf07c0a",
- remote = "https://github.com/bazelbuild/buildifier.git",
+ importpath = "github.com/golang/glog",
)
-X_TOOLS_BUILD = """
-load("@//go:def.bzl", "go_prefix", "go_library")
-
-go_prefix("golang.org/x/tools")
-
-go_library(
- name = "go/vcs",
- srcs = glob(
- include = ["go/vcs/*.go"],
- exclude = ["go/vcs/*_test.go"],
- ),
- visibility = ["//visibility:public"],
-)
-"""
-
-new_git_repository(
- name = "org_golang_x_tools",
- build_file_content = X_TOOLS_BUILD,
- commit = "2bbdb4568e161d12394da43e88b384c6be63928b",
- remote = "https://go.googlesource.com/tools",
-)
+go_internal_tools_deps()
local_repository(
name = "io_bazel_rules_go",
diff --git a/go/def.bzl b/go/def.bzl
index c996fa9ec4..8851074d93 100644
--- a/go/def.bzl
+++ b/go/def.bzl
@@ -999,9 +999,176 @@ def cgo_library(name, srcs,
**kwargs
)
+################
+
+def _go_repository_impl(ctx):
+ fetch_repo = ctx.path(ctx.attr._fetch_repo)
+
+ if ctx.attr.commit and ctx.attr.tag:
+ fail("cannot specify both of commit and tag", "commit")
+ if ctx.attr.commit:
+ rev = ctx.attr.commit
+ elif ctx.attr.tag:
+ rev = ctx.attr.tag
+ else:
+ fail("neither commit or tag is specified", "commit")
+
+ # TODO(yugui): support submodule?
+ # c.f. https://www.bazel.io/versions/master/docs/be/workspace.html#git_repository.init_submodules
+ result = ctx.execute([
+ fetch_repo,
+ '--dest', ctx.path(''),
+ '--remote', ctx.attr.importpath,
+ '--rev', rev])
+ if result.return_code:
+ fail("failed to fetch %s: %s" % (ctx.attr.importpath, result.stderr))
+
+def _new_go_repository_impl(ctx):
+ _go_repository_impl(ctx)
+ gazelle = ctx.path(ctx.attr._gazelle)
+
+ result = ctx.execute([
+ gazelle,
+ '--go_prefix', ctx.attr.importpath, '--mode', 'fix',
+ ctx.path('')])
+ if result.return_code:
+ fail("failed to generate BUILD files for %s: %s" % (
+ ctx.attr.importpath, result.stderr))
+
+_go_repository_attrs = {
+ "importpath": attr.string(mandatory = True),
+ "commit": attr.string(),
+ "tag": attr.string(),
+
+ "_fetch_repo": attr.label(
+ default = Label("@io_bazel_rules_go_repository_tools//:bin/fetch_repo"),
+ allow_files = True,
+ single_file = True,
+ executable = True,
+ ),
+}
+
+go_repository = repository_rule(
+ implementation = _go_repository_impl,
+ attrs = _go_repository_attrs,
+)
+
+new_go_repository = repository_rule(
+ implementation = _new_go_repository_impl,
+ attrs = _go_repository_attrs + {
+ "_gazelle": attr.label(
+ default = Label("@io_bazel_rules_go_repository_tools//:bin/gazelle"),
+ allow_files = True,
+ single_file = True,
+ executable = True,
+ ),
+ },
+)
################
+repository_tool_deps = {
+ 'buildifier': struct(
+ importpath = 'github.com/bazelbuild/buildifier',
+ repo = 'https://github.com/bazelbuild/buildifier',
+ commit = '0ca1d7991357ae7a7555589af88930d82cf07c0a',
+ ),
+ 'tools': struct(
+ importpath = 'golang.org/x/tools',
+ repo = 'https://github.com/golang/tools',
+ commit = '2bbdb4568e161d12394da43e88b384c6be63928b',
+ )
+}
+
+def go_internal_tools_deps():
+ """only for internal use in rules_go"""
+ go_repository(
+ name = "io_bazel_buildifier",
+ commit = repository_tool_deps['buildifier'].commit,
+ importpath = repository_tool_deps['buildifier'].importpath,
+ )
+
+ new_go_repository(
+ name = "org_golang_x_tools",
+ commit = repository_tool_deps['tools'].commit,
+ importpath = repository_tool_deps['tools'].importpath,
+ )
+
+def _fetch_repository_tools_deps(ctx, goroot, gopath):
+ for name, dep in repository_tool_deps.items():
+ result = ctx.execute(['mkdir', '-p', ctx.path('src/' + dep.importpath)])
+ if result.return_code:
+ fail('failed to create directory: %s' % result.stderr)
+ ctx.download_and_extract(
+ '%s/archive/%s.zip' % (dep.repo, dep.commit),
+ 'src/%s' % dep.importpath, '', 'zip', '%s-%s' % (name, dep.commit))
+
+ result = ctx.execute([
+ 'env', 'GOROOT=%s' % goroot, 'GOPATH=%s' % gopath, 'PATH=%s/bin' % goroot,
+ 'go', 'generate', 'github.com/bazelbuild/buildifier/core'])
+ if result.return_code:
+ fail("failed to go genrate: %s" % result.stderr)
+
+_GO_REPOSITORY_TOOLS_BUILD_FILE = """
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "fetch_repo",
+ srcs = ["bin/fetch_repo"],
+)
+
+filegroup(
+ name = "gazelle",
+ srcs = ["bin/gazelle"],
+)
+"""
+
+def _go_repository_tools_impl(ctx):
+ go_tool = ctx.path(ctx.attr._go_tool)
+ goroot = go_tool.dirname.dirname
+ gopath = ctx.path('')
+ prefix = "github.com/bazelbuild/rules_go/" + ctx.attr._tools.package
+ src_path = ctx.path(ctx.attr._tools).dirname
+
+ _fetch_repository_tools_deps(ctx, goroot, gopath)
+
+ for t, pkg in [("gazelle", 'gazelle/gazelle'), ("fetch_repo", "fetch_repo")]:
+ ctx.symlink("%s/%s" % (src_path, t), "src/%s/%s" % (prefix, t))
+
+ result = ctx.execute([
+ 'env', 'GOROOT=%s' % goroot, 'GOPATH=%s' % gopath,
+ go_tool, "build",
+ "-o", ctx.path("bin/" + t), "%s/%s" % (prefix, pkg)])
+ if result.return_code:
+ fail("failed to build %s: %s" % (t, result.stderr))
+ ctx.file('BUILD', _GO_REPOSITORY_TOOLS_BUILD_FILE, False)
+
+_go_repository_tools = repository_rule(
+ _go_repository_tools_impl,
+ attrs = {
+ "_tools": attr.label(
+ default = Label("//go/tools:BUILD"),
+ allow_files = True,
+ single_file = True,
+ ),
+ "_go_tool": attr.label(
+ default = Label("@io_bazel_rules_go_toolchain//:bin/go"),
+ allow_files = True,
+ single_file = True,
+ ),
+ "_x_tools": attr.label(
+ default = Label("@org_golang_x_tools//:BUILD"),
+ allow_files = True,
+ single_file = True,
+ ),
+ "_buildifier": attr.label(
+ default = Label("@io_bazel_buildifier//:BUILD"),
+ allow_files = True,
+ single_file = True,
+ ),
+ },
+)
+
GO_TOOLCHAIN_BUILD_FILE = """
package(
default_visibility = [ "//visibility:public" ])
@@ -1071,3 +1238,6 @@ def go_repositories():
_go_repository_select(
name = "io_bazel_rules_go_toolchain",
)
+ _go_repository_tools(
+ name = "io_bazel_rules_go_repository_tools",
+ )
diff --git a/go/tools/fetch_repo/BUILD b/go/tools/fetch_repo/BUILD
index 70994c61a3..af27089932 100644
--- a/go/tools/fetch_repo/BUILD
+++ b/go/tools/fetch_repo/BUILD
@@ -3,5 +3,5 @@ load("//go:def.bzl", "go_binary")
go_binary(
name = "fetch_repo",
srcs = ["main.go"],
- deps = ["@org_golang_x_tools//:go/vcs"],
+ deps = ["@org_golang_x_tools//go/vcs:go_default_library"],
)
diff --git a/go/tools/gazelle/gazelle/main.go b/go/tools/gazelle/gazelle/main.go
index e7d12c7975..ae04a3f332 100644
--- a/go/tools/gazelle/gazelle/main.go
+++ b/go/tools/gazelle/gazelle/main.go
@@ -67,7 +67,7 @@ func usage() {
Gazel is a BUILD file generator for Go projects.
Currently its primary usage is to generate BUILD files for external dependencies
-in a go_vendor repository rule.
+in a go_repository rule.
You can still use Gazel for other purposes, but its interface can change without
notice.
diff --git a/go/tools/gazelle/rules/BUILD b/go/tools/gazelle/rules/BUILD
index a91dbf6578..4aed56737b 100644
--- a/go/tools/gazelle/rules/BUILD
+++ b/go/tools/gazelle/rules/BUILD
@@ -13,7 +13,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"@io_bazel_buildifier//core:go_default_library",
- "@org_golang_x_tools//:go/vcs",
+ "@org_golang_x_tools//go/vcs:go_default_library",
],
)