| #!/usr/bin/env python3 | 
 | # 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. | 
 | from __future__ import print_function | 
 | import os | 
 | import sys | 
 | import zipfile | 
 |  | 
 |  | 
 | # Proguard lookup program classes before library classes. In R8 this is | 
 | # not the behaviour (it used to be) R8 will check library classes before | 
 | # program classes. Some apps have duplicate classes in the library and program. | 
 | # To make these apps work with R8 simulate program classes before library | 
 | # classes by creating a new library jar which have all the provided library | 
 | # classes which are not also in program classes. | 
 | def SanitizeLibrariesInPgconf(sanitized_lib_path, | 
 |                               sanitized_pgconf_path, | 
 |                               pgconfs, | 
 |                               injars=None, | 
 |                               libraryjars=None): | 
 |     with open(sanitized_pgconf_path, 'w') as sanitized_pgconf: | 
 |         injars = [] if injars is None else injars | 
 |         libraryjars = [] if libraryjars is None else libraryjars | 
 |         for pgconf in pgconfs: | 
 |             pgconf_dirname = os.path.abspath(os.path.dirname(pgconf)) | 
 |             first_library_jar = True | 
 |             with open(pgconf) as pgconf_file: | 
 |                 for line in pgconf_file: | 
 |                     trimmed = line.strip() | 
 |                     if trimmed.startswith('-injars'): | 
 |                         # Collect -injars and leave them in the configuration. | 
 |                         injar = os.path.join(pgconf_dirname, | 
 |                                              trimmed[len('-injars'):].strip()) | 
 |                         injars.append(injar) | 
 |                         sanitized_pgconf.write('-injars {}\n'.format(injar)) | 
 |                     elif trimmed.startswith('-libraryjars'): | 
 |                         # Collect -libraryjars and replace them with the sanitized library. | 
 |                         libraryjar = os.path.join( | 
 |                             pgconf_dirname, | 
 |                             trimmed[len('-libraryjars'):].strip()) | 
 |                         libraryjars.append(libraryjar) | 
 |                         if first_library_jar: | 
 |                             sanitized_pgconf.write( | 
 |                                 '-libraryjars {}\n'.format(sanitized_lib_path)) | 
 |                             first_library_jar = False | 
 |                         sanitized_pgconf.write('# {}'.format(line)) | 
 |                     else: | 
 |                         sanitized_pgconf.write(line) | 
 |  | 
 |     SanitizeLibraries(sanitized_lib_path, libraryjars, injars) | 
 |  | 
 |  | 
 | def SanitizeLibraries(sanitized_lib_path, libraryjars, injars): | 
 |     program_entries = set() | 
 |     library_entries = set() | 
 |  | 
 |     for injar in injars: | 
 |         with zipfile.ZipFile(injar, 'r') as injar_zf: | 
 |             for zipinfo in injar_zf.infolist(): | 
 |                 program_entries.add(zipinfo.filename) | 
 |  | 
 |     with zipfile.ZipFile(sanitized_lib_path, 'w') as output_zf: | 
 |         for libraryjar in libraryjars: | 
 |             with zipfile.ZipFile(libraryjar, 'r') as input_zf: | 
 |                 for zipinfo in input_zf.infolist(): | 
 |                     if (not zipinfo.filename in program_entries and | 
 |                             not zipinfo.filename in library_entries): | 
 |                         library_entries.add(zipinfo.filename) | 
 |                         output_zf.writestr(zipinfo, input_zf.read(zipinfo)) | 
 |  | 
 |  | 
 | def usage(argv, error): | 
 |     print(error) | 
 |     print("Usage: sanitize_libraries.py <sanitized_lib> <sanitized_pgconf> (" + | 
 |           "--injar <existing_injar>" + "|--libraryjar <existing_library_jar>" + | 
 |           "|--pgconf <existing_pgconf>)+") | 
 |     return 1 | 
 |  | 
 |  | 
 | def main(argv): | 
 |     if (len(argv) < 4): | 
 |         return usage(argv, "Wrong number of arguments!") | 
 |     pgconfs = [] | 
 |     injars = [] | 
 |     libraryjars = [] | 
 |     i = 2 | 
 |     while i < len(argv): | 
 |         directive = argv[i] | 
 |         if directive not in ['--pgconf', '--injar', '--libraryjar']: | 
 |             return usage( | 
 |                 argv, | 
 |                 'Unexpected argument, expected one of --pgconf, --injar, and ' + | 
 |                 '--libraryjar.') | 
 |         if i + 1 >= len(argv): | 
 |             return usage(argv, 'Expected argument after ' + directive + '.') | 
 |         file = argv[i + 1] | 
 |         if directive == '--pgconf': | 
 |             pgconfs.append(file) | 
 |         elif directive == '--injar': | 
 |             injars.append(file) | 
 |         elif directive == '--libraryjar': | 
 |             libraryjars.append(file) | 
 |         i = i + 2 | 
 |     SanitizeLibrariesInPgconf(argv[0], argv[1], pgconfs, injars, libraryjars) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     sys.exit(main(sys.argv[1:])) |