Extend compiledump to desugared library keep rules

This adds an extra output artifact desugared-library-keep-rules.config when using D8/R8 with a desugared library configuration.

This also adds a new flag --pg-conf to compiledump.py. This makes it possibly to pass the desugared-library-keep-rules.config file to the L8 compilation of another dump.

Change-Id: I8a737bd4c84c1bcb57eae884748d0d1df381011d
diff --git a/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java b/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
index 919d998..57cdc5f 100644
--- a/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
+++ b/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.R8;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.R8Command.Builder;
+import com.android.tools.r8.StringConsumer;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.nio.file.Files;
@@ -60,6 +61,7 @@
           "--pg-conf",
           "--pg-map-output",
           "--desugared-lib",
+          "--desugared-lib-pg-conf-output",
           "--threads",
           "--startup-profile");
 
@@ -80,6 +82,7 @@
     Path outputPath = null;
     Path pgMapOutput = null;
     Path desugaredLibJson = null;
+    StringConsumer desugaredLibKeepRuleConsumer = null;
     CompilationMode compilationMode = CompilationMode.RELEASE;
     List<Path> program = new ArrayList<>();
     Map<Path, Path> features = new LinkedHashMap<>();
@@ -163,6 +166,11 @@
               desugaredLibJson = Paths.get(operand);
               break;
             }
+          case "--desugared-lib-pg-conf-output":
+            {
+              desugaredLibKeepRuleConsumer = new StringConsumer.FileConsumer(Paths.get(operand));
+              break;
+            }
           case "--threads":
             {
               threads = Integer.parseInt(operand);
@@ -222,6 +230,9 @@
     if (desugaredLibJson != null) {
       commandBuilder.addDesugaredLibraryConfiguration(readAllBytesJava7(desugaredLibJson));
     }
+    if (desugaredLibKeepRuleConsumer != null) {
+      commandBuilder.setDesugaredLibraryKeepRuleConsumer(desugaredLibKeepRuleConsumer);
+    }
     if (outputMode != OutputMode.ClassFile) {
       commandBuilder.setMinApiLevel(minApi);
     }
diff --git a/tools/compiledump.py b/tools/compiledump.py
index 3af251e..12c8288 100755
--- a/tools/compiledump.py
+++ b/tools/compiledump.py
@@ -5,6 +5,7 @@
 
 import argparse
 import os
+import shutil
 import subprocess
 import sys
 import zipfile
@@ -73,6 +74,10 @@
     '--r8-flags', '--r8_flags',
     help='Additional option(s) for the compiler.')
   parser.add_argument(
+    '--pg-conf', '--pg_conf',
+    help='Keep rule file(s).',
+    action='append')
+  parser.add_argument(
     '--override',
     help='Do not override any extracted dump in temp-dir',
     default=False,
@@ -273,6 +278,22 @@
 def is_l8_compiler(compiler):
   return compiler.startswith('l8')
 
+def is_r8_compiler(compiler):
+  return compiler.startswith('r8')
+
+def determine_config_files(args, dump, temp):
+  if args.pg_conf:
+    config_files = []
+    for config_file in args.pg_conf:
+      dst = os.path.join(temp, 'proguard-%s.config' % len(config_files))
+      shutil.copyfile(config_file, dst)
+      config_files.append(dst)
+    return config_files
+  dump_config_file = dump.config_file()
+  if dump_config_file:
+    return [dump_config_file]
+  return []
+
 def determine_output(args, temp):
   return os.path.join(temp, 'out.jar')
 
@@ -283,6 +304,9 @@
     return build_properties.get('min-api')
   return None
 
+def determine_desugared_lib_pg_conf_output(temp):
+  return os.path.join(temp, 'desugared-library-keep-rules.config')
+
 def determine_feature_output(feature_jar, temp):
   return os.path.join(temp, os.path.basename(feature_jar)[:-4] + ".out.jar")
 
@@ -337,6 +361,9 @@
   utils.download_file_from_cloud_storage(source, dest)
   return dest
 
+def clean_configs(files, args):
+  for file in files:
+    clean_config(file, args)
 
 def clean_config(file, args):
   with open(file) as f:
@@ -362,7 +389,7 @@
 
 def clean_config_line(line, minify, optimize, shrink):
   if ('-injars' in line or '-libraryjars' in line or
-      '-print' in line):
+      '-print' in line or '-applymapping' in line):
     return True
   if minify == 'force-enable' and '-dontobfuscate' in line:
     return True
@@ -424,6 +451,7 @@
     build_properties = determine_build_properties(args, dump)
     version = determine_version(args, dump)
     compiler = determine_compiler(args, build_properties)
+    config_files = determine_config_files(args, dump, temp)
     out = determine_output(args, temp)
     min_api = determine_min_api(args, build_properties)
     classfile = determine_class_file(args, build_properties)
@@ -479,28 +507,26 @@
       cmd.extend(['--classpath', dump.classpath_jar()])
     if dump.desugared_library_json() and not args.disable_desugared_lib:
       cmd.extend(['--desugared-lib', dump.desugared_library_json()])
-    if compiler != 'd8' and compiler != 'l8d8' and dump.config_file():
-      if hasattr(args, 'config_file_consumer') and args.config_file_consumer:
-        args.config_file_consumer(dump.config_file())
+      if not is_l8_compiler(compiler):
+        cmd.extend([
+            '--desugared-lib-pg-conf-output',
+            determine_desugared_lib_pg_conf_output(temp)])
+    if (is_r8_compiler(compiler) or compiler == 'l8') and config_files:
+      if hasattr(args, 'config_files_consumer') and args.config_files_consumer:
+        args.config_files_consumer(config_files)
       else:
         # If we get a dump from the wild we can't use -injars, -libraryjars or
         # -print{mapping,usage}
-        clean_config(dump.config_file(), args)
-      cmd.extend(['--pg-conf', dump.config_file()])
+        clean_configs(config_files, args)
+      for config_file in config_files:
+        cmd.extend(['--pg-conf', config_file])
+      cmd.extend(['--pg-map-output', '%s.map' % out])
     if dump.main_dex_list_resource():
       cmd.extend(['--main-dex-list', dump.main_dex_list_resource()])
     if dump.main_dex_rules_resource():
       cmd.extend(['--main-dex-rules', dump.main_dex_rules_resource()])
     for startup_profile_resource in dump.startup_profile_resources():
       cmd.extend(['--startup-profile', startup_profile_resource])
-    if is_l8_compiler(compiler):
-      if compiler == 'l8':
-        if dump.config_file():
-          cmd.extend(['--pg-map-output', '%s.map' % out])
-      else:
-        assert compiler == 'l8d8'
-    elif compiler != 'd8':
-      cmd.extend(['--pg-map-output', '%s.map' % out])
     if min_api:
       cmd.extend(['--min-api', min_api])
     if classfile:
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py
index 0f90ab1..78b12c7 100755
--- a/tools/run_on_app_dump.py
+++ b/tools/run_on_app_dump.py
@@ -666,9 +666,10 @@
 def build_app_with_shrinker(app, options, temp_dir, app_dir, shrinker,
                             compilation_step_index, compilation_steps,
                             prev_recomp_jar):
-  def config_file_consumer(file):
-    compiledump.clean_config(file, options)
-    remove_print_lines(file)
+  def config_files_consumer(files):
+    for file in files:
+      compiledump.clean_config(file, options)
+      remove_print_lines(file)
   args = AttrDict({
     'dump': dump_for_app(app_dir, app),
     'r8_jar': get_r8_jar(options, temp_dir, shrinker),
@@ -679,7 +680,7 @@
     'debug_agent': options.debug_agent,
     'program_jar': prev_recomp_jar,
     'nolib': not is_minified_r8(shrinker),
-    'config_file_consumer': config_file_consumer,
+    'config_files_consumer': config_files_consumer,
     'properties': app.compiler_properties,
     'disable_desugared_lib': False,
     'print_times': options.print_times,
@@ -720,16 +721,20 @@
 def build_test_with_shrinker(app, options, temp_dir, app_dir, shrinker,
                              compilation_step_index, mapping):
 
-  def rewrite_file(file):
-    compiledump.clean_config(file, options)
-    remove_print_lines(file)
-    with open(file) as f:
-      lines = f.readlines()
-    with open(file, 'w') as f:
-      for line in lines:
-        if '-applymapping' not in line:
-          f.write(line + '\n')
-      f.write("-applymapping " + mapping + '\n')
+  def rewrite_files(files):
+    add_applymapping = True
+    for file in files:
+      compiledump.clean_config(file, options)
+      remove_print_lines(file)
+      with open(file) as f:
+        lines = f.readlines()
+      with open(file, 'w') as f:
+        for line in lines:
+          if '-applymapping' not in line:
+            f.write(line + '\n')
+        if add_applymapping:
+          f.write("-applymapping " + mapping + '\n')
+          add_applymapping = False
 
   args = AttrDict({
     'dump': dump_test_for_app(app_dir, app),
@@ -741,7 +746,7 @@
     'nolib': not is_minified_r8(shrinker),
     # The config file will have an -applymapping reference to an old map.
     # Update it to point to mapping file build in the compilation of the app.
-    'config_file_consumer': rewrite_file,
+    'config_files_consumer': rewrite_files,
   })
 
   test_jar = os.path.join(