Subversion Repositories HelenOS

Rev

Rev 3017 | Rev 3804 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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