oldconfig.py 7.9 KB

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