Skip to content

Commit

Permalink
Add go_repository and new_go_repository rules (#84)
Browse files Browse the repository at this point in the history
* build fetch_repo and gazelle in analysis phase

* Add go_repository rule

* Apply go_repository to rules_go itself
  • Loading branch information
yugui authored and pmbethe09 committed Sep 16, 2016
1 parent 7ae658a commit cca9e30
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 49 deletions.
129 changes: 129 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
<div class="toc">
<h2>Rules</h2>
<ul>
<li><a href="#go_repositories">go_repositories</a></li>
<li><a href="#go_repository">go_repository</a></li>
<li><a href="#new_go_repository">new_go_repository</a></li>
<li><a href="#go_prefix">go_prefix</a></li>
<li><a href="#go_library">go_library</a></li>
<li><a href="#cgo_library">cgo_library</a></li>
Expand Down Expand Up @@ -120,6 +123,132 @@ and it should work.

These rules are not supported by Google's Go team.

<a name="go_repositories"></a>
## 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.


<a name="go_repository"></a>
## 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.

<table class="table table-condensed table-bordered table-params">
<colgroup>
<col class="col-param" />
<col class="param-description" />
</colgroup>
<thead>
<tr>
<th colspan="2">Attributes</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>name</code></td>
<td>
<code>String, required</code>
<p>A unique name for this external dependency.</p>
</td>
</tr>
<tr>
<td><code>importpath</code></td>
<td>
<code>String, required</code>
<p>An import path in Go, which corresponds to the root of the target
remote repository</p>
</td>
</tr>
<tr>
<td><code>commit</code></td>
<td>
<code>String, coptional</code>
<p>The commit hash to checkout in the repository.</p>
<p>Note that one of either <code>commit</code> or <code>tag</code> must be defined.</p>
</td>
</tr>
<tr>
<td><code>tag</code></td>
<td>
<code>String, coptional</code>
<p>The tag to checkout in the repository.</p>
<p>Note that one of either <code>commit</code> or <code>tag</code> must be defined.</p>
</td>
</tr>
</tbody>
</table>


<a name="new_go_repository"></a>
## 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.

<table class="table table-condensed table-bordered table-params">
<colgroup>
<col class="col-param" />
<col class="param-description" />
</colgroup>
<thead>
<tr>
<th colspan="2">Attributes</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>name</code></td>
<td>
<code>String, required</code>
<p>A unique name for this external dependency.</p>
</td>
</tr>
<tr>
<td><code>importpath</code></td>
<td>
<code>String, required</code>
<p>An import path in Go, which corresponds to the root of the target
remote repository</p>
</td>
</tr>
<tr>
<td><code>commit</code></td>
<td>
<code>String, coptional</code>
<p>The commit hash to checkout in the repository.</p>
<p>Note that one of either <code>commit</code> or <code>tag</code> must be defined.</p>
</td>
</tr>
<tr>
<td><code>tag</code></td>
<td>
<code>String, coptional</code>
<p>The tag to checkout in the repository.</p>
<p>Note that one of either <code>commit</code> or <code>tag</code> must be defined.</p>
</td>
</tr>
</tbody>
</table>


<a name="go_prefix"></a>
## go\_prefix

Expand Down
50 changes: 4 additions & 46 deletions WORKSPACE
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
170 changes: 170 additions & 0 deletions go/def.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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" ])
Expand Down Expand Up @@ -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",
)
2 changes: 1 addition & 1 deletion go/tools/fetch_repo/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
)
Loading

0 comments on commit cca9e30

Please sign in to comment.