Bug 1444546 - Part 4b: Make AnnotationProcessor avoid writing, like Python's FileAvoidWrite. r=jchen draft
authorNick Alexander <nalexander@mozilla.com>
Mon, 26 Mar 2018 09:36:19 -0700
changeset 792122 b2e4aad7024123b42988b5ceb471d5be8a307839
parent 792121 201247e7df2534686759007284bb9244b4b9abb1
child 792123 5ca16f23556d5d49ff93bdaf46ee237ad8c1677f
push id108998
push usernalexander@mozilla.com
push dateMon, 07 May 2018 17:26:10 +0000
reviewersjchen
bugs1444546
milestone61.0a1
Bug 1444546 - Part 4b: Make AnnotationProcessor avoid writing, like Python's FileAvoidWrite. r=jchen This allows us to invoke AnnotationProcessor more than is strictly necessary and not trigger expensive native code compilations unless the native code has actually evolved. MozReview-Commit-ID: H1BIzJsdyIh
mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/AnnotationProcessor.java
--- a/mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/AnnotationProcessor.java
+++ b/mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/AnnotationProcessor.java
@@ -4,18 +4,24 @@
 
 package org.mozilla.gecko.annotationProcessors;
 
 import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
 import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
 import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
 import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.util.Arrays;
 import java.util.Iterator;
 
 public class AnnotationProcessor {
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
             "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
             "// from annotations on Java methods. To update, change the annotations on the\n" +
@@ -100,22 +106,25 @@ public class AnnotationProcessor {
                 "} /* mozilla */\n" +
                 "#endif // " + getHeaderGuardName(HEADER_FILE) + "\n");
 
         nativesFile.append(
                 "} /* java */\n" +
                 "} /* mozilla */\n" +
                 "#endif // " + getHeaderGuardName(NATIVES_FILE) + "\n");
 
-        writeOutputFile(SOURCE_FILE, implementationFile);
-        writeOutputFile(HEADER_FILE, headerFile);
-        writeOutputFile(NATIVES_FILE, nativesFile);
+        int ret = 0;
+        ret |= writeOutputFile(SOURCE_FILE, implementationFile);
+        ret |= writeOutputFile(HEADER_FILE, headerFile);
+        ret |= writeOutputFile(NATIVES_FILE, nativesFile);
 
         long e = System.currentTimeMillis();
         System.out.println("Annotation processing complete in " + (e - s) + "ms");
+
+        System.exit(ret);
     }
 
     private static void generateClass(final ClassWithOptions annotatedClass) {
         // Get an iterator over the appropriately generated methods of this class
         final GeneratableElementIterator methodIterator
                 = new GeneratableElementIterator(annotatedClass);
         final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses();
 
@@ -153,29 +162,37 @@ public class AnnotationProcessor {
             generateClass(innerClass);
         }
     }
 
     private static String getHeaderGuardName(final String name) {
         return name.replaceAll("\\W", "_");
     }
 
-    private static void writeOutputFile(final String name,
-                                        final StringBuilder content) {
-        FileOutputStream outStream = null;
+    private static int writeOutputFile(final String name, final StringBuilder content) {
+        final byte[] contentBytes = content.toString().getBytes(StandardCharsets.UTF_8);
+
         try {
-            outStream = new FileOutputStream(name);
-            outStream.write(content.toString().getBytes());
+            final byte[] existingBytes = Files.readAllBytes(new File(name).toPath());
+            if (Arrays.equals(contentBytes, existingBytes)) {
+                return 0;
+            }
+        } catch (FileNotFoundException e) {
+            // Pass.
+        } catch (NoSuchFileException e) {
+            // Pass.
+        } catch (IOException e) {
+            System.err.println("Unable to read " + name + ". Perhaps a permissions issue?");
+            e.printStackTrace(System.err);
+            return 1;
+        }
+
+        try (FileOutputStream outStream = new FileOutputStream(name)) {
+            outStream.write(contentBytes);
         } catch (IOException e) {
             System.err.println("Unable to write " + name + ". Perhaps a permissions issue?");
             e.printStackTrace(System.err);
-        } finally {
-            if (outStream != null) {
-                try {
-                    outStream.close();
-                } catch (IOException e) {
-                    System.err.println("Unable to close outStream due to "+e);
-                    e.printStackTrace(System.err);
-                }
-            }
+            return 1;
         }
+
+        return 0;
     }
 }