From d6fce4428db80f8e5d369581baea415e202cfe62 Mon Sep 17 00:00:00 2001 From: Ulf Adams Date: Wed, 14 Oct 2015 10:08:25 +0000 Subject: Reimplement target pattern parsing in Skyframe. This is currently not hooked up, and we're passing (potentially) massive numbers of targets around. -- MOS_MIGRATED_REVID=105395404 --- .../build/lib/skyframe/TestsInSuiteFunction.java | 229 +++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 src/main/java/com/google/devtools/build/lib/skyframe/TestsInSuiteFunction.java (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/TestsInSuiteFunction.java') diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TestsInSuiteFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TestsInSuiteFunction.java new file mode 100644 index 0000000000..3c559de383 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/TestsInSuiteFunction.java @@ -0,0 +1,229 @@ +// 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.base.Predicate; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.cmdline.PackageIdentifier; +import com.google.devtools.build.lib.cmdline.ResolvedTargets; +import com.google.devtools.build.lib.events.Event; +import com.google.devtools.build.lib.packages.AttributeMap; +import com.google.devtools.build.lib.packages.BuildFileNotFoundException; +import com.google.devtools.build.lib.packages.BuildType; +import com.google.devtools.build.lib.packages.NoSuchTargetException; +import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper; +import com.google.devtools.build.lib.packages.Package; +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 com.google.devtools.build.lib.packages.TestTargetUtils; +import com.google.devtools.build.lib.skyframe.TestsInSuiteValue.TestsInSuite; +import com.google.devtools.build.lib.syntax.Type; +import com.google.devtools.build.lib.util.Pair; +import com.google.devtools.build.skyframe.SkyFunction; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; +import com.google.devtools.build.skyframe.ValueOrException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Nullable; + +/** + * TestsInSuiteFunction takes a single test_suite target and expands all of the tests it contains, + * possibly recursively. + */ +// TODO(ulfjack): What about test_suite rules that include each other. +final class TestsInSuiteFunction implements SkyFunction { + @Override + public SkyValue compute(SkyKey key, Environment env) { + TestsInSuite expansion = (TestsInSuite) key.argument(); + ResolvedTargets result = + computeTestsInSuite(env, expansion.getTestSuite(), expansion.isStrict()); + if (env.valuesMissing()) { + return null; + } + return new TestsInSuiteValue(result); + } + + /** + * Populates 'result' with all the tests associated with the specified + * 'testSuite'. Throws an exception if any target is missing. + * + *

CAUTION! Keep this logic consistent with {@code TestSuite}! + */ + private ResolvedTargets computeTestsInSuite( + Environment env, Rule testSuite, boolean strict) { + ResolvedTargets.Builder builder = ResolvedTargets.builder(); + List testsAndSuites = new ArrayList<>(); + // Note that testsAndSuites can contain input file targets; the test_suite rule does not + // restrict the set of targets that can appear in tests or suites. + builder.mergeError(getPrerequisites(env, testSuite, "tests", testsAndSuites)); + if (testSuite.getRuleClassObject().hasAttr("suites", BuildType.LABEL_LIST)) { + builder.mergeError(getPrerequisites(env, testSuite, "suites", testsAndSuites)); + } + + // 1. Add all tests + for (Target test : testsAndSuites) { + if (TargetUtils.isTestRule(test)) { + builder.add(test); + } else if (strict && !TargetUtils.isTestSuiteRule(test)) { + // If strict mode is enabled, then give an error for any non-test, non-test-suite targets. + // TODO(ulfjack): We need to throw to end the process if we happen to be in --nokeep_going, + // but we can't know whether or not we are at this point. + env.getListener().handle(Event.error(testSuite.getLocation(), + "in test_suite rule '" + testSuite.getLabel() + + "': expecting a test or a test_suite rule but '" + test.getLabel() + + "' is not one.")); + builder.setError(); + } + } + + // 2. Add implicit dependencies on tests in same package, if any. + List implicitTests = new ArrayList<>(); + builder.mergeError(getPrerequisites(env, testSuite, "$implicit_tests", implicitTests)); + for (Target target : implicitTests) { + // The Package construction of $implicit_tests ensures that this check never fails, but we + // add it here anyway for compatibility with future code. + if (TargetUtils.isTestRule(target)) { + builder.add(target); + } + } + + // 3. Filter based on tags, size, env. + filterTests(testSuite, builder); + + // 4. Expand all suites recursively. + for (Target suite : testsAndSuites) { + if (TargetUtils.isTestSuiteRule(suite)) { + TestsInSuiteValue value = + (TestsInSuiteValue) env.getValue(TestsInSuiteValue.key(suite, strict)); + builder.merge(value.getTargets()); + } + } + + return builder.build(); + } + + /** + * Adds the set of targets found in the attribute named {@code attrName}, which must be of label + * list type, of the {@code test_suite} rule named {@code testSuite}. Returns true if the method + * found a problem during the lookup process; the actual error message is reported to the + * environment. + */ + private boolean getPrerequisites(Environment env, Rule testSuite, String attrName, + List targets) { + List