Subversion Repositories HelenOS

Rev

Rev 3386 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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