Convert most of dex2oat script to python and add version support.

Change-Id: Ib18211b12cc83fa371f4ac3f6bec083504af9fd7
diff --git a/scripts/run-dex2oat.sh b/scripts/run-dex2oat.sh
deleted file mode 100755
index 125607e..0000000
--- a/scripts/run-dex2oat.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-#! /bin/bash
-#
-# Copyright (c) 2016, 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.
-
-set -e
-
-if [ -z "$R8_HOME" ]; then
-  R8_HOME="$(realpath $(dirname ${BASH_SOURCE[0]})/..)"
-fi
-
-TOOLSDIR=$R8_HOME/tools/linux
-
-function usage {
-  echo "Usage: $(basename $0) <dex files>"
-  exit 1
-}
-
-# Process options.
-while [ $# -gt 0 ]; do
-  case $1 in
-    -h)
-      usage
-      ;;
-    *)
-      break
-      ;;
-  esac
-done
-
-if [ $# -eq 0 ]; then
-  usage
-fi
-
-TMPDIR=$(mktemp -d "${TMP:-/tmp/}$(basename $0).XXXXXXXXXXXX")
-OATFILE=$TMPDIR/all.oat
-
-if [ $# -gt 1 ]; then
-  JARFILE="$TMPDIR/all.jar"
-  for f in "$@"; do
-    IR=$(dirname "$f")
-    BASE=$(basename "$f")
-    EXT=$(echo "$BASE" | cut -d '.' -f 2)
-    if [ "$EXT" = "dex" ]; then
-      (cd "$DIR" && zip "$JARFILE" "$BASE")
-    else
-      echo "Warning: ignoring non-dex file argument when dex2oat'ing multiple files."
-    fi
-  done
-else
-  JARFILE="$1"
-fi
-
-LD_LIBRARY_PATH=$TOOLSDIR/art/lib $TOOLSDIR/art/bin/dex2oat \
-  --android-root=$TOOLSDIR/art/product/angler \
-  --runtime-arg -Xnorelocate \
-  --boot-image=$TOOLSDIR/art/product/angler/system/framework/boot.art \
-  --dex-file=$JARFILE \
-  --oat-file=$OATFILE \
-  --instruction-set=arm64
-
-rm -rf $TMPDIR
diff --git a/tools/dex2oat.py b/tools/dex2oat.py
new file mode 100755
index 0000000..eab424f
--- /dev/null
+++ b/tools/dex2oat.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+# Copyright (c) 2018, 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.
+
+import optparse
+import os
+import subprocess
+import sys
+
+import utils
+
+LINUX_DIR = os.path.join(utils.TOOLS_DIR, 'linux')
+
+VERSIONS = [
+  'default',
+  '7.0.0',
+  '6.0.1',
+  # TODO(b/79191363): Build a boot image for 5.1.1 dex2oat.
+  # '5.1.1',
+]
+
+DIRS = {
+  'default': 'art',
+  '7.0.0': 'art-7.0.0',
+  '6.0.1': 'art-6.0.1',
+  '5.1.1': 'art-5.1.1',
+}
+
+PRODUCTS = {
+  'default': 'angler',
+  '7.0.0': 'angler',
+  '6.0.1': 'angler',
+  '5.1.1': 'mako',
+}
+
+def ParseOptions():
+  parser = optparse.OptionParser()
+  parser.add_option('--version',
+                    help='Version of dex2oat. (defaults to latest, eg, tools/linux/art).',
+                    choices=VERSIONS,
+                    default='default')
+  parser.add_option('--all',
+                    help='Run dex2oat on all possible versions',
+                    default=False,
+                    action='store_true')
+  parser.add_option('--output',
+                    help='Where to place the output oat (defaults to no output / temp file).',
+                    default=None)
+  return parser.parse_args()
+
+def Main():
+  (options, args) = ParseOptions()
+  if len(args) != 1:
+    print "Can only take a single dex/zip/jar/apk file as input."
+    return 1
+  if options.all and options.output:
+    print "Can't write output when running all versions."
+    return 1
+  dexfile = args[0]
+  oatfile = options.output
+  versions = VERSIONS if options.all else [options.version]
+  for version in versions:
+    run(dexfile, oatfile, version)
+    print
+  return 0
+
+def run(dexfile, oatfile=None, version='default'):
+  # dex2oat accepts non-existent dex files, check here instead
+  if not os.path.exists(dexfile):
+    raise Exception('DEX file not found: "{}"'.format(dexfile))
+  with utils.TempDir() as temp:
+    if not oatfile:
+      oatfile = os.path.join(temp, "out.oat")
+    base = os.path.join(LINUX_DIR, DIRS[version])
+    product = PRODUCTS[version]
+    cmd = [
+      os.path.join(base, 'bin', 'dex2oat'),
+      '--android-root=' + os.path.join(base, 'product', product),
+      '--runtime-arg',
+      '-Xnorelocate',
+      '--boot-image=' + os.path.join(base, 'product', product, 'system', 'framework', 'boot.art'),
+      '--dex-file=' + dexfile,
+      '--oat-file=' + oatfile,
+      '--instruction-set=arm64',
+    ]
+    env = {"LD_LIBRARY_PATH": os.path.join(base, 'lib')}
+    utils.PrintCmd(cmd)
+    subprocess.check_call(cmd, env = env)
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/tools/test_aosp_jar.py b/tools/test_aosp_jar.py
index f3aa392..bf12045 100755
--- a/tools/test_aosp_jar.py
+++ b/tools/test_aosp_jar.py
@@ -16,6 +16,7 @@
 
 import gradle
 
+import dex2oat
 import utils
 
 REPLAY_SCRIPT_DIR = join(utils.REPO_ROOT, 'third_party',
@@ -44,7 +45,7 @@
       for x in os.walk(OUT_DIR)))
 
   for dex_file in dex_files:
-      utils.verify_with_dex2oat(dex_file)
+      dex2oat.run(dex_file)
 
 
 if __name__ == '__main__':
diff --git a/tools/utils.py b/tools/utils.py
index a734ee5..7c5d83e 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -292,36 +292,5 @@
   if m is not None:
     raise Exception("Do not use google JVM for benchmarking: " + version)
 
-def verify_with_dex2oat(dex_file):
-
-  # dex2oat accepts non-existent dex files, check here instead
-  if not os.path.exists(dex_file):
-    raise Exception('Dex file not found: "{}"'.format(dex_file))
-
-  android_root_dir = os.path.join(TOOLS_DIR, 'linux', 'art', 'product',
-    'angler')
-  boot_art = os.path.join(android_root_dir, 'system', 'framework', 'boot.art')
-  dex2oat = os.path.join(TOOLS_DIR, 'linux', 'art', 'bin', 'dex2oat')
-
-  with TempDir() as temp:
-    oat_file = os.path.join(temp, 'all.oat')
-
-    cmd = [
-        dex2oat,
-        '--android-root=' + android_root_dir,
-        '--runtime-arg', '-Xnorelocate',
-        '--boot-image=' + boot_art,
-        '--dex-file=' + dex_file,
-        '--oat-file=' + oat_file,
-        '--instruction-set=arm64',
-        '--compiler-filter=quicken'
-    ]
-
-    PrintCmd(cmd)
-    subprocess.check_call(cmd,
-      env = {"LD_LIBRARY_PATH":
-        os.path.join(TOOLS_DIR, 'linux', 'art', 'lib')}
-    )
-
 def get_android_jar(api):
   return os.path.join(REPO_ROOT, ANDROID_JAR.format(api=api))