示例#1
0
  def errorprone(self, target):
    runtime_classpaths = self.context.products.get_data('runtime_classpath')
    runtime_classpath = [jar for conf, jar in runtime_classpaths.get_for_targets(target.closure(bfs=True))]

    output_dir = os.path.join(self.workdir, target.id)
    safe_mkdir(output_dir)
    runtime_classpath.append(output_dir)

    # Try to run errorprone with the same java version as the target
    # The minimum JDK for errorprone is JDK 1.8
    min_jdk_version = max(target.platform.target_level, Revision.lenient('1.8'))
    if min_jdk_version.components[0] == 1:
      max_jdk_version = Revision(min_jdk_version.components[0], min_jdk_version.components[1], '9999')
    else:
      max_jdk_version = Revision(min_jdk_version.components[0], '9999')
    self.set_distribution(minimum_version=min_jdk_version, maximum_version=max_jdk_version, jdk=True)

    jvm_options = self.get_options().jvm_options[:]
    if self.dist.version < Revision.lenient('9'):
      # For Java 8 we need to add the errorprone javac jar to the bootclasspath to
      # avoid the "java.lang.NoSuchFieldError: ANNOTATION_PROCESSOR_MODULE_PATH" error
      # See https://github.com/google/error-prone/issues/653 for more information
      jvm_options.extend(['-Xbootclasspath/p:{}'.format(self.tool_classpath('errorprone-javac')[0])])

    args = [
      '-d', output_dir,
    ]

    # Errorprone does not recognize source or target 10 yet
    if target.platform.source_level < Revision.lenient('10'):
      args.extend(['-source', str(target.platform.source_level)])

    if target.platform.target_level < Revision.lenient('10'):
      args.extend(['-target', str(target.platform.target_level)])

    errorprone_classpath_file = os.path.join(self.workdir, '{}.classpath'.format(os.path.basename(output_dir)))
    with open(errorprone_classpath_file, 'w') as f:
      f.write('-classpath ')
      f.write(':'.join(runtime_classpath))
    args.append('@{}'.format(errorprone_classpath_file))

    for opt in self.get_options().command_line_options:
      args.extend(safe_shlex_split(opt))

    with argfile.safe_args(self.calculate_sources(target), self.get_options()) as batched_sources:
      args.extend(batched_sources)
      result = self.runjava(classpath=self.tool_classpath('errorprone'),
                            main=self._ERRORPRONE_MAIN,
                            jvm_options=jvm_options,
                            args=args,
                            workunit_name='errorprone',
                            workunit_labels=[WorkUnitLabel.LINT])

      self.context.log.debug('java {main} ... exited with result ({result})'.format(
        main=self._ERRORPRONE_MAIN, result=result))

    return result
示例#2
0
    def _preferred_jvm_distribution_args(cls,
                                         platforms,
                                         strict=None,
                                         jdk=False):
        if not platforms:
            return {"jdk": jdk}
        if strict is False:  # treat all the platforms as non-strict
            min_version = max(p.target_level for p in platforms)
            set_max_version = False
        else:
            # treat strict platforms as strict & ensure no non-strict directive is broken
            strict_target_levels = {
                p.target_level
                for p in platforms if p.strict
            }
            lenient_target_levels = {
                p.target_level
                for p in platforms if not p.strict
            }

            if len(strict_target_levels) == 0:
                min_version = max(lenient_target_levels)
                set_max_version = strict
            elif len(strict_target_levels) > 1:
                differing = ", ".join(str(t) for t in strict_target_levels)
                raise cls.IncompatiblePlatforms(
                    f"Multiple strict platforms with differing target releases were found:"
                    f" {differing}")
            else:
                if len(lenient_target_levels) == 0:
                    min_version = next(iter(strict_target_levels))
                    set_max_version = True
                else:
                    strict_level = next(iter(strict_target_levels))
                    non_strict_max = max(t for t in lenient_target_levels)
                    if non_strict_max and non_strict_max > strict_level:
                        raise cls.IncompatiblePlatforms(
                            f"lenient platform with higher minimum version,"
                            f" {non_strict_max}, than strict requirement of"
                            f" {strict_level}")
                    min_version = strict_level
                    set_max_version = True

        if len(min_version.components
               ) <= 2:  # ensure at least three components.
            min_version = Revision(*(min_version.components + [0] *
                                     (3 - len(min_version.components))))
        max_version = None
        if set_max_version:
            max_version = Revision(*(min_version.components[0:2] + [9999]))
        return {
            "minimum_version": min_version,
            "maximum_version": max_version,
            "jdk": jdk
        }
示例#3
0
 def preferred_jvm_distribution(self, platforms):
   """Returns a jvm Distribution with a version that should work for all the platforms."""
   if not platforms:
     return DistributionLocator.cached()
   min_version = max(platform.target_level for platform in platforms)
   max_version = Revision(*(min_version.components + [9999])) if self._strict_jvm_version else None
   return DistributionLocator.cached(minimum_version=min_version, maximum_version=max_version)
示例#4
0
 def test_preferred_jvm_distributions(self):
     with temporary_dir() as strict_jdk_home:
         with temporary_dir() as non_strict_jdk_home:
             strict_cache_key = (Revision(1, 6), Revision(1, 6,
                                                          9999), False)
             non_strict_cache_key = (Revision(1, 6), None, False)
             DistributionLocator._CACHE[strict_cache_key] = Distribution(
                 home_path=strict_jdk_home)
             DistributionLocator._CACHE[
                 non_strict_cache_key] = Distribution(
                     home_path=non_strict_jdk_home)
             self.assertEqual(
                 {
                     'strict': strict_jdk_home,
                     'non_strict': non_strict_jdk_home
                 },
                 self.execute_export_json()['preferred_jvm_distributions']
                 ['java6'])
示例#5
0
  def _run_tests(self, tests_to_targets, main, extra_jvm_options=None, classpath_prepend=(),
                 classpath_append=()):
    extra_jvm_options = extra_jvm_options or []

    tests_by_properties = self._tests_by_properties(tests_to_targets,
                                                    self._infer_workdir,
                                                    lambda target: target.test_platform)

    result = 0
    for (workdir, platform), tests in tests_by_properties.items():
      for batch in self._partition(tests):
        # Batches of test classes will likely exist within the same targets: dedupe them.
        relevant_targets = set(map(tests_to_targets.get, batch))
        classpath = self._task_exports.classpath(relevant_targets,
                                                 cp=self._task_exports.tool_classpath('junit'))
        complete_classpath = OrderedSet()
        complete_classpath.update(classpath_prepend)
        complete_classpath.update(classpath)
        complete_classpath.update(classpath_append)
        if self._strict_jvm_version:
          max_version = Revision(*(platform.target_level.components + [9999]))
          distribution = Distribution.cached(minimum_version=platform.target_level,
                                             maximum_version=max_version)
        else:
          distribution = Distribution.cached(minimum_version=platform.target_level)
        with binary_util.safe_args(batch, self._task_exports.task_options) as batch_tests:
          self._context.log.debug('CWD = {}'.format(workdir))
          self._context.log.debug('platform = {}'.format(platform))
          result += abs(execute_java(
            classpath=complete_classpath,
            main=main,
            jvm_options=self._task_exports.jvm_options + extra_jvm_options,
            args=self._args + batch_tests + [u'-xmlreport'],
            workunit_factory=self._context.new_workunit,
            workunit_name='run',
            workunit_labels=[WorkUnitLabel.TEST],
            cwd=workdir,
            distribution=distribution,
          ))

          if result != 0 and self._fail_fast:
            break

    if result != 0:
      failed_targets = self._get_failed_targets(tests_to_targets)
      raise TestFailedTaskError(
        'java {0} ... exited non-zero ({1}); {2} failed targets.'
        .format(main, result, len(failed_targets)),
        failed_targets=failed_targets
      )
示例#6
0
  def preferred_jvm_distribution(cls, platforms, strict=False):
    """Returns a jvm Distribution with a version that should work for all the platforms.

    Any one of those distributions whose version is >= all requested platforms' versions
    can be returned unless strict flag is set.

    :param iterable platforms: An iterable of platform settings.
    :param bool strict: If true, only distribution whose version matches the minimum
      required version can be returned, i.e, the max target_level of all the requested
      platforms.
    :returns: Distribution one of the selected distributions.
    """
    if not platforms:
      return DistributionLocator.cached()
    min_version = max(platform.target_level for platform in platforms)
    max_version = Revision(*(min_version.components + [9999])) if strict else None
    return DistributionLocator.cached(minimum_version=min_version, maximum_version=max_version)
示例#7
0
 def test_wire_compiler_version_robust(self):
     # Here the wire compiler is both indirected, and not 1st in the classpath order.
     guava = self.make_target(
         '3rdparty:guava',
         JarLibrary,
         jars=[JarDependency('com.google.guava', 'guava', '18.0')])
     wire = self.make_target(
         '3rdparty:wire',
         JarLibrary,
         jars=[
             JarDependency('com.squareup.wire', 'wire-compiler',
                           '3.0.0').exclude('com.google.guava', 'guava')
         ])
     alias = self.make_target('a/random/long/address:spec',
                              Target,
                              dependencies=[guava, wire])
     self.set_options(wire_compiler='a/random/long/address:spec')
     task = self.create_task(self.context(target_roots=[alias]))
     self.assertEqual(Revision(3, 0, 0), task.wire_compiler_version)
示例#8
0
  def parse_java_version(cls, version):
    """Parses the java version (given a string or Revision object).

    Handles java version-isms, converting things like '7' -> '1.7' appropriately.

    Truncates input versions down to just the major and minor numbers (eg, 1.6), ignoring extra
    versioning information after the second number.

    :param version: the input version, given as a string or Revision object.
    :return: the parsed and cleaned version, suitable as a javac -source or -target argument.
    :rtype: Revision
    """
    conversion = {str(i): '1.{}'.format(i) for i in cls.SUPPORTED_CONVERSION_VERSIONS}
    if str(version) in conversion:
      return Revision.lenient(conversion[str(version)])

    if not hasattr(version, 'components'):
      version = Revision.lenient(version)
    if len(version.components) <= 2:
      return version
    return Revision(*version.components[:2])
示例#9
0
    def format_args_for_target(self, target):
        """Calculate the arguments to pass to the command line for a single target."""
        sources_by_base = self._calculate_sources([target])
        if self.codegen_strategy.name() == 'isolated':
            sources = OrderedSet(target.sources_relative_to_buildroot())
        else:
            sources = OrderedSet(
                itertools.chain.from_iterable(sources_by_base.values()))
        if not self.validate_sources_present(sources, [target]):
            return None
        relative_sources = OrderedSet()
        for source in sources:
            source_root = SourceRoot.find_by_path(source)
            if not source_root:
                source_root = SourceRoot.find(target)
            relative_source = os.path.relpath(source, source_root)
            relative_sources.add(relative_source)
        check_duplicate_conflicting_protos(self, sources_by_base,
                                           relative_sources, self.context.log)

        args = ['--java_out={0}'.format(self.codegen_workdir(target))]

        # Add all params in payload to args

        if target.payload.get_field_value('no_options'):
            args.append('--no_options')

        def append_service_opts(service_type_name, service_type_value,
                                options_values):
            """Append --service_writer or --service_factory args as appropriate.

      :param str service_type_name: the target parameter/option prefix
      :param str service_type_value: class passed to the --service_x= option
      :param list options_values: string options to be passed with --service_x_opt
      """
            if service_type_value:
                args.append('--{0}={1}'.format(service_type_name,
                                               service_type_value))
                if options_values:
                    for opt in options_values:
                        args.append('--{0}_opt'.format(service_type_name))
                        args.append(opt)

        # A check is done in the java_wire_library target  to make sure only one of --service_writer or
        # --service_factory is specified.
        if self.wire_compiler_version < Revision(2, 0):
            if target.payload.service_factory:
                raise TaskError(
                    '{spec} used service_factory, which is not available before Wire 2.0. You '
                    'should use service_writer instead.'.format(
                        spec=target.address.spec))
            append_service_opts('service_writer',
                                target.payload.service_writer,
                                target.payload.service_writer_options)
        else:
            if target.payload.service_writer:
                raise TaskError(
                    '{spec} used service_writer, which is not available after Wire 2.0. You '
                    'should use service_factory instead.'.format(
                        spec=target.address.spec))
            append_service_opts('service_factory',
                                target.payload.service_factory,
                                target.payload.service_factory_options)

        registry_class = target.payload.registry_class
        if registry_class:
            args.append('--registry_class={0}'.format(registry_class))

        if target.payload.roots:
            args.append('--roots={0}'.format(','.join(target.payload.roots)))

        if target.payload.enum_options:
            args.append('--enum_options={0}'.format(','.join(
                target.payload.enum_options)))

        if self.wire_compiler_version < Revision(2, 0):
            args.append('--proto_path={0}'.format(
                os.path.join(get_buildroot(), SourceRoot.find(target))))
        else:
            # NB(gmalmquist): Support for multiple --proto_paths was introduced in Wire 2.0.
            for path in self._calculate_proto_paths(target):
                args.append('--proto_path={0}'.format(path))

        args.extend(relative_sources)
        return args
示例#10
0
    def findbugs(self, target):
        runtime_classpaths = self.context.products.get_data(
            "runtime_classpath")
        runtime_classpath = runtime_classpaths.get_for_targets(
            target.closure(bfs=True))
        aux_classpath = OrderedSet(jar for conf, jar in runtime_classpath
                                   if conf == "default")

        target_jars = OrderedSet(
            jar for conf, jar in runtime_classpaths.get_for_target(target)
            if conf == "default")

        bug_counts = {"error": 0, "high": 0, "normal": 0, "low": 0}

        if not target_jars:
            self.context.log.info("  No jars to be analyzed")
            return bug_counts

        output_dir = os.path.join(self.workdir, target.id)
        safe_mkdir(output_dir)
        output_file = os.path.join(output_dir, "findbugsXml.xml")

        aux_classpath_file = os.path.join(
            self.workdir, "{}.classpath".format(os.path.basename(output_dir)))
        with open(aux_classpath_file, "w") as f:
            f.write("\n".join(aux_classpath - target_jars))

        args = [
            "-auxclasspathFromFile",
            aux_classpath_file,
            "-projectName",
            target.address.spec,
            "-xml:withMessages",
            "-effort:{}".format(self.get_options().effort),
            "-{}".format(self.get_options().threshold),
            "-nested:{}".format(
                "true" if self.get_options().nested else "false"),
            "-output",
            output_file,
            "-noClassOk",
        ]

        if self.get_options().exclude_filter_file:
            args.extend([
                "-exclude",
                os.path.join(get_buildroot(),
                             self.get_options().exclude_filter_file)
            ])

        if self.get_options().include_filter_file:
            args.extend([
                "-include",
                os.path.join(get_buildroot(),
                             self.get_options().include_filter_file)
            ])

        if self.get_options().max_rank:
            args.extend(["-maxRank", str(self.get_options().max_rank)])

        if self.get_options().relaxed:
            args.extend(["-relaxed"])

        if self.debug:
            args.extend(["-progress"])

        args.extend(target_jars)

        # Try to run spotbugs with the same java version as the target
        # The minimum JDK for spotbugs is JDK 1.8
        min_jdk_version = max(target.platform.target_level,
                              Revision.lenient("1.8"))
        if min_jdk_version.components[0] == 1:
            max_jdk_version = Revision(min_jdk_version.components[0],
                                       min_jdk_version.components[1], "9999")
        else:
            max_jdk_version = Revision(min_jdk_version.components[0], "9999")

        self.set_distribution(minimum_version=min_jdk_version,
                              maximum_version=max_jdk_version,
                              jdk=True)

        result = self.runjava(
            classpath=self.tool_classpath("findbugs"),
            main=self._FINDBUGS_MAIN,
            jvm_options=self.get_options().jvm_options,
            args=args,
            workunit_name="findbugs",
            workunit_labels=[WorkUnitLabel.LINT],
        )
        if result != 0:
            raise TaskError(
                "java {main} ... exited non-zero ({result})".format(
                    main=self._FINDBUGS_MAIN, result=result))

        xml = XmlParser.from_file(output_file)
        for error in xml.parsed.getElementsByTagName("Error"):
            self.context.log.warn(
                "Error: {msg}".format(msg=error.getElementsByTagName(
                    "ErrorMessage")[0].firstChild.data))
            bug_counts["error"] += 1

        for bug_instance in xml.parsed.getElementsByTagName("BugInstance"):
            bug_rank = bug_instance.getAttribute("rank")
            if int(bug_rank) <= self._HIGH_PRIORITY_LOWEST_RANK:
                priority = "high"
            elif int(bug_rank) <= self._NORMAL_PRIORITY_LOWEST_RANK:
                priority = "normal"
            else:
                priority = "low"
            bug_counts[priority] += 1

            source_line = bug_instance.getElementsByTagName(
                "Class")[0].getElementsByTagName("SourceLine")[0]
            self.context.log.warn(
                "Bug[{priority}]: {type} {desc} {line}".format(
                    priority=priority,
                    type=bug_instance.getAttribute("type"),
                    desc=bug_instance.getElementsByTagName(
                        "LongMessage")[0].firstChild.data,
                    line=source_line.getElementsByTagName("Message")
                    [0].firstChild.data,
                ))

        return bug_counts
示例#11
0
    def findbugs(self, target):
        runtime_classpaths = self.context.products.get_data(
            'runtime_classpath')
        runtime_classpath = runtime_classpaths.get_for_targets(
            target.closure(bfs=True))
        aux_classpath = OrderedSet(jar for conf, jar in runtime_classpath
                                   if conf == 'default')

        target_jars = OrderedSet(
            jar for conf, jar in runtime_classpaths.get_for_target(target)
            if conf == 'default')

        bug_counts = {'error': 0, 'high': 0, 'normal': 0, 'low': 0}

        if not target_jars:
            self.context.log.info('  No jars to be analyzed')
            return bug_counts

        output_dir = os.path.join(self.workdir, target.id)
        safe_mkdir(output_dir)
        output_file = os.path.join(output_dir, 'findbugsXml.xml')

        aux_classpath_file = os.path.join(
            self.workdir, '{}.classpath'.format(os.path.basename(output_dir)))
        with open(aux_classpath_file, 'w') as f:
            f.write('\n'.join(aux_classpath - target_jars))

        args = [
            '-auxclasspathFromFile', aux_classpath_file, '-projectName',
            target.address.spec, '-xml:withMessages',
            '-effort:{}'.format(self.get_options().effort),
            '-{}'.format(self.get_options().threshold), '-nested:{}'.format(
                'true' if self.get_options().nested else 'false'), '-output',
            output_file, '-noClassOk'
        ]

        if self.get_options().exclude_filter_file:
            args.extend([
                '-exclude',
                os.path.join(get_buildroot(),
                             self.get_options().exclude_filter_file)
            ])

        if self.get_options().include_filter_file:
            args.extend([
                '-include',
                os.path.join(get_buildroot(),
                             self.get_options().include_filter_file)
            ])

        if self.get_options().max_rank:
            args.extend(['-maxRank', str(self.get_options().max_rank)])

        if self.get_options().relaxed:
            args.extend(['-relaxed'])

        if self.get_options().level == 'debug':
            args.extend(['-progress'])

        args.extend(target_jars)

        # Try to run spotbugs with the same java version as the target
        # The minimum JDK for spotbugs is JDK 1.8
        min_jdk_version = max(target.platform.target_level,
                              Revision.lenient('1.8'))
        if min_jdk_version.components[0] == 1:
            max_jdk_version = Revision(min_jdk_version.components[0],
                                       min_jdk_version.components[1], '9999')
        else:
            max_jdk_version = Revision(min_jdk_version.components[0], '9999')

        self.set_distribution(minimum_version=min_jdk_version,
                              maximum_version=max_jdk_version,
                              jdk=True)

        result = self.runjava(classpath=self.tool_classpath('findbugs'),
                              main=self._FINDBUGS_MAIN,
                              jvm_options=self.get_options().jvm_options,
                              args=args,
                              workunit_name='findbugs',
                              workunit_labels=[WorkUnitLabel.LINT])
        if result != 0:
            raise TaskError(
                'java {main} ... exited non-zero ({result})'.format(
                    main=self._FINDBUGS_MAIN, result=result))

        xml = XmlParser.from_file(output_file)
        for error in xml.parsed.getElementsByTagName('Error'):
            self.context.log.warn(
                'Error: {msg}'.format(msg=error.getElementsByTagName(
                    'ErrorMessage')[0].firstChild.data))
            bug_counts['error'] += 1

        for bug_instance in xml.parsed.getElementsByTagName('BugInstance'):
            bug_rank = bug_instance.getAttribute('rank')
            if int(bug_rank) <= self._HIGH_PRIORITY_LOWEST_RANK:
                priority = 'high'
            elif int(bug_rank) <= self._NORMAL_PRIORITY_LOWEST_RANK:
                priority = 'normal'
            else:
                priority = 'low'
            bug_counts[priority] += 1

            source_line = bug_instance.getElementsByTagName(
                'Class')[0].getElementsByTagName('SourceLine')[0]
            self.context.log.warn(
                'Bug[{priority}]: {type} {desc} {line}'.format(
                    priority=priority,
                    type=bug_instance.getAttribute('type'),
                    desc=bug_instance.getElementsByTagName(
                        'LongMessage')[0].firstChild.data,
                    line=source_line.getElementsByTagName(
                        'Message')[0].firstChild.data))

        return bug_counts