Atlas - menuconfig_example.py
Home / ext / kconfiglib / examples Lines: 3 | Size: 12044 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1#!/usr/bin/env python3 2 3# Implements a simple configuration interface on top of Kconfiglib to 4# demonstrate concepts for building a menuconfig-like. Emulates how the 5# standard menuconfig prints menu entries. 6# 7# Always displays the entire Kconfig tree to keep things as simple as possible 8# (all symbols, choices, menus, and comments). 9# 10# Usage: 11# 12# $ python(3) Kconfiglib/examples/menuconfig.py <Kconfig file> 13# 14# A sample Kconfig is available in Kconfiglib/examples/Kmenuconfig. 15# 16# Here's a notation guide. The notation matches the one used by menuconfig 17# (scripts/kconfig/mconf): 18# 19# [ ] prompt - Bool 20# < > prompt - Tristate 21# {M} prompt - Tristate selected to m. Can only be set to m or y. 22# -*- prompt - Bool/tristate selected to y, pinning it 23# -M- prompt - Tristate selected to m that also has m visibility, 24# pinning it to m 25# (foo) prompt - String/int/hex symbol with value "foo" 26# --> prompt - The selected symbol in a choice in y mode. This 27# syntax is unique to this example. 28# 29# When modules are disabled, the .type attribute of TRISTATE symbols and 30# choices automatically changes to BOOL. This trick is used by the C 31# implementation as well, and gives the expected behavior without having to do 32# anything extra here. The original type is available in .orig_type if needed. 33# 34# The Kconfiglib/examples/Kmenuconfig example uses named choices to be able to 35# refer to choices by name. Named choices are supported in the C tools too, but 36# I don't think I've ever seen them used in the wild. 37# 38# Sample session: 39# 40# $ python Kconfiglib/examples/menuconfig.py Kconfiglib/examples/Kmenuconfig 41# 42# ======== Example Kconfig configuration ======== 43# 44# [*] Enable loadable module support (MODULES) 45# Bool and tristate symbols 46# [*] Bool symbol (BOOL) 47# [ ] Dependent bool symbol (BOOL_DEP) 48# < > Dependent tristate symbol (TRI_DEP) 49# [ ] First prompt (TWO_MENU_NODES) 50# < > Tristate symbol (TRI) 51# [ ] Second prompt (TWO_MENU_NODES) 52# *** These are selected by TRI_DEP *** 53# < > Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP) 54# < > Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP) 55# String, int, and hex symbols 56# (foo) String symbol (STRING) 57# (747) Int symbol (INT) 58# (0xABC) Hex symbol (HEX) 59# Various choices 60# -*- Bool choice (BOOL_CHOICE) 61# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1) 62# Bool choice sym 2 (BOOL_CHOICE_SYM_2) 63# {M} Tristate choice (TRI_CHOICE) 64# < > Tristate choice sym 1 (TRI_CHOICE_SYM_1) 65# < > Tristate choice sym 2 (TRI_CHOICE_SYM_2) 66# [ ] Optional bool choice (OPT_BOOL_CHOICE) 67# 68# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): BOOL 69# Value for BOOL (available: n, y): n 70# 71# ======== Example Kconfig configuration ======== 72# 73# [*] Enable loadable module support (MODULES) 74# Bool and tristate symbols 75# [ ] Bool symbol (BOOL) 76# < > Tristate symbol (TRI) 77# [ ] Second prompt (TWO_MENU_NODES) 78# *** These are selected by TRI_DEP *** 79# < > Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP) 80# < > Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP) 81# String, int, and hex symbols 82# (foo) String symbol (STRING) 83# (747) Int symbol (INT) 84# (0xABC) Hex symbol (HEX) 85# Various choices 86# -*- Bool choice (BOOL_CHOICE) 87# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1) 88# Bool choice sym 2 (BOOL_CHOICE_SYM_2) 89# {M} Tristate choice (TRI_CHOICE) 90# < > Tristate choice sym 1 (TRI_CHOICE_SYM_1) 91# < > Tristate choice sym 2 (TRI_CHOICE_SYM_2) 92# [ ] Optional bool choice (OPT_BOOL_CHOICE) 93# 94# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): MODULES 95# Value for MODULES (available: n, y): n 96# 97# ======== Example Kconfig configuration ======== 98# 99# [ ] Enable loadable module support (MODULES) 100# Bool and tristate symbols 101# [ ] Bool symbol (BOOL) 102# [ ] Tristate symbol (TRI) 103# [ ] Second prompt (TWO_MENU_NODES) 104# *** These are selected by TRI_DEP *** 105# [ ] Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP) 106# [ ] Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP) 107# String, int, and hex symbols 108# (foo) String symbol (STRING) 109# (747) Int symbol (INT) 110# (0xABC) Hex symbol (HEX) 111# Various choices 112# -*- Bool choice (BOOL_CHOICE) 113# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1) 114# Bool choice sym 2 (BOOL_CHOICE_SYM_2) 115# -*- Tristate choice (TRI_CHOICE) 116# --> Tristate choice sym 1 (TRI_CHOICE_SYM_1) 117# Tristate choice sym 2 (TRI_CHOICE_SYM_2) 118# [ ] Optional bool choice (OPT_BOOL_CHOICE) 119# 120# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): ^D 121 122from __future__ import print_function 123import readline 124import sys 125 126from kconfiglib import Kconfig, \ 127 Symbol, MENU, COMMENT, \ 128 BOOL, TRISTATE, STRING, INT, HEX, UNKNOWN, \ 129 expr_value, \ 130 TRI_TO_STR 131 132 133# Python 2/3 compatibility hack 134if sys.version_info[0] < 3: 135 input = raw_input 136 137 138def indent_print(s, indent): 139 print(indent*" " + s) 140 141 142def value_str(sc): 143 """ 144 Returns the value part ("[*]", "<M>", "(foo)" etc.) of a menu entry. 145 146 sc: Symbol or Choice. 147 """ 148 if sc.type in (STRING, INT, HEX): 149 return "({})".format(sc.str_value) 150 151 # BOOL or TRISTATE 152 153 # The choice mode is an upper bound on the visibility of choice symbols, so 154 # we can check the choice symbols' own visibility to see if the choice is 155 # in y mode 156 if isinstance(sc, Symbol) and sc.choice and sc.visibility == 2: 157 # For choices in y mode, print '-->' next to the selected symbol 158 return "-->" if sc.choice.selection is sc else " " 159 160 tri_val_str = (" ", "M", "*")[sc.tri_value] 161 162 if len(sc.assignable) == 1: 163 # Pinned to a single value 164 return "-{}-".format(tri_val_str) 165 166 if sc.type == BOOL: 167 return "[{}]".format(tri_val_str) 168 169 if sc.type == TRISTATE: 170 if sc.assignable == (1, 2): 171 # m and y available 172 return "{" + tri_val_str + "}" # Gets a bit confusing with .format() 173 return "<{}>".format(tri_val_str) 174 175 176def node_str(node): 177 """ 178 Returns the complete menu entry text for a menu node, or "" for invisible 179 menu nodes. Invisible menu nodes are those that lack a prompt or that do 180 not have a satisfied prompt condition. 181 182 Example return value: "[*] Bool symbol (BOOL)" 183 184 The symbol name is printed in parentheses to the right of the prompt. This 185 is so that symbols can easily be referred to in the configuration 186 interface. 187 """ 188 if not node.prompt: 189 return "" 190 191 # Even for menu nodes for symbols and choices, it's wrong to check 192 # Symbol.visibility / Choice.visibility here. The reason is that a symbol 193 # (and a choice, in theory) can be defined in multiple locations, giving it 194 # multiple menu nodes, which do not necessarily all have the same prompt 195 # visibility. Symbol.visibility / Choice.visibility is calculated as the OR 196 # of the visibility of all the prompts. 197 prompt, prompt_cond = node.prompt 198 if not expr_value(prompt_cond): 199 return "" 200 201 if node.item == MENU: 202 return " " + prompt 203 204 if node.item == COMMENT: 205 return " *** {} ***".format(prompt) 206 207 # Symbol or Choice 208 209 sc = node.item 210 211 if sc.type == UNKNOWN: 212 # Skip symbols defined without a type (these are obscure and generate 213 # a warning) 214 return "" 215 216 # {:3} sets the field width to three. Gives nice alignment for empty string 217 # values. 218 res = "{:3} {}".format(value_str(sc), prompt) 219 220 # Don't print the name for unnamed choices (the normal kind) 221 if sc.name is not None: 222 res += " ({})".format(sc.name) 223 224 return res 225 226 227def print_menuconfig_nodes(node, indent): 228 """ 229 Prints a tree with all the menu entries rooted at 'node'. Child menu 230 entries are indented. 231 """ 232 while node: 233 string = node_str(node) 234 if string: 235 indent_print(string, indent) 236 237 if node.list: 238 print_menuconfig_nodes(node.list, indent + 8) 239 240 node = node.next 241 242 243def print_menuconfig(kconf): 244 """ 245 Prints all menu entries for the configuration. 246 """ 247 # Print the expanded mainmenu text at the top. This is the same as 248 # kconf.top_node.prompt[0], but with variable references expanded. 249 print("\n======== {} ========\n".format(kconf.mainmenu_text)) 250 251 print_menuconfig_nodes(kconf.top_node.list, 0) 252 print("") 253 254 255def get_value_from_user(sc): 256 """ 257 Prompts the user for a value for the symbol or choice 'sc'. For 258 bool/tristate symbols and choices, provides a list of all the assignable 259 values. 260 """ 261 if not sc.visibility: 262 print(sc.name + " is not currently visible") 263 return False 264 265 prompt = "Value for {}".format(sc.name) 266 if sc.type in (BOOL, TRISTATE): 267 prompt += " (available: {})" \ 268 .format(", ".join(TRI_TO_STR[val] for val in sc.assignable)) 269 prompt += ": " 270 271 val = input(prompt) 272 273 # Automatically add a "0x" prefix for hex symbols, like the menuconfig 274 # interface does. This isn't done when loading .config files, hence why 275 # set_value() doesn't do it automatically. 276 if sc.type == HEX and not val.startswith(("0x", "0X")): 277 val = "0x" + val 278 279 # Let Kconfiglib itself print a warning here if the value is invalid. We 280 # could also disable warnings temporarily with 'kconf.warn = False' and 281 # print our own warning. 282 return sc.set_value(val) 283 284 285if __name__ == "__main__": 286 if len(sys.argv) != 2: 287 sys.exit("usage: menuconfig.py <Kconfig file>") 288 289 # Load Kconfig configuration files 290 kconf = Kconfig(sys.argv[1]) 291 292 # Print the initial configuration tree 293 print_menuconfig(kconf) 294 295 while True: 296 try: 297 cmd = input('Enter a symbol/choice name, "load_config", or ' 298 '"write_config" (or press CTRL+D to exit): ').strip() 299 except EOFError: 300 print("") 301 break 302 303 if cmd == "load_config": 304 config_filename = input(".config file to load: ") 305 try: 306 # Returns a message telling which file got loaded 307 print(kconf.load_config(config_filename)) 308 except EnvironmentError as e: 309 print(e, file=sys.stderr) 310 311 print_menuconfig(kconf) 312 continue 313 314 if cmd == "write_config": 315 config_filename = input("To this file: ") 316 try: 317 # Returns a message telling which file got saved 318 print(kconf.write_config(config_filename)) 319 except EnvironmentError as e: 320 print(e, file=sys.stderr) 321 322 continue 323 324 # Assume 'cmd' is the name of a symbol or choice if it isn't one of the 325 # commands above, prompt the user for a value for it, and print the new 326 # configuration tree 327 328 if cmd in kconf.syms: 329 if get_value_from_user(kconf.syms[cmd]): 330 print_menuconfig(kconf) 331 332 continue 333 334 if cmd in kconf.named_choices: 335 if get_value_from_user(kconf.named_choices[cmd]): 336 print_menuconfig(kconf) 337 338 continue 339 340 print("No symbol/choice named '{}' in the configuration".format(cmd), 341 file=sys.stderr) 342[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.