Subversion Repositories HelenOS

Rev

Rev 3022 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3022 Rev 4055
Line 1... Line 1...
1
#!/usr/bin/env python
1
#!/usr/bin/env python
2
#
2
#
3
# Copyright (c) 2006 Ondrej Palkovsky
3
# Copyright (c) 2006 Ondrej Palkovsky
-
 
4
# Copyright (c) 2009 Martin Decky
4
# All rights reserved.
5
# All rights reserved.
5
#
6
#
6
# Redistribution and use in source and binary forms, with or without
7
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions
8
# modification, are permitted provided that the following conditions
8
# are met:
9
# are met:
Line 25... Line 26...
25
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
#
29
#
29
"""
30
"""
30
HelenOS configuration script
31
HelenOS configuration system
31
"""
32
"""
32
import sys
33
import sys
33
import os
34
import os
34
import re
35
import re
35
import commands
36
import commands
-
 
37
import xtui
36
 
38
 
37
INPUT = sys.argv[1]
39
INPUT = sys.argv[1]
38
OUTPUT = 'Makefile.config'
40
MAKEFILE = 'Makefile.config'
39
TMPOUTPUT = 'Makefile.config.tmp'
41
MACROS = 'config.h'
-
 
42
DEFS = 'config.defs'
40
 
43
 
41
class DefaultDialog:
44
def read_defaults(fname, defaults):
42
    "Wrapper dialog that tries to return default values"
45
    "Read saved values from last configuration run"
43
    def __init__(self, dlg):
46
   
44
        self.dlg = dlg
47
    inf = file(fname, 'r')
45
 
48
   
46
    def set_title(self,text):
49
    for line in inf:
47
        self.dlg.set_title(text)
50
        res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line)
48
       
51
        if (res):
49
    def yesno(self, text, default=None):
52
            defaults[res.group(1)] = res.group(2)
50
        if default is not None:
53
   
51
            return default
54
    inf.close()
52
        return self.dlg.yesno(text, default)
55
 
53
    def noyes(self, text, default=None):
56
def check_condition(text, defaults, ask_names):
54
        if default is not None:
57
    "Check that the condition specified on input line is True (only CNF and DNF is supported)"
55
            return default
58
   
56
        return self.dlg.noyes(text, default)
59
    ctype = 'cnf'
57
   
60
   
58
    def choice(self, text, choices, defopt=None):
61
    if ((')|' in text) or ('|(' in text)):
59
        if defopt is not None:
62
        ctype = 'dnf'
60
            return choices[defopt][0]
63
   
61
        return self.dlg.choice(text, choices, defopt)
64
    if (ctype == 'cnf'):
62
 
65
        conds = text.split('&')
63
class NoDialog:
66
    else:
64
    def __init__(self):
67
        conds = text.split('|')
65
        self.printed = None
68
   
66
        self.title = 'HelenOS Configuration'
69
    for cond in conds:
67
 
70
        if (cond.startswith('(')) and (cond.endswith(')')):
68
    def print_title(self):
71
            cond = cond[1:-1]
69
        if not self.printed:
72
       
70
            sys.stdout.write("\n*** %s ***\n" % self.title)
73
        inside = check_inside(cond, defaults, ctype)
71
            self.printed = True
74
       
72
 
75
        if (ctype == 'cnf') and (not inside):
73
    def set_title(self, text):
76
            return False
74
        self.title = text
77
       
75
        self.printed = False
78
        if (ctype == 'dnf') and (inside):
76
   
79
            return True
77
    def noyes(self, text, default=None):
80
   
78
        if not default:
81
    if (ctype == 'cnf'):
79
            default = 'n'
82
        return True
80
        return self.yesno(text, default)
83
    return False
81
   
84
 
82
    def yesno(self, text, default=None):
85
def check_inside(text, defaults, ctype):
83
        self.print_title()
86
    "Check for condition"
84
       
87
   
85
        if default != 'n':
88
    if (ctype == 'cnf'):
86
            default = 'y'
89
        conds = text.split('|')
87
        while 1:
90
    else:
88
            sys.stdout.write("%s (y/n)[%s]: " % (text,default))
91
        conds = text.split('&')
89
            inp = sys.stdin.readline()
92
   
90
            if not inp:
93
    for cond in conds:
91
                raise EOFError
94
        res = re.match(r'^(.*?)(!?=)(.*)$', cond)
92
            inp = inp.strip().lower()
95
        if (not res):
93
            if not inp:
96
            raise RuntimeError("Invalid condition: %s" % cond)
94
                return default
97
       
95
            if inp == 'y':
98
        condname = res.group(1)
96
                return 'y'
99
        oper = res.group(2)
97
            elif inp == 'n':
100
        condval = res.group(3)
98
                return 'n'
101
       
99
 
102
        if (not defaults.has_key(condname)):
100
    def _print_choice(self, text, choices, defopt):
103
            varval = ''
101
        sys.stdout.write('%s:\n' % text)
104
        else:
102
        for i,(text,descr) in enumerate(choices):
105
            varval = defaults[condname]
103
            if descr is '':
106
            if (varval == '*'):
104
                sys.stdout.write('\t%2d. %s\n' % (i, text))
107
                varval = 'y'
105
            else:
108
       
106
                sys.stdout.write('\t%2d. %s\n' % (i, descr))
109
        if (ctype == 'cnf'):
107
        if defopt is not None:
110
            if (oper == '=') and (condval == varval):
108
            sys.stdout.write('Enter choice number[%d]: ' % defopt)
111
                return True
109
        else:
112
       
110
            sys.stdout.write('Enter choice number: ')
113
            if (oper == '!=') and (condval != varval):
111
 
114
                return True
112
    def menu(self, text, choices, button, defopt=None):
115
        else:
113
        self.title = 'Main menu'
116
            if (oper == '=') and (condval != varval):
114
        menu = []
117
                return False
115
        for key, descr in choices:
118
           
116
            txt = key + (45-len(key))*' ' + ': ' + descr
119
            if (oper == '!=') and (condval == varval):
117
            menu.append((key, txt))
120
                return False
118
           
121
   
119
        return self.choice(text, [button] + menu)
122
    if (ctype == 'cnf'):
120
       
123
        return False
121
    def choice(self, text, choices, defopt=None):
124
   
122
        self.print_title()
125
    return True
123
        while 1:
126
 
124
            self._print_choice(text, choices, defopt)
127
def parse_config(fname, ask_names):
125
            inp = sys.stdin.readline()
128
    "Parse configuration file"
126
            if not inp:
129
   
127
                raise EOFError
130
    inf = file(fname, 'r')
128
            if not inp.strip():
131
   
129
                if defopt is not None:
132
    name = ''
130
                    return choices[defopt][0]
133
    choices = []
131
                continue
134
   
132
            try:
135
    for line in inf:
133
                number = int(inp.strip())
136
       
134
            except ValueError:
137
        if (line.startswith('!')):
135
                continue
138
            # Ask a question
136
            if number < 0 or number >= len(choices):
139
            res = re.search(r'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line)
137
                continue
140
           
138
            return choices[number][0]
141
            if (not res):
139
 
142
                raise RuntimeError("Weird line: %s" % line)
140
 
143
           
141
def eof_checker(fnc):
144
            cond = res.group(1)
142
    def wrapper(self, *args, **kw):
145
            varname = res.group(2)
143
        try:
146
            vartype = res.group(3)
144
            return fnc(self, *args, **kw)
147
           
145
        except EOFError:
148
            ask_names.append((varname, vartype, name, choices, cond))
146
            return getattr(self.bckdialog,fnc.func_name)(*args, **kw)
149
            name = ''
147
    return wrapper
150
            choices = []
148
 
151
            continue
149
class Dialog(NoDialog):
152
       
150
    def __init__(self):
153
        if (line.startswith('@')):
151
        NoDialog.__init__(self)
154
            # Add new line into the 'choices' array
152
        self.dlgcmd = os.environ.get('DIALOG','dialog')
155
            res = re.match(r'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line)
153
        self.title = ''
156
           
154
        self.backtitle = 'HelenOS Configuration'
157
            if not res:
155
       
158
                raise RuntimeError("Bad line: %s" % line)
156
        if os.system('%s --print-maxsize >/dev/null 2>&1' % self.dlgcmd) != 0:
159
           
157
            raise NotImplementedError
160
            choices.append((res.group(2), res.group(3)))
158
       
161
            continue
159
        self.bckdialog = NoDialog()
162
       
160
 
163
        if (line.startswith('%')):
161
    def set_title(self,text):
164
            # Name of the option
162
        self.title = text
165
            name = line[1:].strip()
163
        self.bckdialog.set_title(text)
166
            continue
164
       
167
       
165
    def calldlg(self,*args,**kw):
168
        if ((line.startswith('#')) or (line == '\n')):
166
        "Wrapper for calling 'dialog' program"
169
            # Comment or empty line
167
        indesc, outdesc = os.pipe()
170
            continue
168
        pid = os.fork()
171
       
169
        if not pid:
172
       
170
            os.close(2)
173
        raise RuntimeError("Unknown syntax: %s" % line)
171
            os.dup(outdesc)
174
   
172
            os.close(indesc)
175
    inf.close()
173
           
176
 
174
            dlgargs = [self.dlgcmd,'--title',self.title,
177
def yes_no(default):
175
                       '--backtitle', self.backtitle]
178
    "Return '*' if yes, ' ' if no"
176
            for key,val in kw.items():
179
   
177
                dlgargs.append('--'+key)
180
    if (default == 'y'):
178
                dlgargs.append(val)
181
        return '*'
179
            dlgargs += args            
182
   
180
            os.execlp(self.dlgcmd,*dlgargs)
183
    return ' '
181
 
184
 
182
        os.close(outdesc)
185
def subchoice(screen, name, choices, default):
183
       
186
    "Return choice of choices"
184
        try:
187
   
185
            errout = os.fdopen(indesc,'r')
188
    maxkey = 0
186
            data = errout.read()
189
    for key, val in choices:
187
            errout.close()
190
        length = len(key)
188
            pid,status = os.wait()
191
        if (length > maxkey):
189
        except:
192
            maxkey = length
190
            os.system('reset') # Reset terminal
193
   
191
            raise
194
    options = []
192
       
195
    position = None
193
        if not os.WIFEXITED(status):
196
    cnt = 0
194
            os.system('reset') # Reset terminal
197
    for key, val in choices:
195
            raise EOFError
198
        if ((default) and (key == default)):
196
       
199
            position = cnt
197
        status = os.WEXITSTATUS(status)
200
       
198
        if status == 255:
201
        options.append(" %-*s  %s " % (maxkey, key, val))
199
            raise EOFError
202
        cnt += 1
200
        return status,data
203
   
201
       
204
    (button, value) = xtui.choice_window(screen, name, 'Choose value', options, position)
202
    def yesno(self, text, default=None):
205
   
203
        if text[-1] not in ('?',':'):
206
    if (button == 'cancel'):
204
            text = text + ':'
207
        return None
205
        width = '50'
208
   
206
        height = '5'
209
    return choices[value][0]
207
        if len(text) < 48:
210
 
208
            text = ' '*int(((48-len(text))/2)) + text
211
def check_choices(defaults, ask_names):
209
        else:
212
    "Check whether all accessible variables have a default"
210
            width = '0'
213
   
211
            height = '0'
214
    for varname, vartype, name, choices, cond in ask_names:
212
        if default == 'n':
215
        if ((cond) and (not check_condition(cond, defaults, ask_names))):
213
            res,data = self.calldlg('--defaultno','--yesno',text,height,width)
216
            continue
214
        else:
217
       
215
            res,data = self.calldlg('--yesno',text,height,width)
218
        if (not defaults.has_key(varname)):
216
 
219
            return False
217
        if res == 0:
220
   
218
            return 'y'
221
    return True
219
        return 'n'
222
 
220
    yesno = eof_checker(yesno)
223
def create_output(mkname, mcname, dfname, defaults, ask_names):
221
 
224
    "Create output configuration"
222
    def menu(self, text, choices, button, defopt=None):
225
   
223
        self.title = 'Main menu'
226
    revision = commands.getoutput('svnversion . 2> /dev/null')
224
        text = text + ':'
227
    timestamp = commands.getoutput('date "+%Y-%m-%d %H:%M:%S"')
225
        width = '70'
228
   
226
        height = str(8 + len(choices))
229
    outmk = file(mkname, 'w')
227
        args = []
230
    outmc = file(mcname, 'w')
228
        for key,val in choices:
231
    outdf = file(dfname, 'w')
229
            args.append(key)
232
   
230
            args.append(val)
233
    outmk.write('#########################################\n')
231
 
234
    outmk.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n')
232
        kw = {}
235
    outmk.write('#########################################\n\n')
233
        if defopt:
236
   
234
            kw['default-item'] = choices[defopt][0]
237
    outmc.write('/***************************************\n')
235
        res,data = self.calldlg('--ok-label','Change',
238
    outmc.write(' * AUTO-GENERATED FILE, DO NOT EDIT!!! *\n')
236
                                '--extra-label',button[1],
239
    outmc.write(' ***************************************/\n\n')
237
                                '--extra-button',
240
   
238
                                '--menu',text,height,width,
241
    outdf.write('#########################################\n')
239
                                str(len(choices)),*args,**kw)
242
    outdf.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n')
240
        if res == 3:
243
    outdf.write('#########################################\n\n')
241
            return button[0]
244
    outdf.write('CONFIG_DEFS =')
242
        if res == 1: # Cancel
245
   
243
            sys.exit(1)
246
    for varname, vartype, name, choices, cond in ask_names:
244
        elif res:
247
        if ((cond) and (not check_condition(cond, defaults, ask_names))):
245
            print data
248
            continue
246
            raise EOFError
249
       
247
        return data
250
        if (not defaults.has_key(varname)):
248
    menu = eof_checker(menu)
251
            default = ''
249
   
252
        else:
250
    def choice(self, text, choices, defopt=None):
253
            default = defaults[varname]
251
        text = text + ':'
254
            if (default == '*'):
252
        width = '50'
255
                default = 'y'
253
        height = str(8 + len(choices))
256
       
254
        args = []
257
        outmk.write('# %s\n%s = %s\n\n' % (name, varname, default))
255
        for key,val in choices:
258
       
256
            args.append(key)
259
        if ((vartype == "y") or (vartype == "y/n") or (vartype == "n/y")):
257
            args.append(val)
260
            if (default == "y"):
258
 
261
                outmc.write('/* %s */\n#define %s\n\n' % (name, varname))
259
        kw = {}
262
                outdf.write(' -D%s' % varname)
260
        if defopt:
263
        else:
261
            kw['default-item'] = choices[defopt][0]
264
            outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, default, varname, default))
262
        res,data = self.calldlg('--nocancel','--menu',text,height,width,
265
            outdf.write(' -D%s=%s -D%s_%s' % (varname, default, varname, default))
263
                                str(len(choices)),*args, **kw)
266
   
264
        if res:
267
    outmk.write('REVISION = %s\n' % revision)
265
            print data
268
    outmk.write('TIMESTAMP = %s\n' % timestamp)
266
            raise EOFError
269
   
267
        return data
270
    outmc.write('#define REVISION %s\n' % revision)
268
    choice = eof_checker(choice)
271
    outmc.write('#define TIMESTAMP %s\n' % timestamp)
269
   
272
   
270
def read_defaults(fname,defaults):
273
    outdf.write(' "-DREVISION=%s" "-DTIMESTAMP=%s"\n' % (revision, timestamp))
271
    "Read saved values from last configuration run"
274
   
272
    f = file(fname,'r')
275
    outmk.close()
273
    for line in f:
276
    outmc.close()
274
        res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line)
277
    outdf.close()
275
        if res:
-
 
276
            defaults[res.group(1)] = res.group(2)
-
 
277
    f.close()
-
 
278
 
-
 
279
def check_condition(text, defaults, asked_names):
-
 
280
    seen_vars = [ x[0] for x in asked_names ]
-
 
281
    ctype = 'cnf'
-
 
282
    if ')|' in text or '|(' in text:
-
 
283
        ctype = 'dnf'
-
 
284
   
-
 
285
    if ctype == 'cnf':
-
 
286
        conds = text.split('&')
-
 
287
    else:
-
 
288
        conds = text.split('|')
-
 
289
 
-
 
290
    for cond in conds:
-
 
291
        if cond.startswith('(') and cond.endswith(')'):
-
 
292
            cond = cond[1:-1]
-
 
293
           
-
 
294
        inside = check_inside(cond, defaults, ctype, seen_vars)
-
 
295
       
-
 
296
        if ctype == 'cnf' and not inside:
-
 
297
            return False
-
 
298
        if ctype == 'dnf' and inside:
-
 
299
            return True
-
 
300
 
-
 
301
    if ctype == 'cnf':
-
 
302
        return True
-
 
303
    return False
-
 
304
 
-
 
305
def check_inside(text, defaults, ctype, seen_vars):
-
 
306
    """
-
 
307
    Check that the condition specified on input line is True
-
 
308
 
-
 
309
    only CNF is supported
-
 
310
    """
-
 
311
    if ctype == 'cnf':
-
 
312
        conds = text.split('|')
-
 
313
    else:
-
 
314
        conds = text.split('&')
-
 
315
    for cond in conds:
-
 
316
        res = re.match(r'^(.*?)(!?=)(.*)$', cond)
-
 
317
        if not res:
-
 
318
            raise RuntimeError("Invalid condition: %s" % cond)
-
 
319
        condname = res.group(1)
-
 
320
        oper = res.group(2)
-
 
321
        condval = res.group(3)
-
 
322
        if condname not in seen_vars:
-
 
323
            varval = ''
-
 
324
##             raise RuntimeError("Variable %s not defined before being asked." %\
-
 
325
##                                condname)
-
 
326
        elif not defaults.has_key(condname):
-
 
327
            raise RuntimeError("Condition var %s does not exist: %s" % \
-
 
328
                               (condname,text))
-
 
329
        else:
-
 
330
            varval = defaults[condname]
-
 
331
        if ctype == 'cnf':
-
 
332
            if oper == '=' and  condval == varval:
-
 
333
                return True
-
 
334
            if oper == '!=' and condval != varval:
-
 
335
                return True
-
 
336
        else:
-
 
337
            if oper== '=' and condval != varval:
-
 
338
                return False
-
 
339
            if oper== '!=' and condval == varval:
-
 
340
                return False
-
 
341
    if ctype=='cnf':
-
 
342
        return False
-
 
343
    return True
-
 
344
 
-
 
345
def parse_config(input, output, dlg, defaults={}, askonly=None):
-
 
346
    "Parse configuration file and create Makefile.config on the fly"
-
 
347
    def ask_the_question(dialog):
-
 
348
        "Ask question based on the type of variables to ask"
-
 
349
        # This is quite a hack, this thingy is written just to
-
 
350
        # have access to local variables..
-
 
351
        if vartype == 'y/n':
-
 
352
            return dialog.yesno(comment, default)
-
 
353
        elif vartype == 'n/y':
-
 
354
            return dialog.noyes(comment, default)
-
 
355
        elif vartype == 'choice':
-
 
356
            defopt = None
-
 
357
            if default is not None:
-
 
358
                for i,(key,val) in enumerate(choices):
-
 
359
                    if key == default:
-
 
360
                        defopt = i
-
 
361
                        break
-
 
362
            return dialog.choice(comment, choices, defopt)
-
 
363
        else:
-
 
364
            raise RuntimeError("Bad method: %s" % vartype)
-
 
365
 
-
 
366
   
-
 
367
    f = file(input, 'r')
-
 
368
    outf = file(output, 'w')
-
 
369
 
-
 
370
    outf.write('#########################################\n')
-
 
371
    outf.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n')
-
 
372
    outf.write('#########################################\n\n')
-
 
373
 
-
 
374
    asked_names = []
-
 
375
 
-
 
376
    comment = ''
-
 
377
    default = None
-
 
378
    choices = []
-
 
379
    for line in f:
-
 
380
        if line.startswith('%'):
-
 
381
            res = re.match(r'^%\s*(?:\[(.*?)\])?\s*(.*)$', line)
-
 
382
            if not res:
-
 
383
                raise RuntimeError('Invalid command: %s' % line)
-
 
384
            if res.group(1):
-
 
385
                if not check_condition(res.group(1), defaults,
-
 
386
                                       asked_names):
-
 
387
                    continue
-
 
388
            args = res.group(2).strip().split(' ')
-
 
389
            cmd = args[0].lower()
-
 
390
            args = args[1:]
-
 
391
            if cmd == 'saveas':
-
 
392
                outf.write('%s = %s\n' % (args[1],defaults[args[0]]))
-
 
393
            elif cmd == 'shellcmd':
-
 
394
                varname = args[0]
-
 
395
                args = args[1:]
-
 
396
                for i,arg in enumerate(args):
-
 
397
                    if arg.startswith('$'):
-
 
398
                        args[i] = defaults[arg[1:]]
-
 
399
                data,status = commands.getstatusoutput(' '.join(args))
-
 
400
                if status:
-
 
401
                    raise RuntimeError('Error running: %s' % ' '.join(args))
-
 
402
                outf.write('%s = %s\n' % (varname,data.strip()))
-
 
403
            continue
-
 
404
           
-
 
405
        if line.startswith('!'):
-
 
406
            # Ask a question
-
 
407
            res = re.search(r'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line)
-
 
408
            if not res:
-
 
409
                raise RuntimeError("Weird line: %s" % line)
-
 
410
            varname = res.group(2)
-
 
411
            vartype = res.group(3)
-
 
412
 
-
 
413
            default = defaults.get(varname,None)
-
 
414
           
-
 
415
            if res.group(1):
-
 
416
                if not check_condition(res.group(1), defaults,
-
 
417
                                       asked_names):
-
 
418
                    if default is not None:
-
 
419
                        outf.write('#!# %s = %s\n' % (varname, default))
-
 
420
                    # Clear cumulated values
-
 
421
                    comment = ''
-
 
422
                    default = None
-
 
423
                    choices = []
-
 
424
                    continue
-
 
425
               
-
 
426
            asked_names.append((varname,comment))
-
 
427
 
-
 
428
            if default is None or not askonly or askonly == varname:
-
 
429
                default = ask_the_question(dlg)
-
 
430
            else:
-
 
431
                default = ask_the_question(DefaultDialog(dlg))
-
 
432
 
-
 
433
            outf.write('%s = %s\n' % (varname, default))
-
 
434
            # Remeber the selected value
-
 
435
            defaults[varname] = default
-
 
436
            # Clear cumulated values
-
 
437
            comment = ''
-
 
438
            default = None
-
 
439
            choices = []
-
 
440
            continue
-
 
441
       
-
 
442
        if line.startswith('@'):
-
 
443
            # Add new line into the 'choice array' 
-
 
444
            res = re.match(r'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line)
-
 
445
            if not res:
-
 
446
                raise RuntimeError("Bad line: %s" % line)
-
 
447
            if res.group(1):
-
 
448
                if not check_condition(res.group(1),defaults,
-
 
449
                                       asked_names):
-
 
450
                    continue
-
 
451
            choices.append((res.group(2), res.group(3)))
-
 
452
            continue
-
 
453
 
-
 
454
        # All other things print to output file
-
 
455
        outf.write(line)
-
 
456
        if re.match(r'^#[^#]', line):
-
 
457
            # Last comment before question will be displayed to the user
-
 
458
            comment = line[1:].strip()
-
 
459
        elif line.startswith('## '):
-
 
460
            # Set title of the dialog window
-
 
461
            dlg.set_title(line[2:].strip())
-
 
462
 
-
 
463
    outf.write('\n')
-
 
464
    outf.write('REVISION = %s\n' % commands.getoutput('svnversion . 2> /dev/null'))
-
 
465
    outf.write('TIMESTAMP = %s\n' % commands.getoutput('date "+%Y-%m-%d %H:%M:%S"'))
-
 
466
    outf.close()
-
 
467
    f.close()
-
 
468
    return asked_names
-
 
469
 
278
 
470
def main():
279
def main():
471
    defaults = {}
280
    defaults = {}
472
    try:
-
 
473
        dlg = Dialog()
281
    ask_names = []
474
    except NotImplementedError:
-
 
475
        dlg = NoDialog()
-
 
476
 
282
   
477
    if len(sys.argv) >= 3 and sys.argv[2]=='default':
-
 
478
        defmode = True
283
    # Parse configuration file
479
    else:
-
 
480
        defmode = False
284
    parse_config(INPUT, ask_names)
481
 
285
   
482
    # Default run will update the configuration file
-
 
483
    # with newest options
286
    # Read defaults from previous run
484
    if os.path.exists(OUTPUT):
287
    if os.path.exists(MAKEFILE):
485
        read_defaults(OUTPUT, defaults)
288
        read_defaults(MAKEFILE, defaults)
486
 
289
   
487
    # Get ARCH from command line if specified
290
    # Default mode: only check defaults and regenerate configuration
488
    if len(sys.argv) >= 4:
291
    if ((len(sys.argv) >= 3) and (sys.argv[2] == 'default')):
489
        defaults['ARCH'] = sys.argv[3]
292
        if (check_choices(defaults, ask_names)):
490
        defaults['PLATFORM'] = sys.argv[3]
293
            create_output(MAKEFILE, MACROS, DEFS, defaults, ask_names)
-
 
294
            return 0
491
   
295
   
492
    # Get COMPILER from command line if specified
296
    # Check mode: only check defaults
493
    if len(sys.argv) >= 5:
297
    if ((len(sys.argv) >= 3) and (sys.argv[2] == 'check')):
494
        defaults['COMPILER'] = sys.argv[4]
298
        if (check_choices(defaults, ask_names)):
-
 
299
            return 0
-
 
300
        return 1
495
   
301
   
-
 
302
    screen = xtui.screen_init()
-
 
303
    try:
-
 
304
        selname = None
-
 
305
        while True:
-
 
306
           
496
    # Get CONFIG_DEBUG from command line if specified
307
            # Cancel out all defaults which have to be deduced
497
    if len(sys.argv) >= 6:
308
            for varname, vartype, name, choices, cond in ask_names:
-
 
309
                if ((vartype == 'y') and (defaults.has_key(varname)) and (defaults[varname] == '*')):
498
        defaults['CONFIG_DEBUG'] = sys.argv[5]
310
                    defaults[varname] = None
499
   
311
           
-
 
312
            options = []
-
 
313
            opt2row = {}
-
 
314
            position = None
-
 
315
            cnt = 0
500
    # Get MACHINE/IMAGE from command line if specified
316
            for varname, vartype, name, choices, cond in ask_names:
-
 
317
               
-
 
318
                if ((cond) and (not check_condition(cond, defaults, ask_names))):
-
 
319
                    continue
-
 
320
               
501
    if len(sys.argv) >= 7:
321
                if (varname == selname):
-
 
322
                    position = cnt
-
 
323
               
502
        defaults['MACHINE'] = sys.argv[6]
324
                if (not defaults.has_key(varname)):
-
 
325
                    default = None
-
 
326
                else:
503
        defaults['IMAGE'] = sys.argv[6]
327
                    default = defaults[varname]
504
 
328
               
505
    # Dry run only with defaults
329
                if (vartype == 'choice'):
506
    varnames = parse_config(INPUT, TMPOUTPUT, DefaultDialog(dlg), defaults)
330
                    # Check if the default is an acceptable value
507
    # If not in default mode, present selection of all possibilities
331
                    if ((default) and (not default in [choice[0] for choice in choices])):
508
    if not defmode:
332
                        default = None
-
 
333
                        defaults.pop(varname)
-
 
334
                   
509
        defopt = 0
335
                    # If there is just one option, use it
510
        while 1:
336
                    if (len(choices) == 1):
511
            # varnames contains variable names that were in the
337
                        defaults[varname] = choices[0][0]
-
 
338
                        continue
-
 
339
                   
512
            # last question set
340
                    if (default == None):
513
            choices = [ (x[1],defaults[x[0]]) for x in varnames ]
341
                        options.append("?     %s --> " % name)
-
 
342
                    else:
514
            res = dlg.menu('Configuration',choices,('save','Save'),defopt)
343
                        options.append("      %s [%s] --> " % (name, default))
-
 
344
                elif (vartype == 'y'):
-
 
345
                    defaults[varname] = '*'
-
 
346
                    continue
515
            if res == 'save':
347
                elif (vartype == 'y/n'):
-
 
348
                    if (default == None):
-
 
349
                        default = 'y'
-
 
350
                        defaults[varname] = default
516
                parse_config(INPUT, TMPOUTPUT, DefaultDialog(dlg), defaults)
351
                    options.append("  <%s> %s " % (yes_no(default), name))
-
 
352
                elif (vartype == 'n/y'):
517
                break
353
                    if (default == None):
-
 
354
                        default = 'n'
-
 
355
                        defaults[varname] = default
518
            # transfer description back to varname
356
                    options.append("  <%s> %s " % (yes_no(default), name))
-
 
357
                else:
-
 
358
                    raise RuntimeError("Unknown variable type: %s" % vartype)
-
 
359
               
519
            for i,(vname,descr) in enumerate(varnames):
360
                opt2row[cnt] = (varname, vartype, name, choices)
-
 
361
               
-
 
362
                cnt += 1
-
 
363
           
-
 
364
            (button, value) = xtui.choice_window(screen, 'HelenOS configuration', 'Choose configuration option', options, position)
-
 
365
           
520
                if res == descr:
366
            if (button == 'cancel'):
521
                    defopt = i
367
                return 'Configuration canceled'
-
 
368
           
522
                    break
369
            if (not opt2row.has_key(value)):
523
            # Ask the user a simple question, produce output
370
                raise RuntimeError("Error selecting value: %s" % value)
-
 
371
           
524
            # as if the user answered all the other questions
372
            (selname, seltype, name, choices) = opt2row[value]
-
 
373
           
-
 
374
            if (not defaults.has_key(selname)):
-
 
375
                    default = None
-
 
376
            else:
525
            # with default answer
377
                default = defaults[selname]
-
 
378
           
526
            varnames = parse_config(INPUT, TMPOUTPUT, dlg, defaults,
379
            if (button == 'done'):
527
                                    askonly=varnames[i][0])
380
                if (check_choices(defaults, ask_names)):
-
 
381
                    break
528
       
382
                else:
-
 
383
                    xtui.error_dialog(screen, 'Error', 'Some options have still undefined values. These options are marked with the "?" sign.')
-
 
384
                    continue
529
   
385
           
530
    if os.path.exists(OUTPUT):
386
            if (seltype == 'choice'):
-
 
387
                defaults[selname] = subchoice(screen, name, choices, default)
-
 
388
            elif ((seltype == 'y/n') or (seltype == 'n/y')):
531
        os.unlink(OUTPUT)
389
                if (defaults[selname] == 'y'):
532
    os.rename(TMPOUTPUT, OUTPUT)
390
                    defaults[selname] = 'n'
533
   
391
                else:
534
    if not defmode and dlg.yesno('Rebuild everything?') == 'y':
392
                    defaults[selname] = 'y'
-
 
393
    finally:
-
 
394
        xtui.screen_done(screen)
-
 
395
   
535
        os.execlp('make','make','clean','build')
396
    create_output(MAKEFILE, MACROS, DEFS, defaults, ask_names)
-
 
397
    return 0
536
 
398
 
537
if __name__ == '__main__':
399
if __name__ == '__main__':
538
    main()
400
    sys.exit(main())