summaryrefslogtreecommitdiff
path: root/examples/allyesconfig.py
blob: 1c85d607f3ecb1e77704aeccedd25aed998f49bc (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
# Works like 'make allyesconfig'. Verified by the test suite to generate
# identical output to 'make allyesconfig' for all ARCHES.
#
# This could be implemented as a straightforward tree walk just like
# allnoconfig.py (or even simpler like allnoconfig_simpler.py), but do it a bit
# differently (roundabout) just to demonstrate some other possibilities.
#
# allyesconfig is a bit more involved than allnoconfig as we need to handle
# choices in two different modes:
#
#   y: One symbol is y, the rest are n
#   m: Any number of symbols are m, the rest are n
#
# Only tristate choices can be in m mode. No m mode choices seem to appear for
# allyesconfig on the kernel Kconfigs as of 4.14, but we still handle it.
#
# Usage:
#
#   $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/allyesconfig.py

from kconfiglib import Kconfig, Choice, STR_TO_TRI
import sys

conf = Kconfig(sys.argv[1])

# Collect all the choices in the configuration. Demonstrates how the menu node
# tree can be walked iteratively by using the parent pointers.

choices = []
node = conf.top_node

while 1:
    if isinstance(node.item, Choice):
        choices.append(node.item)

    # Iterative tree walking by using parent pointers.
    #
    # Recursing on next pointers can blow the Python stack. Recursing on child
    # pointers is safe (as is done in the other examples). This gives a
    # template for how you can avoid recursing on both. The same logic is found
    # in the C implementation.

    if node.list is not None:
        # Jump to child node if available
        node = node.list

    elif node.next is not None:
        # Otherwise, jump to next node if available
        node = node.next

    else:
        # Otherwise, look for parents with next nodes to jump to
        while node.parent is not None:
            node = node.parent
            if node.next is not None:
                node = node.next
                break
        else:
            # No parents with next nodes, all nodes visited
            break

# Collect all symbols that are not in choices
non_choice_syms = [sym for sym in conf.defined_syms if sym.choice is None]

while 1:
    no_changes = True

    # Handle symbols outside of choices

    for sym in non_choice_syms:
        # See allnoconfig example. [-1] gives the last (highest) assignable
        # value.
        if sym.assignable and sym.tri_value < sym.assignable[-1]:
            sym.set_value(sym.assignable[-1])
            no_changes = False

    # Handle choices

    for choice in choices:
        # Handle a choice whose visibility allows it to be in y mode

        if choice.visibility == 2:
            # Enable the choice in case it is optional
            choice.set_value(2)

            selection = choice.default_selection

            # Does the choice have a default selection that we haven't already
            # selected?
            if selection is not None and \
               selection is not choice.user_selection:

                # Yup, select it
                selection.set_value(2)
                no_changes = False

        # Handle a choice whose visibility only allows it to be in m mode. This
        # might happen if a choice depends on a symbol that can only be m, for
        # example.

        elif choice.visibility == 1:
            # Enable the choice in case it is optional
            choice.set_value(1)

            for sym in choice.symbols:

                # Does the choice have a symbol that can be m that we haven't
                # already set to m?
                if sym.user_value != 1 and 1 in sym.assignable:

                    # Yup, set it
                    sym.set_value(1)
                    no_changes = False

    if no_changes:
        break

conf.write_config(".config")