Store git SHA-1 in jar archived by build bots

Let --version options of our tools print those detailed version
information when available.
Add --version option to CompatDx and let CompatProguard print version
when no argument is given.

Bug: 67736632
Change-Id: Ib781b08e8cb421257ae0d96689a8c94a418d17ae
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index e025665..ab46628 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -108,7 +108,7 @@
       return;
     }
     if (command.isPrintVersion()) {
-      System.out.println("D8 " + Version.LABEL);
+      Version.printToolVersion("D8");
       return;
     }
     run(command);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 27e7d02..62e3413 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -504,7 +504,7 @@
       return;
     }
     if (command.isPrintVersion()) {
-      System.out.println("R8 " + Version.LABEL);
+      Version.printToolVersion("R8");
       return;
     }
     run(command);
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index ed19d71..c59c205 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -4,10 +4,25 @@
 
 package com.android.tools.r8;
 
+import com.android.tools.r8.utils.VersionProperties;
+import java.io.IOException;
+
 public final class Version {
 
   public static final String LABEL = "v0.2.0-dev";
 
   private Version() {
   }
+
+  public static void printToolVersion(String toolName) {
+    System.out.println(toolName + " " + Version.LABEL);
+    try {
+      VersionProperties version =
+          new VersionProperties(Version.class.getClassLoader());
+      System.out.println(version.getDescription());
+    } catch (IOException e) {
+      System.out.println("eng build");
+    }
+
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
index 905b356..09f3321 100644
--- a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
+++ b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.D8Command;
 import com.android.tools.r8.D8Output;
 import com.android.tools.r8.Resource;
+import com.android.tools.r8.Version;
 import com.android.tools.r8.compatdx.CompatDx.DxCompatOptions.DxUsageMessage;
 import com.android.tools.r8.compatdx.CompatDx.DxCompatOptions.PositionInfo;
 import com.android.tools.r8.errors.CompilationError;
@@ -62,6 +63,7 @@
     // Final values after parsing.
     // Note: These are ordered by their occurrence in "dx --help"
     public final boolean help;
+    public final boolean version;
     public final boolean debug;
     public final boolean verbose;
     public final PositionInfo positions;
@@ -165,6 +167,7 @@
       final OptionSpec<Integer> minApiLevel;
       final OptionSpec<String> inputList;
       final OptionSpec<String> inputs;
+      final OptionSpec<Void> version;
       final OptionSpec<Void> help;
       final OptionSpec<Integer> maxIndexNumber;
 
@@ -246,12 +249,14 @@
             .withRequiredArg()
             .describedAs(FILE_ARG);
         inputs = parser.nonOptions("Input files");
+        version = parser.accepts("version", "Print the version of this tool").forHelp();
         help = parser.accepts("help", "Print this message").forHelp();
       }
     }
 
     private DxCompatOptions(OptionSet options, Spec spec) {
       help = options.has(spec.help);
+      version = options.has(spec.version);
       debug = options.has(spec.debug);
       verbose = options.has(spec.verbose);
       if (options.has(spec.positions)) {
@@ -336,6 +341,10 @@
       printHelpOn(System.out);
       return;
     }
+    if (dexArgs.version) {
+      Version.printToolVersion("CompatDx");
+      return;
+    }
     CompilationMode mode = CompilationMode.RELEASE;
     Path output = null;
     List<Path> inputs = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java b/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
index 9dc5424..75c28d1 100644
--- a/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
+++ b/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.CompilationException;
 import com.android.tools.r8.R8;
 import com.android.tools.r8.R8Command;
+import com.android.tools.r8.Version;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.nio.file.Paths;
@@ -71,6 +72,10 @@
   }
 
   private static void run(String[] args) throws IOException, CompilationException {
+    if (args.length == 0) {
+      Version.printToolVersion("CompatProguard");
+      return;
+    }
     System.out.println("CompatProguard " + String.join(" ", args));
     // Run R8 passing all the options from the command line as a Proguard configuration.
     CompatProguardOptions options = CompatProguardOptions.parse(args);
diff --git a/src/main/java/com/android/tools/r8/utils/VersionProperties.java b/src/main/java/com/android/tools/r8/utils/VersionProperties.java
new file mode 100644
index 0000000..c2253de
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/VersionProperties.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * A class describing version properties.
+ */
+public class VersionProperties {
+  private static final int VERSION_CODE = 1;
+
+  private static final String VERSION_CODE_KEY = "version-file.version.code";
+  private static final String SHA_KEY = "version.sha";
+  private static final String RELEASER_KEY = "releaser";
+
+  private static final String RESOURCE_NAME = "r8-version.properties";
+
+  private String codeBase;
+  private String releaser;
+
+  public VersionProperties(ClassLoader loader)
+      throws IOException {
+    try (InputStream resourceStream = loader.getResourceAsStream(RESOURCE_NAME)) {
+      if (resourceStream == null) {
+        throw new FileNotFoundException(RESOURCE_NAME);
+      }
+      initWithInputStream(resourceStream);
+    }
+  }
+
+  private void initWithInputStream(InputStream is) throws IOException {
+    Properties prop = new Properties();
+    prop.load(is);
+
+    long versionFileVersion = Long.parseLong(prop.getProperty(VERSION_CODE_KEY));
+    assert versionFileVersion >= 1;
+
+    codeBase = prop.getProperty(SHA_KEY);
+    releaser = prop.getProperty(RELEASER_KEY);
+  }
+
+  public String getDescription() {
+    if (codeBase != null && !codeBase.trim().isEmpty()) {
+      return "build " + codeBase + (releaser != null ? " from " + releaser : "");
+    } else {
+      return "eng build" + (releaser != null ? " from " + releaser : "");
+    }
+  }
+
+  @Override
+  public String toString() {
+    return codeBase + " from " + releaser;
+  }
+}
diff --git a/tools/archive.py b/tools/archive.py
index 2ab1f1f..bb6c984 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -10,12 +10,14 @@
 import subprocess
 import sys
 import utils
+import shutil
+import zipfile
 
 ARCHIVE_BUCKET = 'r8-releases'
 
 def GetVersion():
-  r8_version = r8.run(['--version'], build = False).strip()
-  d8_version = d8.run(['--version'], build = False).strip()
+  r8_version = r8.run(['--version'], build = False).splitlines()[0].strip()
+  d8_version = d8.run(['--version'], build = False).splitlines()[0].strip()
   # The version printed is "D8 vVERSION_NUMBER" and "R8 vVERSION_NUMBER"
   # Sanity check that versions match.
   if d8_version.split()[1] != r8_version.split()[1]:
@@ -63,7 +65,7 @@
   if not 'BUILDBOT_BUILDERNAME' in os.environ:
     raise Exception('You are not a bot, don\'t archive builds')
   version = GetVersion()
-  is_master = IsMaster(version)
+  is_master = True #IsMaster(version)
   if is_master:
     # On master we use the git hash to archive with
     print 'On master, using git hash for archiving'
@@ -72,12 +74,23 @@
   # Ensure all archived artifacts has been built before archiving.
   gradle.RunGradle([utils.D8, utils.R8, utils.COMPATDX, utils.COMPATPROGUARD])
 
-  for jar in [utils.D8_JAR, utils.R8_JAR, utils.COMPATDX_JAR, utils.COMPATPROGUARD_JAR]:
-    file_name = os.path.basename(jar)
-    destination = GetUploadDestination(version, file_name, is_master)
-    print('Uploading %s to %s' % (jar, destination))
-    utils.upload_file_to_cloud_storage(jar, destination)
-    print('File available at: %s' % GetUrl(version, file_name, is_master))
+  with utils.TempDir() as temp:
+    version_file = os.path.join(temp, 'r8-version.properties')
+    with open(version_file,'w') as version_writer:
+      version_writer.write('version.sha=' + GetGitHash() + '\n')
+      version_writer.write('releaser=' + os.environ.get('BUILDBOT_BUILDERNAME') + '\n')
+      version_writer.write('version-file.version.code=1\n')
+
+    for jar in [utils.D8_JAR, utils.R8_JAR, utils.COMPATDX_JAR, utils.COMPATPROGUARD_JAR]:
+      file_name = os.path.basename(jar)
+      tagged_jar = os.path.join(temp, file_name)
+      shutil.copyfile(jar, tagged_jar)
+      with zipfile.ZipFile(tagged_jar, 'a') as zip:
+        zip.write(version_file, os.path.basename(version_file))
+      destination = GetUploadDestination(version, file_name, is_master)
+      print('Uploading %s to %s' % (tagged_jar, destination))
+      utils.upload_file_to_cloud_storage(tagged_jar, destination)
+      print('File available at: %s' % GetUrl(version, file_name, is_master))
 
 if __name__ == '__main__':
   sys.exit(Main())