diff options
author | 2017-11-17 15:05:14 -0800 | |
---|---|---|
committer | 2017-11-17 15:06:33 -0800 | |
commit | 2af2bff08c2fab136ea0927242bd4f3fe05456bf (patch) | |
tree | 99d1a217f7d249c390a7bb8cf89949b9dad815c4 /src/main/java/com/google/devtools/build | |
parent | c79c59c9e9cb7055d9b2446028a80eb2b40931be (diff) |
Add --host_deps custom filtering to configuredtargetqueryenvironment.
Notable implementation details:
- split the flag into --experimental_post_build_query and --experimental_query_options
- allow --nohost_dep filtering to be applied to query targets configured in the host configuration (only returns deps also in the host configuration so allow deps as long as it never sees a transition from a host config to a non-host config)
PiperOrigin-RevId: 176165870
Diffstat (limited to 'src/main/java/com/google/devtools/build')
5 files changed, 164 insertions, 22 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD index e5ac63d2c7..a84bae7a83 100644 --- a/src/main/java/com/google/devtools/build/lib/BUILD +++ b/src/main/java/com/google/devtools/build/lib/BUILD @@ -598,6 +598,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib:runtime", "//src/main/java/com/google/devtools/build/lib:util", "//src/main/java/com/google/devtools/build/lib/query2", + "//src/main/java/com/google/devtools/build/lib/query2:abstract-blaze-query-env", "//src/main/java/com/google/devtools/build/lib/query2:query-engine", "//src/main/java/com/google/devtools/common/options", "//third_party:guava", @@ -1014,6 +1015,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/profiler:profiler-output", "//src/main/java/com/google/devtools/build/lib/profiler/memory:allocationtracker", "//src/main/java/com/google/devtools/build/lib/query2", + "//src/main/java/com/google/devtools/build/lib/query2:abstract-blaze-query-env", "//src/main/java/com/google/devtools/build/lib/query2:query-engine", "//src/main/java/com/google/devtools/build/lib/query2:query-output", "//src/main/java/com/google/devtools/build/lib/shell", diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java index a771237955..fc438aa1e1 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java @@ -210,6 +210,14 @@ public class BuildRequestOptions extends OptionsBase { public String queryExpression; @Option( + name = "experimental_query_options", + defaultValue = "null", + documentationCategory = OptionDocumentationCategory.LOGGING, + effectTags = {OptionEffectTag.UNKNOWN} + ) + public String queryOptions; + + @Option( name = "analyze", defaultValue = "true", documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java index d785f51ee6..7607c16f97 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java @@ -77,6 +77,7 @@ import com.google.devtools.build.skyframe.WalkableGraph; import com.google.devtools.common.options.OptionsParsingException; import java.io.IOException; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -422,6 +423,8 @@ public final class BuildTool { runtime.getRuleClassProvider(), env.getSkyframeExecutor()); + String queryExpr = request.getBuildOptions().queryExpression; + // Currently, CTQE assumes that all top level targets take on the same default config and we // don't have the ability to map multiple configs to multiple top level targets. // So for now, we only allow multiple targets when they all carry the same config. @@ -431,7 +434,7 @@ public final class BuildTool { for (TargetAndConfiguration targAndConfig : topLevelTargetsWithConfigs) { if (!targAndConfig.getConfiguration().equals(sampleConfig)) { throw new QueryException( - new TargetLiteral(request.getBuildOptions().queryExpression), + new TargetLiteral(queryExpr), String.format( "Top level targets %s and %s have different configurations (top level " + "targets with different configurations is not supported)", @@ -441,6 +444,7 @@ public final class BuildTool { WalkableGraph walkableGraph = SkyframeExecutorWrappingWalkableGraph.of(env.getSkyframeExecutor()); + String queryOptions = request.getBuildOptions().queryOptions; ConfiguredTargetQueryEnvironment configuredTargetQueryEnvironment = new ConfiguredTargetQueryEnvironment( request.getViewOptions().keepGoing, @@ -450,9 +454,12 @@ public final class BuildTool { configurations.getHostConfiguration(), env.newTargetPatternEvaluator().getOffset(), env.getPackageManager().getPackagePath(), - () -> walkableGraph); + () -> walkableGraph, + queryOptions == null + ? new HashSet<>() + : ConfiguredTargetQueryEnvironment.parseOptions(queryOptions).toSettings()); configuredTargetQueryEnvironment.evaluateQuery( - request.getBuildOptions().queryExpression, + queryExpr, new ThreadSafeOutputFormatterCallback<ConfiguredTarget>() { @Override public void processOutput(Iterable<ConfiguredTarget> partialResult) diff --git a/src/main/java/com/google/devtools/build/lib/query2/BUILD b/src/main/java/com/google/devtools/build/lib/query2/BUILD index 5637e6efcf..8f143033ba 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/BUILD +++ b/src/main/java/com/google/devtools/build/lib/query2/BUILD @@ -8,9 +8,18 @@ filegroup( java_library( name = "query2", - srcs = glob(["*.java"]), + srcs = glob( + ["*.java"], + exclude = [ + "AbstractBlazeQueryEnvironment.java", + "FakeLoadTarget.java", + ], + ), deps = [ + ":abstract-blaze-query-env", + ":fake-load-target", ":query-engine", + ":query-output", "//src/main/java/com/google/devtools/build/lib:build-base", "//src/main/java/com/google/devtools/build/lib:events", "//src/main/java/com/google/devtools/build/lib:packages-internal", @@ -23,6 +32,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/vfs", "//src/main/java/com/google/devtools/build/skyframe", "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects", + "//src/main/java/com/google/devtools/common/options", "//third_party:guava", "//third_party:jsr305", ], @@ -32,8 +42,9 @@ java_library( name = "query-output", srcs = glob(["output/*.java"]), deps = [ + ":abstract-blaze-query-env", + ":fake-load-target", ":query-engine", - ":query2", "//src/main/java/com/google/devtools/build/lib:events", "//src/main/java/com/google/devtools/build/lib:packages-internal", "//src/main/java/com/google/devtools/build/lib:util", @@ -47,6 +58,35 @@ java_library( ], ) +java_library( + name = "abstract-blaze-query-env", + srcs = [ + "AbstractBlazeQueryEnvironment.java", + ], + deps = [ + ":query-engine", + "//src/main/java/com/google/devtools/build/lib:events", + "//src/main/java/com/google/devtools/build/lib:packages-internal", + "//src/main/java/com/google/devtools/build/lib:util", + "//third_party:guava", + "//third_party:jsr305", + ], +) + +java_library( + name = "fake-load-target", + srcs = [ + "FakeLoadTarget.java", + ], + deps = [ + "//src/main/java/com/google/devtools/build/lib:events", + "//src/main/java/com/google/devtools/build/lib:packages-internal", + "//src/main/java/com/google/devtools/build/lib:util", + "//third_party:guava", + "//third_party:jsr305", + ], +) + # Query library. java_library( name = "query-engine", diff --git a/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java index 3628a76ad1..def3b9d4f3 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java +++ b/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java @@ -23,13 +23,16 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.LabelAndConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.TargetParsingException; import com.google.devtools.build.lib.cmdline.TargetPattern; import com.google.devtools.build.lib.cmdline.TargetPattern.Type; +import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet; import com.google.devtools.build.lib.concurrent.MultisetSemaphore; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.ExtendedEventHandler; +import com.google.devtools.build.lib.packages.DependencyFilter; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.pkgcache.FilteringPolicies; @@ -48,6 +51,7 @@ import com.google.devtools.build.lib.query2.engine.QueryUtil.ThreadSafeMutableKe import com.google.devtools.build.lib.query2.engine.QueryUtil.UniquifierImpl; import com.google.devtools.build.lib.query2.engine.ThreadSafeOutputFormatterCallback; import com.google.devtools.build.lib.query2.engine.Uniquifier; +import com.google.devtools.build.lib.query2.output.QueryOptions; import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey; import com.google.devtools.build.lib.skyframe.ConfiguredTargetValue; import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider; @@ -57,14 +61,18 @@ import com.google.devtools.build.lib.skyframe.TargetPatternValue; import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.WalkableGraph; +import com.google.devtools.common.options.OptionsParser; +import com.google.devtools.common.options.OptionsParsingException; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; -import java.util.EnumSet; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -132,15 +140,9 @@ public class ConfiguredTargetQueryEnvironment BuildConfiguration hostConfiguration, String parserPrefix, PathPackageLocator pkgPath, - Supplier<WalkableGraph> walkableGraphSupplier) { - super( - keepGoing, - true, - Rule.ALL_LABELS, - eventHandler, - // TODO(janakr): decide whether to support host and implicit dep filtering. - EnumSet.noneOf(Setting.class), - extraFunctions); + Supplier<WalkableGraph> walkableGraphSupplier, + Set<Setting> settings) { + super(keepGoing, true, Rule.ALL_LABELS, eventHandler, settings, extraFunctions); this.defaultTargetConfiguration = defaultTargetConfiguration; this.hostConfiguration = hostConfiguration; this.parserPrefix = parserPrefix; @@ -148,7 +150,7 @@ public class ConfiguredTargetQueryEnvironment this.walkableGraphSupplier = walkableGraphSupplier; } - private void beforeEvaluateQuery() throws InterruptedException { + private void beforeEvaluateQuery() throws InterruptedException, QueryException { graph = walkableGraphSupplier.get(); GraphBackedRecursivePackageProvider graphBackedRecursivePackageProvider = new GraphBackedRecursivePackageProvider(graph, ALL_PATTERNS, pkgPath); @@ -158,6 +160,20 @@ public class ConfiguredTargetQueryEnvironment eventHandler, FilteringPolicies.NO_FILTER, MultisetSemaphore.unbounded()); + checkSettings(settings); + } + + // Check to make sure the settings requested are currently supported by this class + private void checkSettings(Set<Setting> settings) throws QueryException { + if (settings.contains(Setting.NO_HOST_DEPS)) { + settings = Sets.difference(settings, ImmutableSet.of(Setting.NO_HOST_DEPS)); + } + if (!settings.isEmpty()) { + throw new QueryException( + String.format( + "The following filter(s) are not currently supported by configured query: %s", + settings.toString())); + } } @Nullable @@ -257,6 +273,45 @@ public class ConfiguredTargetQueryEnvironment return result; } + private Collection<ConfiguredTarget> filterFwdDeps( + ConfiguredTarget configTarget, Collection<ConfiguredTarget> rawFwdDeps) + throws InterruptedException { + if (!(configTarget instanceof RuleConfiguredTarget) || settings.isEmpty()) { + return rawFwdDeps; + } + return getAllowedDeps(configTarget.getConfiguration(), rawFwdDeps); + } + + /** + * Note: We should check which settings to filter on here but not doing that since we currently + * only support one setting (NO_HOST_DEPS) and should've already thrown an error by now if it's + * any other filter. + * + * @param currentConfig: the config of the source target. It's possible to query on a target + * that's configured in the host configuration. In those cases, if --nohost_deps is turned on, + * we only allow reachable targets that are ALSO in the host config. This is somewhat + * counterintuitive and subject to change in the future but seems like the best option right + * now. + * @param rawDeps: the next level of deps to filter + */ + private Collection<ConfiguredTarget> getAllowedDeps( + BuildConfiguration currentConfig, Collection<ConfiguredTarget> rawDeps) { + if (currentConfig != null && currentConfig.isHostConfiguration()) { + return rawDeps + .stream() + .filter( + dep -> dep.getConfiguration() != null && dep.getConfiguration().isHostConfiguration()) + .collect(Collectors.toList()); + } else { + return rawDeps + .stream() + .filter( + dep -> + dep.getConfiguration() == null || !dep.getConfiguration().isHostConfiguration()) + .collect(Collectors.toList()); + } + } + @Override public ThreadSafeMutableSet<ConfiguredTarget> getFwdDeps(Iterable<ConfiguredTarget> targets) throws InterruptedException { @@ -276,7 +331,29 @@ public class ConfiguredTargetQueryEnvironment } ThreadSafeMutableSet<ConfiguredTarget> result = createThreadSafeMutableSet(); for (Entry<SkyKey, Collection<ConfiguredTarget>> entry : directDeps.entrySet()) { - result.addAll(entry.getValue()); + result.addAll(filterFwdDeps(targetsByKey.get(entry.getKey()), entry.getValue())); + } + return result; + } + + private Collection<ConfiguredTarget> filterReverseDeps( + Map<SkyKey, Collection<ConfiguredTarget>> rawReverseDeps) { + Set<ConfiguredTarget> result = CompactHashSet.create(); + for (Map.Entry<SkyKey, Collection<ConfiguredTarget>> targetAndRdeps : + rawReverseDeps.entrySet()) { + ImmutableSet.Builder<ConfiguredTarget> ruleDeps = ImmutableSet.builder(); + for (ConfiguredTarget parent : targetAndRdeps.getValue()) { + if (parent instanceof RuleConfiguredTarget + && dependencyFilter != DependencyFilter.ALL_DEPS) { + ruleDeps.add(parent); + } else { + result.add(parent); + } + } + result.addAll( + getAllowedDeps( + ((ConfiguredTargetKey) targetAndRdeps.getKey().argument()).getConfiguration(), + ruleDeps.build())); } return result; } @@ -298,11 +375,7 @@ public class ConfiguredTargetQueryEnvironment .collect(Collectors.toList()); eventHandler.handle(Event.warn("Targets were missing from graph: " + missingTargets)); } - ThreadSafeMutableSet<ConfiguredTarget> result = createThreadSafeMutableSet(); - for (Entry<SkyKey, Collection<ConfiguredTarget>> entry : reverseDeps.entrySet()) { - result.addAll(entry.getValue()); - } - return result; + return reverseDeps.isEmpty() ? Collections.emptyList() : filterReverseDeps(reverseDeps); } @Override @@ -407,4 +480,16 @@ public class ConfiguredTargetQueryEnvironment } } } + + public static QueryOptions parseOptions(String rawOptions) throws QueryException { + List<String> options = new ArrayList<>(Arrays.asList(rawOptions.split(" "))); + OptionsParser parser = OptionsParser.newOptionsParser(QueryOptions.class); + parser.setAllowResidue(false); + try { + parser.parse(options); + } catch (OptionsParsingException e) { + throw new QueryException(e.getMessage()); + } + return parser.getOptions(QueryOptions.class); + } } |