blob: c16bc3be66167cd467afdb0a3fb9d77c673fdaa1 [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.java;
import static com.facebook.buck.rules.BuildableProperties.Kind.PACKAGING;
import com.facebook.buck.io.DirectoryTraverser;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.rules.AbstractBuildRule;
import com.facebook.buck.rules.BinaryBuildRule;
import com.facebook.buck.rules.BuildContext;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRules;
import com.facebook.buck.rules.BuildableContext;
import com.facebook.buck.rules.BuildableProperties;
import com.facebook.buck.rules.RuleKey;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.step.Step;
import com.facebook.buck.step.fs.MakeCleanDirectoryStep;
import com.facebook.buck.step.fs.MkdirAndSymlinkFileStep;
import com.facebook.buck.step.fs.MkdirStep;
import com.facebook.buck.util.BuckConstant;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedSet;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import javax.annotation.Nullable;
@BuildsAnnotationProcessor
public class JavaBinary extends AbstractBuildRule implements BinaryBuildRule, HasClasspathEntries {
private static final BuildableProperties OUTPUT_TYPE = new BuildableProperties(PACKAGING);
@Nullable
private final String mainClass;
@Nullable
private final SourcePath manifestFile;
private final boolean mergeManifests;
@Nullable
private final Path metaInfDirectory;
private final ImmutableSet<String> blacklist;
private final DirectoryTraverser directoryTraverser;
public JavaBinary(
BuildRuleParams params,
SourcePathResolver resolver,
@Nullable String mainClass,
@Nullable SourcePath manifestFile,
boolean mergeManifests,
@Nullable Path metaInfDirectory,
ImmutableSet<String> blacklist,
DirectoryTraverser directoryTraverser) {
super(params, resolver);
this.mainClass = mainClass;
this.manifestFile = manifestFile;
this.mergeManifests = mergeManifests;
this.metaInfDirectory = metaInfDirectory;
this.blacklist = blacklist;
this.directoryTraverser = directoryTraverser;
}
@Override
public RuleKey.Builder appendDetailsToRuleKey(RuleKey.Builder builder) {
return builder
.setReflectively("mainClass", mainClass)
.setReflectively("blacklist", blacklist);
}
@Override
public BuildableProperties getProperties() {
return OUTPUT_TYPE;
}
@Override
public ImmutableCollection<Path> getInputsToCompareToOutput() {
// Build a sorted set so that metaInfDirectory contents are listed in a canonical order.
ImmutableSortedSet.Builder<Path> builder = ImmutableSortedSet.naturalOrder();
if (manifestFile != null) {
builder.addAll(
getResolver().filterInputsToCompareToOutput(Collections.singleton(manifestFile)));
}
BuildRules.addInputsToSortedSet(metaInfDirectory, builder, directoryTraverser);
return builder.build();
}
@Override
public ImmutableList<Step> getBuildSteps(
BuildContext context,
BuildableContext buildableContext) {
ImmutableList.Builder<Step> commands = ImmutableList.builder();
Path outputDirectory = getOutputDirectory();
Step mkdir = new MkdirStep(outputDirectory);
commands.add(mkdir);
ImmutableSet<Path> includePaths;
if (metaInfDirectory != null) {
Path stagingRoot = outputDirectory.resolve("meta_inf_staging");
Path stagingTarget = stagingRoot.resolve("META-INF");
MakeCleanDirectoryStep createStagingRoot = new MakeCleanDirectoryStep(stagingRoot);
commands.add(createStagingRoot);
MkdirAndSymlinkFileStep link = new MkdirAndSymlinkFileStep(
metaInfDirectory, stagingTarget);
commands.add(link);
includePaths = ImmutableSet.<Path>builder()
.add(stagingRoot)
.addAll(getTransitiveClasspathEntries().values())
.build();
} else {
includePaths = ImmutableSet.copyOf(getTransitiveClasspathEntries().values());
}
Path outputFile = getPathToOutputFile();
Path manifestPath = manifestFile == null ? null : getResolver().getPath(manifestFile);
Step jar = new JarDirectoryStep(
outputFile,
includePaths,
mainClass,
manifestPath,
mergeManifests,
blacklist);
commands.add(jar);
buildableContext.recordArtifact(outputFile);
return commands.build();
}
@Override
public ImmutableSetMultimap<JavaLibrary, Path> getTransitiveClasspathEntries() {
return Classpaths.getClasspathEntries(getDeps());
}
private Path getOutputDirectory() {
return Paths.get(String.format("%s/%s", BuckConstant.GEN_DIR, getBuildTarget().getBasePath()));
}
@Override
public Path getPathToOutputFile() {
return Paths.get(
String.format(
"%s/%s.jar",
getOutputDirectory(),
getBuildTarget().getShortNameAndFlavorPostfix()));
}
@Override
public ImmutableList<String> getExecutableCommand(ProjectFilesystem projectFilesystem) {
Preconditions.checkState(
mainClass != null,
"Must specify a main class for %s in order to to run it.",
getBuildTarget());
return ImmutableList.of("java", "-jar",
projectFilesystem.getAbsolutifier().apply(getPathToOutputFile()).toString());
}
}