Merge "Revert "Relax the dead condition of field reads.""
diff --git a/.gitignore b/.gitignore
index 14e24ec..c04d9dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,8 @@
 third_party/kotlin
 third_party/nest/*
 !third_party/nest/*.sha1
+third_party/opensource_apps
+third_party/opensource_apps.tar.gz
 third_party/photos/*
 !third_party/photos/*.sha1
 third_party/proguard/*
diff --git a/build.gradle b/build.gradle
index f129fb5..4ce2e18 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,7 +10,6 @@
 ext {
     androidSupportVersion = '25.4.0'
     asmVersion = '6.2.1'
-    autoValueVersion = '1.5'
     espressoVersion = '3.0.0'
     fastutilVersion = '7.2.0'
     guavaVersion = '23.0'
@@ -66,7 +65,6 @@
     dependencies {
         classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
         classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13"
-        classpath "net.ltgt.gradle:gradle-apt-plugin:0.12"
         classpath "com.gradle:build-scan-plugin:1.14"
     }
 }
@@ -81,7 +79,6 @@
 apply plugin: 'java'
 apply plugin: 'idea'
 apply plugin: 'net.ltgt.errorprone-base'
-apply plugin: "net.ltgt.apt"
 
 if (project.hasProperty('with_code_coverage')) {
     apply plugin: 'jacoco'
@@ -257,7 +254,6 @@
     examplesCompile "com.google.guava:guava:$guavaVersion"
     examplesCompile "junit:junit:$junitVersion"
     examplesCompile "org.mockito:mockito-core:$mockitoVersion"
-    examplesCompileOnly "com.google.auto.value:auto-value:$autoValueVersion"
     supportLibs "com.android.support:support-v4:$androidSupportVersion"
     supportLibs "junit:junit:$junitVersion"
     supportLibs "com.android.support.test.espresso:espresso-core:$espressoVersion"
@@ -266,7 +262,6 @@
     debugTestResourcesKotlinCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
     examplesKotlinCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
     kotlinR8TestResourcesCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
-    apt "com.google.auto.value:auto-value:$autoValueVersion"
 }
 
 def r8LibPath = "$buildDir/libs/r8lib.jar"
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index f78912f..27c564a 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -58,6 +58,7 @@
     InternalOptions options = command.getInternalOptions();
     options.enableDesugaring = false;
     options.enableMainDexListCheck = false;
+    options.ignoreMainDexMissingClasses = true;
     options.minimalMainDex = false;
     options.enableMinification = false;
     options.enableInlining = false;
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 0e62775..0d12915 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -307,11 +307,13 @@
             mainDexFile.addClass(programClass);
             classes.remove(programClass);
           } else {
-            options.reporter.warning(
-                new StringDiagnostic(
-                    "Application does not contain `"
-                        + type.toSourceString()
-                        + "` as referenced in main-dex-list."));
+            if (!options.ignoreMainDexMissingClasses) {
+              options.reporter.warning(
+                  new StringDiagnostic(
+                      "Application does not contain `"
+                          + type.toSourceString()
+                          + "` as referenced in main-dex-list."));
+            }
           }
           mainDexFile.commitTransaction();
         }
diff --git a/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java b/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
index 9062ae7..4b89d9e 100644
--- a/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
+++ b/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
@@ -86,7 +86,7 @@
 
   @Keep
   public static final class Options {
-    private final DiagnosticsHandler diagnosticsHandler = new DiagnosticsHandler() {};
+    private final DiagnosticsHandler diagnosticsHandler;
     private List<String> inputArchives = new ArrayList<>();
     private List<FeatureJar> featureJars = new ArrayList<>();
     private List<String> baseJars = new ArrayList<>();
@@ -97,6 +97,14 @@
     private String mainDexList;
     private boolean splitNonClassResources = false;
 
+    public Options() {
+      this(new DiagnosticsHandler() {});
+    }
+
+    public Options(DiagnosticsHandler diagnosticsHandler) {
+      this.diagnosticsHandler = diagnosticsHandler;
+    }
+
     public DiagnosticsHandler getDiagnosticsHandler() {
       return diagnosticsHandler;
     }
@@ -293,7 +301,9 @@
       throw new AbortException();
     }
 
-    D8Command.Builder builder = D8Command.builder();
+    D8Command.Builder builder = D8Command.builder(options.diagnosticsHandler);
+
+
     for (String s : options.inputArchives) {
       builder.addProgramFiles(Paths.get(s));
     }
diff --git a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
index 21900a01..42ebde9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
@@ -62,7 +62,8 @@
   private void write(ThrowingFunction<DexClass, PrintStream, IOException> outputStreamProvider,
       Consumer<PrintStream> closer)
       throws IOException {
-    for (DexProgramClass clazz : application.classes()) {
+    Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder();
+    for (DexProgramClass clazz : classes) {
       if (anyMethodMatches(clazz)) {
         PrintStream ps = outputStreamProvider.apply(clazz);
         try {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index a35100e..a5854b6 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -147,6 +147,10 @@
   // Throw exception if there is a warning about invalid debug info.
   public boolean invalidDebugInfoFatal = false;
 
+  // When dexsplitting we ignore main dex classes missing in the application. These will be
+  // fused together by play store when shipped for pre-L devices.
+  public boolean ignoreMainDexMissingClasses = false;
+
   // Hidden marker for classes.dex
   private boolean hasMarker = false;
   private Marker marker;
diff --git a/src/test/examples/autovalue/SimpleAutoValue.java b/src/test/examples/autovalue/SimpleAutoValue.java
deleted file mode 100644
index 2c0b2c6..0000000
--- a/src/test/examples/autovalue/SimpleAutoValue.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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 autovalue;
-
-import com.google.auto.value.AutoValue;
-import javax.annotation.Nullable;
-
-public class SimpleAutoValue {
-
-  @AutoValue
-  static abstract class Pair {
-
-    Pair() {
-      // Intentionally left empty.
-    }
-
-    abstract int getOne();
-
-    @Nullable
-    abstract String getOther();
-
-    abstract String getRequiredOther();
-
-    static Builder builder() {
-      return new AutoValue_SimpleAutoValue_Pair.Builder();
-    }
-
-    @AutoValue.Builder
-    abstract static class Builder {
-
-      abstract Builder setOne(int value);
-
-      abstract Builder setOther(String value);
-
-      abstract Builder setRequiredOther(String value);
-
-      abstract Pair build();
-    }
-  }
-
-  public static void main(String... args) {
-    Pair.Builder builder = Pair.builder();
-    builder.setOne(42);
-    builder.setRequiredOther("123");
-    System.out.println(builder.build());
-    builder = Pair.builder();
-    try {
-      builder.build();
-    } catch (Exception e) {
-      System.out.println(e.getMessage());
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 37e4dec..c807a5d 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -87,8 +87,8 @@
     return self();
   }
 
-  public D8TestBuilder setIntermediate(boolean b) {
-    builder.setIntermediate(true);
+  public D8TestBuilder setIntermediate(boolean intermediate) {
+    builder.setIntermediate(intermediate);
     return self();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
index 15c03dc..7ad544b 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
 
+import com.android.tools.r8.utils.ListUtils;
 import java.util.ArrayList;
 import java.util.List;
 import org.hamcrest.Matcher;
@@ -44,25 +45,34 @@
     return errors;
   }
 
+  private void assertEmpty(String type, List<Diagnostic> messages) {
+    assertEquals(
+        "Expected no "
+            + type
+            + " messages, got:\n"
+            + String.join("\n", ListUtils.map(messages, m -> m.getDiagnosticMessage())),
+        0,
+        messages.size());
+  }
 
   public TestDiagnosticMessages assertNoMessages() {
-    assertEquals(0, getInfos().size());
-    assertEquals(0, getWarnings().size());
-    assertEquals(0, getErrors().size());
+    assertEmpty("info", getInfos());
+    assertEmpty("warning", getWarnings());
+    assertEmpty("error", getErrors());
     return this;
   }
 
   public TestDiagnosticMessages assertOnlyInfos() {
     assertNotEquals(0, getInfos().size());
-    assertEquals(0, getWarnings().size());
-    assertEquals(0, getErrors().size());
+    assertEmpty("warning", getWarnings());
+    assertEmpty("error", getErrors());
     return this;
   }
 
   public TestDiagnosticMessages assertOnlyWarnings() {
-    assertEquals(0, getInfos().size());
+    assertEmpty("info", getInfos());
     assertNotEquals(0, getWarnings().size());
-    assertEquals(0, getErrors().size());
+    assertEmpty("error", getErrors());
     return this;
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java
new file mode 100644
index 0000000..e9b1b8c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2019, 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.desugar;
+
+public class DefaultLambdaWithInvokeInterfaceTest {
+
+  public interface I {
+    int run();
+  }
+
+  public interface J {
+    default String stateless() {
+      return "hest";
+    }
+
+    default I stateful() {
+      return () -> stateless().length();
+    }
+  }
+
+  public static void main(String[] args) {
+    System.out.println(new J() {}.stateful().run());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
new file mode 100644
index 0000000..732612d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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.desugar;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+
+public class DefaultLambdaWithInvokeInterfaceTestRunner extends TestBase {
+
+  final Class<?> CLASS = DefaultLambdaWithInvokeInterfaceTest.class;
+  final String EXPECTED = StringUtils.lines("4");
+
+  @Test
+  public void testJvm() throws Exception {
+    testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForD8()
+        .addProgramClassesAndInnerClasses(CLASS)
+        .setMinApi(AndroidApiLevel.K)
+        .compile()
+        // TODO(b/123506120): Add .assertNoMessages()
+        .run(CLASS)
+        .assertSuccessWithOutput(EXPECTED)
+        .inspect(inspector -> assertThat(inspector.clazz(CLASS), isPresent()));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java
new file mode 100644
index 0000000..eb4e75b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2019, 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.desugar;
+
+public class DefaultLambdaWithSelfReferenceTest {
+
+  interface I {
+    String foo();
+
+    default I stateless() {
+      return () -> "stateless";
+    }
+
+    default I stateful() {
+      return () -> "stateful(" + stateless().foo() + ")";
+    }
+  }
+
+  public static void main(String[] args) {
+    System.out.println(((I) () -> "foo").stateful().foo());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
new file mode 100644
index 0000000..bc193c8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
@@ -0,0 +1,94 @@
+// Copyright (c) 2019, 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.desugar;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.Disassemble;
+import com.android.tools.r8.Disassemble.DisassembleCommand;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+public class DefaultLambdaWithSelfReferenceTestRunner extends TestBase {
+
+  final Class<?> CLASS = DefaultLambdaWithSelfReferenceTest.class;
+  final String EXPECTED = StringUtils.lines("stateful(stateless)");
+
+  @Test
+  public void testJvm() throws Exception {
+    testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void test() throws Exception {
+    Path out1 = temp.newFolder().toPath().resolve("out1.zip");
+    testForD8()
+        .addProgramClassesAndInnerClasses(CLASS)
+        .setMinApi(AndroidApiLevel.K)
+        .compile()
+        // TODO(b/123506120): Add .assertNoMessages()
+        .writeToZip(out1)
+        .run(CLASS)
+        .assertSuccessWithOutput(EXPECTED);
+
+    Path outPerClassDir = temp.newFolder().toPath();
+    Collection<Path> innerClasses =
+        ToolHelper.getClassFilesForInnerClasses(Collections.singleton(CLASS));
+
+    int i = 0;
+    List<Path> outs = new ArrayList<>();
+    {
+      Path mainOut = outPerClassDir.resolve("class" + i++ + ".zip");
+      outs.add(mainOut);
+      testForD8()
+          .addProgramClasses(CLASS)
+          .addClasspathFiles(ToolHelper.getClassPathForTests())
+          .setIntermediate(true)
+          .setMinApi(AndroidApiLevel.K)
+          .compile()
+          // TODO(b/123506120): Add .assertNoMessages()
+          .writeToZip(mainOut);
+    }
+    for (Path innerClass : innerClasses) {
+      Path out = outPerClassDir.resolve("class" + i++ + ".zip");
+      outs.add(out);
+      testForD8()
+          .addProgramFiles(innerClass)
+          .addClasspathFiles(ToolHelper.getClassPathForTests())
+          .setIntermediate(true)
+          .setMinApi(AndroidApiLevel.K)
+          .compile()
+          // TODO(b/123506120): Add .assertNoMessages()
+          .writeToZip(out);
+    }
+
+    Path out2 = temp.newFolder().toPath().resolve("out2.zip");
+    testForD8()
+        .addProgramFiles(outs)
+        .compile()
+        // TODO(b/123506120): Add .assertNoMessages()
+        .writeToZip(out2)
+        .run(CLASS)
+        .assertSuccessWithOutput(EXPECTED);
+
+    Path dissasemble1 = temp.newFolder().toPath().resolve("disassemble1.txt");
+    Path dissasemble2 = temp.newFolder().toPath().resolve("disassemble2.txt");
+    Disassemble.disassemble(
+        DisassembleCommand.builder().addProgramFiles(out1).setOutputPath(dissasemble1).build());
+    Disassemble.disassemble(
+        DisassembleCommand.builder().addProgramFiles(out2).setOutputPath(dissasemble2).build());
+    String content1 = StringUtils.join(Files.readAllLines(dissasemble1), "\n");
+    String content2 = StringUtils.join(Files.readAllLines(dissasemble2), "\n");
+    assertEquals(content1, content2);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index ff948aa..5103951 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -226,14 +226,15 @@
   @Test
   public void everyThirdClassInMainWithDexSplitter() throws Throwable {
     List<String> featureMappings = new ArrayList<>();
+    List<String> inFeatureMapping = new ArrayList<>();
 
     ImmutableList.Builder<String> mainDexBuilder = ImmutableList.builder();
     for (int i = 0; i < MANY_CLASSES.size(); i++) {
       String clazz = MANY_CLASSES.get(i);
       // Write the first 2 classes into the split.
-      if (i < 2) {
+      if (i < 10) {
         featureMappings.add(clazz + ":feature1");
-        continue;
+        inFeatureMapping.add(clazz);
       }
       if (i % 3 == 0) {
         mainDexBuilder.add(clazz);
@@ -246,19 +247,20 @@
     FileUtils.writeTextFile(mainDexFile, ListUtils.map(mainDexList, MainDexListTests::typeToEntry));
     Path output = temp.getRoot().toPath().resolve("split_output");
     Files.createDirectories(output);
-
-    Options options = new Options();
+    TestDiagnosticsHandler diagnosticsHandler = new TestDiagnosticsHandler();
+    Options options = new Options(diagnosticsHandler);
     options.addInputArchive(getManyClassesMultiDexAppPath().toString());
     options.setFeatureSplitMapping(featureSplitMapping.toString());
     options.setOutput(output.toString());
     options.setMainDexList(mainDexFile.toString());
     DexSplitter.run(options);
+    assertEquals(0, diagnosticsHandler.numberOfErrorsAndWarnings());
     Path baseDir = output.resolve("base");
     CodeInspector inspector =
         new CodeInspector(
             AndroidApp.builder().addProgramFiles(baseDir.resolve("classes.dex")).build());
     for (String clazz : mainDexList) {
-      if (!inspector.clazz(clazz).isPresent()) {
+      if (!inspector.clazz(clazz).isPresent() && !inFeatureMapping.contains(clazz)) {
         failedToFindClassInExpectedFile(baseDir, clazz);
       }
     }
@@ -923,10 +925,20 @@
   private class TestDiagnosticsHandler implements DiagnosticsHandler {
 
     public List<Diagnostic> errors = new ArrayList<>();
+    public List<Diagnostic> warnings = new ArrayList<>();
+
+    public int numberOfErrorsAndWarnings() {
+      return errors.size() + warnings.size();
+    }
 
     @Override
     public void error(Diagnostic error) {
       errors.add(error);
     }
+
+    @Override
+    public void warning(Diagnostic warning) {
+      warnings.add(warning);
+    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java b/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
index 5038729..e191921 100644
--- a/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.shaking.desugar.interfacemethods;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
@@ -60,11 +59,9 @@
     MethodSubject m = c.uniqueMethodWithName("m");
     assertThat(m, isPresent());
     assertTrue(m.getMethod().hasCode());
-    // TODO(b/123778921): why are I and C not merged without merge annotations?
+    // TODO(b/124017330): Verify that I$-CC.m() has been inlined into C.m().
     //assertTrue(
     //    m.iterateInstructions(i -> i.isConstString("I::m", JumboStringMode.ALLOW)).hasNext());
-
-    // TODO(b/123778921): No companion class is in the output.
     //codeInspector.forAllClasses(classSubject -> {
     //  assertFalse(classSubject.getOriginalDescriptor().contains("$-CC"));
     //});
diff --git a/third_party/opensource_apps.tar.gz.sha1 b/third_party/opensource_apps.tar.gz.sha1
new file mode 100644
index 0000000..9fb2bb2
--- /dev/null
+++ b/third_party/opensource_apps.tar.gz.sha1
@@ -0,0 +1 @@
+64b0689bce8f6789320b34da4e91c6dbcc1296e9
\ No newline at end of file
diff --git a/tools/apk_utils.py b/tools/apk_utils.py
index 5a6aa94..af24ec1 100644
--- a/tools/apk_utils.py
+++ b/tools/apk_utils.py
@@ -23,7 +23,8 @@
   ]
   utils.RunCmd(cmd, quiet=quiet)
 
-def sign_with_apksigner(build_tools_dir, unsigned_apk, signed_apk, keystore, password):
+def sign_with_apksigner(
+    build_tools_dir, unsigned_apk, signed_apk, keystore, password, quiet=False):
   cmd = [
     os.path.join(build_tools_dir, 'apksigner'),
     'sign',
@@ -34,5 +35,4 @@
     '--out', signed_apk,
     unsigned_apk
   ]
-  utils.PrintCmd(cmd)
-  subprocess.check_call(cmd)
+  utils.RunCmd(cmd, quiet=quiet)
diff --git a/tools/as_utils.py b/tools/as_utils.py
index 5f224a6..7a6528a 100644
--- a/tools/as_utils.py
+++ b/tools/as_utils.py
@@ -127,7 +127,7 @@
       if '-printconfiguration' not in line:
         f.write(line)
     # Check that there is a line-break at the end of the file or insert one.
-    if lines[-1].strip():
+    if len(lines) and lines[-1].strip():
       f.write('\n')
     f.write('-printconfiguration {}\n'.format(destination))
 
@@ -159,7 +159,7 @@
   Move(src, dst, quiet=quiet)
 
 def MoveFile(src, dst, quiet=False):
-  assert os.path.isfile(src)
+  assert os.path.isfile(src), "Expected a file to be present at " + src
   Move(src, dst, quiet=quiet)
 
 def MoveProfileReportTo(dest_dir, build_stdout, quiet=False):
diff --git a/tools/download_all_benchmark_dependencies.py b/tools/download_all_benchmark_dependencies.py
new file mode 100755
index 0000000..43ec0ab
--- /dev/null
+++ b/tools/download_all_benchmark_dependencies.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# Copyright (c) 2019, 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.
+
+# Utility script to make it easier to update what golem builds.
+
+import gradle
+import sys
+import utils
+
+BUILD_TARGETS = ['downloadDeps', 'downloadAndroidCts', 'downloadDx']
+
+def Main():
+  gradle.RunGradle(BUILD_TARGETS)
+  # Download opensource_apps and place in build.
+  utils.DownloadFromX20(utils.OPENSOURCE_APPS_SHA_FILE)
+
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index 3a9bf8c..55c8857 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -5,6 +5,7 @@
 
 import apk_masseur
 import apk_utils
+import golem
 import gradle
 import os
 import optparse
@@ -17,15 +18,20 @@
 
 import as_utils
 
-SHRINKERS = ['r8', 'r8-minified', 'r8full', 'r8full-minified', 'proguard']
-WORKING_DIR = utils.BUILD
+SHRINKERS = ['r8', 'r8-full', 'r8-nolib', 'r8-nolib-full', 'pg']
+WORKING_DIR = os.path.join(utils.BUILD, 'opensource_apps')
 
-if 'R8_BENCHMARK_DIR' in os.environ and os.path.isdir(os.environ['R8_BENCHMARK_DIR']):
+if ('R8_BENCHMARK_DIR' in os.environ
+    and os.path.isdir(os.environ['R8_BENCHMARK_DIR'])):
   WORKING_DIR = os.environ['R8_BENCHMARK_DIR']
 
+# For running on Golem all APPS are bundled as an x20-dependency and then copied
+# to WORKING_DIR. To make it easier to update the app-bundle, remove the folder
+# WORKING_DIR and then run run_on_as_app.py --download-only.
 APPS = {
   # 'app-name': {
   #     'git_repo': ...
+  #     'revision': ...,
   #     'app_module': ... (default app)
   #     'archives_base_name': ... (default same as app_module)
   #     'flavor': ... (default no flavor)
@@ -34,6 +40,7 @@
   'AnExplorer': {
       'app_id': 'dev.dworks.apps.anexplorer.pro',
       'git_repo': 'https://github.com/christofferqa/AnExplorer',
+      'revision': '365927477b8eab4052a1882d5e358057ae3dee4d',
       'flavor': 'googleMobilePro',
       'signed-apk-name': 'AnExplorer-googleMobileProRelease-4.0.3.apk',
       'min_sdk': 17
@@ -41,6 +48,7 @@
   'AntennaPod': {
       'app_id': 'de.danoeh.antennapod',
       'git_repo': 'https://github.com/christofferqa/AntennaPod.git',
+      'revision': '77e94f4783a16abe9cc5b78dc2d2b2b1867d8c06',
       'flavor': 'play',
       'min_sdk': 14,
       'compile_sdk': 26
@@ -48,78 +56,105 @@
   'apps-android-wikipedia': {
       'app_id': 'org.wikipedia',
       'git_repo': 'https://github.com/christofferqa/apps-android-wikipedia',
+      'revision': '686e8aa5682af8e6a905054b935dd2daa57e63ee',
       'flavor': 'prod',
-      'signed-apk-name': 'app-prod-universal-release.apk'
+      'signed-apk-name': 'app-prod-universal-release.apk',
   },
   'chanu': {
-    'app_id': 'com.chanapps.four.activity',
-    'git_repo': 'https://github.com/mkj-gram/chanu.git',
+      'app_id': 'com.chanapps.four.activity',
+      'git_repo': 'https://github.com/mkj-gram/chanu.git',
+      'revision': '04ade1e9c33d707f0850d5eb9d6fa5e8af814a26',
   },
   'friendlyeats-android': {
       'app_id': 'com.google.firebase.example.fireeats',
-      'git_repo': 'https://github.com/christofferqa/friendlyeats-android.git'
+      'git_repo': 'https://github.com/christofferqa/friendlyeats-android.git',
+      'revision': '10091fa0ec37da12e66286559ad1b6098976b07b',
+  },
+  'Instabug-Android': {
+      'app_id': 'com.example.instabug',
+      'git_repo': 'https://github.com/christofferqa/Instabug-Android.git',
+      'revision': 'b8df78c96630a6537fbc07787b4990afc030cc0f'
   },
   'KISS': {
       'app_id': 'fr.neamar.kiss',
       'git_repo': 'https://github.com/christofferqa/KISS',
+      'revision': '093da9ee0512e67192f62951c45a07a616fc3224',
   },
   'materialistic': {
       'app_id': 'io.github.hidroh.materialistic',
       'git_repo': 'https://github.com/christofferqa/materialistic',
+      'revision': '2b2b2ee25ce9e672d5aab1dc90a354af1522b1d9',
   },
   'Minimal-Todo': {
       'app_id': 'com.avjindersinghsekhon.minimaltodo',
       'git_repo': 'https://github.com/christofferqa/Minimal-Todo',
+      'revision': '9d8c73746762cd376b718858ec1e8783ca07ba7c',
   },
   'NewPipe': {
       'app_id': 'org.schabi.newpipe',
       'git_repo': 'https://github.com/christofferqa/NewPipe',
+      'revision': 'ed543099c7823be00f15d9340f94bdb7cb37d1e6',
   },
   'rover-android': {
-    'app_id': 'io.rover.app.debug',
-    'app_module': 'debug-app',
-    'git_repo': 'https://github.com/mkj-gram/rover-android.git',
+      'app_id': 'io.rover.app.debug',
+      'app_module': 'debug-app',
+      'git_repo': 'https://github.com/mkj-gram/rover-android.git',
+      'revision': 'd2e876e597b3af7eab406e38a0e08327a38bd942',
   },
   'Signal-Android': {
-    'app_id': 'org.thoughtcrime.securesms',
-    'app_module': '',
-    'flavor': 'play',
-    'git_repo': 'https://github.com/mkj-gram/Signal-Android.git',
-    'releaseTarget': 'assemblePlayRelease',
-    'signed-apk-name': 'Signal-play-release-4.32.7.apk',
+      'app_id': 'org.thoughtcrime.securesms',
+      'app_module': '',
+      'flavor': 'play',
+      'git_repo': 'https://github.com/mkj-gram/Signal-Android.git',
+      'revision': '85e1a10993e5e9ffe923f0798b26cbc44068ba31',
+      'releaseTarget': 'assemblePlayRelease',
+      'signed-apk-name': 'Signal-play-release-4.32.7.apk',
   },
   'Simple-Calendar': {
       'app_id': 'com.simplemobiletools.calendar.pro',
       'git_repo': 'https://github.com/christofferqa/Simple-Calendar',
+      'revision': '82dad8c203eea5a0f0ddb513506d8f1de986ef2b',
       'signed-apk-name': 'calendar-release.apk'
   },
+  'sqldelight': {
+      'app_id': 'com.example.sqldelight.hockey',
+      'git_repo': 'https://github.com/christofferqa/sqldelight.git',
+      'revision': '2e67a1126b6df05e4119d1e3a432fde51d76cdc8',
+      'app_module': 'sample/android',
+      'archives_base_name': 'android',
+      'min_sdk': 14,
+      'compile_sdk': 28,
+  },
   'tachiyomi': {
       'app_id': 'eu.kanade.tachiyomi',
       'git_repo': 'https://github.com/sgjesse/tachiyomi.git',
+      'revision': 'b15d2fe16864645055af6a745a62cc5566629798',
       'flavor': 'standard',
       'releaseTarget': 'app:assembleRelease',
       'min_sdk': 16
   },
   'tivi': {
       'app_id': 'app.tivi',
-      # Forked from https://github.com/chrisbanes/tivi.git removing
-      # signingConfigs.
       'git_repo': 'https://github.com/sgjesse/tivi.git',
-      # TODO(123047413): Fails with R8.
-      'skip': True,
+      'revision': '7d7f591d6f39d7caeb88dd13bf476c0c06accdfb',
+      'min_sdk': 23,
+      'compile_sdk': 28,
   },
   'Tusky': {
-    'app_id': 'com.keylesspalace.tusky',
-    'git_repo': 'https://github.com/mkj-gram/Tusky.git',
-    'flavor': 'blue'
+      'app_id': 'com.keylesspalace.tusky',
+      'git_repo': 'https://github.com/mkj-gram/Tusky.git',
+      'revision': 'b794f3ab90388add98461ffe70edb65c39351c33',
+      'flavor': 'blue'
   },
   'Vungle-Android-SDK': {
-    'app_id': 'com.publisher.vungle.sample',
-    'git_repo': 'https://github.com/mkj-gram/Vungle-Android-SDK.git',
+      'app_id': 'com.publisher.vungle.sample',
+      'git_repo': 'https://github.com/mkj-gram/Vungle-Android-SDK.git',
+      'revision': '3e231396ea7ce97b2655e03607497c75730e45f6',
   },
   # This does not build yet.
   'muzei': {
       'git_repo': 'https://github.com/sgjesse/muzei.git',
+      'revision': 'bed2a5f79c6e08b0a21e3e3f9242232d0848ef74',
       'app_module': 'main',
       'archives_base_name': 'muzei',
       'skip': True,
@@ -151,17 +186,21 @@
   return '~~R8' in subprocess.check_output(cmd).strip()
 
 def IsMinifiedR8(shrinker):
-  return shrinker == 'r8-minified' or shrinker == 'r8full-minified'
+  return 'nolib' not in shrinker
 
 def IsTrackedByGit(file):
   return subprocess.check_output(['git', 'ls-files', file]).strip() != ''
 
-def GitClone(git_url):
-  return subprocess.check_output(['git', 'clone', git_url]).strip()
-
-def GitPull():
-  # Use --no-edit to accept the auto-generated merge message, if any.
-  return subprocess.call(['git', 'pull', '--no-edit']) == 0
+def GitClone(git_url, revision, checkout_dir, options):
+  result = subprocess.check_output(
+      ['git', 'clone', git_url, checkout_dir]).strip()
+  head_rev = utils.get_HEAD_sha1_for_checkout(checkout_dir)
+  if revision == head_rev:
+    return result
+  warn('Target revision is not head in {}.'.format(checkout_dir))
+  with utils.ChangedWorkingDirectory(checkout_dir, quiet=options.quiet):
+    subprocess.check_output(['git', 'reset', '--hard', revision])
+  return result
 
 def GitCheckout(file):
   return subprocess.check_output(['git', 'checkout', file]).strip()
@@ -220,26 +259,23 @@
       return True
 
 def GetResultsForApp(app, config, options, temp_dir):
-  git_repo = config['git_repo']
-
   # Checkout and build in the build directory.
   checkout_dir = os.path.join(WORKING_DIR, app)
 
   result = {}
 
-  if not os.path.exists(checkout_dir):
+  if not os.path.exists(checkout_dir) and not options.golem:
     with utils.ChangedWorkingDirectory(WORKING_DIR, quiet=options.quiet):
-      GitClone(git_repo)
-  elif options.pull:
-    with utils.ChangedWorkingDirectory(checkout_dir, quiet=options.quiet):
-      # Checkout build.gradle to avoid merge conflicts.
-      if IsTrackedByGit('build.gradle'):
-        GitCheckout('build.gradle')
+      GitClone(config['git_repo'], config['revision'], checkout_dir, options)
 
-      if not GitPull():
-        result['status'] = 'failed'
-        result['error_message'] = 'Unable to pull from remote'
-        return result
+  checkout_rev = utils.get_HEAD_sha1_for_checkout(checkout_dir)
+  if config['revision'] != checkout_rev:
+    msg = 'Checkout is not target revision for {} in {}.'.format(
+        app, checkout_dir)
+    if options.ignore_versions:
+      warn(msg)
+    else:
+      raise Exception(msg)
 
   result['status'] = 'success'
 
@@ -267,7 +303,7 @@
             BuildAppWithShrinker(app, config, shrinker, checkout_dir, out_dir,
                 temp_dir, options)
         dex_size = ComputeSizeOfDexFilesInApk(apk_dest)
-        result['apk_dest'] = apk_dest,
+        result['apk_dest'] = apk_dest
         result['build_status'] = 'success'
         result['dex_size'] = dex_size
         result['profile_dest_dir'] = profile_dest_dir
@@ -357,11 +393,8 @@
       shrinker,
       ' for recompilation' if keepRuleSynthesisForRecompilation else ''))
 
-  # Add/remove 'r8.jar' from top-level build.gradle.
-  if options.disable_tot:
-    as_utils.remove_r8_dependency(checkout_dir)
-  else:
-    as_utils.add_r8_dependency(checkout_dir, temp_dir, IsMinifiedR8(shrinker))
+  # Add 'r8.jar' from top-level build.gradle.
+  as_utils.add_r8_dependency(checkout_dir, temp_dir, IsMinifiedR8(shrinker))
 
   app_module = config.get('app_module', 'app')
   archives_base_name = config.get('archives_base_name', app_module)
@@ -382,13 +415,13 @@
 
   releaseTarget = config.get('releaseTarget')
   if not releaseTarget:
-    releaseTarget = app_module + ':' + 'assemble' + (
+    releaseTarget = app_module.replace('/', ':') + ':' + 'assemble' + (
         flavor.capitalize() if flavor else '') + 'Release'
 
   # Value for property android.enableR8.
   enableR8 = 'r8' in shrinker
   # Value for property android.enableR8.fullMode.
-  enableR8FullMode = shrinker == 'r8full' or shrinker == 'r8full-minified'
+  enableR8FullMode = shrinker == 'r8-full' or shrinker == 'r8-nolib-full'
   # Build gradlew command line.
   cmd = ['./gradlew', '--no-daemon', 'clean', releaseTarget,
          '--profile', '--stacktrace',
@@ -419,14 +452,13 @@
   if options.sign_apks and not os.path.isfile(signed_apk):
     assert os.path.isfile(unsigned_apk)
     if options.sign_apks:
-      keystore = 'app.keystore'
-      keystore_password = 'android'
       apk_utils.sign_with_apksigner(
           utils.ANDROID_BUILD_TOOLS,
           unsigned_apk,
           signed_apk,
-          keystore,
-          keystore_password)
+          options.keystore,
+          options.keystore_password,
+          quiet=options.quiet)
 
   if os.path.isfile(signed_apk):
     apk_dest = os.path.join(out_dir, signed_apk_name)
@@ -507,10 +539,28 @@
 def LogResultsForApps(result_per_shrinker_per_app, options):
   print('')
   for app, result_per_shrinker in sorted(
-      result_per_shrinker_per_app.iteritems()):
+      result_per_shrinker_per_app.iteritems(), key=lambda s: s[0].lower()):
     LogResultsForApp(app, result_per_shrinker, options)
 
 def LogResultsForApp(app, result_per_shrinker, options):
+  if options.print_dexsegments:
+    LogSegmentsForApp(app, result_per_shrinker, options)
+  else:
+    LogComparisonResultsForApp(app, result_per_shrinker, options)
+
+def LogSegmentsForApp(app, result_per_shrinker, options):
+  for shrinker in SHRINKERS:
+    if shrinker not in result_per_shrinker:
+      continue
+    result = result_per_shrinker[shrinker];
+    benchmark_name = '{}-{}'.format(options.print_dexsegments, app)
+    utils.print_dexsegments(benchmark_name, [result.get('apk_dest')])
+    duration = sum(result.get('profile').values())
+    print('%s-Total(RunTimeRaw): %s ms' % (benchmark_name, duration * 1000))
+    print('%s-Total(CodeSize): %s' % (benchmark_name, result.get('dex_size')))
+
+
+def LogComparisonResultsForApp(app, result_per_shrinker, options):
   print(app + ':')
 
   if result_per_shrinker.get('status', 'success') != 'success':
@@ -518,7 +568,7 @@
     print('  skipped ({})'.format(error_message))
     return
 
-  proguard_result = result_per_shrinker.get('proguard', {})
+  proguard_result = result_per_shrinker.get('pg', {})
   proguard_dex_size = float(proguard_result.get('dex_size', -1))
   proguard_duration = sum(proguard_result.get('profile', {}).values())
 
@@ -587,6 +637,27 @@
   result.add_option('--app',
                     help='What app to run on',
                     choices=APPS.keys())
+  result.add_option('--download-only', '--download_only',
+                    help='Whether to download apps without any compilation',
+                    default=False,
+                    action='store_true')
+  result.add_option('--golem',
+                    help='Running on golem, do not download',
+                    default=False,
+                    action='store_true')
+  result.add_option('--gradle-flags', '--gradle_flags',
+                    help='Flags to pass in to gradle')
+  result.add_option('--ignore-versions', '--ignore_versions',
+                    help='Allow checked-out app to differ in revision from '
+                         'pinned',
+                    default=False,
+                    action='store_true')
+  result.add_option('--keystore',
+                    help='Path to app.keystore',
+                    default='app.keystore')
+  result.add_option('--keystore-password', '--keystore_password',
+                    help='Password for app.keystore',
+                    default='android')
   result.add_option('--monkey',
                     help='Whether to install and run app(s) with monkey',
                     default=False,
@@ -595,10 +666,23 @@
                     help='Number of events that the monkey should trigger',
                     default=250,
                     type=int)
-  result.add_option('--pull',
-                    help='Whether to pull the latest version of each app',
+  result.add_option('--no-build', '--no_build',
+                    help='Run without building ToT first (only when using ToT)',
                     default=False,
                     action='store_true')
+  result.add_option('--quiet',
+                    help='Disable verbose logging',
+                    default=False,
+                    action='store_true')
+  result.add_option('--print-dexsegments',
+                    metavar='BENCHMARKNAME',
+                    help='Print the sizes of individual dex segments as ' +
+                         '\'<BENCHMARKNAME>-<APP>-<segment>(CodeSize): '
+                         '<bytes>\'')
+  result.add_option('--r8-compilation-steps', '--r8_compilation_steps',
+                    help='Number of times R8 should be run on each app',
+                    default=2,
+                    type=int)
   result.add_option('--sign-apks', '--sign_apks',
                     help='Whether the APKs should be signed',
                     default=False,
@@ -606,57 +690,50 @@
   result.add_option('--shrinker',
                     help='The shrinkers to use (by default, all are run)',
                     action='append')
-  result.add_option('--r8-compilation-steps', '--r8_compilation_steps',
-                    help='Number of times R8 should be run on each app',
-                    default=2,
-                    type=int)
-  result.add_option('--disable-tot', '--disable_tot',
-                    help='Whether to disable the use of the ToT version of R8',
-                    default=False,
-                    action='store_true')
-  result.add_option('--no-build', '--no_build',
-                    help='Run without building ToT first (only when using ToT)',
-                    default=False,
-                    action='store_true')
-  result.add_option('--gradle-flags', '--gradle_flags',
-                    help='Flags to pass in to gradle')
-  result.add_option('--quiet',
-                    help='Disable verbose logging',
-                    default=False,
-                    action='store_true')
   (options, args) = result.parse_args(argv)
-  if options.disable_tot:
-    # r8.jar is required for recompiling the generated APK
-    options.r8_compilation_steps = 1
   if options.shrinker:
     for shrinker in options.shrinker:
       assert shrinker in SHRINKERS
   return (options, args)
 
+def download_apps(options):
+  # Download apps and place in build
+  with utils.ChangedWorkingDirectory(WORKING_DIR):
+    for app, config in APPS.iteritems():
+      app_dir = os.path.join(WORKING_DIR, app)
+      if not os.path.exists(app_dir):
+        GitClone(config['git_repo'], config['revision'], app_dir, options)
+
+
 def main(argv):
   global SHRINKERS
 
   (options, args) = ParseOptions(argv)
 
+  if options.golem:
+    golem.link_third_party()
+    if os.path.exists(WORKING_DIR):
+      shutil.rmtree(WORKING_DIR)
+    shutil.copytree(utils.OPENSOURCE_APPS_FOLDER, WORKING_DIR)
+
+  if not os.path.exists(WORKING_DIR):
+    os.makedirs(WORKING_DIR)
+
+  if options.download_only:
+    download_apps(options)
+    return
+
   with utils.TempDir() as temp_dir:
-    if options.disable_tot:
-      # Cannot run r8 lib without adding r8lib.jar as an dependency
-      SHRINKERS = [
-          shrinker for shrinker in SHRINKERS
-          if 'minified' not in shrinker]
-    else:
-      if not options.no_build:
-        gradle.RunGradle(['r8', 'r8lib'])
+    if not options.no_build or options.golem:
+      gradle.RunGradle(['r8', 'r8lib'])
 
-      assert os.path.isfile(utils.R8_JAR), (
-          'Cannot build from ToT without r8.jar')
-      assert os.path.isfile(utils.R8LIB_JAR), (
-          'Cannot build from ToT without r8lib.jar')
+    assert os.path.isfile(utils.R8_JAR), 'Cannot build without r8.jar'
+    assert os.path.isfile(utils.R8LIB_JAR), 'Cannot build without r8lib.jar'
 
-      # Make a copy of r8.jar and r8lib.jar such that they stay the same for
-      # the entire execution of this script.
-      shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
-      shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))
+    # Make a copy of r8.jar and r8lib.jar such that they stay the same for
+    # the entire execution of this script.
+    shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
+    shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))
 
     result_per_shrinker_per_app = {}
 
@@ -664,7 +741,7 @@
       result_per_shrinker_per_app[options.app] = GetResultsForApp(
           options.app, APPS.get(options.app), options, temp_dir)
     else:
-      for app, config in sorted(APPS.iteritems()):
+      for app, config in sorted(APPS.iteritems(), key=lambda s: s[0].lower()):
         if not config.get('skip', False):
           result_per_shrinker_per_app[app] = GetResultsForApp(
               app, config, options, temp_dir)
diff --git a/tools/utils.py b/tools/utils.py
index aff96a3..08faec6 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -62,6 +62,10 @@
 CF_SEGMENTS_TOOL = os.path.join(THIRD_PARTY, 'cf_segments')
 PINNED_R8_JAR = os.path.join(REPO_ROOT, 'third_party/r8/r8.jar')
 PINNED_PGR8_JAR = os.path.join(REPO_ROOT, 'third_party/r8/r8-pg6.0.1.jar')
+OPENSOURCE_APPS_SHA_FILE = os.path.join(
+    REPO_ROOT,
+    'third_party/opensource_apps.tar.gz.sha1')
+OPENSOURCE_APPS_FOLDER = os.path.join(REPO_ROOT, 'third_party/opensource_apps/')
 
 
 # Common environment setup.
@@ -184,9 +188,12 @@
   return 'origin/master' in remotes
 
 def get_HEAD_sha1():
+  return get_HEAD_sha1_for_checkout(REPO_ROOT)
+
+def get_HEAD_sha1_for_checkout(checkout):
   cmd = ['git', 'rev-parse', 'HEAD']
   PrintCmd(cmd)
-  with ChangedWorkingDirectory(REPO_ROOT):
+  with ChangedWorkingDirectory(checkout):
     return subprocess.check_output(cmd).strip()
 
 def makedirs_if_needed(path):