summaryrefslogtreecommitdiff
path: root/src/tox/tox_env/info.py
blob: 1371a7a28daf221d1c4ccafdae673399778ab222 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
"""
Declare and handle the tox env info file (a file at the root of every tox environment that contains information about
the status of the tox environment - python version of the environment, installed packages, etc.).
"""
from __future__ import annotations

import json
from contextlib import contextmanager
from pathlib import Path
from typing import Any, Iterator


class Info:
    """Stores metadata about the tox environment."""

    def __init__(self, path: Path) -> None:
        self._path = path / ".tox-info.json"
        try:
            value = json.loads(self._path.read_text())
        except (ValueError, OSError):
            value = {}
        self._content = value

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}(path={self._path})"

    @contextmanager
    def compare(
        self,
        value: Any,
        section: str,
        sub_section: str | None = None,
    ) -> Iterator[tuple[bool, Any | None]]:
        """
        Compare new information with the existing one and update if differs.

        :param value: the value stored
        :param section: the primary key of the information
        :param sub_section: the secondary key of the information
        :return: a tuple where the first value is if it differs and the second is the old value
        """
        old = self._content.get(section)
        if sub_section is not None and old is not None:
            old = old.get(sub_section)

        if old == value:
            yield True, old
        else:
            yield False, old
            # if no exception thrown update
            if sub_section is None:
                self._content[section] = value
            else:
                if self._content.get(section) is None:
                    self._content[section] = {sub_section: value}
                else:
                    self._content[section][sub_section] = value
            self._write()

    def reset(self) -> None:
        self._content = {}

    def _write(self) -> None:
        self._path.parent.mkdir(parents=True, exist_ok=True)
        self._path.write_text(json.dumps(self._content, indent=2))


__all__ = ("Info",)