| /* |
| * 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.extension; |
| |
| import com.facebook.buck.java.Classpaths; |
| import com.facebook.buck.java.CopyResourcesStep; |
| import com.facebook.buck.java.JarDirectoryStep; |
| import com.facebook.buck.java.JavacOptions; |
| import com.facebook.buck.java.JavacStep; |
| import com.facebook.buck.model.BuildTarget; |
| import com.facebook.buck.model.BuildTargets; |
| import com.facebook.buck.rules.AbstractBuildRule; |
| import com.facebook.buck.rules.BuildContext; |
| import com.facebook.buck.rules.BuildDependencies; |
| import com.facebook.buck.rules.BuildRuleParams; |
| import com.facebook.buck.rules.BuildableContext; |
| 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.MkdirStep; |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Optional; |
| 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.ImmutableSortedSet; |
| import com.google.common.collect.Iterables; |
| |
| import java.io.File; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.nio.file.Path; |
| import java.util.Collection; |
| |
| /** |
| * Builds an extension for buck. This is similar to a {@code java_library}, but will automatically |
| * have the classpath of buck itself added to its dependencies. |
| */ |
| public class BuckExtension extends AbstractBuildRule { |
| |
| private final JavacOptions javacOptions; |
| private final ImmutableSortedSet<? extends SourcePath> srcs; |
| private final ImmutableSortedSet<? extends SourcePath> resources; |
| private final Path output; |
| private final Path working; |
| |
| public BuckExtension( |
| BuildRuleParams params, |
| JavacOptions javacOptions, |
| SourcePathResolver resolver, |
| ImmutableSortedSet<? extends SourcePath> srcs, |
| ImmutableSortedSet<? extends SourcePath> resources) { |
| super(params, resolver); |
| |
| this.javacOptions = javacOptions; |
| this.srcs = srcs; |
| this.resources = resources; |
| |
| BuildTarget target = params.getBuildTarget(); |
| this.output = BuildTargets.getGenPath(target, "%s-buck.jar"); |
| this.working = BuildTargets.getBinPath(target, "__%s__"); |
| } |
| |
| @Override |
| public ImmutableCollection<Path> getInputsToCompareToOutput() { |
| return getResolver().filterInputsToCompareToOutput(Iterables.concat(srcs, resources)); |
| } |
| |
| @Override |
| public ImmutableList<Step> getBuildSteps( |
| BuildContext context, |
| BuildableContext buildableContext) { |
| |
| ImmutableSortedSet.Builder<Path> classpath = ImmutableSortedSet.naturalOrder(); |
| ImmutableCollection<Path> depPaths = Classpaths.getClasspathEntries(getDeclaredDeps()).values(); |
| classpath.addAll(depPaths); |
| readBuckClasspath(classpath); |
| ImmutableSortedSet<Path> declaredClasspath = classpath.build(); |
| |
| ImmutableList.Builder<Step> steps = ImmutableList.builder(); |
| |
| steps.add(new MakeCleanDirectoryStep(working)); |
| steps.add(new MkdirStep(output.getParent())); |
| |
| steps.add( |
| new JavacStep( |
| working, |
| Optional.<Path>absent(), |
| ImmutableSet.copyOf(getResolver().getAllPaths(srcs)), |
| Optional.<Path>absent(), |
| /* transitive classpath */ ImmutableSortedSet.<Path>of(), |
| declaredClasspath, |
| javacOptions, |
| getBuildTarget(), |
| BuildDependencies.FIRST_ORDER_ONLY, |
| Optional.<JavacStep.SuggestBuildRules>absent())); |
| steps.add(new CopyResourcesStep( |
| getResolver(), |
| getBuildTarget(), |
| resources, |
| output, |
| context.getJavaPackageFinder())); |
| steps.add(new JarDirectoryStep( |
| output, |
| ImmutableSortedSet.<Path>naturalOrder().add(working).addAll(depPaths).build(), |
| /* main class */ null, |
| /* manifest file */ null)); |
| |
| return steps.build(); |
| } |
| |
| @VisibleForTesting |
| static Collection<Path> readBuckClasspath(ImmutableSortedSet.Builder<Path> builder) { |
| ClassLoader classLoader = BuckExtension.class.getClassLoader(); |
| Preconditions.checkState(classLoader instanceof URLClassLoader); |
| |
| @SuppressWarnings("resource") |
| // Because this ClassLoader comes from BuckExtension.class, it is not obvious that it would |
| // be safe to close it. See |
| // http://docs.oracle.com/javase/7/docs/technotes/guides/net/ClassLoader.html. |
| URLClassLoader urlLoader = (URLClassLoader) classLoader; |
| for (URL url : urlLoader.getURLs()) { |
| try { |
| if (!"file".equals(url.toURI().getScheme())) { |
| continue; |
| } |
| builder.add(new File(url.toURI()).toPath().toAbsolutePath().normalize()); |
| } catch (URISyntaxException e) { |
| // There's no sane way that this will happen. |
| throw new RuntimeException(e); |
| } |
| } |
| |
| return builder.build(); |
| } |
| |
| @Override |
| public RuleKey.Builder appendDetailsToRuleKey(RuleKey.Builder builder) { |
| return builder; |
| } |
| |
| @Override |
| public Path getPathToOutputFile() { |
| return output; |
| } |
| } |