Subversion Repositories HelenOS

Rev

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