Пример #1
0
 def Generate(self, root_entry):
   # TODO(agrieve): Add an option to use interface jars and see if that speeds
   # things up at all.
   variables = {}
   java_dirs, excludes = self._GenJavaDirs(root_entry)
   java_dirs.extend(
       e.GeneratedJavaSubdir() for e in self._GetEntries(root_entry))
   self.processed_java_dirs.update(java_dirs)
   java_dirs.sort()
   variables['java_dirs'] = self._Relativize(root_entry, java_dirs)
   variables['java_excludes'] = excludes
   variables['jni_libs'] = self._Relativize(
       root_entry, set(self._GenJniLibs(root_entry)))
   prebuilts = set(
       p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars())
   self.processed_prebuilts.update(prebuilts)
   variables['prebuilts'] = self._Relativize(root_entry, prebuilts)
   res_sources_files = _RebasePath(
       set(p for e in self._GetEntries(root_entry) for p in e.ResSources()))
   res_sources = []
   for res_sources_file in res_sources_files:
     res_sources.extend(build_utils.ReadSourcesList(res_sources_file))
   res_dirs = resource_utils.DeduceResourceDirsFromFileList(res_sources)
   # Do not add generated resources for the all module since it creates many
   # duplicates, and currently resources are only used for editing.
   self.processed_res_dirs.update(res_dirs)
   variables['res_dirs'] = self._Relativize(root_entry, res_dirs)
   if self.split_projects:
     deps = [_ProjectEntry.FromBuildConfigPath(p)
             for p in root_entry.Gradle()['dependent_android_projects']]
     variables['android_project_deps'] = [d.ProjectName() for d in deps]
     deps = [_ProjectEntry.FromBuildConfigPath(p)
             for p in root_entry.Gradle()['dependent_java_projects']]
     variables['java_project_deps'] = [d.ProjectName() for d in deps]
   return variables
Пример #2
0
def _ParseArgs(args):
    """Parses command line options.

  Returns:
    An options object as from argparse.ArgumentParser.parse_args()
  """
    parser, input_opts, output_opts = resource_utils.ResourceArgsParser()

    input_opts.add_argument(
        '--res-sources-path',
        required=True,
        help='Path to a list of input resources for this target.')

    input_opts.add_argument(
        '--shared-resources',
        action='store_true',
        help='Make resources shareable by generating an onResourcesLoaded() '
        'method in the R.java source file.')

    input_opts.add_argument('--custom-package',
                            help='Optional Java package for main R.java.')

    input_opts.add_argument(
        '--android-manifest',
        help='Optional AndroidManifest.xml path. Only used to extract a package '
        'name for R.java if a --custom-package is not provided.')

    output_opts.add_argument(
        '--resource-zip-out',
        help='Path to a zip archive containing all resources from '
        '--resource-dirs, merged into a single directory tree.')

    output_opts.add_argument(
        '--srcjar-out',
        help='Path to .srcjar to contain the generated R.java.')

    output_opts.add_argument('--r-text-out',
                             help='Path to store the generated R.txt file.')

    input_opts.add_argument('--strip-drawables',
                            action="store_true",
                            help='Remove drawables from the resources.')

    options = parser.parse_args(args)

    resource_utils.HandleCommonOptions(options)

    with open(options.res_sources_path) as f:
        options.sources = f.read().splitlines()
    options.resource_dirs = resource_utils.DeduceResourceDirsFromFileList(
        options.sources)

    return options
Пример #3
0
def _ParseArgs(args):
    """Parses command line options.

  Returns:
    An options object as from argparse.ArgumentParser.parse_args()
  """
    parser = argparse.ArgumentParser(description=__doc__)
    build_utils.AddDepfileOption(parser)

    parser.add_argument(
        '--res-sources-path',
        required=True,
        help='Path to a list of input resources for this target.')

    parser.add_argument(
        '--r-text-in',
        help='Path to pre-existing R.txt. Its resource IDs override those found '
        'in the generated R.txt when generating R.java.')

    parser.add_argument(
        '--allow-missing-resources',
        action='store_true',
        help='Do not fail if some resources exist in the res/ dir but are not '
        'listed in the sources.')

    parser.add_argument(
        '--resource-zip-out',
        help='Path to a zip archive containing all resources from '
        '--resource-dirs, merged into a single directory tree.')

    parser.add_argument('--r-text-out',
                        help='Path to store the generated R.txt file.')

    parser.add_argument('--strip-drawables',
                        action="store_true",
                        help='Remove drawables from the resources.')

    options = parser.parse_args(args)

    with open(options.res_sources_path) as f:
        options.sources = f.read().splitlines()
    options.resource_dirs = resource_utils.DeduceResourceDirsFromFileList(
        options.sources)

    return options
Пример #4
0
def _RunLint(lint_path,
             config_path,
             manifest_path,
             result_path,
             product_dir,
             sources,
             cache_dir,
             android_sdk_version,
             srcjars,
             min_sdk_version,
             manifest_package,
             resource_sources,
             resource_zips,
             can_fail_build=False,
             include_unexpected=False,
             silent=False):
    logging.info('Lint starting')

    def _RebasePath(path):
        """Returns relative path to top-level src dir.

    Args:
      path: A path relative to cwd.
    """
        ret = os.path.relpath(os.path.abspath(path),
                              build_utils.DIR_SOURCE_ROOT)
        # If it's outside of src/, just use abspath.
        if ret.startswith('..'):
            ret = os.path.abspath(path)
        return ret

    def _ProcessResultFile():
        with open(result_path, 'rb') as f:
            content = f.read().replace(_RebasePath(product_dir), 'PRODUCT_DIR')

        with open(result_path, 'wb') as f:
            f.write(content)

    def _ParseAndShowResultFile():
        dom = minidom.parse(result_path)
        issues = dom.getElementsByTagName('issue')
        if not silent:
            print(file=sys.stderr)
            for issue in issues:
                issue_id = issue.attributes['id'].value
                message = issue.attributes['message'].value
                location_elem = issue.getElementsByTagName('location')[0]
                path = location_elem.attributes['file'].value
                line = location_elem.getAttribute('line')
                error = '%s:%s %s: %s [warning]' % (path, line, message,
                                                    issue_id)
                print(error.encode('utf-8'), file=sys.stderr)
                for attr in ['errorLine1', 'errorLine2']:
                    error_line = issue.getAttribute(attr)
                    if error_line:
                        print(error_line.encode('utf-8'), file=sys.stderr)
        return len(issues)

    with build_utils.TempDir() as temp_dir:
        cmd = [
            _RebasePath(lint_path),
            '-Werror',
            '--exitcode',
            '--showall',
            '--xml',
            _RebasePath(result_path),
        ]
        if config_path:
            cmd.extend(['--config', _RebasePath(config_path)])

        tmp_dir_counter = [0]

        def _NewTempSubdir(prefix, append_digit=True):
            # Helper function to create a new sub directory based on the number of
            # subdirs created earlier.
            if append_digit:
                tmp_dir_counter[0] += 1
                prefix += str(tmp_dir_counter[0])
            new_dir = os.path.join(temp_dir, prefix)
            os.makedirs(new_dir)
            return new_dir

        resource_dirs = resource_utils.DeduceResourceDirsFromFileList(
            resource_sources)
        # These are zip files with generated resources (e. g. strings from GRD).
        for resource_zip in resource_zips:
            resource_dir = _NewTempSubdir(resource_zip, append_digit=False)
            resource_dirs.append(resource_dir)
            build_utils.ExtractAll(resource_zip, path=resource_dir)

        for resource_dir in resource_dirs:
            cmd.extend(['--resources', _RebasePath(resource_dir)])

        # There may be multiple source files with the same basename (but in
        # different directories). It is difficult to determine what part of the path
        # corresponds to the java package, and so instead just link the source files
        # into temporary directories (creating a new one whenever there is a name
        # conflict).
        def PathInDir(d, src):
            subpath = os.path.join(d, _RebasePath(src))
            subdir = os.path.dirname(subpath)
            if not os.path.exists(subdir):
                os.makedirs(subdir)
            return subpath

        src_dirs = []
        for src in sources:
            src_dir = None
            for d in src_dirs:
                if not os.path.exists(PathInDir(d, src)):
                    src_dir = d
                    break
            if not src_dir:
                src_dir = _NewTempSubdir('SRC_ROOT')
                src_dirs.append(src_dir)
                cmd.extend(['--sources', _RebasePath(src_dir)])
            # In cases where the build dir is outside of the src dir, this can
            # result in trying to symlink a file to itself for this file:
            # gen/components/version_info/android/java/org/chromium/
            #   components/version_info/VersionConstants.java
            src = os.path.abspath(src)
            dst = PathInDir(src_dir, src)
            if src == dst:
                continue
            os.symlink(src, dst)

        if srcjars:
            srcjar_dir = _NewTempSubdir('GENERATED_SRC_ROOT',
                                        append_digit=False)
            cmd.extend(['--sources', _RebasePath(srcjar_dir)])
            for srcjar in srcjars:
                # We choose to allow srcjars that contain java files which have the
                # same package and name to clobber each other. This happens for
                # generated files like BuildConfig.java. It is generated for
                # targets like base_build_config_gen as well as targets like
                # chrome_modern_public_base_bundle_module__build_config_srcjar.
                # Although we could extract each srcjar to a separate folder, that
                # slows down some invocations of lint by 20 seconds or more.
                # TODO(wnwen): Switch lint.py to generate a project.xml file which
                #              supports srcjar inputs by default.
                build_utils.ExtractAll(srcjar,
                                       path=srcjar_dir,
                                       no_clobber=False)

        project_dir = _NewTempSubdir('PROJECT_ROOT', append_digit=False)
        if android_sdk_version:
            # Create dummy project.properies file in a temporary "project" directory.
            # It is the only way to add Android SDK to the Lint's classpath. Proper
            # classpath is necessary for most source-level checks.
            with open(os.path.join(project_dir, 'project.properties'), 'w') \
                as propfile:
                print('target=android-{}'.format(android_sdk_version),
                      file=propfile)

        # Put the manifest in a temporary directory in order to avoid lint detecting
        # sibling res/ and src/ directories (which should be pass explicitly if they
        # are to be included).
        if not manifest_path:
            manifest_path = os.path.join(build_utils.DIR_SOURCE_ROOT, 'build',
                                         'android', 'AndroidManifest.xml')
        lint_manifest_path = os.path.join(project_dir, 'AndroidManifest.xml')
        shutil.copyfile(os.path.abspath(manifest_path), lint_manifest_path)

        # Check that minSdkVersion and package is correct and add it to the manifest
        # in case it does not exist.
        doc, manifest, _ = manifest_utils.ParseManifest(lint_manifest_path)
        manifest_utils.AssertUsesSdk(manifest, min_sdk_version)
        manifest_utils.AssertPackage(manifest, manifest_package)
        uses_sdk = manifest.find('./uses-sdk')
        if uses_sdk is None:
            uses_sdk = ElementTree.Element('uses-sdk')
            manifest.insert(0, uses_sdk)
        uses_sdk.set('{%s}minSdkVersion' % manifest_utils.ANDROID_NAMESPACE,
                     min_sdk_version)
        if manifest_package:
            manifest.set('package', manifest_package)
        manifest_utils.SaveManifest(doc, lint_manifest_path)

        cmd.append(project_dir)

        if os.path.exists(result_path):
            os.remove(result_path)

        env = os.environ.copy()
        stderr_filter = build_utils.FilterReflectiveAccessJavaWarnings
        if cache_dir:
            env['_JAVA_OPTIONS'] = '-Duser.home=%s' % _RebasePath(cache_dir)
            # When _JAVA_OPTIONS is set, java prints to stderr:
            # Picked up _JAVA_OPTIONS: ...
            #
            # We drop all lines that contain _JAVA_OPTIONS from the output
            stderr_filter = lambda l: re.sub(
                r'.*_JAVA_OPTIONS.*\n?', '',
                build_utils.FilterReflectiveAccessJavaWarnings(l))

        def fail_func(returncode, stderr):
            if returncode != 0:
                return True
            if (include_unexpected
                    and 'Unexpected failure during lint analysis' in stderr):
                return True
            return False

        try:
            env['JAVA_HOME'] = os.path.relpath(build_utils.JAVA_HOME,
                                               build_utils.DIR_SOURCE_ROOT)
            logging.debug('Lint command %s', cmd)
            start = time.time()
            build_utils.CheckOutput(cmd,
                                    cwd=build_utils.DIR_SOURCE_ROOT,
                                    env=env or None,
                                    stderr_filter=stderr_filter,
                                    fail_func=fail_func)
            end = time.time() - start
            logging.info('Lint command took %ss', end)
        except build_utils.CalledProcessError:
            # There is a problem with lint usage
            if not os.path.exists(result_path):
                raise

            # Sometimes produces empty (almost) files:
            if os.path.getsize(result_path) < 10:
                if can_fail_build:
                    raise
                elif not silent:
                    traceback.print_exc()
                return

            # There are actual lint issues
            try:
                num_issues = _ParseAndShowResultFile()
            except Exception:  # pylint: disable=broad-except
                if not silent:
                    print('Lint created unparseable xml file...')
                    print('File contents:')
                    with open(result_path) as f:
                        print(f.read())
                    if can_fail_build:
                        traceback.print_exc()
                if can_fail_build:
                    raise
                else:
                    return

            _ProcessResultFile()
            if num_issues == 0 and include_unexpected:
                msg = 'Please refer to output above for unexpected lint failures.\n'
            else:
                msg = (
                    '\nLint found %d new issues.\n'
                    ' - For full explanation, please refer to %s\n'
                    ' - For more information about lint and how to fix lint issues,'
                    ' please refer to %s\n' %
                    (num_issues, _RebasePath(result_path), _LINT_MD_URL))
            if not silent:
                print(msg, file=sys.stderr)
            if can_fail_build:
                raise Exception('Lint failed.')

    logging.info('Lint completed')