aboutsummaryrefslogtreecommitdiff
blob: 4dfa54faa40637b45890f0a98e35863fcdefcbcb (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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
from collections import defaultdict
from datetime import datetime
from itertools import chain

from snakeoil.klass import jit_attr
from snakeoil.strings import pluralism as _pl

from .. import base, git, results, sources
from . import GentooRepoCheck

day = 24*3600


class StableRequest(results.VersionResult, results.Info):
    """Unstable package added over thirty days ago that could be stabilized."""

    def __init__(self, slot, keywords, age, **kwargs):
        super().__init__(**kwargs)
        self.slot = slot
        self.keywords = tuple(keywords)
        self.age = age

    @property
    def desc(self):
        return (
            f"slot({self.slot}) no change in {self.age} days for unstable "
            "keyword%s: [ %s ]" % (_pl(self.keywords), ', '.join(self.keywords))
        )


class StableRequestCheck(GentooRepoCheck):
    """Ebuilds that have sat unstable with no changes for over a month.

    By default, only triggered for arches with stable profiles. To check
    additional arches outside the stable set specify them manually using the
    -a/--arches option.

    Note that packages with no stable keywords won't trigger this at all.
    Instead they'll be caught by the UnstableOnly check.
    """
    scope = base.package_scope
    _source = (sources.PackageRepoSource, (), (('source', sources.UnmaskedRepoSource),))
    required_addons = (git.GitAddon,)
    known_results = frozenset([StableRequest])

    def __init__(self, *args, git_addon=None):
        super().__init__(*args)
        self.today = datetime.today()
        self._git_addon = git_addon

    @jit_attr
    def modified_repo(self):
        return self._git_addon.cached_repo(git.GitModifiedRepo)

    def feed(self, pkgset):
        # disable check when git repo parsing is disabled
        if self.modified_repo is None:
            return

        pkg_slotted = defaultdict(list)
        for pkg in pkgset:
            pkg_slotted[pkg.slot].append(pkg)

        pkg_keywords = set(chain.from_iterable(pkg.keywords for pkg in pkgset))
        stable_pkg_keywords = {x for x in pkg_keywords if x[0] not in {'-', '~'}}
        if stable_pkg_keywords:
            for slot, pkgs in sorted(pkg_slotted.items()):
                slot_keywords = set(chain.from_iterable(pkg.keywords for pkg in pkgs))
                stable_slot_keywords = slot_keywords.intersection(stable_pkg_keywords)
                for pkg in reversed(pkgs):
                    # skip unkeyworded/live pkgs
                    if not pkg.keywords:
                        continue

                    # stop scanning pkgs if one newer than 30 days has stable keywords
                    # from the stable arches set
                    if set(pkg.keywords).intersection(stable_pkg_keywords):
                        break

                    try:
                        match = self.modified_repo.match(pkg.versioned_atom)[0]
                    except IndexError:
                        # probably an uncommitted, local ebuild... skipping
                        continue
                    added = datetime.strptime(match.date, '%Y-%m-%d')
                    days_old = (self.today - added).days
                    if days_old >= 30:
                        pkg_stable_keywords = {x.lstrip('~') for x in pkg.keywords}
                        if stable_slot_keywords:
                            keywords = stable_slot_keywords.intersection(pkg_stable_keywords)
                        else:
                            keywords = stable_pkg_keywords.intersection(pkg_stable_keywords)
                        keywords = sorted('~' + x for x in keywords)
                        yield StableRequest(slot, keywords, days_old, pkg=pkg)
                        break