Subversion Repositories HelenOS

Rev

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