/* * Copyright 2014-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.jvm.java; import com.facebook.buck.cxx.CxxPlatform; import com.facebook.buck.cxx.CxxPlatforms; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.Flavor; import com.facebook.buck.model.InternalFlavor; import com.facebook.buck.parser.NoSuchBuildTargetException; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.CellPathResolver; import com.facebook.buck.rules.CommonDescriptionArg; import com.facebook.buck.rules.Description; import com.facebook.buck.rules.HasDeclaredDeps; import com.facebook.buck.rules.HasTests; import com.facebook.buck.rules.ImplicitDepsInferringDescription; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathRuleFinder; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.util.immutables.BuckStyleImmutable; import com.facebook.buck.versions.VersionRoot; import com.google.common.base.Preconditions; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import java.nio.file.Path; import java.util.Optional; import java.util.regex.Pattern; import org.immutables.value.Value; public class JavaBinaryDescription implements Description<JavaBinaryDescriptionArg>, ImplicitDepsInferringDescription<JavaBinaryDescription.AbstractJavaBinaryDescriptionArg>, VersionRoot<JavaBinaryDescriptionArg> { private static final Flavor FAT_JAR_INNER_JAR_FLAVOR = InternalFlavor.of("inner-jar"); private final JavacOptions javacOptions; private final CxxPlatform cxxPlatform; private final JavaOptions javaOptions; private final JavaBuckConfig javaBuckConfig; public JavaBinaryDescription( JavaOptions javaOptions, JavacOptions javacOptions, CxxPlatform cxxPlatform, JavaBuckConfig javaBuckConfig) { this.javaOptions = javaOptions; this.javacOptions = Preconditions.checkNotNull(javacOptions); this.cxxPlatform = Preconditions.checkNotNull(cxxPlatform); this.javaBuckConfig = Preconditions.checkNotNull(javaBuckConfig); } @Override public Class<JavaBinaryDescriptionArg> getConstructorArgType() { return JavaBinaryDescriptionArg.class; } @Override public BuildRule createBuildRule( TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, CellPathResolver cellRoots, JavaBinaryDescriptionArg args) throws NoSuchBuildTargetException { SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver); ImmutableMap<String, SourcePath> nativeLibraries = JavaLibraryRules.getNativeLibraries(params.getBuildDeps(), cxxPlatform); BuildRuleParams binaryParams = params; // If we're packaging native libraries, we'll build the binary JAR in a separate rule and // package it into the final fat JAR, so adjust it's params to use a flavored target. if (!nativeLibraries.isEmpty()) { binaryParams = params.withAppendedFlavor(FAT_JAR_INNER_JAR_FLAVOR); } // Construct the build rule to build the binary JAR. ImmutableSet<JavaLibrary> transitiveClasspathDeps = JavaLibraryClasspathProvider.getClasspathDeps(binaryParams.getBuildDeps()); ImmutableSet<SourcePath> transitiveClasspaths = JavaLibraryClasspathProvider.getClasspathsFromLibraries(transitiveClasspathDeps); BuildRule rule = new JavaBinary( binaryParams.copyAppendingExtraDeps(transitiveClasspathDeps), javaOptions.getJavaRuntimeLauncher(), args.getMainClass().orElse(null), args.getManifestFile().orElse(null), args.getMergeManifests().orElse(true), args.getMetaInfDirectory().orElse(null), args.getBlacklist(), transitiveClasspathDeps, transitiveClasspaths, javaBuckConfig.shouldCacheBinaries()); // If we're packaging native libraries, construct the rule to build the fat JAR, which packages // up the original binary JAR and any required native libraries. if (!nativeLibraries.isEmpty()) { BuildRule innerJarRule = rule; resolver.addToIndex(innerJarRule); SourcePath innerJar = innerJarRule.getSourcePathToOutput(); rule = new JarFattener( params.copyAppendingExtraDeps( Suppliers.<Iterable<BuildRule>>ofInstance( ruleFinder.filterBuildRuleInputs( ImmutableList.<SourcePath>builder() .add(innerJar) .addAll(nativeLibraries.values()) .build()))), ruleFinder, JavacFactory.create(ruleFinder, javaBuckConfig, null), javacOptions, innerJar, nativeLibraries, javaOptions.getJavaRuntimeLauncher()); } return rule; } @Override public void findDepsForTargetFromConstructorArgs( BuildTarget buildTarget, CellPathResolver cellRoots, AbstractJavaBinaryDescriptionArg constructorArg, ImmutableCollection.Builder<BuildTarget> extraDepsBuilder, ImmutableCollection.Builder<BuildTarget> targetGraphOnlyDepsBuilder) { extraDepsBuilder.addAll(CxxPlatforms.getParseTimeDeps(cxxPlatform)); } @Override public boolean isVersionRoot(ImmutableSet<Flavor> flavors) { return true; } @BuckStyleImmutable @Value.Immutable interface AbstractJavaBinaryDescriptionArg extends CommonDescriptionArg, HasDeclaredDeps, HasTests { Optional<String> getMainClass(); Optional<SourcePath> getManifestFile(); Optional<Boolean> getMergeManifests(); Optional<Path> getMetaInfDirectory(); ImmutableSet<Pattern> getBlacklist(); } }