예제 #1
0
    def check_build_for_current_platform_only(self, targets):
        """
    Performs a check of whether the current target closure has native sources and if so, ensures
    that Pants is only targeting the current platform.

    :param tgts: a list of :class:`Target` objects.
    :return: a boolean value indicating whether the current target closure has native sources.
    :raises: :class:`pants.base.exceptions.IncompatiblePlatformsError`
    """
        if not self._any_targets_have_native_sources(targets):
            return False

        targets_by_platform = pex_build_util.targets_by_platform(
            targets, self._python_setup)
        platforms_with_sources = self._get_targets_by_declared_platform_with_placeholders(
            targets_by_platform)
        platform_names = list(platforms_with_sources.keys())

        if len(platform_names) < 1:
            raise self.PythonNativeCodeError(
                "Error: there should be at least one platform in the target closure, because "
                "we checked that there are native sources.")

        if platform_names == ['current']:
            return True

        raise IncompatiblePlatformsError(
            'The target set contains one or more targets that depend on '
            'native code. Please ensure that the platform arguments in all relevant targets and build '
            'options are compatible with the current platform. Found targets for platforms: {}'
            .format(str(platforms_with_sources)))
예제 #2
0
  def check_build_for_current_platform_only(self, targets):
    """
    Performs a check of whether the current target closure has native sources and if so, ensures
    that Pants is only targeting the current platform.

    :param tgts: a list of :class:`Target` objects.
    :return: a boolean value indicating whether the current target closure has native sources.
    :raises: :class:`pants.base.exceptions.IncompatiblePlatformsError`
    """
    # TODO(#5949): convert this to checking if the closure of python requirements has any
    # platform-specific packages (maybe find the platforms there too?).
    if not self._any_targets_have_native_sources(targets):
      return False

    platforms_with_sources = pex_build_util.targets_by_platform(targets, self._python_setup)
    platform_names = list(platforms_with_sources.keys())

    if not platform_names or platform_names == ['current']:
      return True

    bad_targets = set()
    for platform, targets in platforms_with_sources.items():
      if platform == 'current':
        continue
      bad_targets.update(targets)

    raise IncompatiblePlatformsError(dedent("""\
      Pants doesn't currently support cross-compiling native code.
      The following targets set platforms arguments other than ['current'], which is unsupported for this reason.
      Please either remove the platforms argument from these targets, or set them to exactly ['current'].
      Bad targets:
      {}
      """.format('\n'.join(sorted(target.address.reference() for target in bad_targets)))
    ))
예제 #3
0
  def check_build_for_current_platform_only(self, targets):
    """
    Performs a check of whether the current target closure has native sources and if so, ensures
    that Pants is only targeting the current platform.

    :param tgts: a list of :class:`Target` objects.
    :return: a boolean value indicating whether the current target closure has native sources.
    :raises: :class:`pants.base.exceptions.IncompatiblePlatformsError`
    """
    if not self._any_targets_have_native_sources(targets):
      return False

    targets_by_platform = pex_build_util.targets_by_platform(targets, self._python_setup)
    platforms_with_sources = self._get_targets_by_declared_platform_with_placeholders(targets_by_platform)
    platform_names = list(platforms_with_sources.keys())

    if len(platform_names) < 1:
      raise self.PythonNativeCodeError(
        "Error: there should be at least one platform in the target closure, because "
        "we checked that there are native sources.")

    if platform_names == ['current']:
      return True

    raise IncompatiblePlatformsError(
      'The target set contains one or more targets that depend on '
      'native code. Please ensure that the platform arguments in all relevant targets and build '
      'options are compatible with the current platform. Found targets for platforms: {}'
      .format(str(platforms_with_sources)))
예제 #4
0
  def check_build_for_current_platform_only(self, targets):
    """
    Performs a check of whether the current target closure has native sources and if so, ensures
    that Pants is only targeting the current platform.

    :param tgts: a list of :class:`Target` objects.
    :return: a boolean value indicating whether the current target closure has native sources.
    :raises: :class:`pants.base.exceptions.IncompatiblePlatformsError`
    """
    # TODO(#5949): convert this to checking if the closure of python requirements has any
    # platform-specific packages (maybe find the platforms there too?).
    if not self._any_targets_have_native_sources(targets):
      return False

    platforms_with_sources = pex_build_util.targets_by_platform(targets, self._python_setup)
    platform_names = list(platforms_with_sources.keys())

    if not platform_names or platform_names == ['current']:
      return True

    bad_targets = set()
    for platform, targets in platforms_with_sources.items():
      if platform == 'current':
        continue
      bad_targets.update(targets)

    raise IncompatiblePlatformsError(dedent("""\
      Pants doesn't currently support cross-compiling native code.
      The following targets set platforms arguments other than ['current'], which is unsupported for this reason.
      Please either remove the platforms argument from these targets, or set them to exactly ['current'].
      Bad targets:
      {}
      """.format('\n'.join(sorted(target.address.reference() for target in bad_targets)))
    ))
예제 #5
0
    def resolve_requirements(self, interpreter, req_libs):
        """Requirements resolution for PEX files.

    :param interpreter: Resolve against this :class:`PythonInterpreter`.
    :param req_libs: A list of :class:`PythonRequirementLibrary` targets to resolve.
    :returns: a PEX containing target requirements and any specified python dist targets.
    """
        with self.invalidated(req_libs) as invalidation_check:
            # If there are no relevant targets, we still go through the motions of resolving
            # an empty set of requirements, to prevent downstream tasks from having to check
            # for this special case.
            if invalidation_check.all_vts:
                target_set_id = VersionedTargetSet.from_versioned_targets(
                    invalidation_check.all_vts).cache_key.hash
            else:
                target_set_id = 'no_targets'

            # We need to ensure that we are resolving for only the current platform if we are
            # including local python dist targets that have native extensions.
            targets_by_platform = pex_build_util.targets_by_platform(
                self.context.targets(), self._python_setup)
            if self._python_native_code_settings.check_build_for_current_platform_only(
                    targets_by_platform):
                platforms = ['current']
            else:
                platforms = list(sorted(targets_by_platform.keys()))

            path = os.path.realpath(
                os.path.join(self.workdir, str(interpreter.identity),
                             target_set_id))
            # Note that we check for the existence of the directory, instead of for invalid_vts,
            # to cover the empty case.
            if not os.path.isdir(path):
                with safe_concurrent_creation(path) as safe_path:
                    pex_builder = PexBuilderWrapper.Factory.create(
                        builder=PEXBuilder(path=safe_path,
                                           interpreter=interpreter,
                                           copy=True),
                        log=self.context.log)
                    pex_builder.add_requirement_libs_from(req_libs,
                                                          platforms=platforms)
                    pex_builder.freeze()
        return PEX(path, interpreter=interpreter)
  def resolve_requirements(self, interpreter, req_libs):
    """Requirements resolution for PEX files.

    :param interpreter: Resolve against this :class:`PythonInterpreter`.
    :param req_libs: A list of :class:`PythonRequirementLibrary` targets to resolve.
    :returns: a PEX containing target requirements and any specified python dist targets.
    """
    with self.invalidated(req_libs) as invalidation_check:
      # If there are no relevant targets, we still go through the motions of resolving
      # an empty set of requirements, to prevent downstream tasks from having to check
      # for this special case.
      if invalidation_check.all_vts:
        target_set_id = VersionedTargetSet.from_versioned_targets(
            invalidation_check.all_vts).cache_key.hash
      else:
        target_set_id = 'no_targets'

      # We need to ensure that we are resolving for only the current platform if we are
      # including local python dist targets that have native extensions.
      targets_by_platform = pex_build_util.targets_by_platform(self.context.targets(), self._python_setup)
      if self._python_native_code_settings.check_build_for_current_platform_only(targets_by_platform):
        platforms = ['current']
      else:
        platforms = list(sorted(targets_by_platform.keys()))

      path = os.path.realpath(os.path.join(self.workdir, str(interpreter.identity), target_set_id))
      # Note that we check for the existence of the directory, instead of for invalid_vts,
      # to cover the empty case.
      if not os.path.isdir(path):
        with safe_concurrent_creation(path) as safe_path:
          pex_builder = PexBuilderWrapper.Factory.create(
            builder=PEXBuilder(path=safe_path, interpreter=interpreter, copy=True),
            log=self.context.log)
          pex_builder.add_requirement_libs_from(req_libs, platforms=platforms)
          pex_builder.freeze()
    return PEX(path, interpreter=interpreter)