aboutsummaryrefslogtreecommitdiff
blob: 5ca892eb9abb74d8a291908cd0e7df07683fee7c (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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# 	vim:fileencoding=utf-8
# Copyright 2001-2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

__all__ = ["keywords_header"]

from portage import settings as ports
from gentoolkit.eshowkw.display_pretty import colorize_string
from gentoolkit.eshowkw.display_pretty import align_string
from gentoolkit.profile import load_profile_data


def gen_arch_list(status):
    _arch_status = load_profile_data()
    if status == "stable":
        return [arch for arch in _arch_status if _arch_status[arch][0] == "stable"]
    elif status == "dev":
        return [arch for arch in _arch_status if _arch_status[arch][0] == "dev"]
    elif status == "exp":
        return [arch for arch in _arch_status if _arch_status[arch][0] == "exp"]
    elif status == "arch":
        return [arch for arch in _arch_status if _arch_status[arch][1] == "arch"]
    elif status == "~arch":
        return [arch for arch in _arch_status if _arch_status[arch][1] == "~arch"]
    else:
        raise TypeError


class keywords_header:
    __IMPARCHS = gen_arch_list("stable")
    __DEV_ARCHS = gen_arch_list("dev")
    __EXP_ARCHS = gen_arch_list("exp")
    __TESTING_KW_ARCHS = gen_arch_list("~arch")
    __ADDITIONAL_FIELDS = ["eapi", "unused", "slot"]
    __EXTRA_FIELDS = ["repo"]

    @staticmethod
    def __readKeywords():
        """Read all available keywords from portage."""
        return [x for x in ports.archlist() if not x.startswith("~")]

    @staticmethod
    def __isPrefix(k):
        spl = k.split("-")
        # *-fbsd are not prefix
        return len(spl) > 1 and spl[1] != "fbsd"

    def __sortKeywords(self, keywords, prefix=False, required_keywords=[]):
        """Sort keywords: order by status (IMP, then DEV, then EXP, then
        prefix), then by name."""

        # user specified only some keywords to display
        if len(required_keywords) != 0:
            tmpkeywords = [k for k in keywords if k in required_keywords]
            # idiots might specify non-existant archs
            if len(tmpkeywords) != 0:
                keywords = tmpkeywords

        normal = [k for k in keywords if not self.__isPrefix(k)]
        if prefix:
            longer = [k for k in keywords if self.__isPrefix(k)]
            normal.extend(longer)

        lists = (self.__IMPARCHS + self.__DEV_ARCHS), self.__EXP_ARCHS
        levels = {}
        for kw in normal:
            for level, ls in enumerate(lists):
                if kw in ls:
                    levels[kw] = level
                    break

        # sort by, in order (to match Bugzilla):
        # 1. non-prefix, then prefix (stable output between -P and not)
        # 2. arch, then ~arch
        # 3. profile stability
        # 4. short keywords, then long (prefix, fbsd)
        # 5. keyword name in reverse component order
        normal.sort(
            key=lambda kw: (
                self.__isPrefix(kw),
                kw in self.__TESTING_KW_ARCHS,
                levels.get(kw, 99),
                kw.count("-"),
                list(reversed(kw.split("-"))),
            )
        )
        return normal

    def __readAdditionalFields(self):
        """Prepare list of aditional fileds displayed by eshowkw (2nd part)"""
        return self.__ADDITIONAL_FIELDS

    def __readExtraFields(self):
        """Prepare list of extra fileds displayed by eshowkw (3rd part)"""
        return self.__EXTRA_FIELDS

    def __formatKeywords(self, keywords, align, length):
        """Append colors and align keywords properly"""
        tmp = []
        for keyword in keywords:
            tmp2 = keyword
            keyword = align_string(keyword, align, length)
            # % are used as separators for further split so we wont loose spaces and coloring
            keyword = "%".join(list(keyword))
            if tmp2 in self.__IMPARCHS:
                tmp.append(colorize_string("darkyellow", keyword))
            elif tmp2 in self.__EXP_ARCHS:
                tmp.append(colorize_string("darkgray", keyword))
            else:
                tmp.append(keyword)
        return tmp

    @staticmethod
    def __formatAdditional(additional, align, length):
        """Align additional items properly"""
        # % are used as separators for further split so we wont loose spaces and coloring
        return ["%".join(align_string(x, align, length)) for x in additional]

    def __prepareExtra(self, extra, align, length):
        content = []
        content.append("".ljust(length, "-"))
        content.extend(self.__formatAdditional(extra, align, length))
        return content

    def __prepareResult(self, keywords, additional, align, length):
        """Parse keywords and additional fields into one list with proper separators"""
        content = []
        content.append("".ljust(length, "-"))
        content.extend(self.__formatKeywords(keywords, align, length))
        content.append("".ljust(length, "-"))
        content.extend(self.__formatAdditional(additional, align, length))
        return content

    def __init__(self, prefix=False, required_keywords=[], keywords_align="bottom"):
        """Initialize keywords header."""
        additional = self.__readAdditionalFields()
        extra = self.__readExtraFields()
        self.keywords = self.__sortKeywords(
            self.__readKeywords(), prefix, required_keywords
        )
        self.length = max(
            max([len(x) for x in self.keywords]),
            max([len(x) for x in additional]),
            max([len(x) for x in extra]),
        )
        # len(max([max(self.keywords, key=len), max(additional, key=len)], key=len))
        self.keywords_count = len(self.keywords)
        self.additional_count = len(additional)
        self.extra_count = len(extra)
        self.content = self.__prepareResult(
            self.keywords, additional, keywords_align, self.length
        )
        self.extra = self.__prepareExtra(extra, keywords_align, self.length)