blob: a1826bd46be6cabfb769562314f1c8add6dc7d9b [file] [log] [blame]
/*
* Copyright 2012-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.step;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.util.concurrent.MoreFutures;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
public final class DefaultStepRunner implements StepRunner {
private final ExecutionContext context;
private final ListeningExecutorService listeningExecutorService;
/**
* This StepRunner will run all steps on the same thread.
*/
public DefaultStepRunner(ExecutionContext context) {
this(context, MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1)));
}
public DefaultStepRunner(ExecutionContext context,
ListeningExecutorService listeningExecutorService) {
this.context = Preconditions.checkNotNull(context);
this.listeningExecutorService = Preconditions.checkNotNull(listeningExecutorService);
}
@Override
public ListeningExecutorService getListeningExecutorService() {
return listeningExecutorService;
}
@Override
public void runStep(Step step) throws StepFailedException {
runStepInternal(step, Optional.<BuildTarget>absent());
}
@Override
public void runStepForBuildTarget(Step step, BuildTarget buildTarget) throws StepFailedException {
runStepInternal(step, Optional.of(buildTarget));
}
protected void runStepInternal(final Step step, final Optional<BuildTarget> buildTarget)
throws StepFailedException {
Preconditions.checkNotNull(step);
if (context.getVerbosity().shouldPrintCommand()) {
context.getStdErr().println(step.getDescription(context));
}
context.postEvent(StepEvent.started(step, step.getDescription(context)));
int exitCode = step.execute(context);
context.postEvent(StepEvent.finished(step, step.getDescription(context), exitCode));
if (exitCode != 0) {
throw StepFailedException.createForFailingStep(step, context, exitCode, buildTarget);
}
}
@Override
public <T> ListenableFuture<T> runStepsAndYieldResult(final List<Step> steps,
final Callable<T> interpretResults,
final BuildTarget buildTarget) {
Callable<T> callable = new Callable<T>() {
@Override
public T call() throws Exception {
for (Step step : steps) {
runStepForBuildTarget(step, buildTarget);
}
return interpretResults.call();
}
};
return listeningExecutorService.submit(callable);
}
/**
* Run multiple steps in parallel and block waiting for all of them to finish. An
* exception is thrown (immediately) if any step fails.
*
* @param steps List of steps to execute.
*/
public void runStepsInParallelAndWait(final List<Step> steps)
throws StepFailedException {
List<Callable<Void>> callables = Lists.transform(steps,
new Function<Step, Callable<Void>>() {
@Override
public Callable<Void> apply(final Step step) {
return new Callable<Void>() {
@Override
public Void call() throws Exception {
runStep(step);
return null;
}
};
}
});
try {
MoreFutures.getAllUninterruptibly(getListeningExecutorService(), callables);
} catch (ExecutionException e) {
Throwable cause = e.getCause();
Throwables.propagateIfInstanceOf(cause, StepFailedException.class);
// Programmer error. Boo-urns.
throw new RuntimeException(cause);
}
}
}