# 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. """