aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/java_tools/buildjar/java/com/google/devtools/build
diff options
context:
space:
mode:
authorGravatar Liam Miller-Cushon <cushon@google.com>2015-06-08 21:05:29 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2015-06-09 09:57:14 +0000
commit438126ce44e3c5c8313329e7d579f4c13c3e210f (patch)
tree24cc2e98a93024fe6f734b759a5acc89f3e770ae /src/java_tools/buildjar/java/com/google/devtools/build
parent50e3f04c17bb5d6d8adecbe2849b4ab887803d5d (diff)
Add --generated_class_output to JavaBuilder.
If enabled, JavaBuilder will write a jar containing classes generated by annotation processors to the given path. -- MOS_MIGRATED_REVID=95470914
Diffstat (limited to 'src/java_tools/buildjar/java/com/google/devtools/build')
-rw-r--r--src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractJavaBuilder.java3
-rw-r--r--src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractLibraryBuilder.java30
-rw-r--r--src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java68
-rw-r--r--src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java8
-rw-r--r--src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/processing/AnnotationProcessingModule.java108
-rw-r--r--src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/processing/AnnotationProcessingPlugin.java75
6 files changed, 275 insertions, 17 deletions
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractJavaBuilder.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractJavaBuilder.java
index 15349a1789..1ba28bf0bc 100644
--- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractJavaBuilder.java
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractJavaBuilder.java
@@ -168,6 +168,9 @@ public abstract class AbstractJavaBuilder extends AbstractLibraryBuilder {
if (build.getGeneratedSourcesOutputJar() != null) {
buildGensrcJar(build, err);
}
+ if (build.getGeneratedClassOutputJar() != null) {
+ buildGenclassJar(build);
+ }
}
successful = true;
} finally {
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractLibraryBuilder.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractLibraryBuilder.java
index cf1c985b0f..c402cc07a9 100644
--- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractLibraryBuilder.java
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/AbstractLibraryBuilder.java
@@ -22,6 +22,12 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
@@ -78,6 +84,30 @@ public abstract class AbstractLibraryBuilder extends CommonJavaLibraryProcessor
}
/**
+ * Build a jar file containing class files that were generated by an annotation processor.
+ */
+ public void buildGenclassJar(final JavaLibraryBuildRequest build) throws IOException {
+ final JarCreator jar = new JarCreator(build.getGeneratedClassOutputJar());
+ jar.setNormalize(true);
+ jar.setCompression(build.compressJar());
+ final Path classDir = Paths.get(build.getClassDir()).toAbsolutePath();
+ Files.walkFileTree(
+ classDir,
+ new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ throws IOException {
+ if (build.getProcessingModule().isGeneratedClass(file)) {
+ file = file.toAbsolutePath();
+ jar.addEntry(classDir.relativize(file).toString(), file.toString());
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ jar.execute();
+ }
+
+ /**
* Adds a collection of resource entries. Each entry is a string composed of a
* pair of parts separated by a colon ':'. The name of the resource comes from
* the second part, and the path to the resource comes from the whole string
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java
index 350da64e0e..4d14071d93 100644
--- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java
@@ -17,8 +17,10 @@ package com.google.devtools.build.buildjar;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.buildjar.javac.plugins.BlazeJavaCompilerPlugin;
import com.google.devtools.build.buildjar.javac.plugins.dependency.DependencyModule;
+import com.google.devtools.build.buildjar.javac.plugins.processing.AnnotationProcessingModule;
import java.io.IOException;
+import java.nio.file.Paths;
import java.util.List;
import java.util.Map.Entry;
@@ -38,6 +40,11 @@ public final class JavaLibraryBuildRequest {
*/
private final String generatedSourcesOutputJar;
+ /**
+ * The path to an output jar for classfiles generated by annotation processors.
+ */
+ private final String generatedClassOutputJar;
+
private final List<String> sourceFiles;
private final ImmutableList<String> sourceJars;
private final ImmutableList<String> messageFiles;
@@ -69,6 +76,11 @@ public final class JavaLibraryBuildRequest {
private final DependencyModule dependencyModule;
/**
+ * Repository for information about annotation processor-generated symbols.
+ */
+ private final AnnotationProcessingModule processingModule;
+
+ /**
* List of plugins that are given to javac.
*/
private final ImmutableList<BlazeJavaCompilerPlugin> plugins;
@@ -92,41 +104,54 @@ public final class JavaLibraryBuildRequest {
*
* @param args the list of command line args
* @param extraPlugins extraneous plugins to use in addition to the strict dependency module.
- * @param builder a preconstructed dependency module builder.
+ * @param depsBuilder a preconstructed dependency module builder.
* @throws InvalidCommandLineException on any command line error
*/
- public JavaLibraryBuildRequest(List<String> args, List<BlazeJavaCompilerPlugin> extraPlugins,
- DependencyModule.Builder builder)
+ public JavaLibraryBuildRequest(
+ List<String> args,
+ List<BlazeJavaCompilerPlugin> extraPlugins,
+ DependencyModule.Builder depsBuilder)
throws InvalidCommandLineException, IOException {
OptionsParser optionsParser = new OptionsParser(args);
- builder.addDirectMappings(optionsParser.getDirectMappings());
- builder.addIndirectMappings(optionsParser.getIndirectMappings());
+ depsBuilder.addDirectMappings(optionsParser.getDirectMappings());
+ depsBuilder.addIndirectMappings(optionsParser.getIndirectMappings());
if (optionsParser.getStrictJavaDeps() != null) {
- builder.setStrictJavaDeps(optionsParser.getStrictJavaDeps());
+ depsBuilder.setStrictJavaDeps(optionsParser.getStrictJavaDeps());
}
if (optionsParser.getOutputDepsFile() != null) {
- builder.setOutputDepsFile(optionsParser.getOutputDepsFile());
+ depsBuilder.setOutputDepsFile(optionsParser.getOutputDepsFile());
}
if (optionsParser.getOutputDepsProtoFile() != null) {
- builder.setOutputDepsProtoFile(optionsParser.getOutputDepsProtoFile());
+ depsBuilder.setOutputDepsProtoFile(optionsParser.getOutputDepsProtoFile());
}
- builder.addDepsArtifacts(optionsParser.getDepsArtifacts());
+ depsBuilder.addDepsArtifacts(optionsParser.getDepsArtifacts());
if (optionsParser.reduceClasspath()) {
- builder.setReduceClasspath();
+ depsBuilder.setReduceClasspath();
}
if (optionsParser.getRuleKind() != null) {
- builder.setRuleKind(optionsParser.getRuleKind());
+ depsBuilder.setRuleKind(optionsParser.getRuleKind());
}
if (optionsParser.getTargetLabel() != null) {
- builder.setTargetLabel(optionsParser.getTargetLabel());
+ depsBuilder.setTargetLabel(optionsParser.getTargetLabel());
}
- this.dependencyModule = builder.build();
+ this.dependencyModule = depsBuilder.build();
+
+ AnnotationProcessingModule.Builder processingBuilder = AnnotationProcessingModule.builder();
+ if (optionsParser.getSourceGenDir() != null) {
+ processingBuilder.setSourceGenDir(Paths.get(optionsParser.getSourceGenDir()));
+ }
+ if (optionsParser.getClassDir() != null) {
+ processingBuilder.setClassDir(Paths.get(optionsParser.getClassDir()));
+ }
+ this.processingModule = processingBuilder.build();
+
+ ImmutableList.Builder<BlazeJavaCompilerPlugin> pluginsBuilder =
+ ImmutableList.<BlazeJavaCompilerPlugin>builder().add(dependencyModule.getPlugin());
+ processingModule.registerPlugin(pluginsBuilder);
+ pluginsBuilder.addAll(extraPlugins);
+ this.plugins = pluginsBuilder.build();
- this.plugins = ImmutableList.<BlazeJavaCompilerPlugin>builder()
- .add(dependencyModule.getPlugin())
- .addAll(extraPlugins)
- .build();
this.compressJar = optionsParser.compressJar();
this.sourceFiles = optionsParser.getSourceFiles();
this.sourceJars = ImmutableList.copyOf(optionsParser.getSourceJars());
@@ -159,6 +184,7 @@ public final class JavaLibraryBuildRequest {
this.javacOpts = ImmutableList.copyOf(optionsParser.getJavacOpts());
this.sourceGenDir = optionsParser.getSourceGenDir();
this.generatedSourcesOutputJar = optionsParser.getGeneratedSourcesOutputJar();
+ this.generatedClassOutputJar = optionsParser.getGeneratedClassOutputJar();
}
public ImmutableList<String> getJavacOpts() {
@@ -177,6 +203,10 @@ public final class JavaLibraryBuildRequest {
return generatedSourcesOutputJar;
}
+ public String getGeneratedClassOutputJar() {
+ return generatedClassOutputJar;
+ }
+
public List<String> getSourceFiles() {
// TODO(bazel-team): This is being modified after parsing to add files from source jars.
return sourceFiles;
@@ -244,6 +274,10 @@ public final class JavaLibraryBuildRequest {
return dependencyModule;
}
+ public AnnotationProcessingModule getProcessingModule() {
+ return processingModule;
+ }
+
public ImmutableList<BlazeJavaCompilerPlugin> getPlugins() {
return plugins;
}
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java
index 99962bcca3..93c6c94576 100644
--- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java
@@ -51,6 +51,7 @@ public final class OptionsParser {
private String sourceGenDir;
private String generatedSourcesOutputJar;
+ private String generatedClassOutputJar;
private final List<String> sourceFiles = new ArrayList<>();
private final List<String> sourceJars = new ArrayList<>();
@@ -138,6 +139,9 @@ public final class OptionsParser {
case "--generated_sources_output":
generatedSourcesOutputJar = getArgument(argQueue, arg);
break;
+ case "--classes_from_generated_sources_output":
+ generatedClassOutputJar = getArgument(argQueue, arg);
+ break;
case "--sources":
collectFlagArguments(sourceFiles, argQueue, "-");
break;
@@ -335,6 +339,10 @@ public final class OptionsParser {
return generatedSourcesOutputJar;
}
+ public String getGeneratedClassOutputJar() {
+ return generatedClassOutputJar;
+ }
+
public List<String> getSourceFiles() {
return sourceFiles;
}
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/processing/AnnotationProcessingModule.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/processing/AnnotationProcessingModule.java
new file mode 100644
index 0000000000..e9d4c1832a
--- /dev/null
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/processing/AnnotationProcessingModule.java
@@ -0,0 +1,108 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// 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.google.devtools.build.buildjar.javac.plugins.processing;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.buildjar.javac.plugins.BlazeJavaCompilerPlugin;
+
+import java.nio.file.Path;
+import java.util.HashSet;
+
+/**
+ * A module for information about the compilation's annotation processing.
+ */
+public class AnnotationProcessingModule {
+
+ /**
+ * A builder for {@link AnnotationProcessingModule}s.
+ */
+ public static class Builder {
+ private Path sourceGenDir;
+ private Path classDir;
+
+ private Builder() {}
+
+ public AnnotationProcessingModule build() {
+ return new AnnotationProcessingModule(sourceGenDir, classDir);
+ }
+
+ public void setSourceGenDir(Path sourceGenDir) {
+ this.sourceGenDir = sourceGenDir.toAbsolutePath();
+ }
+
+ public void setClassDir(Path classDir) {
+ this.classDir = classDir.toAbsolutePath();
+ }
+ }
+
+ private final boolean enabled;
+ private final Path sourceGenDir;
+ private final Path classDir;
+
+ public Path sourceGenDir() {
+ return sourceGenDir;
+ }
+
+ private AnnotationProcessingModule(Path sourceGenDir, Path classDir) {
+ this.sourceGenDir = sourceGenDir;
+ this.classDir = classDir;
+ this.enabled = sourceGenDir != null && classDir != null;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public void registerPlugin(ImmutableList.Builder<BlazeJavaCompilerPlugin> builder) {
+ if (enabled) {
+ builder.add(new AnnotationProcessingPlugin(this));
+ }
+ }
+
+ /**
+ * The set of prefixes of generated class files.
+ */
+ private final HashSet<String> pathPrefixes = new HashSet<>();
+
+ /**
+ * Record the prefix of a group of generated class files.
+ *
+ * <p>Prefixes are used to handle generated inner classes. Since
+ * e.g. j/c/g/Foo.class and j/c/g/Foo$Inner.class both correspond to the
+ * same generated source file, only the prefix "j/c/g/Foo" is recorded.
+ */
+ void recordPrefix(String pathPrefix) {
+ pathPrefixes.add(pathPrefix);
+ }
+
+ /** Returns true if the given path is to a generated source file. */
+ public boolean isGeneratedSource(Path sourcePath) {
+ return sourcePath.toAbsolutePath().startsWith(sourceGenDir);
+ }
+
+ /** Returns true if the given path is to a generated class file. */
+ public boolean isGeneratedClass(Path path) {
+ if (!path.getFileName().toString().endsWith(".class")) {
+ return false;
+ }
+ String prefix = classDir.relativize(path.toAbsolutePath()).toString();
+ prefix = prefix.substring(0, prefix.length() - ".class".length());
+ int idx = prefix.lastIndexOf('$');
+ if (idx > 0) {
+ prefix = prefix.substring(0, idx);
+ }
+ return pathPrefixes.contains(prefix);
+ }
+}
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/processing/AnnotationProcessingPlugin.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/processing/AnnotationProcessingPlugin.java
new file mode 100644
index 0000000000..315e6fed88
--- /dev/null
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/processing/AnnotationProcessingPlugin.java
@@ -0,0 +1,75 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// 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.google.devtools.build.buildjar.javac.plugins.processing;
+
+import com.google.devtools.build.buildjar.javac.plugins.BlazeJavaCompilerPlugin;
+
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Env;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashSet;
+
+/**
+ * A plugin that records information about sources generated during annotation
+ * processing.
+ */
+public class AnnotationProcessingPlugin extends BlazeJavaCompilerPlugin {
+
+ private final HashSet<JCCompilationUnit> toplevels = new HashSet<>();
+ private final AnnotationProcessingModule processingModule;
+
+ public AnnotationProcessingPlugin(AnnotationProcessingModule processingModule) {
+ this.processingModule = processingModule;
+ }
+
+ @Override
+ public void postAttribute(Env<AttrContext> env) {
+ if (toplevels.add(env.toplevel)) {
+ recordSymbols(env.toplevel);
+ }
+ }
+
+ /**
+ * For each top-level type, record the path prefixes of that type's class,
+ * and all inner and anonymous classes declared inside that type.
+ *
+ * <p>e.g. for j.c.g.Foo we record the prefix j/c/g/Foo, which will match
+ * j/c/g/Foo.class, j/c/g/Foo$Inner.class, j/c/g/Foo$1.class, etc.
+ */
+ private void recordSymbols(JCCompilationUnit toplevel) {
+ if (toplevel.sourcefile == null) {
+ return;
+ }
+ Path sourcePath = Paths.get(toplevel.sourcefile.toUri());
+ if (!processingModule.isGeneratedSource(sourcePath)) {
+ return;
+ }
+ String packageBase = "";
+ if (toplevel.getPackageName() != null) {
+ packageBase = toplevel.getPackageName().toString().replace('.', '/') + "/";
+ }
+ for (JCTree decl : toplevel.defs) {
+ if (decl instanceof JCClassDecl) {
+ String pathPrefix = packageBase + ((JCClassDecl) decl).getSimpleName();
+ processingModule.recordPrefix(pathPrefix);
+ }
+ }
+ }
+}