|  | // Copyright 2014 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.pkgcache; | 
|  |  | 
|  | import com.google.common.base.Preconditions; | 
|  | import com.google.common.collect.Collections2; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import com.google.common.collect.ImmutableMap; | 
|  | import com.google.common.collect.ImmutableSet; | 
|  | import com.google.common.collect.ImmutableSetMultimap; | 
|  | import com.google.common.collect.Iterables; | 
|  | import com.google.devtools.build.lib.buildeventstream.BuildEventContext; | 
|  | import com.google.devtools.build.lib.buildeventstream.BuildEventIdUtil; | 
|  | import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos; | 
|  | import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId; | 
|  | import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.PatternExpanded; | 
|  | import com.google.devtools.build.lib.buildeventstream.BuildEventWithOrderConstraint; | 
|  | import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent; | 
|  | import com.google.devtools.build.lib.cmdline.Label; | 
|  | import com.google.devtools.build.lib.packages.Rule; | 
|  | import com.google.devtools.build.lib.packages.Target; | 
|  | import com.google.devtools.build.lib.packages.TargetUtils; | 
|  | import java.util.Collection; | 
|  | import javax.annotation.Nullable; | 
|  |  | 
|  | /** This event is fired just after target pattern evaluation is completed. */ | 
|  | public final class TargetParsingCompleteEvent implements BuildEventWithOrderConstraint { | 
|  | /** A target-like object that is lighter than a target but has all data needed by callers. */ | 
|  | public static final class ThinTarget { | 
|  | private final Label label; | 
|  | @Nullable private final String ruleClass; | 
|  | private final String targetKind; | 
|  |  | 
|  | private ThinTarget(Target target) { | 
|  | this.label = target.getLabel(); | 
|  | this.targetKind = target.getTargetKind(); | 
|  | this.ruleClass = (target instanceof Rule) ? ((Rule) target).getRuleClass() : null; | 
|  | } | 
|  |  | 
|  | public boolean isRule() { | 
|  | return ruleClass != null; | 
|  | } | 
|  |  | 
|  | public String getTargetKind() { | 
|  | return targetKind; | 
|  | } | 
|  |  | 
|  | public Label getLabel() { | 
|  | return label; | 
|  | } | 
|  |  | 
|  | /** Gets the rule class of this target. Caller must already know it {@link #isRule}. */ | 
|  | public String getRuleClass() { | 
|  | return Preconditions.checkNotNull(ruleClass, label); | 
|  | } | 
|  |  | 
|  | public boolean isTestSuiteRule() { | 
|  | return isRule() && TargetUtils.isTestSuiteRuleName(getRuleClass()); | 
|  | } | 
|  |  | 
|  | public boolean isNotATestOrTestSuite() { | 
|  | return !isRule() || (!isTestSuiteRule() && !TargetUtils.isTestRuleName(getRuleClass())); | 
|  | } | 
|  | } | 
|  |  | 
|  | private final ImmutableList<String> originalTargetPattern; | 
|  | private final ImmutableList<String> failedTargetPatterns; | 
|  | private final ImmutableSet<ThinTarget> targets; | 
|  | private final ImmutableSet<ThinTarget> filteredTargets; | 
|  | private final ImmutableSet<ThinTarget> testFilteredTargets; | 
|  | private final ImmutableSet<ThinTarget> expandedTargets; | 
|  | private final ImmutableSetMultimap<String, Label> originalPatternsToLabels; | 
|  | private final ImmutableMap<Label, ImmutableSet<Label>> testSuiteExpansions; | 
|  |  | 
|  | public TargetParsingCompleteEvent( | 
|  | Collection<Target> targets, | 
|  | Collection<Target> filteredTargets, | 
|  | Collection<Target> testFilteredTargets, | 
|  | ImmutableList<String> originalTargetPattern, | 
|  | Collection<Target> expandedTargets, | 
|  | ImmutableList<String> failedTargetPatterns, | 
|  | ImmutableSetMultimap<String, Label> originalPatternsToLabels, | 
|  | ImmutableMap<Label, ImmutableSet<Label>> testSuiteExpansions) { | 
|  | this.targets = asThinTargets(targets); | 
|  | this.filteredTargets = asThinTargets(filteredTargets); | 
|  | this.testFilteredTargets = asThinTargets(testFilteredTargets); | 
|  | this.originalTargetPattern = Preconditions.checkNotNull(originalTargetPattern); | 
|  | this.expandedTargets = asThinTargets(expandedTargets); | 
|  | this.failedTargetPatterns = Preconditions.checkNotNull(failedTargetPatterns); | 
|  | this.originalPatternsToLabels = Preconditions.checkNotNull(originalPatternsToLabels); | 
|  | this.testSuiteExpansions = Preconditions.checkNotNull(testSuiteExpansions); | 
|  | } | 
|  |  | 
|  | public ImmutableList<String> getOriginalTargetPattern() { | 
|  | return originalTargetPattern; | 
|  | } | 
|  |  | 
|  | public ImmutableList<String> getFailedTargetPatterns() { | 
|  | return failedTargetPatterns; | 
|  | } | 
|  |  | 
|  | /** @return the parsed targets, which will subsequently be loaded */ | 
|  | public ImmutableSet<ThinTarget> getTargets() { | 
|  | return targets; | 
|  | } | 
|  |  | 
|  | public Iterable<Label> getLabels() { | 
|  | return Iterables.transform(targets, ThinTarget::getLabel); | 
|  | } | 
|  |  | 
|  | public Iterable<Label> getFilteredLabels() { | 
|  | return Iterables.transform(filteredTargets, ThinTarget::getLabel); | 
|  | } | 
|  |  | 
|  | public Iterable<Label> getTestFilteredLabels() { | 
|  | return Iterables.transform(testFilteredTargets, ThinTarget::getLabel); | 
|  | } | 
|  |  | 
|  | /** @return the filtered targets (i.e., using -//foo:bar on the command-line) */ | 
|  | public ImmutableSet<ThinTarget> getFilteredTargets() { | 
|  | return filteredTargets; | 
|  | } | 
|  |  | 
|  | /** @return the test-filtered targets, if --build_test_only is in effect */ | 
|  | public ImmutableSet<ThinTarget> getTestFilteredTargets() { | 
|  | return testFilteredTargets; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a mapping from patterns originally passed on the command line to the labels they were | 
|  | * expanded to. | 
|  | * | 
|  | * <p>Negative patterns are not included here. Neither are labels of targets that are skipped due | 
|  | * to matching a negative pattern (even if they also matched a positive pattern). | 
|  | * | 
|  | * <p>Test suite labels are included here, but not the labels of the tests that the suite expanded | 
|  | * to. | 
|  | */ | 
|  | public ImmutableSetMultimap<String, Label> getOriginalPatternsToLabels() { | 
|  | return originalPatternsToLabels; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public BuildEventId getEventId() { | 
|  | return BuildEventIdUtil.targetPatternExpanded(originalTargetPattern); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public Collection<BuildEventId> postedAfter() { | 
|  | return ImmutableList.of(BuildEventIdUtil.buildStartedId()); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public Collection<BuildEventId> getChildrenEvents() { | 
|  | ImmutableList.Builder<BuildEventId> childrenBuilder = ImmutableList.builder(); | 
|  | for (String failedTargetPattern : failedTargetPatterns) { | 
|  | childrenBuilder.add( | 
|  | BuildEventIdUtil.targetPatternExpanded(ImmutableList.of(failedTargetPattern))); | 
|  | } | 
|  | for (ThinTarget target : expandedTargets) { | 
|  | // Test suites won't produce target configuration and target-complete events, so do not | 
|  | // announce here completion as children. | 
|  | if (!target.isTestSuiteRule()) { | 
|  | childrenBuilder.add(BuildEventIdUtil.targetConfigured(target.getLabel())); | 
|  | } | 
|  | } | 
|  | return childrenBuilder.build(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) { | 
|  | PatternExpanded.Builder expanded = PatternExpanded.newBuilder(); | 
|  | testSuiteExpansions.forEach( | 
|  | (suite, tests) -> | 
|  | expanded | 
|  | .addTestSuiteExpansionsBuilder() | 
|  | .setSuiteLabel(suite.toString()) | 
|  | .addAllTestLabels(Collections2.transform(tests, Label::toString))); | 
|  |  | 
|  | return GenericBuildEvent.protoChaining(this).setExpanded(expanded).build(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean storeForReplay() { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | private static ImmutableSet<ThinTarget> asThinTargets(Collection<Target> targets) { | 
|  | return targets.stream().map(ThinTarget::new).collect(ImmutableSet.toImmutableSet()); | 
|  | } | 
|  | } |