Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
pantsbuild.pants / build_graph / target_scopes.py
Size: Mime:
# Copyright 2016 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from pants.build_graph.intermediate_target_factory import IntermediateTargetFactoryBase


class Scope(frozenset):
    """Represents a set of dependency scope names.

    It is the responsibility of individual tasks to read and respect these scopes by using functions
    such as target.closure() and BuildGraph.closure().
    """

    @classmethod
    def _parse(cls, scope):
        """Parses the input scope into a normalized set of strings.

        :param scope: A string or tuple containing zero or more scope names.
        :return: A set of scope name strings, or a tuple with the default scope name.
        :rtype: set
        """
        if not scope:
            return ("default",)
        if isinstance(scope, str):
            scope = scope.split(" ")
        scope = {str(s).lower() for s in scope if s}
        return scope or ("default",)

    def __new__(cls, scope):
        return super().__new__(cls, cls._parse(scope))

    def in_scope(self, exclude_scopes=None, include_scopes=None):
        """Whether this scope should be included by the given inclusion and exclusion rules.

        :param Scope exclude_scopes: An optional Scope containing scope names to exclude. None (the
          default value) indicates that no filtering should be done based on exclude_scopes.
        :param Scope include_scopes: An optional Scope containing scope names to include. None (the
          default value) indicates that no filtering should be done based on include_scopes.
        :return: True if none of the input scopes are in `exclude_scopes`, and either (a) no include
          scopes are provided, or (b) at least one input scope is included in the `include_scopes` list.
        :rtype: bool
        """
        if include_scopes is not None and not isinstance(include_scopes, Scope):
            raise ValueError(
                "include_scopes must be a Scope instance but was {}.".format(type(include_scopes))
            )
        if exclude_scopes is not None and not isinstance(exclude_scopes, Scope):
            raise ValueError(
                "exclude_scopes must be a Scope instance but was {}.".format(type(exclude_scopes))
            )
        if exclude_scopes and any(s in exclude_scopes for s in self):
            return False
        if include_scopes and not any(s in include_scopes for s in self):
            return False
        return True

    def __add__(self, other):
        return Scope(super().__or__(other))

    def __or__(self, other):
        return Scope(super().__or__(other))

    def __str__(self):
        return " ".join(sorted(self))


class Scopes:
    """Default scope constants."""

    DEFAULT = Scope("DEFAULT")
    # The `FORCED` scope is equivalent to DEFAULT, but additionally declares that a dep
    # might not be detected as used at compile time, and should thus always be considered
    # to have been used at compile time.
    FORCED = Scope("FORCED")
    COMPILE = Scope("COMPILE")
    RUNTIME = Scope("RUNTIME")
    TEST = Scope("TEST")

    DEFAULT_OR_FORCED = DEFAULT | FORCED

    JVM_COMPILE_SCOPES = DEFAULT_OR_FORCED | COMPILE
    JVM_RUNTIME_SCOPES = DEFAULT_OR_FORCED | RUNTIME
    JVM_TEST_SCOPES = DEFAULT_OR_FORCED | RUNTIME | TEST


class ScopedDependencyFactory(IntermediateTargetFactoryBase):
    """Creates a dependency with the given scope.

    For example, this makes the syntax:

    ```
        jar_library(name='gson',
          jars=[...],
        )

        target(name='foo',
          dependencies=[
            scoped(':gson', scope='runtime'),
          ],
        )
    ```

    Equivalent to:

    ```
        jar_library(name='gson',
          jars=[...],
        )

        target(name='gson-runtime',
          dependencies=[
            ':gson',
          ],
          scope='runtime',
        )

        target(name='foo',
          dependencies=[
            ':gson-runtime',
          ],
        )
    ```

    The syntax for this feature is experimental and may change in the future.
    """

    def __init__(self, parse_context):
        super().__init__(parse_context)
        self._scope = None

    @property
    def extra_target_arguments(self):
        """Extra keyword arguments to pass to the target constructor."""
        return dict(scope=self._scope) if self._scope else dict()

    def __call__(self, address, scope=None):
        """
        :param string address: A target address.
        :param string scope: The scope of this dependency.
        :returns: The address of a synthetic intermediary target.
        """
        scope = Scope(scope)
        self._scope = str(scope)
        return self._create_intermediate_target(address, self._scope)