From 2d699e9f5570cd0a96e712bd8ab89fe36b08ad6d Mon Sep 17 00:00:00 2001 From: Michajlo Matijkiw Date: Mon, 30 Nov 2015 17:42:26 +0000 Subject: [PATCH] Simplify rule fingerprinting in RepositoryFunction -- MOS_MIGRATED_REVID=108986856 --- .../lib/packages/PackageDeserializer.java | 834 ------------------ .../build/lib/packages/PackageSerializer.java | 329 ------- .../build/lib/packages/RuleSerializer.java | 37 + .../rules/repository/RepositoryFunction.java | 6 +- .../packages/PackageSerializationTest.java | 282 ------ .../util/PackageSerializationTestCase.java | 148 ---- 6 files changed, 40 insertions(+), 1596 deletions(-) delete mode 100644 src/main/java/com/google/devtools/build/lib/packages/PackageDeserializer.java delete mode 100644 src/main/java/com/google/devtools/build/lib/packages/PackageSerializer.java create mode 100644 src/main/java/com/google/devtools/build/lib/packages/RuleSerializer.java delete mode 100644 src/test/java/com/google/devtools/build/lib/packages/PackageSerializationTest.java delete mode 100644 src/test/java/com/google/devtools/build/lib/packages/util/PackageSerializationTestCase.java diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageDeserializer.java b/src/main/java/com/google/devtools/build/lib/packages/PackageDeserializer.java deleted file mode 100644 index f393a78f773b05..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/packages/PackageDeserializer.java +++ /dev/null @@ -1,834 +0,0 @@ -// 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. - -package com.google.devtools.build.lib.packages; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Interner; -import com.google.common.collect.Interners; -import com.google.common.collect.Sets; -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.cmdline.LabelSyntaxException; -import com.google.devtools.build.lib.cmdline.PackageIdentifier; -import com.google.devtools.build.lib.events.Event; -import com.google.devtools.build.lib.events.EventHandler; -import com.google.devtools.build.lib.events.Location; -import com.google.devtools.build.lib.events.NullEventHandler; -import com.google.devtools.build.lib.events.StoredEventHandler; -import com.google.devtools.build.lib.packages.License.DistributionType; -import com.google.devtools.build.lib.packages.License.LicenseParsingException; -import com.google.devtools.build.lib.packages.Package.Builder.GeneratedLabelConflict; -import com.google.devtools.build.lib.packages.Package.NameConflictException; -import com.google.devtools.build.lib.query2.proto.proto2api.Build; -import com.google.devtools.build.lib.query2.proto.proto2api.Build.StringDictUnaryEntry; -import com.google.devtools.build.lib.syntax.GlobCriteria; -import com.google.devtools.build.lib.syntax.GlobList; -import com.google.devtools.build.lib.syntax.Type; -import com.google.devtools.build.lib.syntax.Type.ConversionException; -import com.google.devtools.build.lib.vfs.Path; -import com.google.devtools.build.lib.vfs.PathFragment; -import com.google.protobuf.CodedInputStream; -import com.google.protobuf.ExtensionRegistryLite; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.annotation.Nullable; - -/** - * Functionality to deserialize loaded packages. - */ -public class PackageDeserializer { - - private static final Logger LOG = Logger.getLogger(PackageDeserializer.class.getName()); - - /** - * Provides the deserializer with tools it needs to build a package from its serialized form. - */ - public interface PackageDeserializationEnvironment { - - /** Converts the serialized package's path string into a {@link Path} object. */ - Path getPath(String buildFilePath); - - /** Returns a {@link RuleClass} object for the serialized rule. */ - RuleClass getRuleClass(Build.Rule rulePb, Location ruleLocation) - throws PackageDeserializationException; - - /** Description of what rule attributes of each rule should be deserialized. */ - AttributesToDeserialize attributesToDeserialize(); - } - - /** - * A class that defines what attributes to keep after deserialization. Note that all attributes of - * type label are kept in order to navigate between dependencies. - * - *

If {@code addSyntheticAttributeHash} is {@code true}, a synthetic attribute is added to each - * Rule that contains a stable hash of the entire serialized rule for the sake of permitting - * equality comparisons that respect the attributes that were dropped according to {@code - * attributesToKeep}. - */ - public static class AttributesToDeserialize { - - private final boolean addSyntheticAttributeHash; - private final Predicate shouldKeepAttributeWithName; - - public AttributesToDeserialize(boolean addSyntheticAttributeHash, - Predicate shouldKeepAttributeWithName) { - this.addSyntheticAttributeHash = addSyntheticAttributeHash; - this.shouldKeepAttributeWithName = shouldKeepAttributeWithName; - } - - public boolean includeAttribute(String attr) { - return shouldKeepAttributeWithName.apply(attr); - } - } - - public static final AttributesToDeserialize DESERIALIZE_ALL_ATTRS = - new AttributesToDeserialize(false, Predicates.alwaysTrue()); - - // Workaround for Java serialization making it tough to pass in a deserialization environment - // manually. - // volatile is needed to ensure that the objects are published safely. - // TODO(bazel-team): Subclass ObjectOutputStream to pass this through instead. - public static volatile PackageDeserializationEnvironment defaultPackageDeserializationEnvironment; - - // Cache label deserialization across all instances- PackgeDeserializers need to be created on - // demand due to initialiation constraints wrt the setting of static members. - private static final Interner

Expects {@code codedIn} to contain a single - * {@link com.google.devtools.build.lib.query2.proto.proto2api.Build.Package} message followed - * by a series of - * {@link com.google.devtools.build.lib.query2.proto.proto2api.Build.TargetOrTerminator} - * messages encoding the associated targets. - * - * @param codedIn stream to read from - * @return a new {@link Package} as read from {@code in} - * @throws PackageDeserializationException on failures deserializing the input - * @throws IOException on failures reading from {@code in} - * @throws InterruptedException - */ - public Package deserialize(CodedInputStream codedIn) - throws PackageDeserializationException, IOException, InterruptedException { - try { - return deserializeInternal(codedIn); - } catch (PackageDeserializationException | RuntimeException e) { - LOG.log(Level.WARNING, "Failed to deserialize Package object", e); - throw e; - } - } - - private Package deserializeInternal(CodedInputStream codedIn) - throws PackageDeserializationException, IOException, InterruptedException { - // Read the initial Package message so we have the data to initialize the builder. We will read - // the Targets in individually later. - Build.Package packagePb = readPackageProto(codedIn); - PackageIdentifier packageId; - try { - packageId = PackageIdentifier.create( - packagePb.getRepository(), new PathFragment(packagePb.getName())); - } catch (LabelSyntaxException e) { - throw new PackageDeserializationException(e); - } - - Package.Builder builder = new Package.Builder(packageId, null); - StoredEventHandler eventHandler = new StoredEventHandler(); - deserializeInternal(packageId, packagePb, eventHandler, builder, codedIn); - builder.addEvents(eventHandler.getEvents()); - return builder.build(); - } - - private static Build.Package readPackageProto(CodedInputStream codedIn) throws IOException { - Build.Package.Builder builder = Build.Package.newBuilder(); - codedIn.readMessage(builder, ExtensionRegistryLite.getEmptyRegistry()); - return builder.build(); - } - - private static void deserializeEvent(StoredEventHandler eventHandler, Build.Event event) { - String message = event.getMessage(); - switch (event.getKind()) { - case ERROR: eventHandler.handle(Event.error(message)); break; - case WARNING: eventHandler.handle(Event.warn(message)); break; - case INFO: eventHandler.handle(Event.info(message)); break; - case PROGRESS: eventHandler.handle(Event.progress(message)); break; - default: break; // Ignore - } - } - - private static List deserializeGlobs(List matches, - Build.Attribute attrPb) { - if (attrPb.getGlobCriteriaCount() == 0) { - return matches; - } - - Builder criteriaBuilder = ImmutableList.builder(); - for (Build.GlobCriteria criteriaPb : attrPb.getGlobCriteriaList()) { - if (criteriaPb.hasGlob() && criteriaPb.getGlob()) { - criteriaBuilder.add(GlobCriteria.fromGlobCall( - ImmutableList.copyOf(criteriaPb.getIncludeList()), - ImmutableList.copyOf(criteriaPb.getExcludeList()))); - } else { - criteriaBuilder.add( - GlobCriteria.fromList(ImmutableList.copyOf(criteriaPb.getIncludeList()))); - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) GlobList result = - new GlobList(criteriaBuilder.build(), matches); - return result; - } - - // TODO(bazel-team): Verify that these put sane values in the attribute - @VisibleForTesting - static Object deserializeAttributeValue(Type expectedType, - Build.Attribute attrPb) - throws PackageDeserializationException { - switch (attrPb.getType()) { - case INTEGER: - return attrPb.hasIntValue() ? attrPb.getIntValue() : null; - - case STRING: - if (!attrPb.hasStringValue()) { - return null; - } else if (expectedType == BuildType.NODEP_LABEL) { - return deserializeLabel(attrPb.getStringValue()); - } else { - return attrPb.getStringValue(); - } - - case LABEL: - case OUTPUT: - return attrPb.hasStringValue() ? deserializeLabel(attrPb.getStringValue()) : null; - - case STRING_LIST: - if (expectedType == BuildType.NODEP_LABEL_LIST) { - return deserializeGlobs(deserializeLabels(attrPb.getStringListValueList()), attrPb); - } else { - return deserializeGlobs(ImmutableList.copyOf(attrPb.getStringListValueList()), attrPb); - } - - case LABEL_LIST: - case OUTPUT_LIST: - return deserializeGlobs(deserializeLabels(attrPb.getStringListValueList()), attrPb); - - case DISTRIBUTION_SET: - return deserializeDistribs(attrPb.getStringListValueList()); - - case LICENSE: - return attrPb.hasLicense() ? deserializeLicense(attrPb.getLicense()) : null; - - case STRING_DICT: { - // Building an immutable map will fail if the builder was given duplicate keys. These entry - // lists may contain duplicate keys if the serialized map value was configured (e.g. via - // the select function) and the different configuration values had keys in common. This is - // because serialization flattens configurable map-valued attributes. - // - // As long as serialization does this flattening, to avoid failure during deserialization, - // we dedupe entries in the list by their keys. - // TODO(bazel-team): Serialize and deserialize configured values with fidelity (without - // flattening them). - ImmutableMap.Builder builder = ImmutableMap.builder(); - HashSet keysSeenSoFar = Sets.newHashSet(); - for (Build.StringDictEntry entry : attrPb.getStringDictValueList()) { - String key = entry.getKey(); - if (keysSeenSoFar.add(key)) { - builder.put(key, entry.getValue()); - } - } - return builder.build(); - } - - case STRING_DICT_UNARY: { - // See STRING_DICT case's comment about why this dedupes entries by their keys. - ImmutableMap.Builder builder = ImmutableMap.builder(); - HashSet keysSeenSoFar = Sets.newHashSet(); - for (StringDictUnaryEntry entry : attrPb.getStringDictUnaryValueList()) { - String key = entry.getKey(); - if (keysSeenSoFar.add(key)) { - builder.put(key, entry.getValue()); - } - } - return builder.build(); - } - - case FILESET_ENTRY_LIST: - return deserializeFilesetEntries(attrPb.getFilesetListValueList()); - - case LABEL_LIST_DICT: { - // See STRING_DICT case's comment about why this dedupes entries by their keys. - ImmutableMap.Builder> builder = ImmutableMap.builder(); - HashSet keysSeenSoFar = Sets.newHashSet(); - for (Build.LabelListDictEntry entry : attrPb.getLabelListDictValueList()) { - String key = entry.getKey(); - if (keysSeenSoFar.add(key)) { - builder.put(key, deserializeLabels(entry.getValueList())); - } - } - return builder.build(); - } - - case STRING_LIST_DICT: { - // See STRING_DICT case's comment about why this dedupes entries by their keys. - ImmutableMap.Builder> builder = ImmutableMap.builder(); - HashSet keysSeenSoFar = Sets.newHashSet(); - for (Build.StringListDictEntry entry : attrPb.getStringListDictValueList()) { - String key = entry.getKey(); - if (keysSeenSoFar.add(key)) { - builder.put(key, ImmutableList.copyOf(entry.getValueList())); - } - } - return builder.build(); - } - - case BOOLEAN: - return attrPb.hasBooleanValue() ? attrPb.getBooleanValue() : null; - - case TRISTATE: - return attrPb.hasStringValue() ? deserializeTriStateValue(attrPb.getStringValue()) : null; - - case INTEGER_LIST: - return ImmutableList.copyOf(attrPb.getIntListValueList()); - - default: - throw new PackageDeserializationException("Invalid discriminator: " + attrPb.getType()); - } - } - - private static FilesetEntry.SymlinkBehavior pbToSymlinkBehavior( - Build.FilesetEntry.SymlinkBehavior symlinkBehavior) { - switch (symlinkBehavior) { - case COPY: - return FilesetEntry.SymlinkBehavior.COPY; - case DEREFERENCE: - return FilesetEntry.SymlinkBehavior.DEREFERENCE; - default: - throw new IllegalStateException(); - } - } - - /** - * An special {@code AttributeContainer} implementation that does not keep - * the location and can contain a hashcode of the target attributes. - */ - public static class AttributeContainerWithoutLocation extends AttributeContainer { - - @Nullable - private final byte[] syntheticAttrHash; - - private AttributeContainerWithoutLocation(RuleClass ruleClass, - @Nullable byte[] syntheticAttrHash) { - super(ruleClass, null); - this.syntheticAttrHash = syntheticAttrHash; - } - - @Override - public Location getAttributeLocation(String attrName) { - return EmptyLocation.INSTANCE; - } - - @Override - void setAttributeLocation(int attrIndex, Location location) { - throw new UnsupportedOperationException("Setting location not supported"); - } - - @Override - void setAttributeLocation(Attribute attribute, Location location) { - throw new UnsupportedOperationException("Setting location not supported"); - } - - @Nullable - public byte[] getSyntheticAttrHash() { - return syntheticAttrHash; - } - - private void clearIfNotLabel(String attr) { - setAttributeValueByName(attr, null); - } - } - - /** - * Creates a rule with the attribute values that are already parsed. - * - *

WARNING: This assumes that the attribute values here have the right type and - * bypasses some sanity checks. If they are of the wrong type, everything will come down burning. - */ - @SuppressWarnings("unchecked") - private static Rule createRuleWithParsedAttributeValues(RuleClass ruleClass, Label label, - Package.Builder pkgBuilder, Location ruleLocation, - Map attributeValues, EventHandler eventHandler, - AttributeContainer attributeContainer) - throws LabelSyntaxException, InterruptedException { - Rule rule = pkgBuilder.newRuleWithLabelAndAttrContainer(label, ruleClass, ruleLocation, - attributeContainer); - rule.checkValidityPredicate(eventHandler); - - for (Attribute attribute : rule.getRuleClassObject().getAttributes()) { - ParsedAttributeValue value = attributeValues.get(attribute.getName()); - if (attribute.isMandatory()) { - Preconditions.checkState(value != null); - } - - if (value == null) { - continue; - } - - rule.setAttributeValue(attribute, value.value, value.explicitlySpecified); - ruleClass.checkAllowedValues(rule, attribute, eventHandler); - - if (attribute.getName().equals("visibility")) { - // TODO(bazel-team): Verify that this cast works - rule.setVisibility(PackageFactory.getVisibility((List

Writes pkg as a single - * {@link com.google.devtools.build.lib.query2.proto.proto2api.Build.Package} protocol buffer - * message followed by a series of - * {@link com.google.devtools.build.lib.query2.proto.proto2api.Build.TargetOrTerminator} messages - * encoding the targets. - * - * @param pkg the {@link Package} to be serialized - * @param codedOut the stream to pkg's serialized representation to - * @throws IOException on failure writing to {@code out} - */ - public void serialize(Package pkg, CodedOutputStream codedOut) throws IOException { - Build.Package.Builder builder = Build.Package.newBuilder(); - builder.setName(pkg.getName()); - builder.setRepository(pkg.getPackageIdentifier().getRepository().getName()); - builder.setBuildFilePath(pkg.getFilename().getPathString()); - // The extra bit is needed to handle the corner case when the default visibility is [], i.e. - // zero labels. - builder.setDefaultVisibilitySet(pkg.isDefaultVisibilitySet()); - if (pkg.isDefaultVisibilitySet()) { - for (Label visibilityLabel : pkg.getDefaultVisibility().getDeclaredLabels()) { - builder.addDefaultVisibilityLabel(visibilityLabel.toString()); - } - } - - builder.setDefaultTestonly(pkg.getDefaultTestOnly()); - if (pkg.getDefaultDeprecation() != null) { - builder.setDefaultDeprecation(pkg.getDefaultDeprecation()); - } - - for (String defaultCopt : pkg.getDefaultCopts()) { - builder.addDefaultCopt(defaultCopt); - } - - if (pkg.isDefaultHdrsCheckSet()) { - builder.setDefaultHdrsCheck(pkg.getDefaultHdrsCheck()); - } - - builder.setDefaultLicense(serializeLicense(pkg.getDefaultLicense())); - - for (DistributionType distributionType : pkg.getDefaultDistribs()) { - builder.addDefaultDistrib(distributionType.toString()); - } - - for (String feature : pkg.getFeatures()) { - builder.addDefaultSetting(feature); - } - - for (Label subincludeLabel : pkg.getSubincludeLabels()) { - builder.addSubincludeLabel(subincludeLabel.toString()); - } - - for (Label skylarkLabel : pkg.getSkylarkFileDependencies()) { - builder.addSkylarkLabel(skylarkLabel.toString()); - } - - for (Build.MakeVar makeVar : - serializeMakeEnvironment(pkg.getMakeEnvironment())) { - builder.addMakeVariable(makeVar); - } - - for (Event event : pkg.getEvents()) { - builder.addEvent(serializeEvent(event)); - } - - builder.setContainsErrors(pkg.containsErrors()); - - builder.setWorkspaceName(pkg.getWorkspaceName()); - - codedOut.writeMessageNoTag(builder.build()); - - // Targets are emitted separately as individual protocol buffers as to prevent overwhelming - // protocol buffer deserialization size limits. - emitTargets(pkg.getTargets(), codedOut); - } - - private Build.Target serializeInputFile(InputFile inputFile) { - Build.SourceFile.Builder builder = Build.SourceFile.newBuilder(); - builder.setName(inputFile.getLabel().getName()); - if (inputFile.isVisibilitySpecified()) { - for (Label visibilityLabel : inputFile.getVisibility().getDeclaredLabels()) { - builder.addVisibilityLabel(visibilityLabel.toString()); - } - } - if (inputFile.isLicenseSpecified()) { - builder.setLicense(serializeLicense(inputFile.getLicense())); - } - - return Build.Target.newBuilder() - .setType(Build.Target.Discriminator.SOURCE_FILE) - .setSourceFile(builder.build()) - .build(); - } - - private Build.Target serializePackageGroup(PackageGroup packageGroup) { - Build.PackageGroup.Builder builder = Build.PackageGroup.newBuilder(); - - builder.setName(packageGroup.getLabel().getName()); - - for (PackageSpecification packageSpecification : packageGroup.getPackageSpecifications()) { - builder.addContainedPackage(packageSpecification.toString()); - } - - for (Label include : packageGroup.getIncludes()) { - builder.addIncludedPackageGroup(include.toString()); - } - - return Build.Target.newBuilder() - .setType(Build.Target.Discriminator.PACKAGE_GROUP) - .setPackageGroup(builder.build()) - .build(); - } - - public Build.Target serializeRule(Rule rule) { - Build.Rule.Builder builder = Build.Rule.newBuilder(); - builder.setName(rule.getLabel().getName()); - builder.setRuleClass(rule.getRuleClass()); - builder.setPublicByDefault(rule.getRuleClassObject().isPublicByDefault()); - for (Attribute attribute : rule.getAttributes()) { - builder.addAttribute( - AttributeSerializer.getAttributeProto( - attribute, - AttributeSerializer.getAttributeValues(rule, attribute), - rule.isAttributeValueExplicitlySpecified(attribute), - /*includeGlobs=*/ true)); - } - maybeSerializeAdditionalDataForRule(rule, builder); - - return Build.Target.newBuilder() - .setType(Build.Target.Discriminator.RULE) - .setRule(builder.build()) - .build(); - } - - public Build.SkylarkAspect serializeSkylarkAspect(Rule rule, Aspect aspect) { - SkylarkAspectClass aspectClass = (SkylarkAspectClass) aspect.getAspectClass(); - - SkylarkAspect.Builder builder = SkylarkAspect.newBuilder() - .setExtensionFileLabel(aspectClass.getExtensionLabel().toString()) - .setExportedName(aspectClass.getExportedName()); - - AspectDefinition definition = aspect.getDefinition(); - for (Entry entry : definition.getAttributes().entrySet()) { - Attribute attribute = entry.getValue(); - Object defaultValue = attribute.getDefaultValue(rule); - Verify.verify(defaultValue != null, "Aspect attributes must have default values."); - Build.Attribute attributePb = - AttributeSerializer.getAttributeProto( - attribute, ImmutableList.of(defaultValue), true, false); - builder.addAttribute(attributePb); - } - return builder.build(); - } - - private static List serializeMakeEnvironment(MakeEnvironment makeEnv) { - List result = new ArrayList<>(); - - for (Map.Entry> var : makeEnv.getBindings().entrySet()) { - Build.MakeVar.Builder varPb = Build.MakeVar.newBuilder(); - varPb.setName(var.getKey()); - for (Binding binding : var.getValue()) { - Build.MakeVarBinding.Builder bindingPb = Build.MakeVarBinding.newBuilder(); - bindingPb.setValue(binding.getValue()); - bindingPb.setPlatformSetRegexp(binding.getPlatformSetRegexp()); - varPb.addBinding(bindingPb); - } - - result.add(varPb.build()); - } - - return result; - } - - private static Build.License serializeLicense(License license) { - Build.License.Builder result = Build.License.newBuilder(); - - for (License.LicenseType licenseType : license.getLicenseTypes()) { - result.addLicenseType(licenseType.toString()); - } - - for (Label exception : license.getExceptions()) { - result.addException(exception.toString()); - } - return result.build(); - } - - private Build.Event serializeEvent(Event event) { - Build.Event.Builder result = Build.Event.newBuilder(); - result.setMessage(event.getMessage()); - - Build.Event.EventKind kind; - switch (event.getKind()) { - case ERROR: - kind = Build.Event.EventKind.ERROR; - break; - case WARNING: - kind = Build.Event.EventKind.WARNING; - break; - case INFO: - kind = Build.Event.EventKind.INFO; - break; - case PROGRESS: - kind = Build.Event.EventKind.PROGRESS; - break; - default: throw new IllegalArgumentException("unexpected event type: " + event.getKind()); - } - - result.setKind(kind); - return result.build(); - } - - /** Writes targets as a series of separate TargetOrTerminator messages to out. */ - private void emitTargets(Collection targets, CodedOutputStream codedOut) - throws IOException { - for (Target target : targets) { - if (target instanceof InputFile) { - emitTarget(serializeInputFile((InputFile) target), codedOut); - } else if (target instanceof OutputFile) { - // Output files are not serialized; they are recreated by the RuleClass on deserialization. - } else if (target instanceof PackageGroup) { - emitTarget(serializePackageGroup((PackageGroup) target), codedOut); - } else if (target instanceof Rule) { - emitTarget(serializeRule((Rule) target), codedOut); - } - } - - // Terminate stream with isTerminator = true. - codedOut.writeMessageNoTag(Build.TargetOrTerminator.newBuilder() - .setIsTerminator(true) - .build()); - } - - private static void emitTarget(Build.Target target, CodedOutputStream codedOut) - throws IOException { - codedOut.writeMessageNoTag(Build.TargetOrTerminator.newBuilder() - .setTarget(target) - .build()); - } - - private void maybeSerializeAdditionalDataForRule(Rule rule, Build.Rule.Builder builder) { - if (rule.getRuleClassObject().isSkylark()) { - builder.setIsSkylark(true); - // We explicitly serialize the implicit output files for this rule so that we can recreate - // them on deserialization via our fake placeholder rule class's - // RuleClass#getImplicitOutputsFunction. Note that since explicit outputs are already handled - // via the serialization of attributes with type OUTPUT or OUTPUT_LIST we don't bother with - // those. - Collection outputsFromAttributes = rule.getOutputFileMap().values(); - Set