From 1a4f79192868d1f5ee858cc4fc03285b7ade8215 Mon Sep 17 00:00:00 2001 From: Shahan Yang Date: Tue, 19 Dec 2017 14:50:53 -0800 Subject: Attempt #4 Adds FakeAutoCodecProcessor to bazel-distfile. Change-Id: Ie8dd0aa0ed6234fc3fd2e337fd50f9f7d5c7d2c1 PiperOrigin-RevId: 179607524 --- BUILD | 2 + .../autocodec/AutoCodecProcessor.java | 28 +---- .../serialization/autocodec/AutoCodecUtil.java | 42 ++++++++ .../lib/skyframe/serialization/autocodec/BUILD | 42 ++++++++ .../autocodec/FakeAutoCodecProcessor.java | 114 +++++++++++++++++++++ 5 files changed, 204 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecUtil.java create mode 100644 src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/FakeAutoCodecProcessor.java diff --git a/BUILD b/BUILD index f21bbad90c..32b9c62031 100644 --- a/BUILD +++ b/BUILD @@ -83,6 +83,7 @@ genrule( srcs = [ ":bazel-srcs", "//src:derived_java_srcs", + "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec:bootstrap_autocodec.tar", ], outs = ["bazel-distfile.zip"], cmd = "$(location :combine_distfiles) $@ $(SRCS)", @@ -96,6 +97,7 @@ genrule( srcs = [ ":bazel-srcs", "//src:derived_java_srcs", + "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec:bootstrap_autocodec.tar", ], outs = ["bazel-distfile.tar"], cmd = "$(location :combine_distfiles_to_tar.sh) $@ $(SRCS)", diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java index 29df3cb46e..ed54d58508 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java @@ -15,7 +15,6 @@ package com.google.devtools.build.lib.skyframe.serialization.autocodec; import com.google.auto.service.AutoService; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; @@ -55,10 +54,6 @@ import javax.tools.Diagnostic; */ @AutoService(Processor.class) public class AutoCodecProcessor extends AbstractProcessor { - // Synthesized classes will be prefixed with AutoCodec_. - public static final String GENERATED_CLASS_NAME_PREFIX = "AutoCodec"; - private static final Class ANNOTATION = AutoCodec.class; - /** * Passing {@code --javacopt=-Aautocodec_print_generated} to {@code blaze build} tells AutoCodec * to print the generated code. @@ -74,7 +69,7 @@ public class AutoCodecProcessor extends AbstractProcessor { @Override public Set getSupportedAnnotationTypes() { - return ImmutableSet.of(ANNOTATION.getCanonicalName()); + return ImmutableSet.of(AutoCodecUtil.ANNOTATION.getCanonicalName()); } @Override @@ -90,8 +85,8 @@ public class AutoCodecProcessor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - for (Element element : roundEnv.getElementsAnnotatedWith(ANNOTATION)) { - AutoCodec annotation = element.getAnnotation(ANNOTATION); + for (Element element : roundEnv.getElementsAnnotatedWith(AutoCodecUtil.ANNOTATION)) { + AutoCodec annotation = element.getAnnotation(AutoCodecUtil.ANNOTATION); switch (annotation.strategy()) { case CONSTRUCTOR: buildCodecUsingConstructor((TypeElement) element); @@ -120,7 +115,7 @@ public class AutoCodecProcessor extends AbstractProcessor { */ private void buildCodecUsingConstructor(TypeElement classElement) { TypeSpec.Builder codecClassBuilder = - TypeSpec.classBuilder(getCodecName(classElement)) + TypeSpec.classBuilder(AutoCodecUtil.getCodecName(classElement)) .superclass(TypeName.get(classElement.asType())); TypeElement encodedType = getEncodedType(classElement); @@ -166,21 +161,6 @@ public class AutoCodecProcessor extends AbstractProcessor { return "get" + name.substring(0, 1).toUpperCase() + name.substring(1) + "()"; } - /** - * Name of the generated codec class. - * - *

For {@code Foo.Bar.Codec} this is {@code AutoCodec_Foo_Bar_Codec}. - */ - private static String getCodecName(Element element) { - ImmutableList.Builder classNamesBuilder = new ImmutableList.Builder<>(); - do { - classNamesBuilder.add(element.getSimpleName().toString()); - element = element.getEnclosingElement(); - } while (element instanceof TypeElement); - classNamesBuilder.add(GENERATED_CLASS_NAME_PREFIX); - return classNamesBuilder.build().reverse().stream().collect(Collectors.joining("_")); - } - private void addSerializeMethodUsingConstructor( TypeSpec.Builder codecClassBuilder, TypeElement encodedType, diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecUtil.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecUtil.java new file mode 100644 index 0000000000..a4b39c8ee1 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecUtil.java @@ -0,0 +1,42 @@ +// Copyright 2017 The Bazel Authors. 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.lib.skyframe.serialization.autocodec; + +import com.google.common.collect.ImmutableList; +import java.util.stream.Collectors; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +/** Static utilities for AutoCodec processors. */ +class AutoCodecUtil { + // Synthesized classes will have `_AutoCodec` suffix added. + public static final String GENERATED_CLASS_NAME_SUFFIX = "AutoCodec"; + static final Class ANNOTATION = AutoCodec.class; + + /** + * Name of the generated codec class. + * + *

For {@code Foo.Bar} this is {@code Foo_Bar_AutoCodec}. + */ + static String getCodecName(Element element) { + ImmutableList.Builder classNamesBuilder = new ImmutableList.Builder<>(); + classNamesBuilder.add(GENERATED_CLASS_NAME_SUFFIX); + do { + classNamesBuilder.add(element.getSimpleName().toString()); + element = element.getEnclosingElement(); + } while (element instanceof TypeElement); + return classNamesBuilder.build().reverse().stream().collect(Collectors.joining("_")); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/BUILD index 5807597e65..193570ebb4 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/BUILD @@ -35,6 +35,7 @@ java_library( srcs = ["AutoCodecProcessor.java"], deps = [ ":autocodec-annotation", + ":autocodec-util", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization", "//third_party:auto_service", "//third_party:guava", @@ -42,3 +43,44 @@ java_library( "//third_party/protobuf:protobuf_java", ], ) + +# Code shared between autocodec-processor and fake-autocodec-processor. +java_library( + name = "autocodec-util", + srcs = ["AutoCodecUtil.java"], + deps = [ + ":autocodec-annotation", + "//third_party:guava", + ], +) + +# This is a fake implementation for bootstrapping. It must *not* be used in production. +java_library( + name = "fake-autocodec-processor", + srcs = ["FakeAutoCodecProcessor.java"], + deps = [ + ":autocodec-util", + "//src/main/java/com/google/devtools/build/lib/skyframe/serialization", + "//third_party:auto_service", + "//third_party:guava", + "//third_party/java/javapoet", + "//third_party/protobuf:protobuf_java", + ], +) + +load("//tools/build_defs/pkg:pkg.bzl", "pkg_tar") + +# .tar archive of dependencies used for bootstrapping. +pkg_tar( + name = "bootstrap_autocodec", + # The .jar files are created within the .tar file under third_party/bazel_bootstrap so that + # they will appear there in bazel-distfile, which in turn makes them visible for bootstrapping + # from the LIBRARY_JARS rule of bazel/scripts/bootstrap/compile.sh. + files = { + ":libautocodec-annotation.jar": "third_party/bazel_bootstrap/libautocodec-annotation.jar", + ":libautocodec-util.jar": "third_party/bazel_bootstrap/libautocodec-util.jar", + ":libfake-autocodec-processor.jar": "third_party/bazel_bootstrap/libfake-autocodec-processor.jar", + "//src/main/java/com/google/devtools/build/lib/skyframe/serialization:libserialization.jar": "third_party/bazel_bootstrap/libserialization.jar", + }, + visibility = ["//visibility:public"], +) diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/FakeAutoCodecProcessor.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/FakeAutoCodecProcessor.java new file mode 100644 index 0000000000..bdd8462a3b --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/FakeAutoCodecProcessor.java @@ -0,0 +1,114 @@ +// Copyright 2017 The Bazel Authors. 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.lib.skyframe.serialization.autocodec; + +import com.google.auto.service.AutoService; +import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; +import com.google.protobuf.CodedInputStream; +import com.google.protobuf.CodedOutputStream; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import java.io.IOException; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; + +/** + * A fake annotation processor for bootstrapping. + * + *

When bootstrapping, annotation processors inside the Bazel source tree are not available which + * means that if there are dependencies on generated code, bootstrapping will fail. This processor + * generates stub code to pass the initial boostrapping phase. + */ +@AutoService(Processor.class) +public class FakeAutoCodecProcessor extends AbstractProcessor { + private ProcessingEnvironment env; // Captured from `init` method. + + @Override + public Set getSupportedAnnotationTypes() { + return ImmutableSet.of(AutoCodecUtil.ANNOTATION.getCanonicalName()); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); // Supports all versions of Java. + } + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.env = processingEnv; + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (Element element : roundEnv.getElementsAnnotatedWith(AutoCodecUtil.ANNOTATION)) { + TypeElement encodedType = (TypeElement) element; + TypeSpec.Builder codecClassBuilder = + TypeSpec.classBuilder(AutoCodecUtil.getCodecName(encodedType)) + .addSuperinterface( + ParameterizedTypeName.get( + ClassName.get(ObjectCodec.class), TypeName.get(encodedType.asType()))); + codecClassBuilder.addMethod( + MethodSpec.methodBuilder("getEncodedClass") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns( + ParameterizedTypeName.get( + ClassName.get(Class.class), TypeName.get(encodedType.asType()))) + .addStatement("throw new RuntimeException(\"Shouldn't be called.\")") + .build()); + codecClassBuilder.addMethod( + MethodSpec.methodBuilder("serialize") + .addModifiers(Modifier.PUBLIC) + .addParameter(TypeName.get(encodedType.asType()), "input") + .addParameter(CodedOutputStream.class, "codedOut") + .addAnnotation(Override.class) + .addStatement("throw new RuntimeException(\"Shouldn't be called.\")") + .build()); + codecClassBuilder.addMethod( + MethodSpec.methodBuilder("deserialize") + .addModifiers(Modifier.PUBLIC) + .returns(TypeName.get(encodedType.asType())) + .addParameter(CodedInputStream.class, "codedIn") + .addAnnotation(Override.class) + .addStatement("throw new RuntimeException(\"Shouldn't be called.\")") + .build()); + String packageName = + env.getElementUtils().getPackageOf(encodedType).getQualifiedName().toString(); + try { + JavaFile file = JavaFile.builder(packageName, codecClassBuilder.build()).build(); + file.writeTo(env.getFiler()); + } catch (IOException e) { + env.getMessager() + .printMessage( + Diagnostic.Kind.ERROR, "Failed to generate output file: " + e.getMessage()); + } + } + return true; + } +} -- cgit v1.2.3