/* * Copyright 2016-present Facebook, Inc. * * 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.facebook.buck.rules.query; import com.facebook.buck.event.PerfEventId; import com.facebook.buck.event.SimplePerfEvent; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargetPattern; import com.facebook.buck.parser.BuildTargetPatternParser; import com.facebook.buck.query.QueryBuildTarget; import com.facebook.buck.query.QueryException; import com.facebook.buck.query.QueryExpression; import com.facebook.buck.query.QueryTarget; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.CellPathResolver; import com.facebook.buck.rules.TargetGraph; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Stream; /** * Mixin class to allow dynamic dependency resolution at graph enhancement time. New and unstable. * Will almost certainly change in interface and implementation. */ public final class QueryUtils { private QueryUtils() { // This class cannot be instantiated } public static Stream<BuildRule> resolveDepQuery( BuildTarget target, Query query, BuildRuleResolver resolver, CellPathResolver cellRoots, TargetGraph targetGraph, ImmutableSet<BuildTarget> declaredDeps) { GraphEnhancementQueryEnvironment env = new GraphEnhancementQueryEnvironment( Optional.of(resolver), Optional.of(targetGraph), cellRoots, BuildTargetPatternParser.forBaseName(target.getBaseName()), declaredDeps); ListeningExecutorService executorService = MoreExecutors.newDirectExecutorService(); try (SimplePerfEvent.Scope ignored = SimplePerfEvent.scope( Optional.ofNullable(resolver.getEventBus()), PerfEventId.of("resolve_dep_query"), "target", target.toString())) { QueryExpression parsedExp = QueryExpression.parse(query.getQuery(), env); Set<QueryTarget> queryTargets = parsedExp.eval(env, executorService); return queryTargets .stream() .map( queryTarget -> { Preconditions.checkState(queryTarget instanceof QueryBuildTarget); return resolver.getRule(((QueryBuildTarget) queryTarget).getBuildTarget()); }); } catch (QueryException e) { throw new RuntimeException("Error parsing/executing query from deps for " + target, e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Error executing query from deps for " + target, e); } } public static Stream<BuildTarget> extractBuildTargets( CellPathResolver cellPathResolver, BuildTargetPatternParser<BuildTargetPattern> parserPattern, Query query) throws QueryException { GraphEnhancementQueryEnvironment env = new GraphEnhancementQueryEnvironment( Optional.empty(), Optional.empty(), cellPathResolver, parserPattern, ImmutableSet.of()); ListeningExecutorService executorService = MoreExecutors.newDirectExecutorService(); QueryExpression parsedExp = QueryExpression.parse(query.getQuery(), env); List<String> targetLiterals = new ArrayList<>(); parsedExp.collectTargetPatterns(targetLiterals); return targetLiterals .stream() .flatMap( pattern -> { try { return env.getTargetsMatchingPattern(pattern, executorService).stream(); } catch (Exception e) { throw new RuntimeException("Error parsing target expression", e); } }) .map( queryTarget -> { Preconditions.checkState(queryTarget instanceof QueryBuildTarget); return ((QueryBuildTarget) queryTarget).getBuildTarget(); }); } public static Stream<BuildTarget> extractParseTimeTargets( BuildTarget target, CellPathResolver cellNames, Query query) { try { return extractBuildTargets( cellNames, BuildTargetPatternParser.forBaseName(target.getBaseName()), query); } catch (QueryException e) { throw new RuntimeException("Error parsing/executing query from deps for " + target, e); } } }