Add Skylark definitions of {new_,}git_repository.

--
Change-Id: I2c5f09b10430963a1668ec7c842992bc89bfd7b4
Reviewed-on: https://bazel-review.googlesource.com/#/c/3982
MOS_MIGRATED_REVID=128453417
diff --git a/tools/BUILD b/tools/BUILD
index e502539..c1a69c5 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -14,6 +14,7 @@
         "//tools/build_defs/apple/test:srcs",
         "//tools/build_defs/docker:srcs",
         "//tools/build_defs/pkg:srcs",
+        "//tools/build_defs/repo:srcs",
         "//tools/build_rules:srcs",
         "//tools/jdk:srcs",
         "//tools/genrule:srcs",
@@ -36,6 +37,7 @@
         "//tools/build_defs/apple:srcs",
         "//tools/build_defs/docker:srcs",
         "//tools/build_defs/pkg:srcs",
+        "//tools/build_defs/repo:srcs",
         "//tools/build_rules:embedded_tools_srcs",
         "//tools/buildstamp:srcs",
         "//tools/cpp:srcs",
diff --git a/tools/build_defs/repo/BUILD b/tools/build_defs/repo/BUILD
new file mode 100644
index 0000000..1184bb1
--- /dev/null
+++ b/tools/build_defs/repo/BUILD
@@ -0,0 +1,7 @@
+licenses(["notice"])  # Apache 2.0
+
+filegroup(
+    name = "srcs",
+    srcs = glob(["**"]),
+    visibility = ["//tools:__pkg__"],
+)
diff --git a/tools/build_defs/repo/git_repositories.bzl b/tools/build_defs/repo/git_repositories.bzl
new file mode 100644
index 0000000..aa92252
--- /dev/null
+++ b/tools/build_defs/repo/git_repositories.bzl
@@ -0,0 +1,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.
+"""