/*
* 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.cli;
import com.facebook.buck.event.BuckEventBus;
import com.facebook.buck.event.ConsoleEvent;
import com.facebook.buck.json.BuildFileParseException;
import com.facebook.buck.jvm.java.autodeps.JavaDepsFinder;
import com.facebook.buck.model.BuildTargetException;
import com.facebook.buck.parser.BuildFileSpec;
import com.facebook.buck.parser.TargetNodePredicateSpec;
import com.facebook.buck.rules.ActionGraph;
import com.facebook.buck.rules.BuildContext;
import com.facebook.buck.rules.BuildEngineBuildContext;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.CachingBuildEngine;
import com.facebook.buck.rules.CachingBuildEngineBuckConfig;
import com.facebook.buck.rules.Cell;
import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer;
import com.facebook.buck.rules.LocalCachingBuildEngineDelegate;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.keys.DefaultRuleKeyCache;
import com.facebook.buck.rules.keys.RuleKeyFactories;
import com.facebook.buck.step.DefaultStepRunner;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.step.ExecutorPool;
import com.facebook.buck.util.DefaultProcessExecutor;
import com.facebook.buck.util.MoreExceptions;
import com.facebook.buck.util.concurrent.ConcurrencyLimit;
import com.facebook.buck.util.concurrent.WeightedListeningExecutorService;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ListeningExecutorService;
import java.io.IOException;
import java.nio.file.Paths;
/**
* Utility that aids in creating the objects necessary to traverse the target graph with special
* knowledge of Java-based rules. This is needed by commands such as {@code buck suggest}.
*/
final class JavaBuildGraphProcessor {
/** Utility class: do not instantiate. */
private JavaBuildGraphProcessor() {}
/**
* Can be thrown by {@link Processor#process(TargetGraph, JavaDepsFinder,
* WeightedListeningExecutorService)} to indicate the way in which processing has failed. The exit
* code value may be useful if the failure is bubbled up to a Buck command.
*/
static final class ExitCodeException extends Exception {
public final int exitCode;
ExitCodeException(int exitCode) {
this.exitCode = exitCode;
}
}
/**
* Does the user-defined processing on the objects built up by {@link #run(CommandRunnerParams,
* AbstractCommand, Processor)}.
*/
interface Processor {
void process(
TargetGraph graph,
JavaDepsFinder javaDepsFinder,
WeightedListeningExecutorService executorService);
}
/**
* Creates the appropriate target graph and other resources needed for the {@link Processor} and
* runs it. This method will take responsibility for cleaning up the executor service after it
* runs.
*/
static void run(
final CommandRunnerParams params, final AbstractCommand command, final Processor processor)
throws ExitCodeException, InterruptedException, IOException {
final ConcurrencyLimit concurrencyLimit = command.getConcurrencyLimit(params.getBuckConfig());
try (CommandThreadManager pool =
new CommandThreadManager(command.getClass().getName(), concurrencyLimit)) {
Cell cell = params.getCell();
WeightedListeningExecutorService executorService = pool.getExecutor();
TargetGraph graph;
try {
graph =
params
.getParser()
.buildTargetGraphForTargetNodeSpecs(
params.getBuckEventBus(),
cell,
command.getEnableParserProfiling(),
executorService,
ImmutableList.of(
TargetNodePredicateSpec.of(
x -> true,
BuildFileSpec.fromRecursivePath(Paths.get(""), cell.getRoot()))))
.getTargetGraph();
} catch (BuildTargetException | BuildFileParseException e) {
params
.getBuckEventBus()
.post(ConsoleEvent.severe(MoreExceptions.getHumanReadableOrLocalizedMessage(e)));
throw new ExitCodeException(1);
}
BuildRuleResolver buildRuleResolver =
new BuildRuleResolver(graph, new DefaultTargetNodeToBuildRuleTransformer());
CachingBuildEngineBuckConfig cachingBuildEngineBuckConfig =
params.getBuckConfig().getView(CachingBuildEngineBuckConfig.class);
LocalCachingBuildEngineDelegate cachingBuildEngineDelegate =
new LocalCachingBuildEngineDelegate(params.getFileHashCache());
try (CachingBuildEngine buildEngine =
new CachingBuildEngine(
cachingBuildEngineDelegate,
executorService,
executorService,
new DefaultStepRunner(),
CachingBuildEngine.BuildMode.SHALLOW,
cachingBuildEngineBuckConfig.getBuildMetadataStorage(),
cachingBuildEngineBuckConfig.getBuildDepFiles(),
cachingBuildEngineBuckConfig.getBuildMaxDepFileCacheEntries(),
cachingBuildEngineBuckConfig.getBuildArtifactCacheSizeLimit(),
buildRuleResolver,
params.getBuildInfoStoreManager(),
cachingBuildEngineBuckConfig.getResourceAwareSchedulingInfo(),
RuleKeyFactories.of(
params.getBuckConfig().getKeySeed(),
cachingBuildEngineDelegate.getFileHashCache(),
buildRuleResolver,
cachingBuildEngineBuckConfig.getBuildInputRuleKeyFileSizeLimit(),
new DefaultRuleKeyCache<>())); ) {
// Create a BuildEngine because we store symbol information as build artifacts.
BuckEventBus eventBus = params.getBuckEventBus();
ExecutionContext executionContext =
ExecutionContext.builder()
.setConsole(params.getConsole())
.setConcurrencyLimit(concurrencyLimit)
.setBuckEventBus(eventBus)
.setEnvironment(/* environment */ ImmutableMap.of())
.setExecutors(
ImmutableMap.<ExecutorPool, ListeningExecutorService>of(
ExecutorPool.CPU, executorService))
.setJavaPackageFinder(params.getJavaPackageFinder())
.setPlatform(params.getPlatform())
.setCellPathResolver(params.getCell().getCellPathResolver())
.setProcessExecutor(new DefaultProcessExecutor(params.getConsole()))
.build();
SourcePathResolver pathResolver =
new SourcePathResolver(new SourcePathRuleFinder(buildRuleResolver));
BuildEngineBuildContext buildContext =
BuildEngineBuildContext.builder()
.setBuildContext(
BuildContext.builder()
// Note we do not create a real action graph because we do not need one.
.setActionGraph(new ActionGraph(ImmutableList.of()))
.setSourcePathResolver(pathResolver)
.setJavaPackageFinder(executionContext.getJavaPackageFinder())
.setEventBus(eventBus)
.build())
.setClock(params.getClock())
.setArtifactCache(params.getArtifactCacheFactory().newInstance())
.setBuildId(eventBus.getBuildId())
.setEnvironment(executionContext.getEnvironment())
.setKeepGoing(false)
.build();
// Traverse the TargetGraph to find all of the auto-generated dependencies.
JavaDepsFinder javaDepsFinder =
JavaDepsFinder.createJavaDepsFinder(
params.getBuckConfig(), buildContext, executionContext, buildEngine);
processor.process(graph, javaDepsFinder, executorService);
}
}
}
}