Atlas - oldconfig.py

Home / ext / kconfiglib Lines: 3 | Size: 8080 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1#!/usr/bin/env python3 2 3# Copyright (c) 2018-2019, Ulf Magnusson 4# SPDX-License-Identifier: ISC 5 6""" 7Implements oldconfig functionality. 8 9 1. Loads existing .config 10 2. Prompts for the value of all modifiable symbols/choices that 11 aren't already set in the .config 12 3. Writes an updated .config 13 14The default input/output filename is '.config'. A different filename can be 15passed in the KCONFIG_CONFIG environment variable. 16 17When overwriting a configuration file, the old version is saved to 18<filename>.old (e.g. .config.old). 19 20Entering '?' displays the help text of the symbol/choice, if any. 21 22Unlike 'make oldconfig', this script doesn't print menu titles and comments, 23but gives Kconfig definition locations. Printing menus and comments would be 24pretty easy to add: Look at the parents of each item, and print all menu 25prompts and comments unless they have already been printed (assuming you want 26to skip "irrelevant" menus). 27""" 28from __future__ import print_function 29 30import sys 31 32from kconfiglib import Symbol, Choice, BOOL, TRISTATE, HEX, standard_kconfig 33 34 35# Python 2/3 compatibility hack 36if sys.version_info[0] < 3: 37 input = raw_input 38 39 40def _main(): 41 # Earlier symbols in Kconfig files might depend on later symbols and become 42 # visible if their values change. This flag is set to True if the value of 43 # any symbol changes, in which case we rerun the oldconfig to check for new 44 # visible symbols. 45 global conf_changed 46 47 kconf = standard_kconfig(__doc__) 48 print(kconf.load_config()) 49 50 while True: 51 conf_changed = False 52 53 for node in kconf.node_iter(): 54 oldconfig(node) 55 56 if not conf_changed: 57 break 58 59 print(kconf.write_config()) 60 61 62def oldconfig(node): 63 """ 64 Prompts the user for a value if node.item is a visible symbol/choice with 65 no user value. 66 """ 67 # See main() 68 global conf_changed 69 70 # Only symbols and choices can be configured 71 if not isinstance(node.item, (Symbol, Choice)): 72 return 73 74 # Skip symbols and choices that aren't visible 75 if not node.item.visibility: 76 return 77 78 # Skip symbols and choices that don't have a prompt (at this location) 79 if not node.prompt: 80 return 81 82 if isinstance(node.item, Symbol): 83 sym = node.item 84 85 # Skip symbols that already have a user value 86 if sym.user_value is not None: 87 return 88 89 # Skip symbols that can only have a single value, due to selects 90 if len(sym.assignable) == 1: 91 return 92 93 # Skip symbols in choices in y mode. We ask once for the entire choice 94 # instead. 95 if sym.choice and sym.choice.tri_value == 2: 96 return 97 98 # Loop until the user enters a valid value or enters a blank string 99 # (for the default value) 100 while True: 101 val = input("{} ({}) [{}] ".format( 102 node.prompt[0], _name_and_loc_str(sym), 103 _default_value_str(sym))) 104 105 if val == "?": 106 _print_help(node) 107 continue 108 109 # Substitute a blank string with the default value the symbol 110 # would get 111 if not val: 112 val = sym.str_value 113 114 # Automatically add a "0x" prefix for hex symbols, like the 115 # menuconfig interface does. This isn't done when loading .config 116 # files, hence why set_value() doesn't do it automatically. 117 if sym.type == HEX and not val.startswith(("0x", "0X")): 118 val = "0x" + val 119 120 old_str_val = sym.str_value 121 122 # Kconfiglib itself will print a warning here if the value 123 # is invalid, so we don't need to bother 124 if sym.set_value(val): 125 # Valid value input. We're done with this node. 126 127 if sym.str_value != old_str_val: 128 conf_changed = True 129 130 return 131 132 else: 133 choice = node.item 134 135 # Skip choices that already have a visible user selection... 136 if choice.user_selection and choice.user_selection.visibility == 2: 137 # ...unless there are new visible symbols in the choice. (We know 138 # they have y (2) visibility in that case, because m-visible 139 # symbols get demoted to n-visibility in y-mode choices, and the 140 # user-selected symbol had visibility y.) 141 for sym in choice.syms: 142 if sym is not choice.user_selection and sym.visibility and \ 143 sym.user_value is None: 144 # New visible symbols in the choice 145 break 146 else: 147 # No new visible symbols in the choice 148 return 149 150 # Get a list of available selections. The mode of the choice limits 151 # the visibility of the choice value symbols, so this will indirectly 152 # skip choices in n and m mode. 153 options = [sym for sym in choice.syms if sym.visibility == 2] 154 155 if not options: 156 # No y-visible choice value symbols 157 return 158 159 # Loop until the user enters a valid selection or a blank string (for 160 # the default selection) 161 while True: 162 print("{} ({})".format(node.prompt[0], _name_and_loc_str(choice))) 163 164 for i, sym in enumerate(options, 1): 165 print("{} {}. {} ({})".format( 166 ">" if sym is choice.selection else " ", 167 i, 168 # Assume people don't define choice symbols with multiple 169 # prompts. That generates a warning anyway. 170 sym.nodes[0].prompt[0], 171 sym.name)) 172 173 sel_index = input("choice[1-{}]: ".format(len(options))) 174 175 if sel_index == "?": 176 _print_help(node) 177 continue 178 179 # Pick the default selection if the string is blank 180 if not sel_index: 181 choice.selection.set_value(2) 182 break 183 184 try: 185 sel_index = int(sel_index) 186 except ValueError: 187 print("Bad index", file=sys.stderr) 188 continue 189 190 if not 1 <= sel_index <= len(options): 191 print("Bad index", file=sys.stderr) 192 continue 193 194 # Valid selection 195 196 if options[sel_index - 1].tri_value != 2: 197 conf_changed = True 198 199 options[sel_index - 1].set_value(2) 200 break 201 202 # Give all of the non-selected visible choice symbols the user value n. 203 # This makes it so that the choice is no longer considered new once we 204 # do additional passes, if the reason that it was considered new was 205 # that it had new visible choice symbols. 206 # 207 # Only giving visible choice symbols the user value n means we will 208 # prompt for the choice again if later user selections make more new 209 # choice symbols visible, which is correct. 210 for sym in choice.syms: 211 if sym is not choice.user_selection and sym.visibility: 212 sym.set_value(0) 213 214 215def _name_and_loc_str(sc): 216 # Helper for printing the name of the symbol/choice 'sc' along with the 217 # location(s) in the Kconfig files where it is defined. Unnamed choices 218 # return "choice" instead of the name. 219 220 return "{}, defined at {}".format( 221 sc.name or "choice", 222 ", ".join("{}:{}".format(node.filename, node.linenr) 223 for node in sc.nodes)) 224 225 226def _print_help(node): 227 print("\n" + (node.help or "No help text\n")) 228 229 230def _default_value_str(sym): 231 # Returns the "m/M/y" string in e.g. 232 # 233 # TRISTATE_SYM prompt (TRISTATE_SYM, defined at Kconfig:9) [n/M/y]: 234 # 235 # For string/int/hex, returns the default value as-is. 236 237 if sym.type in (BOOL, TRISTATE): 238 return "/".join(("NMY" if sym.tri_value == tri else "nmy")[tri] 239 for tri in sym.assignable) 240 241 # string/int/hex 242 return sym.str_value 243 244 245if __name__ == "__main__": 246 _main() 247
[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.