blob: e74ca179cff99b9bca8d85b846082a08fb7821d1 [file] [log] [blame]
/*
* 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;
}
}