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 / option / option_tracker.py
Size: Mime:
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from collections import defaultdict
from dataclasses import dataclass
from typing import DefaultDict, Iterator, List, Optional

from pants.option.ranked_value import RankedValue


# TODO: Get rid of this? The parser should be able to lazily track.
class OptionTracker:
    """Records a history of what options are set and where they came from."""

    @dataclass(frozen=True)
    class OptionHistoryRecord:
        value: str
        rank: int
        deprecation_version: Optional[str]
        details: Optional[str]

    class OptionHistory:
        """Tracks the history of an individual option."""

        def __init__(self) -> None:
            self.values: List["OptionTracker.OptionHistoryRecord"] = []

        def record_value(
            self,
            value: str,
            rank: int,
            deprecation_version: Optional[str],
            details: Optional[str] = None,
        ) -> None:
            """Record that the option was set to the given value at the given rank.

            :param value: the value the option was set to.
            :param rank: the rank of the option when it was set to this value.
            :param deprecation_version: Deprecation version for this option.
            :param details: optional elaboration of where the option came from (eg, a particular
              config file).
            """
            deprecation_version_to_write = deprecation_version

            if self.latest is not None:
                if self.latest.rank > rank:
                    return
                if self.latest.value == value:
                    return  # No change.
                if self.latest.deprecation_version:
                    # Higher RankedValue may not contain deprecation version, so this make sure
                    # deprecation_version propagate to later and higher ranked value since it is immutable
                    deprecation_version_to_write = (
                        self.latest.deprecation_version or deprecation_version
                    )

            self.values.append(
                OptionTracker.OptionHistoryRecord(
                    value, rank, deprecation_version_to_write, details
                )
            )

        @property
        def was_overridden(self) -> bool:
            """A value was overridden if it has rank greater than 'HARDCODED'."""
            if self.latest is None or len(self.values) < 2:
                return False
            return (
                self.latest.rank > RankedValue.HARDCODED and self.values[-2].rank > RankedValue.NONE
            )

        @property
        def latest(self) -> Optional["OptionTracker.OptionHistoryRecord"]:
            """The most recent value this option was set to, or None if it was never set."""
            return self.values[-1] if self.values else None

        def __iter__(self) -> Iterator["OptionTracker.OptionHistoryRecord"]:
            for record in self.values:
                yield record

        def __len__(self) -> int:
            return len(self.values)

    def __init__(self) -> None:
        self.option_history_by_scope: DefaultDict = defaultdict(dict)

    def record_option(
        self,
        scope: str,
        option: str,
        value: str,
        rank: int,
        deprecation_version: Optional[str] = None,
        details: Optional[str] = None,
    ) -> None:
        """Records that the given option was set to the given value.

        :param scope: scope of the option.
        :param option: name of the option.
        :param value: value the option was set to.
        :param rank: the rank of the option (Eg, RankedValue.HARDCODED), to keep track of where the
          option came from.
        :param deprecation_version: Deprecation version for this option.
        :param details: optional additional details about how the option was set (eg, the name
               of a particular config file, if the rank is RankedValue.CONFIG).
        """
        scoped_options = self.option_history_by_scope[scope]
        if option not in scoped_options:
            scoped_options[option] = self.OptionHistory()
        scoped_options[option].record_value(value, rank, deprecation_version, details)