source: mainline/tools/config.py@ 2d1195c0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2d1195c0 was 571239a, checked in by Martin Sucha <sucha14@…>, 13 years ago

When writing an auto-generated file, note which program generated it.

  • Property mode set to 100755
File size: 16.2 KB
RevLine 
[98376de]1#!/usr/bin/env python
[44882c8]2#
[5a55ae6]3# Copyright (c) 2006 Ondrej Palkovsky
[9a0367f]4# Copyright (c) 2009 Martin Decky
[62bb73e]5# Copyright (c) 2010 Jiri Svoboda
[44882c8]6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11#
12# - Redistributions of source code must retain the above copyright
13# notice, this list of conditions and the following disclaimer.
14# - Redistributions in binary form must reproduce the above copyright
15# notice, this list of conditions and the following disclaimer in the
16# documentation and/or other materials provided with the distribution.
17# - The name of the author may not be used to endorse or promote products
18# derived from this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30#
[3c80f2b]31
[98376de]32"""
[9a0367f]33HelenOS configuration system
[98376de]34"""
[3c80f2b]35
[98376de]36import sys
37import os
38import re
[5a8fbcb9]39import time
40import subprocess
[27fb3d6]41import xtui
[98376de]42
[62bb73e]43RULES_FILE = sys.argv[1]
[84266669]44MAKEFILE = 'Makefile.config'
45MACROS = 'config.h'
[62bb73e]46PRESETS_DIR = 'defaults'
[98376de]47
[62bb73e]48def read_config(fname, config):
[d40ffbb]49 "Read saved values from last configuration run or a preset file"
[9a0367f]50
[28f4adb]51 inf = open(fname, 'r')
[9a0367f]52
53 for line in inf:
54 res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line)
[ba8de9c3]55 if res:
[62bb73e]56 config[res.group(1)] = res.group(2)
[9a0367f]57
58 inf.close()
[98376de]59
[62bb73e]60def check_condition(text, config, rules):
[81c8d54]61 "Check that the condition specified on input line is True (only CNF and DNF is supported)"
[9a0367f]62
63 ctype = 'cnf'
64
[ba8de9c3]65 if (')|' in text) or ('|(' in text):
[9a0367f]66 ctype = 'dnf'
67
[ba8de9c3]68 if ctype == 'cnf':
[9a0367f]69 conds = text.split('&')
70 else:
71 conds = text.split('|')
72
73 for cond in conds:
[ba8de9c3]74 if cond.startswith('(') and cond.endswith(')'):
[9a0367f]75 cond = cond[1:-1]
76
[62bb73e]77 inside = check_inside(cond, config, ctype)
[9a0367f]78
79 if (ctype == 'cnf') and (not inside):
80 return False
81
[ba8de9c3]82 if (ctype == 'dnf') and inside:
[9a0367f]83 return True
84
[ba8de9c3]85 if ctype == 'cnf':
[9a0367f]86 return True
[1f5c9c96]87
[9a0367f]88 return False
[98376de]89
[62bb73e]90def check_inside(text, config, ctype):
[81c8d54]91 "Check for condition"
[9a0367f]92
[ba8de9c3]93 if ctype == 'cnf':
[9a0367f]94 conds = text.split('|')
95 else:
96 conds = text.split('&')
97
98 for cond in conds:
99 res = re.match(r'^(.*?)(!?=)(.*)$', cond)
[ba8de9c3]100 if not res:
[9a0367f]101 raise RuntimeError("Invalid condition: %s" % cond)
102
103 condname = res.group(1)
104 oper = res.group(2)
105 condval = res.group(3)
106
[ba8de9c3]107 if not condname in config:
[9a0367f]108 varval = ''
109 else:
[62bb73e]110 varval = config[condname]
[7aef7ee]111 if (varval == '*'):
112 varval = 'y'
[9a0367f]113
[ba8de9c3]114 if ctype == 'cnf':
[9a0367f]115 if (oper == '=') and (condval == varval):
116 return True
117
118 if (oper == '!=') and (condval != varval):
119 return True
120 else:
121 if (oper == '=') and (condval != varval):
122 return False
123
124 if (oper == '!=') and (condval == varval):
125 return False
126
[ba8de9c3]127 if ctype == 'cnf':
[9a0367f]128 return False
129
130 return True
[98376de]131
[62bb73e]132def parse_rules(fname, rules):
133 "Parse rules file"
[9a0367f]134
[28f4adb]135 inf = open(fname, 'r')
[9a0367f]136
137 name = ''
138 choices = []
139
140 for line in inf:
141
[ba8de9c3]142 if line.startswith('!'):
[9a0367f]143 # Ask a question
144 res = re.search(r'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line)
145
[ba8de9c3]146 if not res:
[9a0367f]147 raise RuntimeError("Weird line: %s" % line)
148
149 cond = res.group(1)
150 varname = res.group(2)
151 vartype = res.group(3)
152
[62bb73e]153 rules.append((varname, vartype, name, choices, cond))
[9a0367f]154 name = ''
155 choices = []
156 continue
157
[ba8de9c3]158 if line.startswith('@'):
[9a0367f]159 # Add new line into the 'choices' array
160 res = re.match(r'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line)
161
162 if not res:
163 raise RuntimeError("Bad line: %s" % line)
164
165 choices.append((res.group(2), res.group(3)))
166 continue
167
[ba8de9c3]168 if line.startswith('%'):
[9a0367f]169 # Name of the option
170 name = line[1:].strip()
171 continue
172
[ba8de9c3]173 if line.startswith('#') or (line == '\n'):
[9a0367f]174 # Comment or empty line
175 continue
176
177
178 raise RuntimeError("Unknown syntax: %s" % line)
179
180 inf.close()
[98376de]181
[9a0367f]182def yes_no(default):
183 "Return '*' if yes, ' ' if no"
184
[ba8de9c3]185 if default == 'y':
[9a0367f]186 return '*'
187
188 return ' '
[98376de]189
[27fb3d6]190def subchoice(screen, name, choices, default):
[9a0367f]191 "Return choice of choices"
192
[27fb3d6]193 maxkey = 0
194 for key, val in choices:
195 length = len(key)
196 if (length > maxkey):
197 maxkey = length
[9a0367f]198
199 options = []
[27fb3d6]200 position = None
201 cnt = 0
202 for key, val in choices:
[ba8de9c3]203 if (default) and (key == default):
[27fb3d6]204 position = cnt
205
206 options.append(" %-*s %s " % (maxkey, key, val))
207 cnt += 1
[9a0367f]208
[27fb3d6]209 (button, value) = xtui.choice_window(screen, name, 'Choose value', options, position)
[9a0367f]210
[ba8de9c3]211 if button == 'cancel':
[9a0367f]212 return None
213
[27fb3d6]214 return choices[value][0]
[98376de]215
[e4d540b]216## Infer and verify configuration values.
217#
[62bb73e]218# Augment @a config with values that can be inferred, purge invalid ones
[e4d540b]219# and verify that all variables have a value (previously specified or inferred).
220#
[d40ffbb]221# @param config Configuration to work on
222# @param rules Rules
[e4d540b]223#
[d40ffbb]224# @return True if configuration is complete and valid, False
225# otherwise.
[e4d540b]226#
[62bb73e]227def infer_verify_choices(config, rules):
[e4d540b]228 "Infer and verify configuration values."
[9a0367f]229
[ba8de9c3]230 for rule in rules:
231 varname, vartype, name, choices, cond = rule
[d40ffbb]232
[ba8de9c3]233 if cond and (not check_condition(cond, config, rules)):
[9a0367f]234 continue
235
[ba8de9c3]236 if not varname in config:
[4756634]237 value = None
[e4d540b]238 else:
[4756634]239 value = config[varname]
[d40ffbb]240
241 if not validate_rule_value(rule, value):
[4756634]242 value = None
[d40ffbb]243
244 default = get_default_rule(rule)
[1f5c9c96]245
[c0bd08d]246 #
247 # If we don't have a value but we do have
248 # a default, use it.
249 #
250 if value == None and default != None:
251 value = default
[4756634]252 config[varname] = default
[d40ffbb]253
[ba8de9c3]254 if not varname in config:
[9a0367f]255 return False
256
257 return True
[98376de]258
[e4d540b]259## Get default value from a rule.
[d40ffbb]260def get_default_rule(rule):
[e4d540b]261 varname, vartype, name, choices, cond = rule
[d40ffbb]262
[e4d540b]263 default = None
[d40ffbb]264
[ba8de9c3]265 if vartype == 'choice':
[e4d540b]266 # If there is just one option, use it
[ba8de9c3]267 if len(choices) == 1:
[e4d540b]268 default = choices[0][0]
[ba8de9c3]269 elif vartype == 'y':
[e4d540b]270 default = '*'
[ba8de9c3]271 elif vartype == 'n':
[e4d540b]272 default = 'n'
[ba8de9c3]273 elif vartype == 'y/n':
[e4d540b]274 default = 'y'
[ba8de9c3]275 elif vartype == 'n/y':
[e4d540b]276 default = 'n'
277 else:
278 raise RuntimeError("Unknown variable type: %s" % vartype)
[d40ffbb]279
[e4d540b]280 return default
281
282## Get option from a rule.
283#
[d40ffbb]284# @param rule Rule for a variable
285# @param value Current value of the variable
[e4d540b]286#
287# @return Option (string) to ask or None which means not to ask.
288#
[d40ffbb]289def get_rule_option(rule, value):
[e4d540b]290 varname, vartype, name, choices, cond = rule
[d40ffbb]291
[e4d540b]292 option = None
[d40ffbb]293
[ba8de9c3]294 if vartype == 'choice':
[e4d540b]295 # If there is just one option, don't ask
[ba8de9c3]296 if len(choices) != 1:
[e4d540b]297 if (value == None):
298 option = "? %s --> " % name
299 else:
300 option = " %s [%s] --> " % (name, value)
[ba8de9c3]301 elif vartype == 'y':
[e4d540b]302 pass
[ba8de9c3]303 elif vartype == 'n':
[e4d540b]304 pass
[ba8de9c3]305 elif vartype == 'y/n':
[e4d540b]306 option = " <%s> %s " % (yes_no(value), name)
[ba8de9c3]307 elif vartype == 'n/y':
[e4d540b]308 option =" <%s> %s " % (yes_no(value), name)
309 else:
310 raise RuntimeError("Unknown variable type: %s" % vartype)
[d40ffbb]311
[e4d540b]312 return option
313
314## Check if variable value is valid.
315#
[d40ffbb]316# @param rule Rule for the variable
317# @param value Value of the variable
[e4d540b]318#
[d40ffbb]319# @return True if valid, False if not valid.
[e4d540b]320#
[d40ffbb]321def validate_rule_value(rule, value):
[e4d540b]322 varname, vartype, name, choices, cond = rule
323
324 if value == None:
325 return True
[d40ffbb]326
[ba8de9c3]327 if vartype == 'choice':
328 if not value in [choice[0] for choice in choices]:
[e4d540b]329 return False
[ba8de9c3]330 elif vartype == 'y':
[e4d540b]331 if value != 'y':
332 return False
[ba8de9c3]333 elif vartype == 'n':
[e4d540b]334 if value != 'n':
335 return False
[ba8de9c3]336 elif vartype == 'y/n':
[e4d540b]337 if not value in ['y', 'n']:
338 return False
[ba8de9c3]339 elif vartype == 'n/y':
[e4d540b]340 if not value in ['y', 'n']:
341 return False
342 else:
343 raise RuntimeError("Unknown variable type: %s" % vartype)
[d40ffbb]344
[e4d540b]345 return True
346
[1f5c9c96]347def preprocess_config(config, rules):
348 "Preprocess configuration"
349
350 varname_mode = 'CONFIG_BFB_MODE'
351 varname_width = 'CONFIG_BFB_WIDTH'
352 varname_height = 'CONFIG_BFB_HEIGHT'
353
354 if varname_mode in config:
355 mode = config[varname_mode].partition('x')
356
357 config[varname_width] = mode[0]
358 rules.append((varname_width, 'choice', 'Default framebuffer width', None, None))
359
360 config[varname_height] = mode[2]
361 rules.append((varname_height, 'choice', 'Default framebuffer height', None, None))
362
[62bb73e]363def create_output(mkname, mcname, config, rules):
[9a0367f]364 "Create output configuration"
365
[5a8fbcb9]366 timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
[fe12f9f4]367
368 sys.stderr.write("Fetching current revision identifier ... ")
[7b76744]369
370 try:
[28f4adb]371 version = subprocess.Popen(['bzr', 'version-info', '--custom', '--template={clean}:{revno}:{revision_id}'], stdout = subprocess.PIPE).communicate()[0].decode().split(':')
[7b76744]372 sys.stderr.write("ok\n")
373 except:
374 version = [1, "unknown", "unknown"]
375 sys.stderr.write("failed\n")
[5a8fbcb9]376
[ba8de9c3]377 if len(version) == 3:
[5a8fbcb9]378 revision = version[1]
[ba8de9c3]379 if version[0] != 1:
[5a8fbcb9]380 revision += 'M'
381 revision += ' (%s)' % version[2]
382 else:
383 revision = None
[84266669]384
[28f4adb]385 outmk = open(mkname, 'w')
386 outmc = open(mcname, 'w')
[84266669]387
388 outmk.write('#########################################\n')
389 outmk.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n')
[571239a]390 outmk.write('## Generated by: tools/config.py ##\n')
[84266669]391 outmk.write('#########################################\n\n')
[9a0367f]392
[84266669]393 outmc.write('/***************************************\n')
394 outmc.write(' * AUTO-GENERATED FILE, DO NOT EDIT!!! *\n')
[571239a]395 outmc.write(' * Generated by: tools/config.py *\n')
[84266669]396 outmc.write(' ***************************************/\n\n')
397
[4e9aaf5]398 defs = 'CONFIG_DEFS ='
[9a0367f]399
[62bb73e]400 for varname, vartype, name, choices, cond in rules:
[ba8de9c3]401 if cond and (not check_condition(cond, config, rules)):
[9a0367f]402 continue
403
[ba8de9c3]404 if not varname in config:
[4756634]405 value = ''
[9a0367f]406 else:
[4756634]407 value = config[varname]
408 if (value == '*'):
409 value = 'y'
[9a0367f]410
[4756634]411 outmk.write('# %s\n%s = %s\n\n' % (name, varname, value))
[84266669]412
[ba8de9c3]413 if vartype in ["y", "n", "y/n", "n/y"]:
414 if value == "y":
[84266669]415 outmc.write('/* %s */\n#define %s\n\n' % (name, varname))
[4e9aaf5]416 defs += ' -D%s' % varname
[84266669]417 else:
[4756634]418 outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, value, varname, value))
419 defs += ' -D%s=%s -D%s_%s' % (varname, value, varname, value)
[9a0367f]420
[ba8de9c3]421 if revision is not None:
[5a8fbcb9]422 outmk.write('REVISION = %s\n' % revision)
423 outmc.write('#define REVISION %s\n' % revision)
[4e9aaf5]424 defs += ' "-DREVISION=%s"' % revision
[84266669]425
[5a8fbcb9]426 outmk.write('TIMESTAMP = %s\n' % timestamp)
[84266669]427 outmc.write('#define TIMESTAMP %s\n' % timestamp)
[4e9aaf5]428 defs += ' "-DTIMESTAMP=%s"\n' % timestamp
429
430 outmk.write(defs)
[84266669]431
432 outmk.close()
433 outmc.close()
[98376de]434
[31fb9a0]435def sorted_dir(root):
436 list = os.listdir(root)
437 list.sort()
438 return list
439
[6ec0acd]440## Ask user to choose a configuration profile.
[62bb73e]441#
[d40ffbb]442def choose_profile(root, fname, screen, config):
[31fb9a0]443 options = []
444 opt2path = {}
445 cnt = 0
446
447 # Look for profiles
448 for name in sorted_dir(root):
449 path = os.path.join(root, name)
450 canon = os.path.join(path, fname)
451
[ba8de9c3]452 if os.path.isdir(path) and os.path.exists(canon) and os.path.isfile(canon):
[31fb9a0]453 subprofile = False
454
455 # Look for subprofiles
456 for subname in sorted_dir(path):
457 subpath = os.path.join(path, subname)
458 subcanon = os.path.join(subpath, fname)
459
[ba8de9c3]460 if os.path.isdir(subpath) and os.path.exists(subcanon) and os.path.isfile(subcanon):
[31fb9a0]461 subprofile = True
462 options.append("%s (%s)" % (name, subname))
[6ec0acd]463 opt2path[cnt] = [name, subname]
[31fb9a0]464 cnt += 1
465
[ba8de9c3]466 if not subprofile:
[31fb9a0]467 options.append(name)
[6ec0acd]468 opt2path[cnt] = [name]
[31fb9a0]469 cnt += 1
470
471 (button, value) = xtui.choice_window(screen, 'Load preconfigured defaults', 'Choose configuration profile', options, None)
472
[ba8de9c3]473 if button == 'cancel':
[31fb9a0]474 return None
475
[6ec0acd]476 return opt2path[value]
477
478## Read presets from a configuration profile.
479#
[d40ffbb]480# @param profile Profile to load from (a list of string components)
481# @param config Output configuration
[6ec0acd]482#
[d40ffbb]483def read_presets(profile, config):
[6ec0acd]484 path = os.path.join(PRESETS_DIR, profile[0], MAKEFILE)
485 read_config(path, config)
[d40ffbb]486
[6ec0acd]487 if len(profile) > 1:
488 path = os.path.join(PRESETS_DIR, profile[0], profile[1], MAKEFILE)
489 read_config(path, config)
490
491## Parse profile name (relative OS path) into a list of components.
492#
[d40ffbb]493# @param profile_name Relative path (using OS separator)
494# @return List of components
[6ec0acd]495#
496def parse_profile_name(profile_name):
497 profile = []
[d40ffbb]498
[6ec0acd]499 head, tail = os.path.split(profile_name)
500 if head != '':
501 profile.append(head)
[d40ffbb]502
[6ec0acd]503 profile.append(tail)
504 return profile
[31fb9a0]505
[98376de]506def main():
[6ec0acd]507 profile = None
[62bb73e]508 config = {}
509 rules = []
[9a0367f]510
[62bb73e]511 # Parse rules file
512 parse_rules(RULES_FILE, rules)
[9a0367f]513
[421250e]514 # Input configuration file can be specified on command line
515 # otherwise configuration from previous run is used.
516 if len(sys.argv) >= 4:
[6ec0acd]517 profile = parse_profile_name(sys.argv[3])
[d40ffbb]518 read_presets(profile, config)
[6ec0acd]519 elif os.path.exists(MAKEFILE):
520 read_config(MAKEFILE, config)
[9a0367f]521
[e3c3172]522 # Default mode: check values and regenerate configuration files
[ba8de9c3]523 if (len(sys.argv) >= 3) and (sys.argv[2] == 'default'):
[62bb73e]524 if (infer_verify_choices(config, rules)):
[1f5c9c96]525 preprocess_config(config, rules)
[62bb73e]526 create_output(MAKEFILE, MACROS, config, rules)
[9a0367f]527 return 0
528
[e3c3172]529 # Hands-off mode: check values and regenerate configuration files,
530 # but no interactive fallback
531 if (len(sys.argv) >= 3) and (sys.argv[2] == 'hands-off'):
532 # We deliberately test sys.argv >= 4 because we do not want
533 # to read implicitly any possible previous run configuration
534 if len(sys.argv) < 4:
535 sys.stderr.write("Configuration error: No presets specified\n")
536 return 2
537
538 if (infer_verify_choices(config, rules)):
[1f5c9c96]539 preprocess_config(config, rules)
[e3c3172]540 create_output(MAKEFILE, MACROS, config, rules)
541 return 0
542
543 sys.stderr.write("Configuration error: The presets are ambiguous\n")
544 return 1
545
[62bb73e]546 # Check mode: only check configuration
[ba8de9c3]547 if (len(sys.argv) >= 3) and (sys.argv[2] == 'check'):
548 if infer_verify_choices(config, rules):
[48c3d50]549 return 0
550 return 1
551
[27fb3d6]552 screen = xtui.screen_init()
[9a0367f]553 try:
554 selname = None
[31fb9a0]555 position = None
[9a0367f]556 while True:
557
[62bb73e]558 # Cancel out all values which have to be deduced
559 for varname, vartype, name, choices, cond in rules:
[ba8de9c3]560 if (vartype == 'y') and (varname in config) and (config[varname] == '*'):
[62bb73e]561 config[varname] = None
[81c8d54]562
[9a0367f]563 options = []
564 opt2row = {}
[31fb9a0]565 cnt = 1
566
567 options.append(" --- Load preconfigured defaults ... ")
568
[62bb73e]569 for rule in rules:
[e4d540b]570 varname, vartype, name, choices, cond = rule
[9a0367f]571
[ba8de9c3]572 if cond and (not check_condition(cond, config, rules)):
[9a0367f]573 continue
574
[ba8de9c3]575 if varname == selname:
[9a0367f]576 position = cnt
577
[ba8de9c3]578 if not varname in config:
[4756634]579 value = None
[9a0367f]580 else:
[4756634]581 value = config[varname]
[9a0367f]582
[d40ffbb]583 if not validate_rule_value(rule, value):
[4756634]584 value = None
[d40ffbb]585
586 default = get_default_rule(rule)
[1f5c9c96]587
[c0bd08d]588 #
589 # If we don't have a value but we do have
590 # a default, use it.
591 #
592 if value == None and default != None:
593 value = default
594 config[varname] = default
[d40ffbb]595
596 option = get_rule_option(rule, value)
[e4d540b]597 if option != None:
598 options.append(option)
[8fe3f832]599 else:
600 continue
[9a0367f]601
[27fb3d6]602 opt2row[cnt] = (varname, vartype, name, choices)
[9a0367f]603
604 cnt += 1
605
[28f4adb]606 if (position != None) and (position >= len(options)):
[31fb9a0]607 position = None
608
[27fb3d6]609 (button, value) = xtui.choice_window(screen, 'HelenOS configuration', 'Choose configuration option', options, position)
[9a0367f]610
[ba8de9c3]611 if button == 'cancel':
[9a0367f]612 return 'Configuration canceled'
613
[ba8de9c3]614 if button == 'done':
[62bb73e]615 if (infer_verify_choices(config, rules)):
[6346efd]616 break
617 else:
618 xtui.error_dialog(screen, 'Error', 'Some options have still undefined values. These options are marked with the "?" sign.')
619 continue
620
[ba8de9c3]621 if value == 0:
[d40ffbb]622 profile = choose_profile(PRESETS_DIR, MAKEFILE, screen, config)
[6ec0acd]623 if profile != None:
[d40ffbb]624 read_presets(profile, config)
[31fb9a0]625 position = 1
626 continue
627
628 position = None
[ba8de9c3]629 if not value in opt2row:
[27fb3d6]630 raise RuntimeError("Error selecting value: %s" % value)
631
632 (selname, seltype, name, choices) = opt2row[value]
[9a0367f]633
[ba8de9c3]634 if not selname in config:
[4756634]635 value = None
[27fb3d6]636 else:
[4756634]637 value = config[selname]
[9a0367f]638
[ba8de9c3]639 if seltype == 'choice':
[4756634]640 config[selname] = subchoice(screen, name, choices, value)
[ba8de9c3]641 elif (seltype == 'y/n') or (seltype == 'n/y'):
642 if config[selname] == 'y':
[62bb73e]643 config[selname] = 'n'
[9a0367f]644 else:
[62bb73e]645 config[selname] = 'y'
[9a0367f]646 finally:
[27fb3d6]647 xtui.screen_done(screen)
[9a0367f]648
[1f5c9c96]649 preprocess_config(config, rules)
[62bb73e]650 create_output(MAKEFILE, MACROS, config, rules)
[9a0367f]651 return 0
[98376de]652
653if __name__ == '__main__':
[43a10c4]654 sys.exit(main())
Note: See TracBrowser for help on using the repository browser.