aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/build_defs/repo/git.bzl
blob: aa92252effc8962eceb99f5f676391e5bbd26b15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# Copyright 2015 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.
"""Rules for cloning external git repositories."""

def _clone_or_update(ctx):
  if ((ctx.attr.tag == "" and ctx.attr.commit == "") or
      (ctx.attr.tag != "" and ctx.attr.commit != "")):
    ctx.fail("Exactly one of commit and tag must be provided")
  if ctx.attr.commit != "":
    ref = ctx.attr.commit
  else:
    ref = "tags/" + ctx.attr.tag

  st = ctx.execute(["bash", '-c', """
set -ex
( cd {working_dir} &&
    if ! ( cd '{dir}' && git rev-parse --git-dir ) >/dev/null 2>&1; then
      rm -rf '{dir}'
      git clone '{remote}' '{dir}'
    fi
    cd '{dir}'
    git reset --hard {ref} || (git fetch && git reset --hard {ref})
    git clean -xdf )
  """.format(
    working_dir=ctx.path(".").dirname,
    dir=ctx.path("."),
    remote=ctx.attr.remote,
    ref=ref,
  )])
  if st.return_code != 0:
    fail("error cloning %s:\n%s" % (ctx.name, st.stderr))
  if ctx.attr.init_submodules:
    st = ctx.execute(["bash", '-c', """
set -ex
(   cd '{dir}'
    git submodule update --init --checkout --force )
  """.format(
    dir=ctx.path("."),
    )])
    if st.return_code != 0:
      fail("error updating submodules %s:\n%s" % (ctx.name, st.stderr))


def _new_git_repository_implementation(ctx):
  if ((ctx.attr.build_file == None and ctx.attr.build_file_content == '') or
      (ctx.attr.build_file != None and ctx.attr.build_file_content != '')):
    ctx.fail("Exactly one of build_file and build_file_content must be provided.")
  _clone_or_update(ctx)
  ctx.file('WORKSPACE', "workspace(name = \"{name}\")\n".format(name=ctx.name))
  if ctx.attr.build_file:
    ctx.symlink(ctx.attr.build_file, 'BUILD')
  else:
    ctx.file('BUILD', ctx.attr.build_file_content)

def _git_repository_implementation(ctx):
  _clone_or_update(ctx)


_common_attrs = {
  "remote": attr.string(mandatory=True),
  "commit": attr.string(default=""),
  "tag": attr.string(default=""),
  "init_submodules": attr.bool(default=False),
}


new_git_repository = repository_rule(
  implementation=_new_git_repository_implementation,
  attrs=_common_attrs + {
    "build_file": attr.label(),
    "build_file_content": attr.string(),
  }
)
"""Clone an external git repository.

Clones a Git repository, checks out the specified tag, or commit, and
makes its targets available for binding.

Args:
  name: A unique name for this rule.

  build_file: The file to use as the BUILD file for this repository.
    Either build_file or build_file_content must be specified.

    This attribute is a label relative to the main workspace. The file
    does not need to be named BUILD, but can be (something like
    BUILD.new-repo-name may work well for distinguishing it from the
    repository's actual BUILD files.

  build_file_content: The content for the BUILD file for this repository.
    Either build_file or build_file_content must be specified.

  init_submodules: Whether to clone submodules in the repository.

  remote: The URI of the remote Git repository.
"""

git_repository = repository_rule(
  implementation=_git_repository_implementation,
  attrs=_common_attrs,
)
"""Clone an external git repository.

Clones a Git repository, checks out the specified tag, or commit, and
makes its targets available for binding.

Args:
  name: A unique name for this rule.

  init_submodules: Whether to clone submodules in the repository.

  remote: The URI of the remote Git repository.
"""