Skip to content

Commit

Permalink
RepositoryResolvedEvent: be lazy about computing the directory hash
Browse files Browse the repository at this point in the history
    The RepositoryResolvedEvent is generated each time a respository was succesfully
    fetched. However, not in all bazel invocations, the resolved object is actually
    used (as not in all cases a resolved file is written). Therefore, delay the expensive
    part of this operation, the computation of the hash of the generated directory,
    till it is needed for the first time.

    Closes #10147

    Change-Id: I9cd9576d75ac8d6aa57ff8f9572417ace14b385a
    PiperOrigin-RevId: 289449062
  • Loading branch information
Luca Di Grazia committed Sep 4, 2022
1 parent 0fc5096 commit cd311ce
Showing 1 changed file with 6 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,16 @@
import static com.google.devtools.build.lib.rules.repository.ResolvedHashesFunction.REPOSITORIES;
import static com.google.devtools.build.lib.rules.repository.ResolvedHashesFunction.RULE_CLASS;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.events.ExtendedEventHandler.ResolvedEvent;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.StructImpl;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.syntax.Starlark;
import com.google.devtools.build.lib.syntax.StarlarkThread;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.Path;
import java.io.IOException;
Expand Down Expand Up @@ -83,7 +82,10 @@ public RepositoryResolvedEvent(Rule rule, StructImpl attrs, Path outputDirectory
String originalClass =
rule.getRuleClassObject().getRuleDefinitionEnvironmentLabel() + "%" + rule.getRuleClass();
resolvedInformationBuilder.put(ORIGINAL_RULE_CLASS, originalClass);
resolvedInformationBuilder.put(DEFINITION_INFORMATION, getRuleDefinitionInformation(rule));

if (!Strings.isNullOrEmpty(rule.getDefinitionInformation())) {
resolvedInformationBuilder.put(DEFINITION_INFORMATION, rule.getDefinitionInformation());
}

ImmutableMap.Builder<String, Object> origAttrBuilder = ImmutableMap.builder();
ImmutableMap.Builder<String, Object> defaults = ImmutableMap.builder();
Expand Down Expand Up @@ -188,14 +190,12 @@ private synchronized void finalizeResolvedInformation() {
}

/** Return the entry for the given rule invocation in a format suitable for WORKSPACE.resolved. */
@Override
public Object getResolvedInformation() {
finalizeResolvedInformation();
return resolvedInformation;
}

/** Return the name of the rule that produced the resolvedInformation */
@Override
public String getName() {
return name;
}
Expand All @@ -218,61 +218,18 @@ public String getMessage() {
return message;
}

/** Returns an unstructured message explaining the origin of this rule. */
public static String getRuleDefinitionInformation(Rule rule) {
StringBuilder buf = new StringBuilder();

// Emit stack of rule instantiation.
buf.append("Repository ").append(rule.getName()).append(" instantiated at:\n");
ImmutableList<StarlarkThread.CallStackEntry> stack = rule.getCallStack().toList();
if (stack.isEmpty()) {
buf.append(" no stack (--record_rule_instantiation_callstack not enabled)\n");
} else {
for (StarlarkThread.CallStackEntry frame : stack) {
buf.append(" ").append(frame.location).append(": in ").append(frame.name).append('\n');
}
}

// Emit stack of rule class declaration.
stack = rule.getRuleClassObject().getCallStack();
if (stack.isEmpty()) {
buf.append("Repository rule ").append(rule.getRuleClass()).append(" is built-in.\n");
} else {
buf.append("Repository rule ").append(rule.getRuleClass()).append(" defined at:\n");
for (StarlarkThread.CallStackEntry frame : stack) {
buf.append(" ").append(frame.location).append(": in ").append(frame.name).append('\n');
}
}

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) {
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();
String key = (String) entry.getKey();
Object old = orig.get(key);
if (old == null) {
Object defaultValue = defaults.get(key);
Expand All @@ -288,9 +245,6 @@ 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

0 comments on commit cd311ce

Please sign in to comment.