| #!/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. |
| 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:])) |