// 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.skyframe; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.pkgcache.LoadingResult; import com.google.devtools.build.lib.pkgcache.TestFilter; import com.google.devtools.build.lib.skyframe.serialization.NotSerializableRuntimeException; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Objects; import javax.annotation.Nullable; /** * A value referring to a computed set of resolved targets. This is used for the results of target * pattern parsing. */ @Immutable @ThreadSafe @VisibleForTesting public final class TargetPatternPhaseValue implements SkyValue { private final ImmutableSet targets; @Nullable private final ImmutableSet testsToRun; private final boolean hasError; private final boolean hasPostExpansionError; private final ImmutableSet filteredTargets; private final ImmutableSet testFilteredTargets; // This field is only for the purposes of generating the LoadingPhaseCompleteEvent. // TODO(ulfjack): Support EventBus event posting in Skyframe, and remove this code again. private final ImmutableSet removedTargets; private final String workspaceName; TargetPatternPhaseValue(ImmutableSet targets, @Nullable ImmutableSet testsToRun, boolean hasError, boolean hasPostExpansionError, ImmutableSet filteredTargets, ImmutableSet testFilteredTargets, ImmutableSet removedTargets, String workspaceName) { this.targets = Preconditions.checkNotNull(targets); this.testsToRun = testsToRun; this.hasError = hasError; this.hasPostExpansionError = hasPostExpansionError; this.filteredTargets = Preconditions.checkNotNull(filteredTargets); this.testFilteredTargets = Preconditions.checkNotNull(testFilteredTargets); this.removedTargets = Preconditions.checkNotNull(removedTargets); this.workspaceName = workspaceName; } public ImmutableSet getTargets() { return targets; } @Nullable public ImmutableSet getTestsToRun() { return testsToRun; } public boolean hasError() { return hasError; } public boolean hasPostExpansionError() { return hasPostExpansionError; } public ImmutableSet getFilteredTargets() { return filteredTargets; } public ImmutableSet getTestFilteredTargets() { return testFilteredTargets; } /** * Returns a set of targets that were present on the command line but got * expanded during the loading phase (currently these are only test suites; * this set is always empty when --expand_test_suites=false. */ public ImmutableSet getRemovedTargets() { return removedTargets; } public String getWorkspaceName() { return workspaceName; } public LoadingResult toLoadingResult() { return new LoadingResult( hasError(), hasPostExpansionError(), getTargets(), getTestsToRun(), getWorkspaceName()); } @SuppressWarnings("unused") private void writeObject(ObjectOutputStream out) { throw new NotSerializableRuntimeException(); } @SuppressWarnings("unused") private void readObject(ObjectInputStream in) { throw new NotSerializableRuntimeException(); } @SuppressWarnings("unused") private void readObjectNoData() { throw new IllegalStateException(); } /** Create a target pattern phase value key. */ @ThreadSafe public static SkyKey key( ImmutableList targetPatterns, String offset, boolean compileOneDependency, boolean buildTestsOnly, boolean determineTests, ImmutableList buildTargetFilter, boolean buildManualTests, boolean expandTestSuites, @Nullable TestFilter testFilter) { return new TargetPatternPhaseKey( targetPatterns, offset, compileOneDependency, buildTestsOnly, determineTests, buildTargetFilter, buildManualTests, expandTestSuites, testFilter); } /** The configuration needed to run the target pattern evaluation phase. */ @ThreadSafe static final class TargetPatternPhaseKey implements SkyKey, Serializable { private final ImmutableList targetPatterns; private final String offset; private final boolean compileOneDependency; private final boolean buildTestsOnly; private final boolean determineTests; private final ImmutableList buildTargetFilter; private final boolean buildManualTests; private final boolean expandTestSuites; @Nullable private final TestFilter testFilter; public TargetPatternPhaseKey( ImmutableList targetPatterns, String offset, boolean compileOneDependency, boolean buildTestsOnly, boolean determineTests, ImmutableList buildTargetFilter, boolean buildManualTests, boolean expandTestSuites, @Nullable TestFilter testFilter) { this.targetPatterns = Preconditions.checkNotNull(targetPatterns); this.offset = Preconditions.checkNotNull(offset); this.compileOneDependency = compileOneDependency; this.buildTestsOnly = buildTestsOnly; this.determineTests = determineTests; this.buildTargetFilter = Preconditions.checkNotNull(buildTargetFilter); this.buildManualTests = buildManualTests; this.expandTestSuites = expandTestSuites; this.testFilter = testFilter; if (buildTestsOnly || determineTests) { Preconditions.checkNotNull(testFilter); } } @Override public SkyFunctionName functionName() { return SkyFunctions.TARGET_PATTERN_PHASE; } public ImmutableList getTargetPatterns() { return targetPatterns; } public String getOffset() { return offset; } public boolean getCompileOneDependency() { return compileOneDependency; } public boolean getBuildTestsOnly() { return buildTestsOnly; } public boolean getDetermineTests() { return determineTests; } public ImmutableList getBuildTargetFilter() { return buildTargetFilter; } public boolean getBuildManualTests() { return buildManualTests; } public TestFilter getTestFilter() { return testFilter; } public boolean isExpandTestSuites() { return expandTestSuites; } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(targetPatterns); if (!offset.isEmpty()) { result.append(" OFFSET=").append(offset); } result.append(compileOneDependency ? " COMPILE_ONE_DEPENDENCY" : ""); result.append(buildTestsOnly ? " BUILD_TESTS_ONLY" : ""); result.append(determineTests ? " DETERMINE_TESTS" : ""); result.append(expandTestSuites ? " EXPAND_TEST_SUITES" : ""); result.append(testFilter != null ? testFilter : ""); return result.toString(); } @Override public int hashCode() { return Objects.hash( targetPatterns, offset, compileOneDependency, buildTestsOnly, determineTests, buildManualTests, expandTestSuites, testFilter); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof TargetPatternPhaseKey)) { return false; } TargetPatternPhaseKey other = (TargetPatternPhaseKey) obj; return other.targetPatterns.equals(this.targetPatterns) && other.offset.equals(this.offset) && other.compileOneDependency == compileOneDependency && other.buildTestsOnly == buildTestsOnly && other.determineTests == determineTests && other.buildTargetFilter.equals(buildTargetFilter) && other.buildManualTests == buildManualTests && other.expandTestSuites == expandTestSuites && Objects.equals(other.testFilter, testFilter); } } }