3 Kernel configuration script
10 INPUT
= 'kernel.config'
11 OUTPUT
= 'Makefile.config'
12 TMPOUTPUT
= 'Makefile.config.tmp'
15 "Wrapper dialog that tries to return default values"
16 def __init__(self
, dlg
):
19 def set_title(self
,text
):
20 self
.dlg
.set_title(text
)
22 def yesno(self
, text
, default
=None):
23 if default
is not None:
25 return self
.dlg
.yesno(text
, default
)
26 def noyes(self
, text
, default
=None):
27 if default
is not None:
29 return self
.dlg
.noyes(text
, default
)
31 def choice(self
, text
, choices
, defopt
=None):
32 if defopt
is not None:
33 return choices
[defopt
][0]
34 return self
.dlg
.choice(text
, choices
, defopt
)
39 self
.title
= 'HelenOS Configuration'
41 def print_title(self
):
43 sys
.stdout
.write("\n*** %s ***\n" % self
.title
)
46 def set_title(self
, text
):
50 def noyes(self
, text
, default
=None):
53 return self
.yesno(text
, default
)
55 def yesno(self
, text
, default
=None):
61 sys
.stdout
.write("%s (y/n)[%s]: " % (text
,default
))
62 inp
= sys
.stdin
.readline()
65 inp
= inp
.strip().lower()
73 def _print_choice(self
, text
, choices
, defopt
):
74 sys
.stdout
.write('%s:\n' % text
)
75 for i
,(text
,descr
) in enumerate(choices
):
76 sys
.stdout
.write('\t%2d. %s\n' % (i
, descr
))
77 if defopt
is not None:
78 sys
.stdout
.write('Enter choice number[%d]: ' % defopt
)
80 sys
.stdout
.write('Enter choice number: ')
82 def menu(self
, text
, choices
, button
, defopt
=None):
83 self
.title
= 'Main menu'
85 for key
, descr
in choices
:
86 txt
= key
+ (45-len(key
))*' ' + ': ' + descr
87 menu
.append((key
, txt
))
89 return self
.choice(text
, [button
] + menu
)
91 def choice(self
, text
, choices
, defopt
=None):
94 self
._print
_choice
(text
, choices
, defopt
)
95 inp
= sys
.stdin
.readline()
99 if defopt
is not None:
100 return choices
[defopt
][0]
103 number
= int(inp
.strip())
106 if number
< 0 or number
>= len(choices
):
108 return choices
[number
][0]
111 class Dialog(NoDialog
):
113 NoDialog
.__init
__(self
)
114 self
.dlgcmd
= os
.environ
.get('DIALOG','dialog')
116 self
.backtitle
= 'HelenOS Kernel Configuration'
118 if os
.system('%s --print-maxsize >/dev/null 2>&1' % self
.dlgcmd
) != 0:
119 raise NotImplementedError
121 def set_title(self
,text
):
124 def calldlg(self
,*args
,**kw
):
125 "Wrapper for calling 'dialog' program"
126 indesc
, outdesc
= os
.pipe()
133 dlgargs
= [self
.dlgcmd
,'--title',self
.title
,
134 '--backtitle', self
.backtitle
]
135 for key
,val
in kw
.items():
136 dlgargs
.append('--'+key
)
139 os
.execlp(self
.dlgcmd
,*dlgargs
)
144 errout
= os
.fdopen(indesc
,'r')
147 pid
,status
= os
.wait()
149 os
.system('reset') # Reset terminal
152 if not os
.WIFEXITED(status
):
153 os
.system('reset') # Reset terminal
156 status
= os
.WEXITSTATUS(status
)
161 def yesno(self
, text
, default
=None):
162 if text
[-1] not in ('?',':'):
167 text
= ' '*int(((48-len(text
))/2)) + text
172 res
,data
= self
.calldlg('--defaultno','--yesno',text
,height
,width
)
174 res
,data
= self
.calldlg('--yesno',text
,height
,width
)
180 def menu(self
, text
, choices
, button
, defopt
=None):
181 self
.title
= 'Main menu'
184 height
= str(8 + len(choices
))
186 for key
,val
in choices
:
192 kw
['default-item'] = choices
[defopt
][0]
193 res
,data
= self
.calldlg('--ok-label','Change',
194 '--extra-label',button
[1],
196 '--menu',text
,height
,width
,
197 str(len(choices
)),*args
,**kw
)
200 if res
== 1: # Cancel
207 def choice(self
, text
, choices
, defopt
=None):
210 height
= str(8 + len(choices
))
212 for key
,val
in choices
:
218 kw
['default-item'] = choices
[defopt
][0]
219 res
,data
= self
.calldlg('--nocancel','--menu',text
,height
,width
,
220 str(len(choices
)),*args
, **kw
)
226 def read_defaults(fname
,defaults
):
227 "Read saved values from last configuration run"
230 res
= re
.match(r
'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line
)
232 defaults
[res
.group(1)] = res
.group(2)
235 def check_condition(text
, defaults
, asked_names
):
236 seen_vars
= [ x
[0] for x
in asked_names
]
238 if ')|' in text
or '|(' in text
:
242 conds
= text
.split('&')
244 conds
= text
.split('|')
247 if cond
.startswith('(') and cond
.endswith(')'):
250 inside
= check_inside(cond
, defaults
, ctype
, seen_vars
)
252 if ctype
== 'cnf' and not inside
:
254 if ctype
== 'dnf' and inside
:
261 def check_inside(text
, defaults
, ctype
, seen_vars
):
263 Check that the condition specified on input line is True
265 only CNF is supported
268 conds
= text
.split('|')
270 conds
= text
.split('&')
272 res
= re
.match(r
'^(.*?)(!?=)(.*)$', cond
)
274 raise RuntimeError("Invalid condition: %s" % cond
)
275 condname
= res
.group(1)
277 condval
= res
.group(3)
278 if condname
not in seen_vars
:
280 ## raise RuntimeError("Variable %s not defined before being asked." %\
282 elif not defaults
.has_key(condname
):
283 raise RuntimeError("Condition var %s does not exist: %s" % \
286 varval
= defaults
[condname
]
288 if oper
== '=' and condval
== varval
:
290 if oper
== '!=' and condval
!= varval
:
293 if oper
== '=' and condval
!= varval
:
295 if oper
== '!=' and condval
== varval
:
301 def parse_config(input, output
, dlg
, defaults
={}, askonly
=None):
302 "Parse configuration file and create Makefile.config on the fly"
303 def ask_the_question(dialog
):
304 "Ask question based on the type of variables to ask"
305 # This is quite a hack, this thingy is written just to
306 # have access to local variables..
308 return dialog
.yesno(comment
, default
)
309 elif vartype
== 'n/y':
310 return dialog
.noyes(comment
, default
)
311 elif vartype
== 'choice':
313 if default
is not None:
314 for i
,(key
,val
) in enumerate(choices
):
318 return dialog
.choice(comment
, choices
, defopt
)
320 raise RuntimeError("Bad method: %s" % vartype
)
324 outf
= file(output
, 'w')
326 outf
.write('#########################################\n')
327 outf
.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n')
328 outf
.write('#########################################\n\n')
336 if line
.startswith('%'):
337 res
= re
.match(r
'^%\s*(?:\[(.*?)\])?\s*(.*)$', line
)
339 raise RuntimeError('Invalid command: %s' % line
)
341 if not check_condition(res
.group(1), defaults
,
344 args
= res
.group(2).strip().split(' ')
345 cmd
= args
[0].lower()
348 outf
.write('%s = %s\n' % (args
[1],defaults
[args
[0]]))
349 elif cmd
== 'shellcmd':
352 for i
,arg
in enumerate(args
):
353 if arg
.startswith('$'):
354 args
[i
] = defaults
[arg
[1:]]
355 data
,status
= commands
.getstatusoutput(' '.join(args
))
357 raise RuntimeError('Error running: %s' % ' '.join(args
))
358 outf
.write('%s = %s\n' % (varname
,data
.strip()))
361 if line
.startswith('!'):
363 res
= re
.search(r
'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line
)
365 raise RuntimeError("Weird line: %s" % line
)
366 varname
= res
.group(2)
367 vartype
= res
.group(3)
369 default
= defaults
.get(varname
,None)
372 if not check_condition(res
.group(1), defaults
,
374 if default
is not None:
375 outf
.write('#!# %s = %s\n' % (varname
, default
))
376 # Clear cumulated values
382 asked_names
.append((varname
,comment
))
384 if default
is None or not askonly
or askonly
== varname
:
385 default
= ask_the_question(dlg
)
387 default
= ask_the_question(DefaultDialog(dlg
))
389 outf
.write('%s = %s\n' % (varname
, default
))
390 # Remeber the selected value
391 defaults
[varname
] = default
392 # Clear cumulated values
398 if line
.startswith('@'):
399 # Add new line into the 'choice array'
400 res
= re
.match(r
'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line
)
402 raise RuntimeError("Bad line: %s" % line
)
404 if not check_condition(res
.group(1),defaults
,
407 choices
.append((res
.group(2), res
.group(3)))
410 # All other things print to output file
412 if re
.match(r
'^#[^#]', line
):
413 # Last comment before question will be displayed to the user
414 comment
= line
[1:].strip()
415 elif line
.startswith('## '):
416 # Set title of the dialog window
417 dlg
.set_title(line
[2:].strip())
420 outf
.write('REVISION = %s\n' % commands
.getoutput('svnversion . 2> /dev/null'))
421 outf
.write('TIMESTAMP = %s\n' % commands
.getoutput('date "+%Y-%m-%d %H:%M:%S"'))
430 except NotImplementedError:
433 if len(sys
.argv
) >= 2 and sys
.argv
[1]=='default':
438 # Default run will update the configuration file
439 # with newest options
440 if os
.path
.exists(OUTPUT
):
441 read_defaults(OUTPUT
, defaults
)
443 # Get ARCH from command line if specified
444 if len(sys
.argv
) >= 3:
445 defaults
['ARCH'] = sys
.argv
[2]
447 # Dry run only with defaults
448 varnames
= parse_config(INPUT
, TMPOUTPUT
, DefaultDialog(dlg
), defaults
)
449 # If not in default mode, present selection of all possibilities
453 # varnames contains variable names that were in the
455 choices
= [ (x
[1],defaults
[x
[0]]) for x
in varnames
]
456 res
= dlg
.menu('Configuration',choices
,('save','Save'),defopt
)
458 parse_config(INPUT
, TMPOUTPUT
, DefaultDialog(dlg
), defaults
)
460 # transfer description back to varname
461 for i
,(vname
,descr
) in enumerate(varnames
):
465 # Ask the user a simple question, produce output
466 # as if the user answered all the other questions
467 # with default answer
468 varnames
= parse_config(INPUT
, TMPOUTPUT
, dlg
, defaults
,
469 askonly
=varnames
[i
][0])
472 if os
.path
.exists(OUTPUT
):
474 os
.rename(TMPOUTPUT
, OUTPUT
)
476 if not defmode
and dlg
.yesno('Rebuild kernel?') == 'y':
477 os
.execlp('make','make','clean','build')
479 if __name__
== '__main__':