blob: 4e75311213594d31118741d489d3a7082d0be5af [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.cli;
import com.facebook.buck.event.BuckEventBus;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.parser.BuildTargetParser;
import com.facebook.buck.parser.NoSuchBuildTargetException;
import com.facebook.buck.parser.ParseContext;
import com.facebook.buck.parser.Parser;
import com.facebook.buck.rules.ArtifactCache;
import com.facebook.buck.rules.DependencyGraph;
import com.facebook.buck.rules.KnownBuildRuleTypes;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.util.Console;
import com.facebook.buck.util.ProjectFilesystem;
import com.facebook.buck.util.environment.Platform;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import javax.annotation.Nullable;
abstract class AbstractCommandRunner<T extends AbstractCommandOptions> implements CommandRunner {
private final CommandRunnerParams commandRunnerParams;
protected final Console console;
private final ProjectFilesystem projectFilesystem;
private final KnownBuildRuleTypes buildRuleTypes;
private final ArtifactCacheFactory artifactCacheFactory;
private final Parser parser;
private final BuckEventBus eventBus;
private final Platform platform;
/** This is constructed lazily. */
@Nullable private T options;
/** This is constructed lazily. */
@Nullable private volatile ArtifactCache artifactCache;
protected AbstractCommandRunner(CommandRunnerParams params) {
this.commandRunnerParams = Preconditions.checkNotNull(params);
this.console = Preconditions.checkNotNull(params.getConsole());
this.projectFilesystem = Preconditions.checkNotNull(params.getProjectFilesystem());
this.buildRuleTypes = Preconditions.checkNotNull(params.getBuildRuleTypes());
this.artifactCacheFactory = Preconditions.checkNotNull(params.getArtifactCacheFactory());
this.parser = Preconditions.checkNotNull(params.getParser());
this.eventBus = Preconditions.checkNotNull(params.getBuckEventBus());
this.platform = Preconditions.checkNotNull(params.getPlatform());
}
abstract T createOptions(BuckConfig buckConfig);
private ParserAndOptions<T> createParser(BuckConfig buckConfig) {
T options = createOptions(buckConfig);
return new ParserAndOptions<>(options);
}
@Override
public final int runCommand(BuckConfig buckConfig, String... args) throws IOException {
ParserAndOptions<T> parserAndOptions = createParser(buckConfig);
T options = parserAndOptions.options;
CmdLineParser parser = parserAndOptions.parser;
boolean hasValidOptions = false;
try {
parser.parseArgument(args);
hasValidOptions = true;
} catch (CmdLineException e) {
console.getStdErr().println(e.getMessage());
}
if (hasValidOptions && !options.showHelp()) {
return runCommandWithOptions(options);
} else {
printUsage(parser);
return 1;
}
}
public final void printUsage(CmdLineParser parser) {
String intro = getUsageIntro();
if (intro != null) {
getStdErr().println(intro);
}
parser.printUsage(getStdErr());
}
/**
* @return the exit code this process should exit with
*/
public synchronized final int runCommandWithOptions(T options) throws IOException {
this.options = options;
return runCommandWithOptionsInternal(options);
}
/**
* Invoked by {@link #runCommandWithOptions(AbstractCommandOptions)} after {@code #options} has
* been set.
* @return the exit code this process should exit with
*/
abstract int runCommandWithOptionsInternal(T options) throws IOException;
/**
* @return may be null
*/
abstract String getUsageIntro();
/**
* Sometimes a {@link CommandRunner} needs to create another {@link CommandRunner}, so it should
* use this method so it can reuse the constructor parameter that it received.
*/
protected CommandRunnerParams getCommandRunnerParams() {
return commandRunnerParams;
}
public ProjectFilesystem getProjectFilesystem() {
return projectFilesystem;
}
public KnownBuildRuleTypes getBuildRuleTypes() {
return buildRuleTypes;
}
/**
* @return A list of {@link BuildTarget}s for the input buildTargetNames.
*/
protected ImmutableList<BuildTarget> getBuildTargets(List<String> buildTargetNames)
throws NoSuchBuildTargetException, IOException {
Preconditions.checkNotNull(buildTargetNames);
ImmutableList.Builder<BuildTarget> buildTargets = ImmutableList.builder();
// Parse all of the build targets specified by the user.
BuildTargetParser buildTargetParser = getParser().getBuildTargetParser();
for (String buildTargetName : buildTargetNames) {
buildTargets.add(buildTargetParser.parse(buildTargetName, ParseContext.fullyQualified()));
}
return buildTargets.build();
}
public ArtifactCache getArtifactCache() {
// Lazily construct the ArtifactCache, as not all commands (like `buck clean`) need it.
if (artifactCache == null) {
synchronized (this) {
if (artifactCache == null) {
Preconditions.checkNotNull(options,
"getArtifactCache() should not be invoked before runCommand().");
artifactCache = artifactCacheFactory.newInstance(options);
}
}
}
return artifactCache;
}
protected PrintStream getStdOut() {
return console.getStdOut();
}
protected PrintStream getStdErr() {
return console.getStdErr();
}
protected BuckEventBus getBuckEventBus() {
return eventBus;
}
/**
* @return Returns a potentially cached Parser for this command.
*/
public Parser getParser() {
return parser;
}
private static class ParserAndOptions<T> {
private final T options;
private final CmdLineParser parser;
private ParserAndOptions(T options) {
this.options = options;
this.parser = new CmdLineParserAdditionalOptions(options);
}
}
protected ExecutionContext createExecutionContext(
T options,
DependencyGraph dependencyGraph) {
return ExecutionContext.builder()
.setProjectFilesystem(getProjectFilesystem())
.setConsole(console)
.setAndroidPlatformTarget(
options.findAndroidPlatformTarget(dependencyGraph, getBuckEventBus()))
.setNdkRoot(options.findAndroidNdkDir(getProjectFilesystem()))
.setEventBus(eventBus)
.setPlatform(platform)
.build();
}
}