Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -244,18 +244,32 @@ public static String getRuleDefinitionInformation(Rule rule) {
return buf.toString();
}

/**
* Attributes that may be defined on a repository rule without affecting its canonical
* representation. These may be created implicitly by Bazel.
*/
private static final ImmutableSet<String> IGNORED_ATTRIBUTE_NAMES =
ImmutableSet.of("generator_name", "generator_function", "generator_location");

/**
* Compare two maps from Strings to objects, returning a pair of the map with all entries not in
* the original map or in the original map, but with a different value, and the keys dropped from
* the original map. However, ignore changes where a value is explicitly set to its default.
*
* <p>Ignores attributes listed in {@code IGNORED_ATTRIBUTE_NAMES}.
*/
static Pair<Map<String, Object>, List<String>> compare(
Map<String, Object> orig, Map<String, Object> defaults, Map<?, ?> modified) {
ImmutableMap.Builder<String, Object> valuesChanged = ImmutableMap.<String, Object>builder();
for (Map.Entry<?, ?> entry : modified.entrySet()) {
if (entry.getKey() instanceof String) {
Object value = entry.getValue();
String key = (String) entry.getKey();
if (IGNORED_ATTRIBUTE_NAMES.contains(key)) {
// The dict returned by the repo rule really shouldn't know about these anyway, but
// for symmetry we'll ignore them if they happen to be present.
continue;
}
Object value = entry.getValue();
Object old = orig.get(key);
if (old == null) {
Object defaultValue = defaults.get(key);
Expand All @@ -271,6 +285,9 @@ static Pair<Map<String, Object>, List<String>> compare(
}
ImmutableList.Builder<String> keysDropped = ImmutableList.<String>builder();
for (String key : orig.keySet()) {
if (IGNORED_ATTRIBUTE_NAMES.contains(key)) {
continue;
}
if (!modified.containsKey(key)) {
keysDropped.add(key);
}
Expand Down
47 changes: 47 additions & 0 deletions src/test/shell/bazel/workspace_resolved_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1216,4 +1216,51 @@ EOF
expect_log " TEST_TMPDIR/.*/external/bazel_tools/tools/build_defs/repo/http.bzl:"
}

# Regression test for #11040.
#
# Test that a canonical repo warning is generated for explicitly specified
# attributes whose values differ, and that it is never generated for implicitly
# created attributes (in particular, the generator_* attributes).
test_canonical_warning() {
EXTREPODIR=`pwd`
tar xvf ${TEST_SRCDIR}/test_WORKSPACE_files/archives.tar

mkdir main
touch main/BUILD
cat > main/reporule.bzl <<EOF
def _impl(repository_ctx):
repository_ctx.file("a.txt", "A")
repository_ctx.file("BUILD.bazel", "exports_files(['a.txt'])")
# Don't include "name", test that we warn about it below.
return {"myattr": "bar"}

reporule = repository_rule(
implementation = _impl,
attrs = {
"myattr": attr.string()
})

# We need to use a macro for the generator_* attributes to be defined.
def instantiate_reporule(name, **kwargs):
reporule(name=name, **kwargs)
EOF
cat > main/WORKSPACE <<EOF
workspace(name = "main")
load("//:reporule.bzl", "instantiate_reporule")
instantiate_reporule(
name = "myrepo",
myattr = "foo"
)
EOF

cd main
# We should get a warning for "myattr" having a changed value and for "name"
# being dropped, but not for the generator_* attributes.
bazel sync --distdir=${EXTREPODIR}/test_WORKSPACE/distdir >/dev/null 2>$TEST_log
expect_log "Rule 'myrepo' indicated that a canonical reproducible form \
can be obtained by modifying arguments myattr = \"bar\" and dropping \
\[.*\"name\".*\]"
expect_not_log "Rule 'myrepo' indicated .*generator"
}

run_suite "workspace_resolved_test tests"