Introduce main method to convert desugared library specifications
Change-Id: Ic38249cca5dca80e3b9e14b2800c5a3a8cd3a8ae
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/DesugaredLibraryConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/DesugaredLibraryConverter.java
new file mode 100644
index 0000000..afddbae
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/DesugaredLibraryConverter.java
@@ -0,0 +1,138 @@
+// Copyright (c) 2022, 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.ir.desugar.desugaredlibrary.specificationconversion;
+
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.isHumanSpecification;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.isMachineSpecification;
+
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.StringResource.FileResource;
+import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.MultiAPILevelHumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.MultiAPILevelHumanDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.MultiAPILevelLegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.MultiAPILevelLegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MultiAPILevelMachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.Box;
+import com.android.tools.r8.utils.ExceptionDiagnostic;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableSet;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+public class DesugaredLibraryConverter {
+
+ public static void main(String[] args) throws IOException {
+ Path jsonFile = Paths.get(args[0]);
+ Path desugaredLibraryJar = Paths.get(args[1]);
+ Path androidJar = Paths.get(args[2]);
+ Path output = Paths.get(args[3]);
+ convertMultiLevelAnythingToMachineSpecification(
+ jsonFile, ImmutableSet.of(desugaredLibraryJar), ImmutableSet.of(androidJar), output);
+ }
+
+ public static void convertMultiLevelAnythingToMachineSpecification(
+ Path jsonSpec, Set<Path> desugaredLibraryFiles, Set<Path> libraryFiles, Path output)
+ throws IOException {
+
+ InternalOptions options = new InternalOptions();
+
+ FileResource jsonResource = StringResource.fromFile(jsonSpec);
+ JsonObject jsonConfig = parseJsonConfig(options, jsonResource);
+
+ if (isMachineSpecification(jsonConfig, options.reporter, jsonResource.getOrigin())) {
+ // Nothing to convert;
+ Files.copy(jsonSpec, output);
+ return;
+ }
+
+ DexApplication appForConversion =
+ getAppForConversion(options, libraryFiles, desugaredLibraryFiles);
+ MultiAPILevelHumanDesugaredLibrarySpecification humanSpec =
+ getInputAsHumanSpecification(options, jsonResource, jsonConfig, appForConversion);
+ String outputString = convertToMachineSpecification(options, appForConversion, humanSpec);
+
+ Files.write(output, Collections.singleton(outputString));
+ }
+
+ private static String convertToMachineSpecification(
+ InternalOptions options,
+ DexApplication appForConversion,
+ MultiAPILevelHumanDesugaredLibrarySpecification humanSpec)
+ throws IOException {
+ HumanToMachineSpecificationConverter converter =
+ new HumanToMachineSpecificationConverter(Timing.empty());
+ MultiAPILevelMachineDesugaredLibrarySpecification machineSpec =
+ converter.convertAllAPILevels(humanSpec, appForConversion);
+ Box<String> machineJson = new Box<>();
+ MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.export(
+ machineSpec, (string, handler) -> machineJson.set(string), options.dexItemFactory());
+ return machineJson.get();
+ }
+
+ private static JsonObject parseJsonConfig(InternalOptions options, FileResource jsonResource) {
+ JsonObject jsonConfig;
+ try {
+ String jsonConfigString = jsonResource.getString();
+ JsonParser parser = new JsonParser();
+ jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
+ } catch (Exception e) {
+ throw options.reporter.fatalError(new ExceptionDiagnostic(e, jsonResource.getOrigin()));
+ }
+ return jsonConfig;
+ }
+
+ /**
+ * Parse the human specification, or parse and convert the legacy specification into human
+ * specification.
+ */
+ private static MultiAPILevelHumanDesugaredLibrarySpecification getInputAsHumanSpecification(
+ InternalOptions options,
+ FileResource jsonResource,
+ JsonObject jsonConfig,
+ DexApplication appForConversion)
+ throws IOException {
+ if (!isHumanSpecification(jsonConfig, options.reporter, jsonResource.getOrigin())) {
+ MultiAPILevelLegacyDesugaredLibrarySpecification legacySpec =
+ new MultiAPILevelLegacyDesugaredLibrarySpecificationParser(
+ options.dexItemFactory(), options.reporter)
+ .parseMultiLevelConfiguration(jsonResource);
+
+ LegacyToHumanSpecificationConverter converter =
+ new LegacyToHumanSpecificationConverter(Timing.empty());
+
+ return converter.convertAllAPILevels(legacySpec, appForConversion);
+ }
+ return new MultiAPILevelHumanDesugaredLibrarySpecificationParser(
+ options.dexItemFactory(), options.reporter)
+ .parseMultiLevelConfiguration(jsonResource);
+ }
+
+ public static DexApplication getAppForConversion(
+ InternalOptions options, Set<Path> androidJar, Set<Path> desugaredlibJar) throws IOException {
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder.addProgramFiles(desugaredlibJar);
+ AndroidApp inputApp = builder.addLibraryFiles(androidJar).build();
+ ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
+ ExecutorService executorService = ThreadUtils.getExecutorService(options);
+ assert !options.ignoreJavaLibraryOverride;
+ options.ignoreJavaLibraryOverride = true;
+ DexApplication app = applicationReader.read(executorService);
+ options.ignoreJavaLibraryOverride = false;
+ return app;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index cd5c568..a8a034d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -32,6 +32,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineTopLevelFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MultiAPILevelMachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.DesugaredLibraryConverter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.origin.Origin;
@@ -41,6 +42,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.Map;
import org.junit.Assume;
import org.junit.Test;
@@ -110,6 +112,35 @@
}
@Test
+ public void testMultiLevelLegacyUsingMain() throws IOException {
+ LibraryDesugaringSpecification legacySpec = LibraryDesugaringSpecification.JDK8;
+ testMultiLevelUsingMain(legacySpec);
+ }
+
+ @Test
+ public void testMultiLevelHumanUsingMain() throws IOException {
+ LibraryDesugaringSpecification humanSpec = LibraryDesugaringSpecification.JDK11;
+ testMultiLevelUsingMain(humanSpec);
+ }
+
+ private void testMultiLevelUsingMain(LibraryDesugaringSpecification spec) throws IOException {
+ Path output = temp.newFile().toPath();
+ DesugaredLibraryConverter.convertMultiLevelAnythingToMachineSpecification(
+ spec.getSpecification(), spec.getDesugarJdkLibs(), spec.getLibraryFiles(), output);
+
+ InternalOptions options = new InternalOptions();
+ MachineDesugaredLibrarySpecification machineSpecParsed =
+ new MachineDesugaredLibrarySpecificationParser(
+ options.dexItemFactory(),
+ options.reporter,
+ true,
+ AndroidApiLevel.B.getLevel(),
+ new SyntheticNaming())
+ .parse(StringResource.fromFile(output));
+ assertFalse(machineSpecParsed.getRewriteType().isEmpty());
+ }
+
+ @Test
public void testSingleLevel() throws IOException {
Assume.assumeTrue(ToolHelper.isLocalDevelopment());