diff options
author | Klaus Aehlig <aehlig@google.com> | 2018-06-15 06:01:26 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-06-15 06:02:53 -0700 |
commit | b42734f4213e505d9582def4cd25bd510f0909a9 (patch) | |
tree | e829f7c821ada256bd5fcab6b8d24132acadd61c | |
parent | f5be981a28fa50ba83391d4cd42a6e8bce07cca0 (diff) |
git_repository: return actual commit
Using that repository rules now may return a non-None value,
make git_repository return the arguments that make the rule
reproducible; in particular, return the actual commit (instead
of a tag) and the date of the commit, so support shallow clones.
The added test also demonstrates how the `bazel sync` command
together with `--experimental_repository_resolved_file` can be
used to replay an earlier state of external dependencies.
Change-Id: Ifa1cfdfdb5eb299a15b9d0ec7d285dc84c0bcdc0
PiperOrigin-RevId: 200705705
-rw-r--r-- | src/test/shell/bazel/BUILD | 2 | ||||
-rwxr-xr-x | src/test/shell/bazel/workspace_resolved_test.sh | 77 | ||||
-rw-r--r-- | tools/build_defs/repo/git.bzl | 81 |
3 files changed, 140 insertions, 20 deletions
diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD index 045f33ed19..0b38915e46 100644 --- a/src/test/shell/bazel/BUILD +++ b/src/test/shell/bazel/BUILD @@ -369,7 +369,7 @@ sh_test( size = "medium", srcs = ["workspace_resolved_test.sh"], data = [":test-deps"], - shard_count = 3, + shard_count = 4, ) sh_test( diff --git a/src/test/shell/bazel/workspace_resolved_test.sh b/src/test/shell/bazel/workspace_resolved_test.sh index 8504bb1512..d00202275c 100755 --- a/src/test/shell/bazel/workspace_resolved_test.sh +++ b/src/test/shell/bazel/workspace_resolved_test.sh @@ -90,6 +90,83 @@ EOF || fail "Not the correct number of original attributes" } +test_git_return_value() { + EXTREPODIR=`pwd` + export GIT_CONFIG_NOSYSTEM=YES + + mkdir extgit + (cd extgit && git init \ + && git config user.email 'me@example.com' \ + && git config user.name 'E X Ample' ) + echo Hello World > extgit/hello.txt + (cd extgit + git add . + git commit --author="A U Thor <author@example.com>" -m 'initial commit' + git tag mytag) + + # Check out the external git repository at the given tag, and record + # the return value of the git rule. + mkdir tagcheckout + cd tagcheckout + cat > WORKSPACE <<EOF +load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") +new_git_repository( + name="ext", + remote="file://${EXTREPODIR}/extgit/.git", + tag="mytag", + build_file_content="exports_files([\"hello.txt\"])", +) +EOF + bazel sync --experimental_repository_resolved_file=../repo.bzl + # some of the file systems on our test machines are really slow to + # notice the creation of a file---even after the call to sync(1). + bazel shutdown; sync; sleep 10 + + cd .. + echo; cat repo.bzl; echo + + # Now add an additional commit to the upstream repository and + # force update the tag + echo CHANGED > extgit/hello.txt + (cd extgit + git add . + git commit --author="A U Thor <author@example.com>" -m 'change hello.txt' + git tag -f mytag) + + # Verify that the recorded resolved information is what we expect. In + # particular, verify that we don't get the new upstream commit. + mkdir analysisrepo + cd analysisrepo + cp ../repo.bzl . + cat > workspace.bzl <<'EOF' +load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") +load("//:repo.bzl", "resolved") + +def repo(): + for entry in resolved: + if entry["original_attributes"]["name"] == "ext": + new_git_repository(**(entry["repositories"][0]["attributes"])) +EOF + cat > WORKSPACE <<'EOF' +load("//:workspace.bzl", "repo") +repo() +EOF + cat > BUILD <<'EOF' +genrule( + name = "out", + outs = ["out.txt"], + srcs = ["@ext//:hello.txt"], + cmd = "cp $< $@", +) +EOF + bazel build //:out + grep "Hello World" `bazel info bazel-genfiles`/out.txt \ + || fail "ext not taken at the right commit" + grep "CHANGED" `bazel info bazel-genfiles`/out.txt \ + && fail "not taking the frozen commit" || : +} + + test_sync_calls_all() { mkdir sync_calls_all && cd sync_calls_all rm -rf fetchrepo diff --git a/tools/build_defs/repo/git.bzl b/tools/build_defs/repo/git.bzl index a46330542c..3663dc804f 100644 --- a/tools/build_defs/repo/git.bzl +++ b/tools/build_defs/repo/git.bzl @@ -80,17 +80,37 @@ set -ex if st.return_code: fail("error updating submodules %s:\n%s" % (ctx.name, st.stderr)) -def _new_git_repository_implementation(ctx): - if ((not ctx.attr.build_file and not ctx.attr.build_file_content) or - (ctx.attr.build_file and ctx.attr.build_file_content)): - fail("Exactly one of build_file and build_file_content must be provided.") - _clone_or_update(ctx) - workspace_and_buildfile(ctx) - patch(ctx) - -def _git_repository_implementation(ctx): - _clone_or_update(ctx) - patch(ctx) + # After the fact, determine the actual commit and its date + actual_commit = ctx.execute([ + bash_exe, + "-c", + "(cd '{directory}' && git log -n 1 --pretty='format:%H')".format( + directory = ctx.path("."), + ), + ]).stdout + shallow_date = ctx.execute([ + bash_exe, + "-c", + "(cd '{directory}' && git log -n 1 --pretty='format:%cd' --date='format:%Y-%d-%m')".format( + directory = ctx.path("."), + ), + ]).stdout + return {"commit": actual_commit, "shallow_since": shallow_date} + +def _update_commit(orig, keys, override): + # Merge the override information into the dict, resulting by taking the + # given keys, as well as the name, form orig (if present there). + result = {} + for key in keys: + if getattr(orig, key) != None: + result[key] = getattr(orig, key) + result["name"] = orig.name + result.update(override) + + # remove tag if we found the actual commit + if "commit" in result: + result.pop("tag", None) + return result _common_attrs = { "remote": attr.string(mandatory = True), @@ -106,19 +126,38 @@ _common_attrs = { "patch_cmds": attr.string_list(default = []), } +_new_git_repository_attrs = dict(_common_attrs.items() + { + "build_file": attr.label(allow_single_file = True), + "build_file_content": attr.string(), + "workspace_file": attr.label(), + "workspace_file_content": attr.string(), +}.items()) + +def _new_git_repository_implementation(ctx): + if ((not ctx.attr.build_file and not ctx.attr.build_file_content) or + (ctx.attr.build_file and ctx.attr.build_file_content)): + fail("Exactly one of build_file and build_file_content must be provided.") + update = _clone_or_update(ctx) + workspace_and_buildfile(ctx) + patch(ctx) + return _update_commit(ctx.attr, _new_git_repository_attrs.keys(), update) + +def _git_repository_implementation(ctx): + update = _clone_or_update(ctx) + patch(ctx) + return _update_commit(ctx.attr, _common_attrs.keys(), update) + new_git_repository = repository_rule( implementation = _new_git_repository_implementation, - attrs = dict(_common_attrs.items() + { - "build_file": attr.label(allow_single_file = True), - "build_file_content": attr.string(), - "workspace_file": attr.label(), - "workspace_file_content": attr.string(), - }.items()), + attrs = _new_git_repository_attrs, ) """Clone an external git repository. Clones a Git repository, checks out the specified tag, or commit, and -makes its targets available for binding. +makes its targets available for binding. Also determine the id of the +commit actually checkted out and its date, and return a dict with paramters +that provide a reproducible version of this rule (which a tag not necessarily +is). Args: name: A unique name for this rule. @@ -173,7 +212,11 @@ git_repository = repository_rule( """Clone an external git repository. Clones a Git repository, checks out the specified tag, or commit, and -makes its targets available for binding. +makes its targets available for binding. Also determine the id of the +commit actually checkted out and its date, and return a dict with paramters +that provide a reproducible version of this rule (which a tag not necessarily +is). + Args: name: A unique name for this rule. |