Exemple #1
0
def CopyMainJar(output_dir, jar_path):
    libs_dir = os.path.join(output_dir, 'libs')
    build_utils.MakeDirectory(libs_dir)
    shutil.copy2(jar_path, libs_dir)
def main(args):
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    debug_temp_resources_dir = os.environ.get(_ENV_DEBUG_VARIABLE)
    if debug_temp_resources_dir:
        debug_temp_resources_dir = os.path.join(
            debug_temp_resources_dir, os.path.basename(options.arsc_path))
        build_utils.DeleteDirectory(debug_temp_resources_dir)
        build_utils.MakeDirectory(debug_temp_resources_dir)

    with resource_utils.BuildContext(debug_temp_resources_dir) as build:
        _PackageApk(options, build)

        # If --shared-resources-whitelist is used, the all resources listed in
        # the corresponding R.txt file will be non-final, and an onResourcesLoaded()
        # will be generated to adjust them at runtime.
        #
        # Otherwise, if --shared-resources is used, the all resources will be
        # non-final, and an onResourcesLoaded() method will be generated too.
        #
        # Otherwise, all resources will be final, and no method will be generated.
        #
        rjava_build_options = resource_utils.RJavaBuildOptions()
        if options.shared_resources_whitelist:
            rjava_build_options.ExportSomeResources(
                options.shared_resources_whitelist)
            rjava_build_options.GenerateOnResourcesLoaded()
        elif options.shared_resources or options.app_as_shared_lib:
            rjava_build_options.ExportAllResources()
            rjava_build_options.GenerateOnResourcesLoaded()

        custom_root_package_name = options.r_java_root_package_name
        grandparent_custom_package_name = None

        if options.package_name and not options.arsc_package_name:
            # Feature modules have their own custom root package name and should
            # inherit from the appropriate base module package. This behaviour should
            # not be present for test apks with an apk under test. Thus,
            # arsc_package_name is used as it is only defined for test apks with an
            # apk under test.
            custom_root_package_name = options.package_name
            grandparent_custom_package_name = options.r_java_root_package_name

        resource_utils.CreateRJavaFiles(
            build.srcjar_dir, None, build.r_txt_path,
            options.extra_res_packages, options.extra_r_text_files,
            rjava_build_options, options.srcjar_out, custom_root_package_name,
            grandparent_custom_package_name, options.extra_main_r_text_files)

        build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)

        # Sanity check that the created resources have the expected package ID.
        expected_id = _PackageIdFromOptions(options)
        if expected_id is None:
            expected_id = '0x00' if options.shared_resources else '0x7f'
        expected_id = int(expected_id, 16)
        _, package_id = resource_utils.ExtractArscPackage(
            options.aapt2_path,
            build.arsc_path if options.arsc_path else build.proto_path)
        if package_id != expected_id:
            raise Exception('Invalid package ID 0x%x (expected 0x%x)' %
                            (package_id, expected_id))

        _WriteOutputs(options, build)

    if options.depfile:
        build_utils.WriteDepfile(options.depfile,
                                 options.srcjar_out,
                                 inputs=options.dependencies_res_zips +
                                 options.extra_r_text_files,
                                 add_pydeps=False)
 def WriteFile(self, file_path, file_name, contents):
     build_utils.MakeDirectory(file_path)
     with open(os.path.join(file_path, file_name), 'w') as f:
         f.write(contents)
Exemple #4
0
def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs,
                classpath):
    logging.info('Starting _OnStaleMd5')
    # Don't bother enabling incremental compilation for non-chromium code.
    incremental = options.incremental and options.chromium_code

    # Compiles with Error Prone take twice as long to run as pure javac. Thus GN
    # rules run both in parallel, with Error Prone only used for checks.
    save_outputs = not options.enable_errorprone

    with build_utils.TempDir() as temp_dir:
        srcjars = options.java_srcjars

        classes_dir = os.path.join(temp_dir, 'classes')
        os.makedirs(classes_dir)

        changed_paths = None
        # jmake can handle deleted files, but it's a rare case and it would
        # complicate this script's logic.
        if incremental and changes.AddedOrModifiedOnly():
            changed_paths = set(changes.IterChangedPaths())
            # Do a full compile if classpath has changed.
            # jmake doesn't seem to do this on its own... Might be that ijars mess up
            # its change-detection logic.
            if any(p in changed_paths for p in classpath_inputs):
                changed_paths = None

        if options.incremental:
            pdb_path = options.jar_path + '.pdb'

        if incremental:
            # jmake is a compiler wrapper that figures out the minimal set of .java
            # files that need to be rebuilt given a set of .java files that have
            # changed.
            # jmake determines what files are stale based on timestamps between .java
            # and .class files. Since we use .jars, .srcjars, and md5 checks,
            # timestamp info isn't accurate for this purpose. Rather than use jmake's
            # programatic interface (like we eventually should), we ensure that all
            # .class files are newer than their .java files, and convey to jmake which
            # sources are stale by having their .class files be missing entirely
            # (by not extracting them).
            javac_cmd = _ConvertToJMakeArgs(javac_cmd, pdb_path)

        if save_outputs:
            generated_java_dir = options.generated_dir
        else:
            generated_java_dir = os.path.join(temp_dir, 'gen')

        # Incremental means not all files will be extracted, so don't bother
        # clearing out stale generated files.
        if not incremental:
            shutil.rmtree(generated_java_dir, True)

        srcjar_files = {}
        if srcjars:
            logging.info('Extracting srcjars to %s', generated_java_dir)
            build_utils.MakeDirectory(generated_java_dir)
            jar_srcs = []
            for srcjar in options.java_srcjars:
                if changed_paths:
                    changed_paths.update(
                        os.path.join(generated_java_dir, f)
                        for f in changes.IterChangedSubpaths(srcjar))
                extracted_files = build_utils.ExtractAll(
                    srcjar,
                    no_clobber=not incremental,
                    path=generated_java_dir,
                    pattern='*.java')
                for path in extracted_files:
                    # We want the path inside the srcjar so the viewer can have a tree
                    # structure.
                    srcjar_files[path] = '{}/{}'.format(
                        srcjar, os.path.relpath(path, generated_java_dir))
                jar_srcs.extend(extracted_files)
            logging.info('Done extracting srcjars')
            java_files.extend(jar_srcs)
            if changed_paths:
                # Set the mtime of all sources to 0 since we use the absence of .class
                # files to tell jmake which files are stale.
                for path in jar_srcs:
                    os.utime(path, (0, 0))

        if java_files:
            if changed_paths:
                changed_java_files = [
                    p for p in java_files if p in changed_paths
                ]
                if os.path.exists(options.jar_path):
                    _ExtractClassFiles(options.jar_path, classes_dir,
                                       changed_java_files)
                # Add the extracted files to the classpath. This is required because
                # when compiling only a subset of files, classes that haven't changed
                # need to be findable.
                classpath.append(classes_dir)

            # Can happen when a target goes from having no sources, to having sources.
            # It's created by the call to build_utils.Touch() below.
            if incremental:
                if os.path.exists(pdb_path) and not os.path.getsize(pdb_path):
                    os.unlink(pdb_path)

            # Don't include the output directory in the initial set of args since it
            # being in a temp dir makes it unstable (breaks md5 stamping).
            cmd = javac_cmd + ['-d', classes_dir]

            # Pass classpath and source paths as response files to avoid extremely
            # long command lines that are tedius to debug.
            if classpath:
                cmd += ['-classpath', ':'.join(classpath)]

            java_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
            with open(java_files_rsp_path, 'w') as f:
                f.write(' '.join(java_files))
            cmd += ['@' + java_files_rsp_path]

            # JMake prints out some diagnostic logs that we want to ignore.
            # This assumes that all compiler output goes through stderr.
            stdout_filter = lambda s: ''
            if md5_check.PRINT_EXPLANATIONS:
                stdout_filter = None

            logging.debug('Build command %s', cmd)
            attempt_build = lambda: build_utils.CheckOutput(
                cmd,
                print_stdout=options.chromium_code,
                stdout_filter=stdout_filter,
                stderr_filter=ProcessJavacOutput)
            try:
                attempt_build()
            except build_utils.CalledProcessError as e:
                # Work-around for a bug in jmake (http://crbug.com/551449).
                if ('project database corrupted' not in e.output
                        and 'jmake: internal Java exception' not in e.output):
                    raise
                logging.error(
                    'Applying work-around for jmake project database corrupted '
                    '(http://crbug.com/551449).')
                os.unlink(pdb_path)
                attempt_build()
            logging.info('Finished build command')

        if options.incremental or save_outputs:
            # Creating the jar file takes the longest, start it first on a separate
            # process to unblock the rest of the post-processing steps.
            jar_file_worker = multiprocessing.Process(
                target=_CreateJarFile,
                args=(options.jar_path, options.provider_configurations,
                      options.additional_jar_files, classes_dir))
            jar_file_worker.start()
        else:
            jar_file_worker = None
            build_utils.Touch(options.jar_path)

        if save_outputs:
            _CreateInfoFile(java_files, options.jar_path,
                            options.chromium_code, srcjar_files, classes_dir,
                            generated_java_dir)
        else:
            build_utils.Touch(options.jar_path + '.info')

        if options.incremental and (not java_files or not incremental):
            # Make sure output exists.
            build_utils.Touch(pdb_path)

        if jar_file_worker:
            jar_file_worker.join()
        logging.info('Completed all steps in _OnStaleMd5')
Exemple #5
0
def main(args):
    args = build_utils.ExpandFileArgs(args)
    parser = optparse.OptionParser()
    build_utils.AddDepfileOption(parser)
    parser.add_option(
        '--clear-dir',
        action='store_true',
        help='If set, the destination directory will be deleted '
        'before copying files to it. This is highly recommended to '
        'ensure that no stale files are left in the directory.')

    parser.add_option('--configuration-name',
                      default='Release',
                      help='Gyp configuration name (i.e. Debug, Release)')
    parser.add_option(
        '--enable-packing',
        choices=['0', '1'],
        help=('Pack relocations if 1 and configuration name is \'Release\','
              ' otherwise plain file copy'))
    parser.add_option('--exclude-packing-list',
                      default='',
                      help='Names of any libraries explicitly not packed')
    parser.add_option('--android-pack-relocations',
                      help='Path to the relocations packer binary')
    parser.add_option('--stripped-libraries-dir',
                      help='Directory for stripped libraries')
    parser.add_option('--packed-libraries-dir',
                      help='Directory for packed libraries')
    parser.add_option('--libraries', action='append', help='List of libraries')
    parser.add_option('--stamp', help='Path to touch on success')
    parser.add_option('--filelistjson',
                      help='Output path of filelist.json to write')

    options, _ = parser.parse_args(args)
    enable_packing = (options.enable_packing == '1'
                      and options.configuration_name == 'Release')
    exclude_packing_set = set(
        build_utils.ParseGypList(options.exclude_packing_list))

    libraries = []
    for libs_arg in options.libraries:
        libraries += build_utils.ParseGypList(libs_arg)

    if options.clear_dir:
        build_utils.DeleteDirectory(options.packed_libraries_dir)

    build_utils.MakeDirectory(options.packed_libraries_dir)

    output_paths = []
    for library in libraries:
        library_path = os.path.join(options.stripped_libraries_dir, library)
        output_path = os.path.join(options.packed_libraries_dir,
                                   os.path.basename(library))
        output_paths.append(output_path)

        if enable_packing and library not in exclude_packing_set:
            PackLibraryRelocations(options.android_pack_relocations,
                                   library_path, output_path)
        else:
            CopyLibraryUnchanged(library_path, output_path)

    if options.filelistjson:
        build_utils.WriteJson({'files': output_paths}, options.filelistjson)

    if options.depfile:
        build_utils.WriteDepfile(
            options.depfile, libraries + build_utils.GetPythonDependencies())

    if options.stamp:
        build_utils.Touch(options.stamp)

    return 0
Exemple #6
0
def main():
  args = build_utils.ExpandFileArgs(sys.argv[1:])

  options = ParseArgs(args)
  android_jar = os.path.join(options.android_sdk, 'android.jar')
  aapt = os.path.join(options.android_sdk_tools, 'aapt')

  input_files = []

  with build_utils.TempDir() as temp_dir:
    deps_dir = os.path.join(temp_dir, 'deps')
    build_utils.MakeDirectory(deps_dir)
    v14_dir = os.path.join(temp_dir, 'v14')
    build_utils.MakeDirectory(v14_dir)

    gen_dir = os.path.join(temp_dir, 'gen')
    build_utils.MakeDirectory(gen_dir)

    input_resource_dirs = build_utils.ParseGypList(options.resource_dirs)

    for resource_dir in input_resource_dirs:
      generate_v14_compatible_resources.GenerateV14Resources(
          resource_dir,
          v14_dir,
          options.v14_verify_only)

    dep_zips = build_utils.ParseGypList(options.dependencies_res_zips)
    input_files += dep_zips
    dep_subdirs = []
    for z in dep_zips:
      subdir = os.path.join(deps_dir, os.path.basename(z))
      if os.path.exists(subdir):
        raise Exception('Resource zip name conflict: ' + os.path.basename(z))
      build_utils.ExtractAll(z, path=subdir)
      dep_subdirs.append(subdir)

    # Generate R.java. This R.java contains non-final constants and is used only
    # while compiling the library jar (e.g. chromium_content.jar). When building
    # an apk, a new R.java file with the correct resource -> ID mappings will be
    # generated by merging the resources from all libraries and the main apk
    # project.
    package_command = [aapt,
                       'package',
                       '-m',
                       '-M', options.android_manifest,
                       '--auto-add-overlay',
                       '-I', android_jar,
                       '--output-text-symbols', gen_dir,
                       '-J', gen_dir]

    for d in input_resource_dirs:
      package_command += ['-S', d]

    for d in dep_subdirs:
      package_command += ['-S', d]

    if options.non_constant_id:
      package_command.append('--non-constant-id')
    if options.custom_package:
      package_command += ['--custom-package', options.custom_package]
    if options.proguard_file:
      package_command += ['-G', options.proguard_file]
    build_utils.CheckOutput(package_command, print_stderr=False)

    if options.extra_res_packages:
      CreateExtraRJavaFiles(
          gen_dir,
          build_utils.ParseGypList(options.extra_res_packages))

    # This is the list of directories with resources to put in the final .zip
    # file. The order of these is important so that crunched/v14 resources
    # override the normal ones.
    zip_resource_dirs = input_resource_dirs + [v14_dir]

    base_crunch_dir = os.path.join(temp_dir, 'crunch')

    # Crunch image resources. This shrinks png files and is necessary for
    # 9-patch images to display correctly. 'aapt crunch' accepts only a single
    # directory at a time and deletes everything in the output directory.
    for idx, d in enumerate(input_resource_dirs):
      crunch_dir = os.path.join(base_crunch_dir, str(idx))
      build_utils.MakeDirectory(crunch_dir)
      zip_resource_dirs.append(crunch_dir)
      aapt_cmd = [aapt,
                  'crunch',
                  '-C', crunch_dir,
                  '-S', d]
      build_utils.CheckOutput(aapt_cmd, stderr_filter=FilterCrunchStderr,
                              fail_func=DidCrunchFail)

    ZipResources(zip_resource_dirs, options.resource_zip_out)

    if options.all_resources_zip_out:
      CombineZips([options.resource_zip_out] + dep_zips,
                  options.all_resources_zip_out)

    if options.R_dir:
      build_utils.DeleteDirectory(options.R_dir)
      shutil.copytree(gen_dir, options.R_dir)
    else:
      build_utils.ZipDir(options.srcjar_out, gen_dir)

  if options.depfile:
    input_files += build_utils.GetPythonDependencies()
    build_utils.WriteDepfile(options.depfile, input_files)

  if options.stamp:
    build_utils.Touch(options.stamp)
Exemple #7
0
def _OnStaleMd5(options, javac_cmd, java_files, classpath):
    logging.info('Starting _OnStaleMd5')

    # Compiles with Error Prone take twice as long to run as pure javac. Thus GN
    # rules run both in parallel, with Error Prone only used for checks.
    save_outputs = not options.enable_errorprone

    with build_utils.TempDir() as temp_dir:
        srcjars = options.java_srcjars

        classes_dir = os.path.join(temp_dir, 'classes')
        os.makedirs(classes_dir)

        if save_outputs:
            generated_java_dir = options.generated_dir
        else:
            generated_java_dir = os.path.join(temp_dir, 'gen')

        shutil.rmtree(generated_java_dir, True)

        srcjar_files = {}
        if srcjars:
            logging.info('Extracting srcjars to %s', generated_java_dir)
            build_utils.MakeDirectory(generated_java_dir)
            jar_srcs = []
            for srcjar in options.java_srcjars:
                extracted_files = build_utils.ExtractAll(
                    srcjar,
                    no_clobber=True,
                    path=generated_java_dir,
                    pattern='*.java')
                for path in extracted_files:
                    # We want the path inside the srcjar so the viewer can have a tree
                    # structure.
                    srcjar_files[path] = '{}/{}'.format(
                        srcjar, os.path.relpath(path, generated_java_dir))
                jar_srcs.extend(extracted_files)
            logging.info('Done extracting srcjars')
            java_files.extend(jar_srcs)

        if java_files:
            # Don't include the output directory in the initial set of args since it
            # being in a temp dir makes it unstable (breaks md5 stamping).
            cmd = javac_cmd + ['-d', classes_dir]

            # Pass classpath and source paths as response files to avoid extremely
            # long command lines that are tedius to debug.
            if classpath:
                cmd += ['-classpath', ':'.join(classpath)]

            java_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
            with open(java_files_rsp_path, 'w') as f:
                f.write(' '.join(java_files))
            cmd += ['@' + java_files_rsp_path]

            logging.debug('Build command %s', cmd)
            build_utils.CheckOutput(cmd,
                                    print_stdout=options.chromium_code,
                                    stderr_filter=ProcessJavacOutput)
            logging.info('Finished build command')

        if save_outputs:
            # Creating the jar file takes the longest, start it first on a separate
            # process to unblock the rest of the post-processing steps.
            jar_file_worker = multiprocessing.Process(
                target=_CreateJarFile,
                args=(options.jar_path, options.provider_configurations,
                      options.additional_jar_files, classes_dir))
            jar_file_worker.start()
        else:
            jar_file_worker = None
            build_utils.Touch(options.jar_path)

        if save_outputs:
            _CreateInfoFile(java_files, options.jar_path,
                            options.chromium_code, srcjar_files, classes_dir,
                            generated_java_dir)
        else:
            build_utils.Touch(options.jar_path + '.info')

        if jar_file_worker:
            jar_file_worker.join()
        logging.info('Completed all steps in _OnStaleMd5')
def _PackageLibrary(options, dep_subdirs, temp_dir, gen_dir):
  v14_dir = os.path.join(temp_dir, 'v14')
  build_utils.MakeDirectory(v14_dir)

  # Generate R.java. This R.java contains non-final constants and is used only
  # while compiling the library jar (e.g. chromium_content.jar). When building
  # an apk, a new R.java file with the correct resource -> ID mappings will be
  # generated by merging the resources from all libraries and the main apk
  # project.
  package_command = [options.aapt_path,
                     'package',
                     '-m',
                     '-M', _EMPTY_ANDROID_MANIFEST_PATH,
                     '--no-crunch',
                     '--auto-add-overlay',
                     '--no-version-vectors',
                     '-I', options.android_sdk_jar,
                     '--output-text-symbols', gen_dir,
                     '-J', gen_dir,  # Required for R.txt generation.
                     '--ignore-assets', build_utils.AAPT_IGNORE_PATTERN]

  # Adding all dependencies as sources is necessary for @type/foo references
  # to symbols within dependencies to resolve. However, it has the side-effect
  # that all Java symbols from dependencies are copied into the new R.java.
  # E.g.: It enables an arguably incorrect usage of
  # "mypackage.R.id.lib_symbol" where "libpackage.R.id.lib_symbol" would be
  # more correct. This is just how Android works.
  for d in dep_subdirs:
    package_command += ['-S', d]

  input_resource_dirs = options.resource_dirs

  for d in input_resource_dirs:
    package_command += ['-S', d]

  if not options.v14_skip:
    for resource_dir in input_resource_dirs:
      generate_v14_compatible_resources.GenerateV14Resources(
          resource_dir,
          v14_dir)

  # This is the list of directories with resources to put in the final .zip
  # file. The order of these is important so that crunched/v14 resources
  # override the normal ones.
  zip_resource_dirs = input_resource_dirs + [v14_dir]

  base_crunch_dir = os.path.join(temp_dir, 'crunch')
  # Crunch image resources. This shrinks png files and is necessary for
  # 9-patch images to display correctly. 'aapt crunch' accepts only a single
  # directory at a time and deletes everything in the output directory.
  for idx, input_dir in enumerate(input_resource_dirs):
    crunch_dir = os.path.join(base_crunch_dir, str(idx))
    build_utils.MakeDirectory(crunch_dir)
    zip_resource_dirs.append(crunch_dir)
    _CrunchDirectory(options.aapt_path, input_dir, crunch_dir)

  if options.resource_zip_out:
    _ZipResources(zip_resource_dirs, options.resource_zip_out,
                  build_utils.AAPT_IGNORE_PATTERN)

  # Only creates an R.txt
  build_utils.CheckOutput(
      package_command, print_stdout=False, print_stderr=False)
Exemple #9
0
def _RunCompiler(changes,
                 options,
                 javac_cmd,
                 java_files,
                 jar_path,
                 jar_info_path=None,
                 intermediates_out_dir=None,
                 enable_partial_javac=False):
    """Runs java compiler.

  Args:
    changes: md5_check.Changes object.
    options: Object with command line flags.
    javac_cmd: Command to execute.
    java_files: List of java files passed from command line.
    jar_path: Path of output jar file.
    jar_info_path: Path of the .info file to generate.
        If None, .info file will not be generated.
    intermediates_out_dir: Directory for saving intermediate outputs.
        If None a temporary directory is used.
    enable_partial_javac: Enables compiling only Java files which have changed
        in the special case that no method signatures have changed. This is
        useful for large GN targets.
        Not supported if compiling generates outputs other than |jar_path| and
        |jar_info_path|.
  """
    logging.info('Starting _RunCompiler')

    java_files = java_files.copy()
    java_srcjars = options.java_srcjars
    save_info_file = jar_info_path is not None

    # Use jar_path's directory to ensure paths are relative (needed for goma).
    temp_dir = jar_path + '.staging'
    shutil.rmtree(temp_dir, True)
    os.makedirs(temp_dir)
    info_file_context = None
    try:
        classes_dir = os.path.join(temp_dir, 'classes')
        service_provider_configuration = os.path.join(
            temp_dir, 'service_provider_configuration')

        if java_files:
            os.makedirs(classes_dir)

            if enable_partial_javac:
                all_changed_paths_are_java = all(
                    p.endswith(".java") for p in changes.IterChangedPaths())
                if (all_changed_paths_are_java
                        and not changes.HasStringChanges()
                        and os.path.exists(jar_path) and
                    (jar_info_path is None or os.path.exists(jar_info_path))):
                    # Log message is used by tests to determine whether partial javac
                    # optimization was used.
                    logging.info(
                        'Using partial javac optimization for %s compile' %
                        (jar_path))

                    # Header jar corresponding to |java_files| did not change.
                    # As a build speed optimization (crbug.com/1170778), re-compile only
                    # java files which have changed. Re-use old jar .info file.
                    java_files = list(changes.IterChangedPaths())
                    java_srcjars = None

                    # Reuse old .info file.
                    save_info_file = False

                    build_utils.ExtractAll(jar_path, classes_dir)

        if save_info_file:
            info_file_context = _InfoFileContext(
                options.chromium_code, options.jar_info_exclude_globs)

        if intermediates_out_dir is None:
            input_srcjars_dir = os.path.join(temp_dir, 'input_srcjars')
        else:
            input_srcjars_dir = os.path.join(intermediates_out_dir,
                                             'input_srcjars')

        if java_srcjars:
            logging.info('Extracting srcjars to %s', input_srcjars_dir)
            build_utils.MakeDirectory(input_srcjars_dir)
            for srcjar in options.java_srcjars:
                extracted_files = build_utils.ExtractAll(
                    srcjar,
                    no_clobber=True,
                    path=input_srcjars_dir,
                    pattern='*.java')
                java_files.extend(extracted_files)
                if save_info_file:
                    info_file_context.AddSrcJarSources(srcjar, extracted_files,
                                                       input_srcjars_dir)
            logging.info('Done extracting srcjars')

        if options.header_jar:
            logging.info('Extracting service provider configs')
            # Extract META-INF/services/* so that it can be copied into the output
            # .jar
            build_utils.ExtractAll(options.header_jar,
                                   no_clobber=True,
                                   path=service_provider_configuration,
                                   pattern='META-INF/services/*')
            logging.info('Done extracting service provider configs')

        if save_info_file and java_files:
            info_file_context.SubmitFiles(java_files)

        if java_files:
            # Don't include the output directory in the initial set of args since it
            # being in a temp dir makes it unstable (breaks md5 stamping).
            cmd = list(javac_cmd)
            cmd += ['-d', classes_dir]

            if options.classpath:
                cmd += ['-classpath', ':'.join(options.classpath)]

            # Pass source paths as response files to avoid extremely long command
            # lines that are tedius to debug.
            java_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
            with open(java_files_rsp_path, 'w') as f:
                f.write(' '.join(java_files))
            cmd += ['@' + java_files_rsp_path]

            process_javac_output_partial = functools.partial(
                ProcessJavacOutput, target_name=options.target_name)

            logging.debug('Build command %s', cmd)
            start = time.time()
            build_utils.CheckOutput(cmd,
                                    print_stdout=options.chromium_code,
                                    stdout_filter=process_javac_output_partial,
                                    stderr_filter=process_javac_output_partial,
                                    fail_on_output=options.warnings_as_errors)
            end = time.time() - start
            logging.info('Java compilation took %ss', end)

        _CreateJarFile(jar_path, service_provider_configuration,
                       options.additional_jar_files, classes_dir)

        if save_info_file:
            info_file_context.Commit(jar_info_path)

        logging.info('Completed all steps in _RunCompiler')
    finally:
        if info_file_context:
            info_file_context.Close()
        shutil.rmtree(temp_dir)
Exemple #10
0
def _OnStaleMd5(options):
  android_jar = os.path.join(options.android_sdk, 'android.jar')
  aapt = options.aapt_path
  with build_utils.TempDir() as temp_dir:
    deps_dir = os.path.join(temp_dir, 'deps')
    build_utils.MakeDirectory(deps_dir)
    v14_dir = os.path.join(temp_dir, 'v14')
    build_utils.MakeDirectory(v14_dir)

    gen_dir = os.path.join(temp_dir, 'gen')
    build_utils.MakeDirectory(gen_dir)

    input_resource_dirs = options.resource_dirs

    if not options.v14_skip:
      for resource_dir in input_resource_dirs:
        generate_v14_compatible_resources.GenerateV14Resources(
            resource_dir,
            v14_dir)

    dep_zips = options.dependencies_res_zips
    dep_subdirs = []
    for z in dep_zips:
      subdir = os.path.join(deps_dir, os.path.basename(z))
      if os.path.exists(subdir):
        raise Exception('Resource zip name conflict: ' + os.path.basename(z))
      build_utils.ExtractAll(z, path=subdir)
      dep_subdirs.append(subdir)

    # Generate R.java. This R.java contains non-final constants and is used only
    # while compiling the library jar (e.g. chromium_content.jar). When building
    # an apk, a new R.java file with the correct resource -> ID mappings will be
    # generated by merging the resources from all libraries and the main apk
    # project.
    package_command = [aapt,
                       'package',
                       '-m',
                       '-M', options.android_manifest,
                       '--auto-add-overlay',
                       '-I', android_jar,
                       '--output-text-symbols', gen_dir,
                       '-J', gen_dir,
                       '--ignore-assets', build_utils.AAPT_IGNORE_PATTERN]

    for d in input_resource_dirs:
      package_command += ['-S', d]

    for d in dep_subdirs:
      package_command += ['-S', d]

    if options.non_constant_id:
      package_command.append('--non-constant-id')
    if options.custom_package:
      package_command += ['--custom-package', options.custom_package]
    if options.proguard_file:
      package_command += ['-G', options.proguard_file]
    if options.shared_resources:
      package_command.append('--shared-lib')
    if options.app_as_shared_lib:
      package_command.append('--app-as-shared-lib')
    build_utils.CheckOutput(package_command, print_stderr=False)

    if options.extra_res_packages:
      CreateExtraRJavaFiles(
          gen_dir,
          options.extra_res_packages,
          options.extra_r_text_files,
          options.shared_resources or options.app_as_shared_lib,
          options.include_all_resources)

    # This is the list of directories with resources to put in the final .zip
    # file. The order of these is important so that crunched/v14 resources
    # override the normal ones.
    zip_resource_dirs = input_resource_dirs + [v14_dir]

    base_crunch_dir = os.path.join(temp_dir, 'crunch')

    # Crunch image resources. This shrinks png files and is necessary for
    # 9-patch images to display correctly. 'aapt crunch' accepts only a single
    # directory at a time and deletes everything in the output directory.
    for idx, input_dir in enumerate(input_resource_dirs):
      crunch_dir = os.path.join(base_crunch_dir, str(idx))
      build_utils.MakeDirectory(crunch_dir)
      zip_resource_dirs.append(crunch_dir)
      CrunchDirectory(aapt, input_dir, crunch_dir)

    ZipResources(zip_resource_dirs, options.resource_zip_out)

    if options.all_resources_zip_out:
      CombineZips([options.resource_zip_out] + dep_zips,
                  options.all_resources_zip_out)

    if options.R_dir:
      build_utils.DeleteDirectory(options.R_dir)
      shutil.copytree(gen_dir, options.R_dir)
    else:
      build_utils.ZipDir(options.srcjar_out, gen_dir)

    if options.r_text_out:
      r_text_path = os.path.join(gen_dir, 'R.txt')
      if os.path.exists(r_text_path):
        shutil.copyfile(r_text_path, options.r_text_out)
      else:
        open(options.r_text_out, 'w').close()
def _RenameLocaleResourceDirs(resource_dirs, path_info):
    """Rename locale resource directories into standard names when necessary.

  This is necessary to deal with the fact that older Android releases only
  support ISO 639-1 two-letter codes, and sometimes even obsolete versions
  of them.

  In practice it means:
    * 3-letter ISO 639-2 qualifiers are renamed under a corresponding
      2-letter one. E.g. for Filipino, strings under values-fil/ will be moved
      to a new corresponding values-tl/ sub-directory.

    * Modern ISO 639-1 codes will be renamed to their obsolete variant
      for Indonesian, Hebrew and Yiddish (e.g. 'values-in/ -> values-id/).

    * Norwegian macrolanguage strings will be renamed to Bokmal (main
      Norway language). See http://crbug.com/920960. In practice this
      means that 'values-no/ -> values-nb/' unless 'values-nb/' already
      exists.

    * BCP 47 langauge tags will be renamed to an equivalent ISO 639-1
      locale qualifier if possible (e.g. 'values-b+en+US/ -> values-en-rUS').

  Args:
    resource_dirs: list of top-level resource directories.
  """
    for resource_dir in resource_dirs:
        ignore_dirs = {}
        for path in _IterFiles(resource_dir):
            locale = resource_utils.FindLocaleInStringResourceFilePath(path)
            if not locale:
                continue
            cr_locale = resource_utils.ToChromiumLocaleName(locale)
            if not cr_locale:
                continue  # Unsupported Android locale qualifier!?
            locale2 = resource_utils.ToAndroidLocaleName(cr_locale)
            if locale != locale2:
                path2 = path.replace('/values-%s/' % locale,
                                     '/values-%s/' % locale2)
                if path == path2:
                    raise Exception(
                        'Could not substitute locale %s for %s in %s' %
                        (locale, locale2, path))

                # Ignore rather than rename when the destination resources config
                # already exists.
                # e.g. some libraries provide both values-nb/ and values-no/.
                # e.g. material design provides:
                # * res/values-rUS/values-rUS.xml
                # * res/values-b+es+419/values-b+es+419.xml
                config_dir = os.path.dirname(path2)
                already_has_renamed_config = ignore_dirs.get(config_dir)
                if already_has_renamed_config is None:
                    # Cache the result of the first time the directory is encountered
                    # since subsequent encounters will find the directory already exists
                    # (due to the rename).
                    already_has_renamed_config = os.path.exists(config_dir)
                    ignore_dirs[config_dir] = already_has_renamed_config
                if already_has_renamed_config:
                    continue

                build_utils.MakeDirectory(os.path.dirname(path2))
                shutil.move(path, path2)
                path_info.RegisterRename(os.path.relpath(path, resource_dir),
                                         os.path.relpath(path2, resource_dir))
Exemple #12
0
def CreateRJavaFiles(srcjar_dir, package, main_r_txt_file, extra_res_packages,
                     extra_r_txt_files, rjava_build_options, srcjar_out):
    """Create all R.java files for a set of packages and R.txt files.

  Args:
    srcjar_dir: The top-level output directory for the generated files.
    package: Top-level package name.
    main_r_txt_file: The main R.txt file containing the valid values
      of _all_ resource IDs.
    extra_res_packages: A list of extra package names.
    extra_r_txt_files: A list of extra R.txt files. One per item in
      |extra_res_packages|. Note that all resource IDs in them will be ignored,
      |and replaced by the values extracted from |main_r_txt_file|.
    rjava_build_options: An RJavaBuildOptions instance that controls how
      exactly the R.java file is generated.
    srcjar_out: Path of desired output srcjar.
  Raises:
    Exception if a package name appears several times in |extra_res_packages|
  """
    assert len(extra_res_packages) == len(extra_r_txt_files), \
           'Need one R.txt file per package'

    packages = list(extra_res_packages)
    r_txt_files = list(extra_r_txt_files)

    if package and package not in packages:
        # Sometimes, an apk target and a resources target share the same
        # AndroidManifest.xml and thus |package| will already be in |packages|.
        packages.append(package)
        r_txt_files.append(main_r_txt_file)

    # Map of (resource_type, name) -> Entry.
    # Contains the correct values for resources.
    all_resources = {}
    all_resources_by_type = collections.defaultdict(list)
    for entry in _ParseTextSymbolsFile(main_r_txt_file, fix_package_ids=True):
        all_resources[(entry.resource_type, entry.name)] = entry
        all_resources_by_type[entry.resource_type].append(entry)

    # Creating the root R.java file. We use srcjar_out to provide unique package
    # names, since when one java target depends on 2 different targets (each with
    # resources), those 2 root resource packages have to be different from one
    # another. We add an underscore before each subdirectory so that if a reserved
    # keyword (for example, "public") is used as a directory name, it will not
    # cause Java to complain.
    root_r_java_package = re.sub('[^\w\.]', '', srcjar_out.replace('/', '._'))
    root_r_java_dir = os.path.join(srcjar_dir, *root_r_java_package.split('.'))
    build_utils.MakeDirectory(root_r_java_dir)
    root_r_java_path = os.path.join(root_r_java_dir, 'R.java')
    root_java_file_contents = _RenderRootRJavaSource(root_r_java_package,
                                                     all_resources_by_type,
                                                     rjava_build_options)
    with open(root_r_java_path, 'w') as f:
        f.write(root_java_file_contents)

    # Map of package_name->resource_type->entry
    resources_by_package = (
        collections.defaultdict(lambda: collections.defaultdict(list)))
    # Build the R.java files using each package's R.txt file, but replacing
    # each entry's placeholder value with correct values from all_resources.
    for package, r_txt_file in zip(packages, r_txt_files):
        if package in resources_by_package:
            raise Exception(
                ('Package name "%s" appeared twice. All '
                 'android_resources() targets must use unique package '
                 'names, or no package name at all.') % package)
        resources_by_type = resources_by_package[package]
        # The sub-R.txt files have the wrong values at this point. Read them to
        # figure out which entries belong to them, but use the values from the
        # main R.txt file.
        for entry in _ParseTextSymbolsFile(r_txt_file):
            entry = all_resources.get((entry.resource_type, entry.name))
            # For most cases missing entry here is an error. It means that some
            # library claims to have or depend on a resource that isn't included into
            # the APK. There is one notable exception: Google Play Services (GMS).
            # GMS is shipped as a bunch of AARs. One of them - basement - contains
            # R.txt with ids of all resources, but most of the resources are in the
            # other AARs. However, all other AARs reference their resources via
            # basement's R.java so the latter must contain all ids that are in its
            # R.txt. Most targets depend on only a subset of GMS AARs so some
            # resources are missing, which is okay because the code that references
            # them is missing too. We can't get an id for a resource that isn't here
            # so the only solution is to skip the resource entry entirely.
            #
            # We can verify that all entries referenced in the code were generated
            # correctly by running Proguard on the APK: it will report missing
            # fields.
            if entry:
                resources_by_type[entry.resource_type].append(entry)

    for package, resources_by_type in resources_by_package.iteritems():
        _CreateRJavaSourceFile(srcjar_dir, package, root_r_java_package,
                               resources_by_type, rjava_build_options)
def CreateExtraRJavaFiles(r_dir, extra_packages, extra_r_text_files,
                          shared_resources, include_all):
    if include_all:
        java_files = build_utils.FindInDirectory(r_dir, "R.java")
        if len(java_files) != 1:
            return
        r_java_file = java_files[0]
        r_java_contents = codecs.open(r_java_file, encoding='utf-8').read()

        for package in extra_packages:
            package_r_java_dir = os.path.join(r_dir, *package.split('.'))
            build_utils.MakeDirectory(package_r_java_dir)
            package_r_java_path = os.path.join(package_r_java_dir, 'R.java')
            new_r_java = re.sub(r'package [.\w]*;', u'package %s;' % package,
                                r_java_contents)
            codecs.open(package_r_java_path, 'w',
                        encoding='utf-8').write(new_r_java)
    else:
        if len(extra_packages) != len(extra_r_text_files):
            raise Exception('Need one R.txt file per extra package')

        r_txt_file = os.path.join(r_dir, 'R.txt')
        if not os.path.exists(r_txt_file):
            return

        # Map of (resource_type, name) -> Entry.
        # Contains the correct values for resources.
        all_resources = {}
        for entry in _ParseTextSymbolsFile(r_txt_file):
            all_resources[(entry.resource_type, entry.name)] = entry

        # Map of package_name->resource_type->entry
        resources_by_package = (
            collections.defaultdict(lambda: collections.defaultdict(list)))
        # Build the R.java files using each package's R.txt file, but replacing
        # each entry's placeholder value with correct values from all_resources.
        for package, r_text_file in zip(extra_packages, extra_r_text_files):
            if not os.path.exists(r_text_file):
                continue
            if package in resources_by_package:
                raise Exception(
                    ('Package name "%s" appeared twice. All '
                     'android_resources() targets must use unique package '
                     'names, or no package name at all.') % package)
            resources_by_type = resources_by_package[package]
            # The sub-R.txt files have the wrong values at this point. Read them to
            # figure out which entries belong to them, but use the values from the
            # main R.txt file.
            for entry in _ParseTextSymbolsFile(r_text_file):
                entry = all_resources[(entry.resource_type, entry.name)]
                resources_by_type[entry.resource_type].append(entry)

        for package, resources_by_type in resources_by_package.iteritems():
            package_r_java_dir = os.path.join(r_dir, *package.split('.'))
            build_utils.MakeDirectory(package_r_java_dir)
            package_r_java_path = os.path.join(package_r_java_dir, 'R.java')
            java_file_contents = _CreateExtraRJavaFile(package,
                                                       resources_by_type,
                                                       shared_resources)
            with open(package_r_java_path, 'w') as f:
                f.write(java_file_contents)
Exemple #14
0
def CopyNativeLibraries(output_dir, abi_name, native_libraries):
    destination_path = os.path.join(output_dir, 'libs', abi_name)
    build_utils.MakeDirectory(destination_path)
    for native_lib in native_libraries:
        shutil.copy2(native_lib, destination_path)
Exemple #15
0
def _OnStaleMd5(options):
    aapt = options.aapt_path
    with build_utils.TempDir() as temp_dir:
        deps_dir = os.path.join(temp_dir, 'deps')
        build_utils.MakeDirectory(deps_dir)
        v14_dir = os.path.join(temp_dir, 'v14')
        build_utils.MakeDirectory(v14_dir)

        gen_dir = os.path.join(temp_dir, 'gen')
        build_utils.MakeDirectory(gen_dir)
        r_txt_path = os.path.join(gen_dir, 'R.txt')
        srcjar_dir = os.path.join(temp_dir, 'java')

        input_resource_dirs = options.resource_dirs

        if not options.v14_skip:
            for resource_dir in input_resource_dirs:
                generate_v14_compatible_resources.GenerateV14Resources(
                    resource_dir, v14_dir)

        dep_zips = options.dependencies_res_zips
        dep_subdirs = []
        for z in dep_zips:
            subdir = os.path.join(deps_dir, os.path.basename(z))
            if os.path.exists(subdir):
                raise Exception('Resource zip name conflict: ' +
                                os.path.basename(z))
            build_utils.ExtractAll(z, path=subdir)
            dep_subdirs.append(subdir)

        # Generate R.java. This R.java contains non-final constants and is used only
        # while compiling the library jar (e.g. chromium_content.jar). When building
        # an apk, a new R.java file with the correct resource -> ID mappings will be
        # generated by merging the resources from all libraries and the main apk
        # project.
        package_command = [
            aapt,
            'package',
            '-m',
            '-M',
            options.android_manifest,
            '--auto-add-overlay',
            '--no-version-vectors',
            '-I',
            options.android_sdk_jar,
            '--output-text-symbols',
            gen_dir,
            '-J',
            gen_dir,  # Required for R.txt generation.
            '--ignore-assets',
            build_utils.AAPT_IGNORE_PATTERN
        ]

        # aapt supports only the "--include-all-resources" mode, where each R.java
        # file ends up with all symbols, rather than only those that it had at the
        # time it was originally generated. This subtle difference makes no
        # difference when compiling, but can lead to increased unused symbols in the
        # resulting R.class files.
        # TODO(agrieve): See if proguard makes this difference actually translate
        # into a size difference. If not, we can delete all of our custom R.java
        # template code above (and make include_all_resources the default).
        if options.include_all_resources:
            srcjar_dir = gen_dir
            if options.extra_res_packages:
                colon_separated = ':'.join(options.extra_res_packages)
                package_command += ['--extra-packages', colon_separated]
            if options.non_constant_id:
                package_command.append('--non-constant-id')
            if options.custom_package:
                package_command += ['--custom-package', options.custom_package]
            if options.shared_resources:
                package_command.append('--shared-lib')
            if options.app_as_shared_lib:
                package_command.append('--app-as-shared-lib')

        for d in input_resource_dirs:
            package_command += ['-S', d]

        # Adding all dependencies as sources is necessary for @type/foo references
        # to symbols within dependencies to resolve. However, it has the side-effect
        # that all Java symbols from dependencies are copied into the new R.java.
        # E.g.: It enables an arguably incorrect usage of
        # "mypackage.R.id.lib_symbol" where "libpackage.R.id.lib_symbol" would be
        # more correct. This is just how Android works.
        for d in dep_subdirs:
            package_command += ['-S', d]

        if options.proguard_file:
            package_command += ['-G', options.proguard_file]
        if options.proguard_file_main_dex:
            package_command += ['-D', options.proguard_file_main_dex]
        build_utils.CheckOutput(package_command, print_stderr=False)

        # When an empty res/ directory is passed, aapt does not write an R.txt.
        if not os.path.exists(r_txt_path):
            build_utils.Touch(r_txt_path)

        if not options.include_all_resources:
            # --include-all-resources can only be specified for generating final R
            # classes for APK. It makes no sense for APK to have pre-generated R.txt
            # though, because aapt-generated already lists all available resources.
            if options.r_text_in:
                r_txt_path = options.r_text_in

            packages = list(options.extra_res_packages)
            r_txt_files = list(options.extra_r_text_files)

            cur_package = options.custom_package
            if not options.custom_package:
                cur_package = _ExtractPackageFromManifest(
                    options.android_manifest)

            # Don't create a .java file for the current resource target when:
            # - no package name was provided (either by manifest or build rules),
            # - there was already a dependent android_resources() with the same
            #   package (occurs mostly when an apk target and resources target share
            #   an AndroidManifest.xml)
            if cur_package != 'org.dummy' and cur_package not in packages:
                packages.append(cur_package)
                r_txt_files.append(r_txt_path)

            if packages:
                shared_resources = options.shared_resources or options.app_as_shared_lib
                CreateRJavaFiles(srcjar_dir, r_txt_path, packages, r_txt_files,
                                 shared_resources)

        # This is the list of directories with resources to put in the final .zip
        # file. The order of these is important so that crunched/v14 resources
        # override the normal ones.
        zip_resource_dirs = input_resource_dirs + [v14_dir]

        base_crunch_dir = os.path.join(temp_dir, 'crunch')

        # Crunch image resources. This shrinks png files and is necessary for
        # 9-patch images to display correctly. 'aapt crunch' accepts only a single
        # directory at a time and deletes everything in the output directory.
        for idx, input_dir in enumerate(input_resource_dirs):
            crunch_dir = os.path.join(base_crunch_dir, str(idx))
            build_utils.MakeDirectory(crunch_dir)
            zip_resource_dirs.append(crunch_dir)
            CrunchDirectory(aapt, input_dir, crunch_dir)

        ZipResources(zip_resource_dirs, options.resource_zip_out)

        if options.all_resources_zip_out:
            CombineZips([options.resource_zip_out] + dep_zips,
                        options.all_resources_zip_out)

        if options.R_dir:
            build_utils.DeleteDirectory(options.R_dir)
            shutil.copytree(srcjar_dir, options.R_dir)
        else:
            build_utils.ZipDir(options.srcjar_out, srcjar_dir)

        if options.r_text_out:
            shutil.copyfile(r_txt_path, options.r_text_out)
Exemple #16
0
 def do_merge_dex():
     merge_dex_timer.Start()
     shards = _AllocateDexShards(dex_files)
     build_utils.MakeDirectory(dex_staging_dir)
     _CreateDexFiles(shards, dex_staging_dir, use_concurrency)
     merge_dex_timer.Stop(log=False)
def main(args):
  build_utils.InitLogging('RESOURCE_DEBUG')
  args = build_utils.ExpandFileArgs(args)
  options = _ParseArgs(args)

  path = options.arsc_path or options.proto_path
  debug_temp_resources_dir = os.environ.get('TEMP_RESOURCES_DIR')
  if debug_temp_resources_dir:
    path = os.path.join(debug_temp_resources_dir, os.path.basename(path))
  else:
    # Use a deterministic temp directory since .pb files embed the absolute
    # path of resources: crbug.com/939984
    path = path + '.tmpdir'
  build_utils.DeleteDirectory(path)
  build_utils.MakeDirectory(path)

  with resource_utils.BuildContext(
      temp_dir=path, keep_files=bool(debug_temp_resources_dir)) as build:
    manifest_package_name = _PackageApk(options, build)

    # If --shared-resources-whitelist is used, the all resources listed in
    # the corresponding R.txt file will be non-final, and an onResourcesLoaded()
    # will be generated to adjust them at runtime.
    #
    # Otherwise, if --shared-resources is used, the all resources will be
    # non-final, and an onResourcesLoaded() method will be generated too.
    #
    # Otherwise, all resources will be final, and no method will be generated.
    #
    rjava_build_options = resource_utils.RJavaBuildOptions()
    if options.shared_resources_whitelist:
      rjava_build_options.ExportSomeResources(
          options.shared_resources_whitelist)
      rjava_build_options.GenerateOnResourcesLoaded()
    elif options.shared_resources or options.app_as_shared_lib:
      rjava_build_options.ExportAllResources()
      rjava_build_options.GenerateOnResourcesLoaded()

    custom_root_package_name = options.r_java_root_package_name
    grandparent_custom_package_name = None

    if options.package_name and not options.arsc_package_name:
      # Feature modules have their own custom root package name and should
      # inherit from the appropriate base module package. This behaviour should
      # not be present for test apks with an apk under test. Thus,
      # arsc_package_name is used as it is only defined for test apks with an
      # apk under test.
      custom_root_package_name = options.package_name
      grandparent_custom_package_name = options.r_java_root_package_name

    if options.shared_resources or options.app_as_shared_lib:
      package_for_library = manifest_package_name
    else:
      package_for_library = None

    logging.debug('Creating R.srcjar')
    resource_utils.CreateRJavaFiles(
        build.srcjar_dir, package_for_library, build.r_txt_path,
        options.extra_res_packages, options.extra_r_text_files,
        rjava_build_options, options.srcjar_out, custom_root_package_name,
        grandparent_custom_package_name, options.extra_main_r_text_files)
    build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)

    # Sanity check that the created resources have the expected package ID.
    logging.debug('Performing sanity check')
    if options.package_id:
      expected_id = options.package_id
    elif options.shared_resources:
      expected_id = 0
    else:
      expected_id = 127  # == '0x7f'.
    _, package_id = resource_utils.ExtractArscPackage(
        options.aapt2_path,
        build.arsc_path if options.arsc_path else build.proto_path)
    if package_id != expected_id:
      raise Exception(
          'Invalid package ID 0x%x (expected 0x%x)' % (package_id, expected_id))

    logging.debug('Copying outputs')
    _WriteOutputs(options, build)

  if options.depfile:
    build_utils.WriteDepfile(
        options.depfile,
        options.srcjar_out,
        inputs=options.dependencies_res_zips + options.extra_r_text_files,
        add_pydeps=False)
Exemple #18
0
def _RunCompiler(options,
                 javac_cmd,
                 java_files,
                 classpath,
                 jar_path,
                 save_outputs=True):
    logging.info('Starting _RunCompiler')

    # Compiles with Error Prone take twice as long to run as pure javac. Thus GN
    # rules run both in parallel, with Error Prone only used for checks.
    save_outputs = not options.enable_errorprone

    # Use jar_path's directory to ensure paths are relative (needed for goma).
    temp_dir = jar_path + '.staging'
    shutil.rmtree(temp_dir, True)
    os.makedirs(temp_dir)
    try:
        classes_dir = os.path.join(temp_dir, 'classes')
        transitive_classes = os.path.join(temp_dir, 'transitive_classes')

        if save_outputs:
            input_srcjars_dir = os.path.join(options.generated_dir,
                                             'input_srcjars')
            annotation_processor_outputs_dir = os.path.join(
                options.generated_dir, 'annotation_processor_outputs')
            # Delete any stale files in the generated directory. The purpose of
            # options.generated_dir is for codesearch.
            shutil.rmtree(options.generated_dir, True)
            info_file_context = _InfoFileContext(
                options.chromium_code, options.jar_info_exclude_globs)
        else:
            input_srcjars_dir = os.path.join(temp_dir, 'input_srcjars')
            annotation_processor_outputs_dir = os.path.join(
                temp_dir, 'annotation_processor_outputs')

        if options.java_srcjars:
            logging.info('Extracting srcjars to %s', input_srcjars_dir)
            build_utils.MakeDirectory(input_srcjars_dir)
            for srcjar in options.java_srcjars:
                extracted_files = build_utils.ExtractAll(
                    srcjar,
                    no_clobber=True,
                    path=input_srcjars_dir,
                    pattern='*.java')
                java_files.extend(extracted_files)
                if save_outputs:
                    info_file_context.AddSrcJarSources(srcjar, extracted_files,
                                                       input_srcjars_dir)
            logging.info('Done extracting srcjars')

        if classpath or options.header_jar:
            logging.info('Extracting transitive classes to %s',
                         transitive_classes)
            # All classes under META-INF/TRANSITIVE of all direct dependencies and the
            # current target's META-INF/TRANSITIVE can be required during compile.
            for path in classpath + [options.header_jar]:
                if path.endswith('.turbine.jar'):
                    # Without the META-INF pattern prefix, it takes more than 4 seconds to
                    # extract all the .class files from chrome_java's header jar. With the
                    # prefix it takes less than 0.6 seconds.
                    # Set no_clobber=False since there are some overlaps in base classes
                    # from various header jars.
                    build_utils.ExtractAll(path,
                                           no_clobber=False,
                                           path=transitive_classes,
                                           pattern='META-INF*.class')
            # Specifying the root directory is required, see:
            # https://docs.oracle.com/javase/8/docs/technotes/tools/findingclasses.html#userclass
            classpath.append(
                os.path.join(transitive_classes, 'META-INF', 'TRANSITIVE'))
            logging.info('Done extracting transitive classes')

        if save_outputs and java_files:
            info_file_context.SubmitFiles(java_files)

        if java_files:
            # Don't include the output directory in the initial set of args since it
            # being in a temp dir makes it unstable (breaks md5 stamping).
            cmd = list(javac_cmd)
            os.makedirs(classes_dir)
            cmd += ['-d', classes_dir]

            if options.processors:
                os.makedirs(annotation_processor_outputs_dir)
                cmd += ['-s', annotation_processor_outputs_dir]

            if classpath:
                cmd += ['-classpath', ':'.join(classpath)]

            # Pass source paths as response files to avoid extremely long command
            # lines that are tedius to debug.
            java_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
            with open(java_files_rsp_path, 'w') as f:
                f.write(' '.join(java_files))
            cmd += ['@' + java_files_rsp_path]

            logging.debug('Build command %s', cmd)
            start = time.time()
            build_utils.CheckOutput(cmd,
                                    print_stdout=options.chromium_code,
                                    stdout_filter=ProcessJavacOutput,
                                    stderr_filter=ProcessJavacOutput)
            end = time.time() - start
            logging.info('Java compilation took %ss', end)

        if save_outputs:
            if options.processors:
                annotation_processor_java_files = build_utils.FindInDirectory(
                    annotation_processor_outputs_dir)
                if annotation_processor_java_files:
                    info_file_context.SubmitFiles(
                        annotation_processor_java_files)

            _CreateJarFile(jar_path, options.provider_configurations,
                           options.additional_jar_files, classes_dir)

            info_file_context.Commit(jar_path + '.info')
        else:
            build_utils.Touch(jar_path)

        logging.info('Completed all steps in _RunCompiler')
    finally:
        shutil.rmtree(temp_dir)
Exemple #19
0
def WriteDomToFile(dom, filename):
    """Write the given dom to filename."""
    build_utils.MakeDirectory(os.path.dirname(filename))
    with open(filename, 'w') as f:
        dom.writexml(f, '', '  ', '\n', encoding='utf-8')
def main(args):
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    debug_temp_resources_dir = os.environ.get(_ENV_DEBUG_VARIABLE)
    if debug_temp_resources_dir:
        debug_temp_resources_dir = os.path.join(
            debug_temp_resources_dir, os.path.basename(options.arsc_path))
        build_utils.DeleteDirectory(debug_temp_resources_dir)
        build_utils.MakeDirectory(debug_temp_resources_dir)

    with resource_utils.BuildContext(debug_temp_resources_dir) as build:
        _PackageApk(options, build)

        # If --shared-resources-whitelist is used, the all resources listed in
        # the corresponding R.txt file will be non-final, and an onResourcesLoaded()
        # will be generated to adjust them at runtime.
        #
        # Otherwise, if --shared-resources is used, the all resources will be
        # non-final, and an onResourcesLoaded() method will be generated too.
        #
        # Otherwise, all resources will be final, and no method will be generated.
        #
        rjava_build_options = resource_utils.RJavaBuildOptions()
        if options.shared_resources_whitelist:
            rjava_build_options.ExportSomeResources(
                options.shared_resources_whitelist)
            rjava_build_options.GenerateOnResourcesLoaded()
        elif options.shared_resources or options.app_as_shared_lib:
            rjava_build_options.ExportAllResources()
            rjava_build_options.GenerateOnResourcesLoaded()

        custom_root_package_name = None
        grandparent_custom_package_name = None

        if options.arsc_package_name:
            # This is for test apks with an apk under test. If we have an apk under
            # test we don't want to name the resources for both the test apk and the
            # under test apk "base". This special case lets us name the test apk's
            # resources "test".
            custom_root_package_name = 'test'
        elif options.package_name:
            # If there exists a custom package name such as vr for a feature module,
            # pass the name and base for the parent_custom_root_package_name.
            custom_root_package_name = options.package_name
            grandparent_custom_package_name = 'base'
        else:
            # No grandparent_custom_package_name for base module
            custom_root_package_name = 'base'

        resource_utils.CreateRJavaFiles(
            build.srcjar_dir, None, build.r_txt_path,
            options.extra_res_packages, options.extra_r_text_files,
            rjava_build_options, options.srcjar_out, custom_root_package_name,
            grandparent_custom_package_name)

        build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)

        # Sanity check that the created resources have the expected package ID.
        expected_id = _PackageIdFromOptions(options)
        if expected_id is None:
            expected_id = '0x00' if options.shared_resources else '0x7f'
        expected_id = int(expected_id, 16)
        _, package_id = resource_utils.ExtractArscPackage(
            options.aapt2_path,
            build.arsc_path if options.arsc_path else build.proto_path)
        if package_id != expected_id:
            raise Exception('Invalid package ID 0x%x (expected 0x%x)' %
                            (package_id, expected_id))

        _WriteOutputs(options, build)

    if options.depfile:
        build_utils.WriteDepfile(options.depfile,
                                 options.srcjar_out,
                                 inputs=options.dependencies_res_zips +
                                 options.extra_r_text_files,
                                 add_pydeps=False)
Exemple #21
0
def _RunCompiler(options,
                 javac_cmd,
                 java_files,
                 classpath,
                 jar_path,
                 save_outputs=True):
    logging.info('Starting _RunCompiler')

    # Compiles with Error Prone take twice as long to run as pure javac. Thus GN
    # rules run both in parallel, with Error Prone only used for checks.
    save_outputs = not options.enable_errorprone

    # Use jar_path's directory to ensure paths are relative (needed for goma).
    temp_dir = jar_path + '.staging'
    shutil.rmtree(temp_dir, True)
    os.makedirs(temp_dir)
    try:
        classes_dir = os.path.join(temp_dir, 'classes')
        service_provider_configuration = os.path.join(
            temp_dir, 'service_provider_configuration')

        if save_outputs:
            input_srcjars_dir = os.path.join(options.generated_dir,
                                             'input_srcjars')
            annotation_processor_outputs_dir = os.path.join(
                options.generated_dir, 'annotation_processor_outputs')
            # Delete any stale files in the generated directory. The purpose of
            # options.generated_dir is for codesearch.
            shutil.rmtree(options.generated_dir, True)
            info_file_context = _InfoFileContext(
                options.chromium_code, options.jar_info_exclude_globs)
        else:
            input_srcjars_dir = os.path.join(temp_dir, 'input_srcjars')
            annotation_processor_outputs_dir = os.path.join(
                temp_dir, 'annotation_processor_outputs')

        if options.java_srcjars:
            logging.info('Extracting srcjars to %s', input_srcjars_dir)
            build_utils.MakeDirectory(input_srcjars_dir)
            for srcjar in options.java_srcjars:
                extracted_files = build_utils.ExtractAll(
                    srcjar,
                    no_clobber=True,
                    path=input_srcjars_dir,
                    pattern='*.java')
                java_files.extend(extracted_files)
                if save_outputs:
                    info_file_context.AddSrcJarSources(srcjar, extracted_files,
                                                       input_srcjars_dir)
            logging.info('Done extracting srcjars')

        if options.header_jar:
            logging.info('Extracting service provider configs')
            # Extract META-INF/services/* so that it can be copied into the output
            # .jar
            build_utils.ExtractAll(options.header_jar,
                                   no_clobber=True,
                                   path=service_provider_configuration,
                                   pattern='META-INF/services/*')
            logging.info('Done extracting service provider configs')

        if save_outputs and java_files:
            info_file_context.SubmitFiles(java_files)

        if java_files:
            # Don't include the output directory in the initial set of args since it
            # being in a temp dir makes it unstable (breaks md5 stamping).
            cmd = list(javac_cmd)
            os.makedirs(classes_dir)
            cmd += ['-d', classes_dir]

            if options.processors:
                os.makedirs(annotation_processor_outputs_dir)
                cmd += ['-s', annotation_processor_outputs_dir]

            if classpath:
                cmd += ['-classpath', ':'.join(classpath)]

            # Pass source paths as response files to avoid extremely long command
            # lines that are tedius to debug.
            java_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
            with open(java_files_rsp_path, 'w') as f:
                f.write(' '.join(java_files))
            cmd += ['@' + java_files_rsp_path]

            logging.debug('Build command %s', cmd)
            start = time.time()
            build_utils.CheckOutput(cmd,
                                    print_stdout=options.chromium_code,
                                    stdout_filter=ProcessJavacOutput,
                                    stderr_filter=ProcessJavacOutput,
                                    fail_on_output=options.warnings_as_errors)
            end = time.time() - start
            logging.info('Java compilation took %ss', end)

        if save_outputs:
            if options.processors:
                annotation_processor_java_files = build_utils.FindInDirectory(
                    annotation_processor_outputs_dir)
                if annotation_processor_java_files:
                    info_file_context.SubmitFiles(
                        annotation_processor_java_files)

            _CreateJarFile(jar_path, service_provider_configuration,
                           options.additional_jar_files, classes_dir)

            info_file_context.Commit(jar_path + '.info')
        else:
            build_utils.Touch(jar_path)

        logging.info('Completed all steps in _RunCompiler')
    finally:
        shutil.rmtree(temp_dir)
Exemple #22
0
def _ConvertToWebP(webp_binary, png_paths, path_info, webp_cache_dir):
    pool = multiprocessing.dummy.Pool(10)

    build_utils.MakeDirectory(webp_cache_dir)

    cwebp_version = subprocess.check_output([webp_binary, '-version']).rstrip()
    cwebp_arguments = ['-mt', '-quiet', '-m', '6', '-q', '100', '-lossless']

    sha1_time = [0]
    cwebp_time = [0]
    cache_hits = [0]

    def cal_sha1(png_path):
        start = time.time()
        with open(png_path, 'rb') as f:
            png_content = f.read()

        sha1_hex = hashlib.sha1(png_content).hexdigest()
        sha1_time[0] += time.time() - start
        return sha1_hex

    def get_converted_image(png_path):
        sha1_hash = cal_sha1(png_path)

        webp_cache_path = os.path.join(
            webp_cache_dir, '{}-{}-{}'.format(sha1_hash, cwebp_version,
                                              ''.join(cwebp_arguments)))
        # No need to add an extension, android can load images fine without them.
        webp_path = os.path.splitext(png_path)[0]

        if os.path.exists(webp_cache_path):
            cache_hits[0] += 1
            os.link(webp_cache_path, webp_path)
        else:
            # We place the generated webp image to webp_path, instead of in the
            # webp_cache_dir to avoid concurrency issues.
            start = time.time()
            args = [webp_binary, png_path
                    ] + cwebp_arguments + ['-o', webp_path]
            subprocess.check_call(args)
            cwebp_time[0] += time.time() - start

            try:
                os.link(webp_path, webp_cache_path)
            except OSError:
                # Because of concurrent run, a webp image may already exists in
                # webp_cache_path.
                pass

        os.remove(png_path)
        original_dir = os.path.dirname(os.path.dirname(png_path))
        path_info.RegisterRename(os.path.relpath(png_path, original_dir),
                                 os.path.relpath(webp_path, original_dir))

    png_paths = [
        f for f in png_paths if not _PNG_WEBP_EXCLUSION_PATTERN.match(f)
    ]
    try:
        pool.map(get_converted_image, png_paths)
    finally:
        pool.close()
        pool.join()
    logging.debug(
        'png->webp: cache: %d/%d sha1 time: %.1fms cwebp time: %.1fms',
        cache_hits[0], len(png_paths), sha1_time[0], cwebp_time[0])
Exemple #23
0
def DoMain(argv):
    usage = 'usage: %prog [options] [output_dir] input_file(s)...'
    parser = optparse.OptionParser(usage=usage)
    build_utils.AddDepfileOption(parser)

    parser.add_option(
        '--assert_file',
        action="append",
        default=[],
        dest="assert_files_list",
        help='Assert that the given '
        'file is an output. There can be multiple occurrences of '
        'this flag.')
    parser.add_option('--srcjar',
                      help='When specified, a .srcjar at the given path is '
                      'created instead of individual .java files.')
    parser.add_option('--print_output_only',
                      help='Only print output paths.',
                      action='store_true')
    parser.add_option('--verbose',
                      help='Print more information.',
                      action='store_true')

    options, args = parser.parse_args(argv)

    if options.srcjar:
        if not args:
            parser.error('Need to specify at least one input file')
        input_paths = args
    else:
        if len(args) < 2:
            parser.error(
                'Need to specify output directory and at least one input file')
        output_dir = args[0]
        input_paths = args[1:]

    if options.depfile:
        python_deps = build_utils.GetPythonDependencies()
        build_utils.WriteDepfile(options.depfile, input_paths + python_deps)

    if options.srcjar:
        if options.print_output_only:
            parser.error('--print_output_only does not work with --srcjar')
        if options.assert_files_list:
            parser.error('--assert_file does not work with --srcjar')

        with zipfile.ZipFile(options.srcjar, 'w',
                             zipfile.ZIP_STORED) as srcjar:
            for output_path, data in DoGenerate(input_paths):
                srcjar.writestr(build_utils.CreateHermeticZipInfo(output_path),
                                data)
    else:
        # TODO(agrieve): Delete this non-srcjar branch once GYP is gone.
        output_paths = []
        for output_path, data in DoGenerate(input_paths):
            full_path = os.path.join(output_dir, output_path)
            output_paths.append(full_path)
            if not options.print_output_only:
                build_utils.MakeDirectory(os.path.dirname(full_path))
                with open(full_path, 'w') as out_file:
                    out_file.write(data)

        if options.assert_files_list:
            AssertFilesList(output_paths, options.assert_files_list)

        if options.verbose:
            print 'Output paths:'
            print '\n'.join(output_paths)

        # Used by GYP.
        return ' '.join(output_paths)
Exemple #24
0
def CreateRJavaFiles(srcjar_dir,
                     package,
                     main_r_txt_file,
                     extra_res_packages,
                     extra_r_txt_files,
                     rjava_build_options,
                     srcjar_out,
                     custom_root_package_name=None,
                     grandparent_custom_package_name=None,
                     extra_main_r_text_files=None):
    """Create all R.java files for a set of packages and R.txt files.

  Args:
    srcjar_dir: The top-level output directory for the generated files.
    package: Package name for R java source files which will inherit
      from the root R java file.
    main_r_txt_file: The main R.txt file containing the valid values
      of _all_ resource IDs.
    extra_res_packages: A list of extra package names.
    extra_r_txt_files: A list of extra R.txt files. One per item in
      |extra_res_packages|. Note that all resource IDs in them will be ignored,
      |and replaced by the values extracted from |main_r_txt_file|.
    rjava_build_options: An RJavaBuildOptions instance that controls how
      exactly the R.java file is generated.
    srcjar_out: Path of desired output srcjar.
    custom_root_package_name: Custom package name for module root R.java file,
      (eg. vr for gen.vr package).
    grandparent_custom_package_name: Custom root package name for the root
      R.java file to inherit from. DFM root R.java files will have "base"
      as the grandparent_custom_package_name. The format of this package name
      is identical to custom_root_package_name.
      (eg. for vr grandparent_custom_package_name would be "base")
    extra_main_r_text_files: R.txt files to be added to the root R.java file.
  Raises:
    Exception if a package name appears several times in |extra_res_packages|
  """
    assert len(extra_res_packages) == len(extra_r_txt_files), \
           'Need one R.txt file per package'

    packages = list(extra_res_packages)
    r_txt_files = list(extra_r_txt_files)

    if package and package not in packages:
        # Sometimes, an apk target and a resources target share the same
        # AndroidManifest.xml and thus |package| will already be in |packages|.
        packages.append(package)
        r_txt_files.append(main_r_txt_file)

    # Map of (resource_type, name) -> Entry.
    # Contains the correct values for resources.
    all_resources = {}
    all_resources_by_type = collections.defaultdict(list)

    main_r_text_files = [main_r_txt_file]
    if extra_main_r_text_files:
        main_r_text_files.extend(extra_main_r_text_files)
    for r_txt_file in main_r_text_files:
        for entry in _ParseTextSymbolsFile(r_txt_file, fix_package_ids=True):
            entry_key = (entry.resource_type, entry.name)
            if entry_key in all_resources:
                assert entry == all_resources[entry_key], (
                    'Input R.txt %s provided a duplicate resource with a different '
                    'entry value. Got %s, expected %s.' %
                    (r_txt_file, entry, all_resources[entry_key]))
            else:
                all_resources[entry_key] = entry
                all_resources_by_type[entry.resource_type].append(entry)
                assert entry.resource_type in _ALL_RESOURCE_TYPES, (
                    'Unknown resource type: %s, add to _ALL_RESOURCE_TYPES!' %
                    entry.resource_type)

    if custom_root_package_name:
        # Custom package name is available, thus use it for root_r_java_package.
        root_r_java_package = GetCustomPackagePath(custom_root_package_name)
    else:
        # Create a unique name using srcjar_out. Underscores are added to ensure
        # no reserved keywords are used for directory names.
        root_r_java_package = re.sub('[^\w\.]', '',
                                     srcjar_out.replace('/', '._'))

    root_r_java_dir = os.path.join(srcjar_dir, *root_r_java_package.split('.'))
    build_utils.MakeDirectory(root_r_java_dir)
    root_r_java_path = os.path.join(root_r_java_dir, 'R.java')
    root_java_file_contents = _RenderRootRJavaSource(
        root_r_java_package, all_resources_by_type, rjava_build_options,
        grandparent_custom_package_name)
    with open(root_r_java_path, 'w') as f:
        f.write(root_java_file_contents)

    # Map of package_name->resource_type->entry
    resources_by_package = (
        collections.defaultdict(lambda: collections.defaultdict(list)))
    # Build the R.java files using each package's R.txt file, but replacing
    # each entry's placeholder value with correct values from all_resources.
    for package, r_txt_file in zip(packages, r_txt_files):
        if package in resources_by_package:
            raise Exception(
                ('Package name "%s" appeared twice. All '
                 'android_resources() targets must use unique package '
                 'names, or no package name at all.') % package)
        resources_by_type = resources_by_package[package]
        # The sub-R.txt files have the wrong values at this point. Read them to
        # figure out which entries belong to them, but use the values from the
        # main R.txt file.
        for entry in _ParseTextSymbolsFile(r_txt_file):
            entry = all_resources.get((entry.resource_type, entry.name))
            # For most cases missing entry here is an error. It means that some
            # library claims to have or depend on a resource that isn't included into
            # the APK. There is one notable exception: Google Play Services (GMS).
            # GMS is shipped as a bunch of AARs. One of them - basement - contains
            # R.txt with ids of all resources, but most of the resources are in the
            # other AARs. However, all other AARs reference their resources via
            # basement's R.java so the latter must contain all ids that are in its
            # R.txt. Most targets depend on only a subset of GMS AARs so some
            # resources are missing, which is okay because the code that references
            # them is missing too. We can't get an id for a resource that isn't here
            # so the only solution is to skip the resource entry entirely.
            #
            # We can verify that all entries referenced in the code were generated
            # correctly by running Proguard on the APK: it will report missing
            # fields.
            if entry:
                resources_by_type[entry.resource_type].append(entry)

    for package, resources_by_type in resources_by_package.iteritems():
        _CreateRJavaSourceFile(srcjar_dir, package, root_r_java_package,
                               resources_by_type, rjava_build_options)
Exemple #25
0
def CreateRJavaFiles(srcjar_dir,
                     package,
                     main_r_txt_file,
                     extra_res_packages,
                     rjava_build_options,
                     srcjar_out,
                     custom_root_package_name=None,
                     grandparent_custom_package_name=None,
                     extra_main_r_text_files=None,
                     ignore_mismatched_values=False):
  """Create all R.java files for a set of packages and R.txt files.

  Args:
    srcjar_dir: The top-level output directory for the generated files.
    package: Package name for R java source files which will inherit
      from the root R java file.
    main_r_txt_file: The main R.txt file containing the valid values
      of _all_ resource IDs.
    extra_res_packages: A list of extra package names.
    rjava_build_options: An RJavaBuildOptions instance that controls how
      exactly the R.java file is generated.
    srcjar_out: Path of desired output srcjar.
    custom_root_package_name: Custom package name for module root R.java file,
      (eg. vr for gen.vr package).
    grandparent_custom_package_name: Custom root package name for the root
      R.java file to inherit from. DFM root R.java files will have "base"
      as the grandparent_custom_package_name. The format of this package name
      is identical to custom_root_package_name.
      (eg. for vr grandparent_custom_package_name would be "base")
    extra_main_r_text_files: R.txt files to be added to the root R.java file.
    ignore_mismatched_values: If True, ignores if a resource appears multiple
      times with different entry values (useful when all the values are
      dummy anyways).
  Raises:
    Exception if a package name appears several times in |extra_res_packages|
  """
  rjava_build_options._MaybeRewriteRTxtPackageIds(main_r_txt_file)

  packages = list(extra_res_packages)

  if package and package not in packages:
    # Sometimes, an apk target and a resources target share the same
    # AndroidManifest.xml and thus |package| will already be in |packages|.
    packages.append(package)

  # Map of (resource_type, name) -> Entry.
  # Contains the correct values for resources.
  all_resources = {}
  all_resources_by_type = collections.defaultdict(list)

  main_r_text_files = [main_r_txt_file]
  if extra_main_r_text_files:
    main_r_text_files.extend(extra_main_r_text_files)
  for r_txt_file in main_r_text_files:
    for entry in _ParseTextSymbolsFile(r_txt_file, fix_package_ids=True):
      entry_key = (entry.resource_type, entry.name)
      if entry_key in all_resources:
        if not ignore_mismatched_values:
          assert entry == all_resources[entry_key], (
              'Input R.txt %s provided a duplicate resource with a different '
              'entry value. Got %s, expected %s.' %
              (r_txt_file, entry, all_resources[entry_key]))
      else:
        all_resources[entry_key] = entry
        all_resources_by_type[entry.resource_type].append(entry)
        assert entry.resource_type in _ALL_RESOURCE_TYPES, (
            'Unknown resource type: %s, add to _ALL_RESOURCE_TYPES!' %
            entry.resource_type)

  if custom_root_package_name:
    # Custom package name is available, thus use it for root_r_java_package.
    root_r_java_package = GetCustomPackagePath(custom_root_package_name)
  else:
    # Create a unique name using srcjar_out. Underscores are added to ensure
    # no reserved keywords are used for directory names.
    root_r_java_package = re.sub('[^\w\.]', '', srcjar_out.replace('/', '._'))

  root_r_java_dir = os.path.join(srcjar_dir, *root_r_java_package.split('.'))
  build_utils.MakeDirectory(root_r_java_dir)
  root_r_java_path = os.path.join(root_r_java_dir, 'R.java')
  root_java_file_contents = _RenderRootRJavaSource(
      root_r_java_package, all_resources_by_type, rjava_build_options,
      grandparent_custom_package_name)
  with open(root_r_java_path, 'w') as f:
    f.write(root_java_file_contents)

  for package in packages:
    _CreateRJavaSourceFile(srcjar_dir, package, root_r_java_package,
                           rjava_build_options)
def _OnStaleMd5(options, javac_cmd, java_files, classpath):
    logging.info('Starting _OnStaleMd5')

    # Compiles with Error Prone take twice as long to run as pure javac. Thus GN
    # rules run both in parallel, with Error Prone only used for checks.
    save_outputs = not options.enable_errorprone

    # Use jar_path's directory to ensure paths are relative (needed for goma).
    temp_dir = options.jar_path + '.staging'
    shutil.rmtree(temp_dir, True)
    os.makedirs(temp_dir)
    try:
        classes_dir = os.path.join(temp_dir, 'classes')

        if save_outputs:
            input_srcjars_dir = os.path.join(options.generated_dir,
                                             'input_srcjars')
            annotation_processor_outputs_dir = os.path.join(
                options.generated_dir, 'annotation_processor_outputs')
            # Delete any stale files in the generated directory. The purpose of
            # options.generated_dir is for codesearch.
            shutil.rmtree(options.generated_dir, True)
            info_file_context = _InfoFileContext(
                options.chromium_code, options.jar_info_exclude_globs)
        else:
            input_srcjars_dir = os.path.join(temp_dir, 'input_srcjars')
            annotation_processor_outputs_dir = os.path.join(
                temp_dir, 'annotation_processor_outputs')

        if options.java_srcjars:
            logging.info('Extracting srcjars to %s', input_srcjars_dir)
            build_utils.MakeDirectory(input_srcjars_dir)
            for srcjar in options.java_srcjars:
                extracted_files = build_utils.ExtractAll(
                    srcjar,
                    no_clobber=True,
                    path=input_srcjars_dir,
                    pattern='*.java')
                java_files.extend(extracted_files)
                if save_outputs:
                    info_file_context.AddSrcJarSources(srcjar, extracted_files,
                                                       input_srcjars_dir)
            logging.info('Done extracting srcjars')

        if save_outputs and java_files:
            info_file_context.SubmitFiles(java_files)

        if java_files:
            # Don't include the output directory in the initial set of args since it
            # being in a temp dir makes it unstable (breaks md5 stamping).
            cmd = [_JAVAC_WRAPPER]
            cmd += javac_cmd
            cmd += ['-d', classes_dir]
            cmd += ['-s', annotation_processor_outputs_dir]

            # Pass classpath and source paths as response files to avoid extremely
            # long command lines that are tedius to debug.
            if classpath:
                cmd += ['-classpath', ':'.join(classpath)]

            java_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
            with open(java_files_rsp_path, 'w') as f:
                f.write(' '.join(java_files))
            cmd += ['@' + java_files_rsp_path]

            logging.debug('Build command %s', cmd)
            os.makedirs(classes_dir)
            os.makedirs(annotation_processor_outputs_dir)
            build_utils.CheckOutput(cmd,
                                    print_stdout=options.chromium_code,
                                    stderr_filter=ProcessJavacOutput)
            logging.info('Finished build command')

        if save_outputs:
            annotation_processor_srcjar = os.path.join(
                annotation_processor_outputs_dir, 'output.srcjar')
            if os.path.exists(annotation_processor_srcjar):
                annotation_processor_java_files = build_utils.ExtractAll(
                    annotation_processor_srcjar,
                    no_clobber=True,
                    path=annotation_processor_outputs_dir)
                os.unlink(annotation_processor_srcjar)
                if annotation_processor_java_files:
                    info_file_context.SubmitFiles(
                        annotation_processor_java_files, close=True)

            with build_utils.AtomicOutput(options.jar_path) as f:
                if java_files:
                    shutil.move(os.path.join(classes_dir, 'classes.jar'),
                                f.name)
                else:
                    zipfile.ZipFile(f.name, 'w').close()
                if options.provider_configurations or options.additional_jar_files:
                    _AddExtraJarFiles(f.name, options.provider_configurations,
                                      options.additional_jar_files)

            info_file_context.Commit(options.jar_path + '.info')
        else:
            build_utils.Touch(options.jar_path)

        logging.info('Completed all steps in _OnStaleMd5')
    finally:
        shutil.rmtree(temp_dir)
def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--input-dir',
        required=True,
        help=('Input source file directory which contains input '
              'files'))
    parser.add_argument(
        '--template-dir',
        help='Templates directory to generate java source file')
    parser.add_argument(
        '--bridge-output',
        required=True,
        help='Output directory where the bridge code is placed.')
    parser.add_argument('--wrapper-output',
                        required=True,
                        help='Output directory where the wrap code is placed.')
    parser.add_argument('--use-srcjars',
                        action='store_true',
                        default=False,
                        help='Write the .java files into .srcjar files.')
    parser.add_argument('--stamp', help='the file to touch on success.')
    parser.add_argument('--api-version', help='API Version')
    parser.add_argument('--min-api-version', help='Min API Version')
    parser.add_argument('--verify-xwalk-apk',
                        action='store_true',
                        default=False,
                        help='Verify Crosswalk library APK before loading.')
    parser.add_argument('--xwalk-build-version', help='XWalk Build Version')

    options = parser.parse_args()

    if os.path.isdir(options.bridge_output):
        shutil.rmtree(options.bridge_output)
    if os.path.isdir(options.wrapper_output):
        shutil.rmtree(options.wrapper_output)

    # TODO(rakuco): once we stop supporting gyp we shouldn't need those.
    build_utils.MakeDirectory(options.bridge_output)
    build_utils.MakeDirectory(options.wrapper_output)

    if options.use_srcjars:
        bridge_path = BRIDGE_PACKAGE.replace('.', os.path.sep)
        bridge_writer = SrcJarJavaWriter(
            os.path.join(options.bridge_output, 'bridge.srcjar'))
        wrapper_path = WRAPPER_PACKAGE.replace('.', os.path.sep)
        wrapper_writer = SrcJarJavaWriter(
            os.path.join(options.wrapper_output, 'wrapper.srcjar'))
    else:
        # TODO(rakuco): remove this code path once we stop supporting gyp.
        bridge_path = os.path.join(options.bridge_output,
                                   BRIDGE_PACKAGE.replace('.', os.path.sep))
        bridge_writer = FileSystemJavaWriter()
        wrapper_path = os.path.join(options.wrapper_output,
                                    WRAPPER_PACKAGE.replace('.', os.path.sep))
        wrapper_writer = FileSystemJavaWriter()

    if options.input_dir:
        GenerateJavaBindingClass(options.input_dir, bridge_path, bridge_writer,
                                 wrapper_path, wrapper_writer)
        GenerateJavaReflectClass(options.input_dir, wrapper_path,
                                 wrapper_writer)

    # TODO(rakuco): template handling should not be done in this script.
    # Once we stop supporting gyp, we should do this as part of the build system.
    if options.template_dir:
        mapping = {
            'API_VERSION': options.api_version,
            'MIN_API_VERSION': options.min_api_version,
            'XWALK_BUILD_VERSION': options.xwalk_build_version,
            'VERIFY_XWALK_APK': str(options.verify_xwalk_apk).lower(),
        }
        GenerateJavaTemplateClass(options.template_dir, bridge_path,
                                  bridge_writer, wrapper_path, wrapper_writer,
                                  mapping)

    if options.stamp:
        build_utils.Touch(options.stamp)
Exemple #28
0
def _CreateRJavaFiles(srcjar_dir, main_r_txt_file, packages, r_txt_files,
                      shared_resources, non_constant_id, whitelist_r_txt_file,
                      is_apk):
    assert len(packages) == len(r_txt_files), 'Need one R.txt file per package'

    # Map of (resource_type, name) -> Entry.
    # Contains the correct values for resources.
    all_resources = {}
    for entry in _ParseTextSymbolsFile(main_r_txt_file):
        entry = entry._replace(value=_FixPackageIds(entry.value))
        all_resources[(entry.resource_type, entry.name)] = entry

    if whitelist_r_txt_file:
        whitelisted_resources = _ResourceWhitelist(
            _ParseTextSymbolsFile(whitelist_r_txt_file))
    else:
        whitelisted_resources = _ResourceWhitelist()

    # Map of package_name->resource_type->entry
    resources_by_package = (
        collections.defaultdict(lambda: collections.defaultdict(list)))
    # Build the R.java files using each package's R.txt file, but replacing
    # each entry's placeholder value with correct values from all_resources.
    for package, r_txt_file in zip(packages, r_txt_files):
        if package in resources_by_package:
            raise Exception(
                ('Package name "%s" appeared twice. All '
                 'android_resources() targets must use unique package '
                 'names, or no package name at all.') % package)
        resources_by_type = resources_by_package[package]
        # The sub-R.txt files have the wrong values at this point. Read them to
        # figure out which entries belong to them, but use the values from the
        # main R.txt file.
        for entry in _ParseTextSymbolsFile(r_txt_file):
            entry = all_resources.get((entry.resource_type, entry.name))
            # For most cases missing entry here is an error. It means that some
            # library claims to have or depend on a resource that isn't included into
            # the APK. There is one notable exception: Google Play Services (GMS).
            # GMS is shipped as a bunch of AARs. One of them - basement - contains
            # R.txt with ids of all resources, but most of the resources are in the
            # other AARs. However, all other AARs reference their resources via
            # basement's R.java so the latter must contain all ids that are in its
            # R.txt. Most targets depend on only a subset of GMS AARs so some
            # resources are missing, which is okay because the code that references
            # them is missing too. We can't get an id for a resource that isn't here
            # so the only solution is to skip the resource entry entirely.
            #
            # We can verify that all entries referenced in the code were generated
            # correctly by running Proguard on the APK: it will report missing
            # fields.
            if entry:
                resources_by_type[entry.resource_type].append(entry)

    for package, resources_by_type in resources_by_package.iteritems():
        package_r_java_dir = os.path.join(srcjar_dir, *package.split('.'))
        build_utils.MakeDirectory(package_r_java_dir)
        package_r_java_path = os.path.join(package_r_java_dir, 'R.java')
        java_file_contents = _CreateRJavaFile(package, resources_by_type,
                                              shared_resources,
                                              non_constant_id,
                                              whitelisted_resources, is_apk)
        with open(package_r_java_path, 'w') as f:
            f.write(java_file_contents)
Exemple #29
0
def main(args):
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    # Order of these must match order specified in GN so that the correct one
    # appears first in the depfile.
    possible_output_paths = [
        options.apk_path,
        options.apk_path + '.info',
        options.r_text_out,
        options.srcjar_out,
        options.proguard_file,
        options.proguard_file_main_dex,
        options.unoptimized_resources_path,
    ]
    output_paths = [x for x in possible_output_paths if x]

    # List python deps in input_strings rather than input_paths since the contents
    # of them does not change what gets written to the depsfile.
    input_strings = options.extra_res_packages + [
        options.shared_resources,
        options.resource_blacklist_regex,
        options.resource_blacklist_exceptions,
        str(options.debuggable),
        str(options.png_to_webp),
        str(options.support_zh_hk),
        str(options.no_xml_namespaces),
        str(options.optimize_resources),
    ]

    input_strings.extend(_CreateLinkApkArgs(options))

    debug_temp_resources_dir = os.environ.get(_ENV_DEBUG_VARIABLE)
    if debug_temp_resources_dir:
        debug_temp_resources_dir = os.path.join(
            debug_temp_resources_dir, os.path.basename(options.apk_path))
        build_utils.DeleteDirectory(debug_temp_resources_dir)
        build_utils.MakeDirectory(debug_temp_resources_dir)

    possible_input_paths = [
        options.aapt_path,
        options.aapt2_path,
        options.android_manifest,
        options.shared_resources_whitelist,
        options.resources_config_path,
    ]
    possible_input_paths += options.include_resources
    input_paths = [x for x in possible_input_paths if x]
    input_paths.extend(options.dependencies_res_zips)
    input_paths.extend(options.extra_r_text_files)

    if options.webp_binary:
        input_paths.append(options.webp_binary)

    build_utils.CallAndWriteDepfileIfStale(
        lambda: _OnStaleMd5(options, debug_temp_resources_dir),
        options,
        input_paths=input_paths,
        input_strings=input_strings,
        output_paths=output_paths,
        force=bool(debug_temp_resources_dir),
        depfile_deps=options.dependencies_res_zips +
        options.extra_r_text_files,
        add_pydeps=False)
Exemple #30
0
def CopyJSBindingFiles(js_files, output_dir):
    res_raw_dir = os.path.join(output_dir, 'res', 'raw')
    build_utils.MakeDirectory(res_raw_dir)
    for js_file in js_files:
        shutil.copy2(js_file, res_raw_dir)