Merge "Use golden files for runtime tests on Windows or Mac"
diff --git a/build.gradle b/build.gradle
index f379bbf..8ea2b3f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1239,6 +1239,18 @@
}
test {
+ if (project.hasProperty('generate_golden_files_to')) {
+ systemProperty 'generate_golden_files_to', project.property('generate_golden_files_to')
+ assert project.hasProperty('HEAD_sha1')
+ systemProperty 'test_git_HEAD_sha1', project.property('HEAD_sha1')
+ }
+
+ if (project.hasProperty('use_golden_files_in')) {
+ systemProperty 'use_golden_files_in', project.property('use_golden_files_in')
+ assert project.hasProperty('HEAD_sha1')
+ systemProperty 'test_git_HEAD_sha1', project.property('HEAD_sha1')
+ }
+
dependsOn getJarsFromSupportLibs
testLogging.exceptionFormat = 'full'
if (project.hasProperty('print_test_stdout')) {
diff --git a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
index ede7e53..e01373c 100644
--- a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
@@ -15,6 +15,7 @@
import org.hamcrest.core.IsInstanceOf;
import org.hamcrest.core.StringContains;
import org.junit.Assert;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.internal.matchers.ThrowableMessageMatcher;
@@ -156,16 +157,20 @@
// TODO check compilation warnings are correctly reported
// Missing interface B is causing the wrong code to be executed.
- if (ToolHelper.artSupported()) {
- thrown.expect(AssertionError.class);
- execute(
- "testMissingInterfaceDesugared2AndroidK",
- "desugaringwithmissingclasstest2.Main",
- new Path[] {
- lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
- },
- new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
+ if (!ToolHelper.artSupported() && !ToolHelper.compareAgaintsGoldenFiles()) {
+ return;
}
+ if (ToolHelper.artSupported() && !ToolHelper.compareAgaintsGoldenFiles()) {
+ thrown.expect(AssertionError.class);
+ }
+ execute(
+ "testMissingInterfaceDesugared2AndroidK",
+ "desugaringwithmissingclasstest2.Main",
+ new Path[] {
+ lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
+ },
+ new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
+
}
@Test
@@ -256,17 +261,20 @@
Path testDex = test.build();
// TODO check compilation warnings are correctly reported
+ Assume.assumeTrue(ToolHelper.artSupported() || ToolHelper.compareAgaintsGoldenFiles());
+
// Missing interface B is causing the wrong method to be executed.
- if (ToolHelper.artSupported()) {
+ if (ToolHelper.artSupported() && !ToolHelper.compareAgaintsGoldenFiles()) {
thrown.expect(AssertionError.class);
- execute(
- "testCallToMissingSuperInterfaceDesugaredAndroidK",
- "desugaringwithmissingclasstest3.Main",
- new Path[] {
- lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
- },
- new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
}
+ execute(
+ "testCallToMissingSuperInterfaceDesugaredAndroidK",
+ "desugaringwithmissingclasstest3.Main",
+ new Path[] {
+ lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
+ },
+ new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
+
}
@Test
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 44eb344..2032866 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Kind;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.ProguardRuleParserException;
@@ -22,6 +23,7 @@
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
@@ -1362,6 +1364,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
public R8RunArtTestsTest(String name, DexTool toolchain) {
this.name = name;
this.toolchain = toolchain;
@@ -1769,7 +1774,7 @@
specification.disableInlining, specification.disableClassInlining,
specification.hasMissingClasses);
- if (!ToolHelper.artSupported()) {
+ if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
return;
}
@@ -1790,9 +1795,11 @@
boolean compileOnly = System.getProperty("jctf_compile_only", "0").equals("1");
if (compileOnly || specification.skipArt) {
- // verify dex code instead of running it
- Path oatFile = temp.getRoot().toPath().resolve("all.oat");
- ToolHelper.runDex2Oat(processedFile.toPath(), oatFile);
+ if (ToolHelper.isDex2OatSupported()) {
+ // verify dex code instead of running it
+ Path oatFile = temp.getRoot().toPath().resolve("all.oat");
+ ToolHelper.runDex2Oat(processedFile.toPath(), oatFile);
+ }
return;
}
@@ -1964,7 +1971,7 @@
specification.hasMissingClasses);
}
- if (!specification.skipArt && ToolHelper.artSupported()) {
+ if (!specification.skipArt && (ToolHelper.artSupported() || ToolHelper.dealsWithGoldenFiles())) {
File originalFile;
File processedFile;
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesCommon.java b/src/test/java/com/android/tools/r8/R8RunExamplesCommon.java
index 62dd4af..fe5ae72 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesCommon.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesCommon.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import java.io.IOException;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
@@ -21,6 +22,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -69,6 +71,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
private final Input input;
private final CompilerUnderTest compiler;
private final CompilationMode mode;
@@ -183,9 +188,8 @@
@Test
public void outputIsIdentical() throws IOException, InterruptedException, ExecutionException {
- if (!ToolHelper.artSupported()) {
- return;
- }
+ Assume.assumeTrue(ToolHelper.artSupported() || ToolHelper.compareAgaintsGoldenFiles());
+
DexVm vm = ToolHelper.getDexVm();
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index fc373d2..0f3cadc 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
@@ -91,6 +92,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
@Parameters(name = "{0}")
public static Collection<String[]> data() {
return Arrays.asList(new String[][]{
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidNTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidNTest.java
index bb8c686..83df845 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidNTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidNTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OffOrAuto;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
@@ -73,7 +74,7 @@
build(inputFile, out);
- if (!ToolHelper.artSupported()) {
+ if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
return;
}
@@ -118,6 +119,8 @@
@Rule public ExpectedException thrown = ExpectedException.none();
+ @Rule public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
@Test
public void staticInterfaceMethods() throws Throwable {
test("staticinterfacemethods", "interfacemethods", "StaticInterfaceMethods")
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 9fdbf0a..2c6a72a 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.utils.DexInspector.InvokeInstructionSubject;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OffOrAuto;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
@@ -47,6 +48,7 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestWatcher;
public abstract class RunExamplesAndroidOTest
<B extends BaseCommand.Builder<? extends BaseCommand, B>> {
@@ -148,7 +150,7 @@
build(inputFile, out);
- if (!ToolHelper.artSupported()) {
+ if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
return;
}
@@ -270,6 +272,9 @@
@Rule
public ExpectedException thrown = ExpectedException.none();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
boolean failsOn(Map<ToolHelper.DexVm.Version, List<String>> failsOn, String name) {
Version vmVersion = ToolHelper.getDexVm().getVersion();
return failsOn.containsKey(vmVersion)
@@ -553,14 +558,14 @@
throws IOException {
boolean expectedToFail = expectedToFail(testName);
- if (expectedToFail) {
+ if (expectedToFail && !ToolHelper.compareAgaintsGoldenFiles()) {
thrown.expect(Throwable.class);
}
String output = ToolHelper.runArtNoVerificationErrors(
Arrays.stream(dexes).map(path -> path.toString()).collect(Collectors.toList()),
qualifiedMainClass,
null);
- if (!expectedToFail && !skipRunningOnJvm(testName)) {
+ if (!expectedToFail && !skipRunningOnJvm(testName) && !ToolHelper.compareAgaintsGoldenFiles()) {
ToolHelper.ProcessResult javaResult =
ToolHelper.runJava(ImmutableList.copyOf(jars), qualifiedMainClass);
assertEquals("JVM run failed", javaResult.exitCode, 0);
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
index bc898bd..182fe80 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.utils.DexInspector.InstructionSubject;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OffOrAuto;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
@@ -143,7 +144,7 @@
build(inputFile, out);
- if (!ToolHelper.artSupported()) {
+ if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
return;
}
@@ -193,6 +194,9 @@
@Rule
public ExpectedException thrown = ExpectedException.none();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
boolean failsOn(Map<DexVm.Version, List<String>> failsOn, String name) {
DexVm.Version vmVersion = ToolHelper.getDexVm().getVersion();
return failsOn.containsKey(vmVersion)
diff --git a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
index 281b0da..284ed68 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.utils.DexInspector.InstructionSubject;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OffOrAuto;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
@@ -143,7 +144,7 @@
build(inputFile, out);
- if (!ToolHelper.artSupported()) {
+ if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
return;
}
@@ -224,6 +225,9 @@
@Rule
public ExpectedException thrown = ExpectedException.none();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
boolean failsOn(Map<DexVm.Version, List<String>> failsOn, String name) {
DexVm.Version vmVersion = ToolHelper.getDexVm().getVersion();
return failsOn.containsKey(vmVersion)
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 331af0a..add86c2 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.PreloadedClassFileProvider;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@@ -59,6 +60,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
/**
* Check if tests should also run Proguard when applicable.
*/
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 0a4416a..000076e 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -23,18 +23,23 @@
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
+import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.ZipUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
+import com.google.gson.Gson;
import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -702,6 +707,10 @@
return true;
}
+ public static boolean isDex2OatSupported() {
+ return !isWindows();
+ }
+
public static Path getClassPathForTests() {
return Paths.get(BUILD_DIR, "classes", "test");
}
@@ -1021,17 +1030,197 @@
return runArtRaw(files, mainClass, extras, null);
}
+ // Index used to name directory aimed at storing dex files and process result
+ // for one invokation of runArtRaw() in order to avoid conflicts in case of
+ // multiple calls within the same test.
+ private static int testOutputPathIndex = 0;
+
public static ProcessResult runArtRaw(List<String> files, String mainClass,
Consumer<ArtCommandBuilder> extras, DexVm version)
throws IOException {
- ArtCommandBuilder builder =
- version != null ? new ArtCommandBuilder(version) : new ArtCommandBuilder();
- files.forEach(builder::appendClasspath);
- builder.setMainClass(mainClass);
- if (extras != null) {
- extras.accept(builder);
+
+ ArtCommandBuilder builder =
+ version != null ? new ArtCommandBuilder(version) : new ArtCommandBuilder();
+ files.forEach(builder::appendClasspath);
+ builder.setMainClass(mainClass);
+ if (extras != null) {
+ extras.accept(builder);
+ }
+
+ ProcessResult processResult = null;
+
+ // Whenever we start a new test method we reset the index count.
+ String reset_output_index = System.getProperty("reset_output_index");
+ if (reset_output_index != null) {
+ System.clearProperty("reset_output_index");
+ testOutputPathIndex = 0;
+ } else {
+ assert testOutputPathIndex >= 0;
+ testOutputPathIndex++;
+ }
+
+ String goldenFilesDirInProp = System.getProperty("use_golden_files_in");
+ if (goldenFilesDirInProp != null) {
+ File goldenFileDir = new File(goldenFilesDirInProp);
+ assert goldenFileDir.isDirectory();
+ processResult = compareAgainstGoldenFiles(
+ files.stream().map(f -> new File(f)).collect(Collectors.toList()), goldenFileDir);
+ if (processResult.exitCode == 0) {
+ processResult = readProcessResult(goldenFileDir);
+ }
+ } else {
+ processResult = runArtProcessRaw(builder);
+ }
+
+ String goldenFilesDirToProp = System.getProperty("generate_golden_files_to");
+ if (goldenFilesDirToProp != null) {
+ File goldenFileDir = new File(goldenFilesDirToProp);
+ assert goldenFileDir.isDirectory();
+ storeAsGoldenFiles(files.stream().map(f -> new File(f)).collect(Collectors.toList()),
+ goldenFileDir);
+ storeProcessResult(processResult, goldenFileDir);
+ }
+
+ return processResult;
+ }
+
+ private static Path findNonConflictingDestinationFilePath(Path testOutputPath) {
+ int index = 0;
+ Path destFilePath;
+ do {
+ destFilePath = Paths.get(testOutputPath.toString(),
+ "classes-" + String.format("%03d", index) + FileUtils.DEX_EXTENSION);
+ index++;
+ } while (destFilePath.toFile().exists());
+
+ return destFilePath;
+ }
+
+ private static Path getTestOutputPath(File destDir) throws IOException {
+ assert destDir.exists();
+ assert destDir.isDirectory();
+
+ String testClassName = System.getProperty("test_class_name");
+ String testName = System.getProperty("test_name");
+ String headSha1 = System.getProperty("test_git_HEAD_sha1");
+
+ assert testClassName != null;
+ assert testName != null;
+ assert headSha1 != null;
+
+ return Files.createDirectories(
+ Paths.get(destDir.getAbsolutePath(), headSha1, testClassName, testName + "-" + String
+ .format("%03d", testOutputPathIndex)));
+ }
+
+ private static List<File> unzipDexFilesArchive(File zipFile) throws IOException {
+ File tmpDir = Files.createTempDirectory("r8-test-").toFile();
+ tmpDir.deleteOnExit();
+ return ZipUtils.unzip(zipFile.getAbsolutePath(), tmpDir);
+ }
+
+ private static void storeAsGoldenFiles(List<File> files, File destDir) throws IOException {
+ Path testOutputPath = getTestOutputPath(destDir);
+
+ for (File f : files) {
+ Path filePath = f.toPath();
+ // TODO(jmhenaff): Check it's been produced by D8/R8?
+ List<File> testFiles = Collections.singletonList(f);
+ if (FileUtils.isArchive(filePath)) {
+ testFiles = unzipDexFilesArchive(f);
+ }
+ for (File testFile : testFiles) {
+ Path testFilePath = testFile.toPath();
+ if (FileUtils.isDexFile(testFilePath)) {
+ Path destFile = findNonConflictingDestinationFilePath(testOutputPath);
+ FileUtils.writeToFile(destFile, null, Files.readAllBytes(testFilePath));
+ }
+ }
}
- return runArtProcessRaw(builder);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void storeProcessResult(ProcessResult processResult, File dest)
+ throws IOException {
+ Gson gson = new Gson();
+ Path testOutputPath = getTestOutputPath(dest);
+ try (FileWriter fw = new FileWriter(new File(testOutputPath.toFile(), "processResult.json"))) {
+ gson.toJson(processResult, ProcessResult.class, fw);
+ }
+ }
+
+ private static ProcessResult readProcessResult(File dest) throws IOException {
+ File processResultFile = new File(getTestOutputPath(dest).toFile(), "processResult.json");
+ Gson gson = new Gson();
+ try (FileReader fr = new FileReader(processResultFile)) {
+ return gson.fromJson(fr, ProcessResult.class);
+ }
+ }
+
+ private static ProcessResult compareAgainstGoldenFiles(List<File> files, File destDir)
+ throws IOException {
+ Path testOutputPath = getTestOutputPath(destDir);
+
+ int index = 0;
+ String stdErr = "";
+ boolean passed = true;
+ for (File f : files) {
+ Path filePath = f.toPath();
+
+ List<File> testFiles = Collections.singletonList(f);
+ if (FileUtils.isArchive(filePath)) {
+ testFiles = unzipDexFilesArchive(f);
+ }
+
+ for (File testFile : testFiles) {
+ Path testFilePath = testFile.toPath();
+ // TODO(jmhenaff): Check it's been produced by D8/R8?
+ if (FileUtils.isDexFile(testFilePath)) {
+ File goldenFile = Paths.get(testOutputPath.toString(),
+ "classes-" + String.format("%03d", index) + FileUtils.DEX_EXTENSION).toFile();
+ if (!goldenFile.exists()) {
+ String fileDesc = "'" + testFile.getAbsolutePath() + "'";
+ if (FileUtils.isZipFile(filePath)) {
+ fileDesc += " (extracted from '" + f.getAbsolutePath() + "')";
+ }
+ stdErr += "Cannot find golden file '" + goldenFile.getAbsolutePath()
+ + "' to compare against test file " + fileDesc + "\n";
+ passed = false;
+ } else if (!com.google.common.io.Files.equal(testFile, goldenFile)) {
+ String fileDesc = "'" + testFile.getAbsolutePath() + "'";
+ if (FileUtils.isZipFile(filePath)) {
+ fileDesc += " (extracted from '" + f.getAbsolutePath() + "')";
+ }
+ stdErr +=
+ "File " + fileDesc + " differs from golden file '" + goldenFile.getAbsolutePath()
+ + "'\n";
+ passed = false;
+ }
+ index++;
+ }
+ }
+ }
+ // Ensure we processed as many files as there are golden files
+ File goldenFile = Paths.get(testOutputPath.toString(),
+ "classes-" + String.format("%03d", index) + FileUtils.DEX_EXTENSION).toFile();
+ if (goldenFile.exists()) {
+ stdErr += "Less dex files have been produced: there is at least one more golden file ('"
+ + goldenFile.getAbsolutePath() + "'\n";
+ passed = false;
+ }
+ return new ProcessResult(passed ? 0 : -1, "", stdErr);
+ }
+
+ public static boolean dealsWithGoldenFiles() {
+ return compareAgaintsGoldenFiles() || generateGoldenFiles();
+ }
+
+ public static boolean compareAgaintsGoldenFiles() {
+ return System.getProperty("use_golden_files_in") != null;
+ }
+
+ public static boolean generateGoldenFiles() {
+ return System.getProperty("generate_golden_files_to") != null;
}
public static ProcessResult runArtNoVerificationErrorsRaw(String file, String mainClass)
@@ -1086,7 +1275,7 @@
}
private static ProcessResult runArtProcessRaw(ArtCommandBuilder builder) throws IOException {
- Assume.assumeTrue(ToolHelper.artSupported());
+ Assume.assumeTrue(artSupported() || dealsWithGoldenFiles());
ProcessResult result;
if (builder.isForDevice()) {
try {
@@ -1161,7 +1350,7 @@
}
public static void runDex2Oat(Path file, Path outFile, DexVm vm) throws IOException {
- Assume.assumeTrue(ToolHelper.artSupported());
+ Assume.assumeTrue(ToolHelper.isDex2OatSupported());
// TODO(jmhenaff): find a way to run this on windows (push dex and run on device/emulator?)
Assume.assumeTrue(!ToolHelper.isWindows());
assert Files.exists(file);
diff --git a/src/test/java/com/android/tools/r8/VmTestRunner.java b/src/test/java/com/android/tools/r8/VmTestRunner.java
index 978cbe7..a3e76a4 100644
--- a/src/test/java/com/android/tools/r8/VmTestRunner.java
+++ b/src/test/java/com/android/tools/r8/VmTestRunner.java
@@ -68,7 +68,7 @@
@Override
protected boolean isIgnored(FrameworkMethod child) {
// Do not run VM tests if running VMs is not even supported.
- if (!ToolHelper.artSupported()) {
+ if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
return true;
}
if (super.isIgnored(child)) {
diff --git a/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java b/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
index a24e95a..7d88649 100644
--- a/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import java.nio.file.Path;
import org.junit.Rule;
import org.junit.Test;
@@ -25,6 +26,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
@Test
public void test() throws Exception {
ProcessResult runInput =
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
index e43ffd7..6069b4c 100644
--- a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
@@ -31,6 +31,7 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+
@RunWith(Parameterized.class)
public class MethodHandleTestRunner extends TestBase {
static final Class<?> CLASS = MethodHandleTest.class;
@@ -143,8 +144,8 @@
if (runInput.exitCode != runDex.exitCode) {
System.out.println(runDex.stderr);
}
- assertEquals(runInput.stdout, runDex.stdout);
assertEquals(runInput.exitCode, runDex.exitCode);
+ assertEquals(runInput.stdout, runDex.stdout);
}
private void build(ProgramConsumer programConsumer) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
index 25356ae..d41ee84 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.naming.MemberNaming.Signature;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
@@ -113,6 +114,9 @@
@Rule
public TestName testName = new TestName();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
protected static final boolean supportsDefaultMethod(DebugTestConfig config) {
return config.isCfRuntime()
|| ToolHelper.getMinApiLevelForDexVm().getLevel() >= AndroidApiLevel.N.getLevel();
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java b/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
index d0ad1df..6f85b18 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
@@ -31,6 +32,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
static AndroidApp compileWithD8(Class... classes) throws IOException, CompilationFailedException {
D8Command.Builder builder = D8Command.builder();
for (Class clazz : classes) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningRegressionTests.java b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningRegressionTests.java
index 6760bdd..cb6df88 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningRegressionTests.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningRegressionTests.java
@@ -35,7 +35,7 @@
}
private void buildAndTest(String folder, String mainClass) throws Exception {
- Assume.assumeTrue(ToolHelper.artSupported());
+ Assume.assumeTrue(ToolHelper.artSupported() || ToolHelper.compareAgaintsGoldenFiles());
Path proguardRules = Paths.get(ToolHelper.EXAMPLES_DIR, folder, "keep-rules.txt");
Path jarFile =
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeInterfaceToInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeInterfaceToInvokeVirtualTest.java
index 57d694d..86c15a2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeInterfaceToInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeInterfaceToInvokeVirtualTest.java
@@ -87,4 +87,4 @@
assertEquals(0, artOutput.exitCode);
assertEquals(javaOutput.stdout.trim(), artOutput.stdout.trim());
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java b/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
index bdedf43..3028525 100644
--- a/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
+++ b/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.io.File;
@@ -30,6 +31,7 @@
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -267,6 +269,9 @@
@ClassRule
public static TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
@BeforeClass
public static void compileLibraries() throws Exception {
// Selects appropriate jar according to min api level for the selected runtime.
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index c175e04..f99934e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -223,7 +223,7 @@
protected void runTest(String folder, String mainClass, String extraProguardRules,
Consumer<InternalOptions> optionsConsumer, AndroidAppInspector inspector) throws Exception {
- Assume.assumeTrue(ToolHelper.artSupported());
+ Assume.assumeTrue(ToolHelper.artSupported() || ToolHelper.compareAgaintsGoldenFiles());
String proguardRules = buildProguardRules(mainClass);
if (extraProguardRules != null) {
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
index e2dfb6d..46a439d 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.utils.DexInspector.InstructionSubject;
import com.android.tools.r8.utils.DexInspector.InvokeInstructionSubject;
import com.android.tools.r8.utils.DexInspector.MethodSubject;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
@@ -26,6 +27,7 @@
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import org.junit.Assert;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -60,6 +62,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
public MemberRebindingTest(TestConfiguration configuration) {
this.kind = configuration.kind;
originalDex = configuration.getDexPath();
@@ -319,9 +324,8 @@
@Test
public void memberRebindingTest() throws IOException, InterruptedException, ExecutionException {
- if (!ToolHelper.artSupported()) {
- return;
- }
+ Assume.assumeTrue(ToolHelper.artSupported() || ToolHelper.compareAgaintsGoldenFiles());
+
String out = temp.getRoot().getCanonicalPath();
Path processed = Paths.get(out, "classes.dex");
diff --git a/src/test/java/com/android/tools/r8/resource/DataResourceTest.java b/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
index 2df0612..66161e1 100644
--- a/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
+++ b/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -23,6 +24,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
@Test
public void dataResourceTest() throws IOException, CompilationFailedException {
String packageName = "dataresource";
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
index f341969..c9488b4 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.utils.DexInspector.FoundFieldSubject;
import com.android.tools.r8.utils.DexInspector.FoundMethodSubject;
import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -76,6 +77,9 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+ @Rule
+ public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+
protected TreeShakingTest(
String name, String mainClass, Frontend frontend, Backend backend, MinifyMode minify) {
this.name = name;
@@ -204,7 +208,7 @@
}
return;
}
- if (!ToolHelper.artSupported()) {
+ if (!ToolHelper.artSupported() && !ToolHelper.compareAgaintsGoldenFiles()) {
return;
}
Consumer<ArtCommandBuilder> extraArtArgs = builder -> {
diff --git a/src/test/java/com/android/tools/r8/utils/TestDescriptionWatcher.java b/src/test/java/com/android/tools/r8/utils/TestDescriptionWatcher.java
new file mode 100644
index 0000000..5295c0e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/TestDescriptionWatcher.java
@@ -0,0 +1,29 @@
+// 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.
+package com.android.tools.r8.utils;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+/**
+ * This {@link TestWatcher} passes test description information
+ * (namely test class and method names) to the test framework
+ * via system properties.
+ */
+public class TestDescriptionWatcher extends TestWatcher {
+
+ @Override
+ protected void starting(Description description) {
+ System.setProperty("test_class_name", description.getClassName());
+ System.setProperty("test_name", description.getMethodName());
+ System.setProperty("reset_output_index", "true");
+ }
+
+ @Override
+ protected void finished(Description description) {
+ System.clearProperty("test_class_name");
+ System.clearProperty("test_name");
+ }
+
+}
diff --git a/tools/download_from_x20.py b/tools/download_from_x20.py
index 01ba4e1..5f64684 100755
--- a/tools/download_from_x20.py
+++ b/tools/download_from_x20.py
@@ -19,17 +19,10 @@
def parse_options():
return optparse.OptionParser().parse_args()
-def extract_dir(filename):
- return filename[0:len(filename) - len('.tar.gz')]
-
-def unpack_archive(filename):
- dest_dir = extract_dir(filename)
- if os.path.exists(dest_dir):
- print 'Deleting existing dir %s' % dest_dir
- shutil.rmtree(dest_dir)
- dirname = os.path.dirname(os.path.abspath(filename))
- with tarfile.open(filename, 'r:gz') as tar:
- tar.extractall(path=dirname)
+def download(src, dest):
+ print 'Downloading %s to %s' % (src, dest)
+ shutil.copyfile(src, dest)
+ utils.unpack_archive(dest)
def Main():
(options, args) = parse_options()
@@ -41,20 +34,18 @@
sha1 = input_sha.readline()
if os.path.exists(dest) and utils.get_sha1(dest) == sha1:
print 'sha1 matches, not downloading'
- dest_dir = extract_dir(dest)
+ dest_dir = utils.extract_dir(dest)
if os.path.exists(dest_dir):
print 'destination directory exists, no extraction'
else:
- unpack_archive(dest)
+ utils.unpack_archive(dest)
return
src = os.path.join(GMSCORE_DEPS, sha1)
if not os.path.exists(src):
print 'File (%s) does not exist on x20' % src
print 'Maybe pass -Pno_internal to your gradle invocation'
return 42
- print 'Downloading %s to %s' % (src, dest)
- shutil.copyfile(src, dest)
- unpack_archive(dest)
+ download(src, dest)
if __name__ == '__main__':
sys.exit(Main())
diff --git a/tools/test.py b/tools/test.py
index ed99c1d..b92c8dc 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -15,6 +15,7 @@
import utils
import uuid
import notify
+import upload_to_x20
ALL_ART_VMS = ["default", "7.0.0", "6.0.1", "5.1.1", "4.4.4", "4.0.4"]
@@ -78,6 +79,13 @@
' Note that the directory will not be cleared before the test.')
result.add_option('--java_home',
help='Use a custom java version to run tests.')
+ result.add_option('--generate_golden_files_to',
+ help='Store dex files produced by tests in the specified directory.'
+ ' It is aimed to be read on platforms with no host runtime available'
+ ' for comparison.')
+ result.add_option('--use_golden_files_in',
+ help='Download golden files hierarchy for this commit in the specified'
+ ' location and use them instead of executing on host runtime.')
return result.parse_args()
@@ -93,7 +101,7 @@
def Main():
(options, args) = ParseOptions()
- gradle_args = []
+ gradle_args = ['--stacktrace']
# Set all necessary Gradle properties and options first.
if options.verbose:
gradle_args.append('-Pprint_test_stdout')
@@ -134,7 +142,16 @@
os.makedirs(options.test_dir)
if options.java_home:
gradle_args.append('-Dorg.gradle.java.home=' + options.java_home)
-
+ if options.generate_golden_files_to:
+ gradle_args.append('-Pgenerate_golden_files_to=' + options.generate_golden_files_to)
+ if not os.path.exists(options.generate_golden_files_to):
+ os.makedirs(options.generate_golden_files_to)
+ gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
+ if options.use_golden_files_in:
+ gradle_args.append('-Puse_golden_files_in=' + options.use_golden_files_in)
+ if not os.path.exists(options.use_golden_files_in):
+ os.makedirs(options.use_golden_files_in)
+ gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
# Add Gradle tasks
gradle_args.append('cleanTest')
gradle_args.append('test')
@@ -146,12 +163,29 @@
# Create Jacoco report after tests.
gradle_args.append('jacocoTestReport')
+ if options.use_golden_files_in:
+ sha1 = '%s' % utils.get_HEAD_sha1()
+ with utils.ChangedWorkingDirectory(options.use_golden_files_in):
+ utils.download_file_from_cloud_storage(
+ 'gs://r8-test-results/golden-files/%s.tar.gz' % sha1,
+ '%s.tar.gz' % sha1)
+ utils.unpack_archive('%s.tar.gz' % sha1)
+
+
# Now run tests on selected runtime(s).
vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
for art_vm in vms_to_test:
vm_kind_to_test = "_" + options.dex_vm_kind if art_vm != "default" else ""
return_code = gradle.RunGradle(gradle_args + ['-Pdex_vm=%s' % (art_vm + vm_kind_to_test)],
throw_on_failure=False)
+
+ if options.generate_golden_files_to:
+ sha1 = '%s' % utils.get_HEAD_sha1()
+ with utils.ChangedWorkingDirectory(options.generate_golden_files_to):
+ archive = utils.create_archive(sha1)
+ utils.upload_file_to_cloud_storage(archive,
+ 'gs://r8-test-results/golden-files/' + archive)
+
if return_code != 0:
if options.archive_failures and os.name != 'nt':
archive_failures()
diff --git a/tools/upload_to_x20.py b/tools/upload_to_x20.py
index 1efacf5..2d08362 100755
--- a/tools/upload_to_x20.py
+++ b/tools/upload_to_x20.py
@@ -20,11 +20,10 @@
def parse_options():
return optparse.OptionParser().parse_args()
-def create_archive(name):
- tarname = '%s.tar.gz' % name
- with tarfile.open(tarname, 'w:gz') as tar:
- tar.add(name)
- return tarname
+def uploadFile(filename, dest):
+ print 'Uploading to %s' % dest
+ shutil.copyfile(filename, dest)
+ subprocess.check_call(['chmod', '664', dest])
def Main():
(options, args) = parse_options()
@@ -34,12 +33,10 @@
if not name in os.listdir('.'):
print 'You must be standing directly below the directory you are uploading'
return 1
- filename = create_archive(name)
+ filename = utils.create_archive(name)
sha1 = utils.get_sha1(filename)
dest = os.path.join(GMSCORE_DEPS, sha1)
- print 'Uploading to %s' % dest
- shutil.copyfile(filename, dest)
- subprocess.check_call(['chmod', '664', dest])
+ uploadFile(filename, dest)
sha1_file = '%s.sha1' % filename
with open(sha1_file, 'w') as output:
output.write(sha1)
diff --git a/tools/utils.py b/tools/utils.py
index 3aab572..859da97 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -10,6 +10,7 @@
import shutil
import subprocess
import sys
+import tarfile
import tempfile
TOOLS_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..')))
@@ -71,6 +72,12 @@
sha1.update(chunk)
return sha1.hexdigest()
+def get_HEAD_sha1():
+ cmd = ['git', 'rev-parse', 'HEAD']
+ PrintCmd(cmd)
+ with ChangedWorkingDirectory(REPO_ROOT):
+ return subprocess.check_output(cmd).strip()
+
def makedirs_if_needed(path):
try:
os.makedirs(path)
@@ -92,6 +99,29 @@
PrintCmd(cmd)
subprocess.check_call(cmd)
+def download_file_from_cloud_storage(source, destination):
+ cmd = ['gsutil.py', 'cp', source, destination]
+ PrintCmd(cmd)
+ subprocess.check_call(cmd)
+
+def create_archive(name):
+ tarname = '%s.tar.gz' % name
+ with tarfile.open(tarname, 'w:gz') as tar:
+ tar.add(name)
+ return tarname
+
+def extract_dir(filename):
+ return filename[0:len(filename) - len('.tar.gz')]
+
+def unpack_archive(filename):
+ dest_dir = extract_dir(filename)
+ if os.path.exists(dest_dir):
+ print 'Deleting existing dir %s' % dest_dir
+ shutil.rmtree(dest_dir)
+ dirname = os.path.dirname(os.path.abspath(filename))
+ with tarfile.open(filename, 'r:gz') as tar:
+ tar.extractall(path=dirname)
+
# Note that gcs is eventually consistent with regards to list operations.
# This is not a problem in our case, but don't ever use this method
# for synchronization.