source: rtems-source-builder/source-builder/sb/config.py @ e5aa419d

5
Last change on this file since e5aa419d was e5aa419d, checked in by Ricardo Cárdenes <rcardenes@…>, on Mar 11, 2021 at 7:32:08 AM

sb/config.py: Fix operator reconstruction

Close #4337

  • Property mode set to 100644
File size: 55.8 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2018 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Permission to use, copy, modify, and/or distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#
21# This code is based on a tool I wrote to parse RPM spec files in the RTEMS
22# project. This is now a configuration file format that has moved away from the
23# spec file format to support the specific needs of cross-compiling GCC. This
24# module parses a configuration file into Python data types that can be used by
25# other software modules.
26#
27
28from __future__ import print_function
29
30import copy
31from functools import reduce
32import os
33import re
34import sys
35
36try:
37    import error
38    import execute
39    import log
40    import options
41    import path
42    import pkgconfig
43    import sources
44except KeyboardInterrupt:
45    print('user terminated', file = sys.stderr)
46    sys.exit(1)
47except:
48    print('error: unknown application load error', file = sys.stderr)
49    sys.exit(1)
50
51def _check_bool(value):
52    istrue = None
53    if value.isdigit():
54        if int(value) == 0:
55            istrue = False
56        else:
57            istrue = True
58    else:
59        if type(value) is str and len(value) == 2 and value[0] == '!':
60            istrue = _check_bool(value[1])
61            if type(istrue) is bool:
62                istrue = not istrue
63    return istrue
64
65def _check_nil(value):
66    if len(value):
67        istrue = True
68    else:
69        istrue = False
70    return istrue
71
72class package:
73
74    def __init__(self, name, arch, config):
75        self._name = name
76        self._arch = arch
77        self.config = config
78        self.directives = {}
79        self.infos = {}
80        self.sizes = {}
81
82    def __str__(self):
83
84        def _dictlist(dl):
85            s = ''
86            dll = list(dl.keys())
87            dll.sort()
88            for d in dll:
89                if d:
90                    s += '  ' + d + ':\n'
91                    for l in dl[d]:
92                        s += '    ' + l + '\n'
93            return s
94
95        s = '\npackage: ' + self._name + \
96            '\n directives:\n' + _dictlist(self.directives) + \
97            '\n infos:\n' + _dictlist(self.infos)
98
99        return s
100
101    def _macro_override(self, info, macro):
102        '''See if a macro overrides this setting.'''
103        overridden = self.config.macros.overridden(macro)
104        if overridden:
105            return self.config.macros.expand(macro)
106        return info
107
108    def directive_extend(self, dir, data):
109        if dir not in self.directives:
110            self.directives[dir] = []
111        for i in range(0, len(data)):
112            data[i] = data[i].strip()
113        self.directives[dir].extend(data)
114        self.config.macros[dir] = '\n'.join(self.directives[dir])
115
116    def info_append(self, info, data):
117        if info not in self.infos:
118            self.infos[info] = []
119        self.infos[info].append(data)
120        self.config.macros[info] = '\n'.join(self.infos[info])
121
122    def get_info(self, info, expand = True):
123        if info in self.config.macros:
124            _info = self.config.macros[info].split('\n')
125            if expand:
126                return self.config.expand(_info)
127            else:
128                return _info
129        return None
130
131    def extract_info(self, label, expand = True):
132        ll = label.lower()
133        infos = {}
134        keys = self.config.macros.find('%s.*' % (ll))
135        for k in keys:
136            if k == ll:
137                k = '%s0' % (ll)
138            elif not k[len(ll):].isdigit():
139                continue
140            infos[k] = [self.config.expand(self.config.macros[k])]
141        return infos
142
143    def _find_macro(self, label, expand = True):
144        if label in self.config.macros:
145            macro = self.config.macros[label].split('\n')
146            if expand:
147                return self.config.expand(macro)
148            else:
149                return macro
150        return None
151
152    def find_info(self, label, expand = True):
153        return self._find_macro(label, expand)
154
155    def find_directive(self, label, expand = True):
156        return self._find_macro(label, expand)
157
158    def name(self):
159        info = self.find_info('name')
160        if info:
161            n = info[0]
162        else:
163            n = self._name
164        return self._macro_override(n, 'name')
165
166    def summary(self):
167        info = self.find_info('summary')
168        if info:
169            return info[0]
170        return ''
171
172    def url(self):
173        info = self.find_info('url')
174        if info:
175            return info[0]
176        return ''
177
178    def version(self):
179        info = self.find_info('version')
180        if not info:
181            return None
182        return info[0]
183
184    def release(self):
185        info = self.find_info('release')
186        if not info:
187            return None
188        return info[0]
189
190    def buildarch(self):
191        info = self.find_info('buildarch')
192        if not info:
193            return self._arch
194        return info[0]
195
196    def sources(self):
197        return self.extract_info('source')
198
199    def patches(self):
200        return self.extract_info('patch')
201
202    def prep(self):
203        return self.find_directive('%prep')
204
205    def build(self):
206        return self.find_directive('%build')
207
208    def install(self):
209        return self.find_directive('%install')
210
211    def clean(self):
212        return self.find_directive('%clean')
213
214    def include(self):
215        return self.find_directive('%include')
216
217    def testing(self):
218        return self.find_directive('%testing')
219
220    def long_name(self):
221        return self.name()
222
223    def disabled(self):
224        return len(self.name()) == 0
225
226    def set_size(self, what, path_):
227        if what not in self.sizes:
228            self.sizes[what] = 0
229        self.sizes[what] += path.get_size(path_)
230
231    def get_size(self, what):
232        if what in self.sizes:
233            return self.sizes[what]
234        return 0
235
236class file:
237    """Parse a config file."""
238
239    _directive = [ '%include',
240                   '%description',
241                   '%prep',
242                   '%build',
243                   '%clean',
244                   '%install',
245                   '%testing' ]
246
247    _ignore = [ re.compile('%setup'),
248                re.compile('%configure'),
249                re.compile('%source'),
250                re.compile('%patch'),
251                re.compile('%hash'),
252                re.compile('%select'),
253                re.compile('%disable') ]
254
255    def __init__(self, name, opts, macros = None):
256        log.trace('config: %s: initialising' % (name))
257        self.opts = opts
258        self.init_name = name
259        self.wss = re.compile(r'\s+')
260        self.tags = re.compile(r':+')
261        self.sf = re.compile(r'%\([^\)]+\)')
262        self.set_macros(macros)
263        self._reset(name)
264        self.load(name)
265
266    def __str__(self):
267
268        def _dict(dd):
269            s = ''
270            ddl = list(dd.keys())
271            ddl.sort()
272            for d in ddl:
273                s += '  ' + d + ': ' + dd[d] + '\n'
274            return s
275
276        s = 'config: %s' % ('.'.join(self.configpath)) + \
277            '\n' + str(self.opts) + \
278            '\nlines parsed: %d' % (self.lc) + \
279            '\nname: ' + self.name + \
280            '\nmacros:\n' + str(self.macros)
281        for _package in self._packages:
282            s += str(self._packages[_package])
283        return s
284
285    def _reset(self, name):
286        self.name = name
287        self.load_depth = 0
288        self.configpath = []
289        self._includes = []
290        self._packages = {}
291        self.in_error = False
292        self.lc = 0
293        self.if_depth = 0
294        self.conditionals = {}
295        self._packages = {}
296        self.package = 'main'
297        self.disable_macro_reassign = False
298        self.pkgconfig_prefix = None
299        self.pkgconfig_crosscompile = False
300        self.pkgconfig_filter_flags = False
301        for arg in self.opts.args:
302            if arg.startswith('--with-') or arg.startswith('--without-'):
303                if '=' in arg:
304                    label, value = arg.split('=', 1)
305                else:
306                    label = arg
307                    value = None
308                label = label[2:].lower().replace('-', '_')
309                if value:
310                    self.macros.define(label, value)
311                else:
312                    self.macros.define(label)
313
314    def _relative_path(self, p):
315        sbdir = None
316        if '_sbdir' in self.macros:
317            sbdir = path.dirname(self.expand('%{_sbdir}'))
318            if p.startswith(sbdir):
319                p = p[len(sbdir) + 1:]
320        return p
321
322    def _name_line_msg(self,  msg):
323        return '%s:%d: %s' % (path.basename(self.name), self.lc,  msg)
324
325    def _output(self, text):
326        if not self.opts.quiet():
327            log.output(text)
328
329    def _error(self, msg):
330        if not self.opts.dry_run():
331            if self.opts.keep_going():
332                err = 'error: %s' % (self._name_line_msg(msg))
333                log.stderr(err)
334                log.output(err)
335                self.in_error = True
336                log.stderr('warning: switched to dry run due to errors')
337                self.opts.set_dry_run()
338        raise error.general(self._name_line_msg(msg))
339
340    def _label(self, name):
341        if name.startswith('%{') and name[-1] == '}':
342            return name
343        return '%{' + name.lower() + '}'
344
345    def _cross_compile(self):
346        _host = self.expand('%{_host}')
347        _build = self.expand('%{_build}')
348        return _host != _build
349
350    def _candian_cross_compile(self):
351        _host = self.expand('%{_host}')
352        _build = self.expand('%{_build}')
353        _target = self.expand('%{_target}')
354        _alloc_cxc = self.defined('%{allow_cxc}')
355        return _alloc_cxc and _host != _build and _host != _target
356
357    def _macro_split(self, s):
358        '''Split the string (s) up by macros. Only split on the
359           outter level. Nested levels will need to split with futher calls.'''
360        trace_me = False
361        if trace_me:
362            print('------------------------------------------------------')
363        macros = []
364        nesting = []
365        has_braces = False
366        c = 0
367        while c < len(s):
368            if trace_me:
369                print('ms:', c, '"' + s[c:] + '"', has_braces, len(nesting), nesting)
370            #
371            # We need to watch for shell type variables or the form '${var}' because
372            # they can upset the brace matching.
373            #
374            if s[c] == '%' or s[c] == '$':
375                start = s[c]
376                c += 1
377                if c == len(s):
378                    continue
379                #
380                # Do we have '%%' or '%(' or '$%' or '$(' or not '${' ?
381                #
382                if s[c] == '%' or s[c] == '(' or (start == '$' and s[c] != '{'):
383                    continue
384                elif not s[c].isspace():
385                    #
386                    # If this is a shell macro and we are at the outter
387                    # level or is '$var' forget it and move on.
388                    #
389                    if start == '$' and (s[c] != '{' or len(nesting) == 0):
390                        continue
391                    if s[c] == '{':
392                        this_has_braces = True
393                    else:
394                        this_has_braces = False
395                    nesting.append((c - 1, has_braces))
396                    has_braces = this_has_braces
397            elif len(nesting) > 0:
398                if s[c] == '}' or (s[c].isspace() and not has_braces):
399                    #
400                    # Can have '%{?test: something %more}' where the
401                    # nested %more ends with the '}' which also ends
402                    # the outter macro.
403                    #
404                    if not has_braces:
405                        if s[c] == '}':
406                            macro_start, has_braces = nesting[len(nesting) - 1]
407                            nesting = nesting[:-1]
408                            if len(nesting) == 0:
409                                macros.append(s[macro_start:c].strip())
410                    if len(nesting) > 0:
411                        macro_start, has_braces = nesting[len(nesting) - 1]
412                        nesting = nesting[:-1]
413                        if len(nesting) == 0:
414                            macros.append(s[macro_start:c + 1].strip())
415            c += 1
416        if trace_me:
417            print('ms:', macros)
418        if trace_me:
419            print('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=')
420        return macros
421
422    def _shell(self, line, nesting = 0):
423        #
424        # Parse the line and handle nesting '()' pairs. If on Windows
425        # handle embedded '"' (double quotes) as the command is run as
426        # a double quoted string.
427        #
428        def _exec(shell_macro):
429            output = ''
430            if len(shell_macro) > 3:
431                e = execute.capture_execution()
432                if options.host_windows:
433                    shell_cmd = ''.join([c if c != '"' else '\\' + c for c in shell_macro[2:-1]])
434                    cmd = '%s -c "%s"' % (self.macros.expand('%{__sh}'), shell_cmd)
435                else:
436                    cmd = shell_macro[2:-1]
437                exit_code, proc, output = e.shell(cmd)
438                log.trace('shell-output: %d %s' % (exit_code, output))
439                if exit_code != 0:
440                    raise error.general('shell macro failed: %s: %d: %s' % (cmd,
441                                                                            exit_code,
442                                                                            output))
443            return output
444
445        if nesting > 200:
446            raise error.general('shell macro failed: too many nesting levels')
447
448        updating = True
449        while updating:
450            updating = False
451            pos = line.find('%(')
452            if pos >= 0:
453                braces = 0
454                for p in range(pos + 2, len(line)):
455                    if line[p] == '(':
456                        braces += 1
457                    elif line[p] == ')':
458                        if braces > 0:
459                            braces -= 1
460                        else:
461                            shell_cmd = '%(' + self._shell(line[pos + 2:p], nesting + 1) + ')'
462                            line = line[:pos] + _exec(shell_cmd) + line[p + 1:]
463                            updating = True
464                            break
465
466        return line
467
468    def _pkgconfig_check(self, test):
469        # Hack to by pass pkgconfig checks when just wanting to download the
470        # source.
471        if self.macros['_dry_run'] == '1' and \
472           ('with_download' in self.macros and self.macros['with_download'] == '1'):
473            return '0'
474        ok = False
475        log.trace('pkgconfig: check: crossc=%d pkg_crossc=%d prefix=%s' % ( self._cross_compile(),
476                                                                            self.pkgconfig_crosscompile,
477                                                                            self.pkgconfig_prefix))
478        log.trace('pkgconfig: check: test=%s' % (test))
479        if type(test) == str:
480            test = test.split()
481        if not self._cross_compile() or self.pkgconfig_crosscompile:
482            try:
483                pkg = pkgconfig.package(test[0],
484                                        prefix = self.pkgconfig_prefix,
485                                        output = self._output,
486                                        src = log.trace)
487                if len(test) != 1 and len(test) != 3:
488                    self._error('malformed check: %s' % (' '.join(test)))
489                else:
490                    op = '>='
491                    ver = '0'
492                    if len(test) == 3:
493                        op = test[1]
494                        ver = self.macros.expand(test[2])
495                    ok = pkg.check(op, ver)
496            except pkgconfig.error as pe:
497                self._error('pkgconfig: check: %s' % (pe))
498            except:
499                raise error.internal('pkgconfig failure')
500        if ok:
501            return '1'
502        return '0'
503
504    def _pkgconfig_flags(self, package, flags):
505        pkg_flags = None
506        if not self._cross_compile() or self.pkgconfig_crosscompile:
507            try:
508                pkg = pkgconfig.package(package,
509                                        prefix = self.pkgconfig_prefix,
510                                        output = self._output,
511                                        src = log.trace)
512                pkg_flags = pkg.get(flags)
513                if pkg_flags and self.pkgconfig_filter_flags:
514                    fflags = []
515                    for f in pkg_flags.split():
516                        if not f.startswith('-W'):
517                            fflags += [f]
518                    pkg_flags = ' '.join(fflags)
519                log.trace('pkgconfig: %s%s' % (flags, pkg_flags))
520            except pkgconfig.error as pe:
521                self._error('pkgconfig: %s%s' % (flags, pe))
522            except:
523                raise error.internal('pkgconfig failure')
524        if pkg_flags is None:
525            pkg_flags = ''
526        return pkg_flags
527
528    def _pkgconfig(self, pcl):
529        ok = False
530        ps = ''
531        if pcl[0] == 'check':
532            ps = self._pkgconfig_check(pcl[1:])
533        elif pcl[0] == 'prefix':
534            if len(pcl) == 2:
535                self.pkgconfig_prefix = pcl[1]
536            else:
537                self._error('prefix error: %s' % (' '.join(pcl)))
538        elif pcl[0] == 'crosscompile':
539            ok = True
540            if len(pcl) == 2:
541                if pcl[1].lower() == 'yes':
542                    self.pkgconfig_crosscompile = True
543                elif pcl[1].lower() == 'no':
544                    self.pkgconfig_crosscompile = False
545                else:
546                    ok = False
547            else:
548                ok = False
549            if not ok:
550                self._error('crosscompile error: %s' % (' '.join(pcl)))
551        elif pcl[0] == 'filter-flags':
552            ok = True
553            if len(pcl) == 2:
554                if pcl[1].lower() == 'yes':
555                    self.pkgconfig_filter_flags = True
556                elif pcl[1].lower() == 'no':
557                    self.pkgconfig_filter_flags = False
558                else:
559                    ok = False
560            else:
561                ok = False
562            if not ok:
563                self._error('crosscompile error: %s' % (' '.join(pcl)))
564        elif pcl[0] in ['ccflags', 'cflags', 'ldflags', 'libs']:
565            ps = self._pkgconfig_flags(pcl[1], pcl[0])
566        else:
567            self._error('pkgconfig error: %s' % (' '.join(pcl)))
568        return ps
569
570    def _expand(self, s):
571        expand_count = 0
572        expanded = True
573        while expanded:
574            expand_count += 1
575            if expand_count > 500:
576                raise error.general('macro expand looping: %s' % (s))
577            expanded = False
578            ms = self._macro_split(s)
579            for m in ms:
580                mn = m
581                #
582                # A macro can be '%{macro}' or '%macro'. Turn the later into
583                # the former.
584                #
585                show_warning = True
586                if mn[1] != '{':
587                    for r in self._ignore:
588                        if r.match(mn) is not None:
589                            mn = None
590                            break
591                    else:
592                        mn = self._label(mn[1:])
593                        show_warning = False
594                elif m.startswith('%{expand'):
595                    colon = m.find(':')
596                    if colon < 8:
597                        log.warning(self._name_line_msg('malformed expand macro, no colon found'))
598                    else:
599                        e = self._expand(m[colon + 1:-1].strip())
600                        s = s.replace(m, self._label(e))
601                        expanded = True
602                        mn = None
603                elif m.startswith('%{with '):
604                    #
605                    # Change the ' ' to '_' because the macros have no spaces.
606                    #
607                    n = self._label('with_' + m[7:-1].strip())
608                    if n in self.macros:
609                        s = s.replace(m, '1')
610                    else:
611                        s = s.replace(m, '0')
612                    expanded = True
613                    mn = None
614                elif m.startswith('%{echo'):
615                    if not m.endswith('}'):
616                        log.warning(self._name_line_msg("malformed conditional macro '%s'" % (m)))
617                        mn = None
618                    else:
619                        e = self._expand(m[6:-1].strip())
620                        log.notice('%s' % (self._name_line_msg(e)))
621                        s = ''
622                        expanded = True
623                        mn = None
624                elif m.startswith('%{defined'):
625                    n = self._label(m[9:-1].strip())
626                    if n in self.macros:
627                        s = s.replace(m, '1')
628                    else:
629                        s = s.replace(m, '0')
630                    expanded = True
631                    mn = None
632                elif m.startswith('%{!defined'):
633                    n = self._label(m[10:-1].strip())
634                    if n in self.macros:
635                        s = s.replace(m, '0')
636                    else:
637                        s = s.replace(m, '1')
638                    expanded = True
639                    mn = None
640                elif m.startswith('%{triplet'):
641                    triplet = m[len('%{triplet'):-1].strip().split()
642                    ok = False
643                    if len(triplet) == 2:
644                        macro = self._expand(triplet[0])
645                        value = self._expand(triplet[1])
646                        vorig = value
647                        arch_value = ''
648                        vendor_value = ''
649                        os_value = ''
650                        dash = value.find('-')
651                        if dash >= 0:
652                            arch_value = value[:dash]
653                            value = value[dash + 1:]
654                        dash = value.find('-')
655                        if dash >= 0:
656                            vendor_value = value[:dash]
657                            value = value[dash + 1:]
658                        if len(value):
659                            os_value = value
660                        self.macros[macro] = vorig
661                        self.macros[macro + '_cpu'] = arch_value
662                        self.macros[macro + '_arch'] = arch_value
663                        self.macros[macro + '_vendor'] = vendor_value
664                        self.macros[macro + '_os'] = os_value
665                        ok = True
666                    if ok:
667                        s = s.replace(m, '')
668                    else:
669                        self._error('triplet error: %s' % (' '.join(triplet)))
670                    mn = None
671                elif m.startswith('%{path '):
672                    pl = m[7:-1].strip().split()
673                    ok = False
674                    result = ''
675                    pl_0 = pl[0].lower()
676                    if pl_0 == 'prepend':
677                        if len(pl) == 2:
678                            ok = True
679                            p = ' '.join([self._expand(pp) for pp in pl[1:]])
680                            if len(self.macros['_pathprepend']):
681                                self.macros['_pathprepend'] = \
682                                    '%s:%s' % (p, self.macros['_pathprepend'])
683                            else:
684                                self.macros['_pathprepend'] = p
685                    elif pl_0 == 'postpend':
686                        if len(pl) == 2:
687                            ok = True
688                            p = ' '.join([self._expand(pp) for pp in pl[1:]])
689                            if len(self.macros['_pathprepend']):
690                                self.macros['_pathprepend'] = \
691                                    '%s:%s' % (self.macros['_pathprepend'], p)
692                            else:
693                                self.macros['_pathprepend'] = p
694                    elif pl_0 == 'check':
695                        if len(pl) == 3:
696                            pl_1 = pl[1].lower()
697                            p = ' '.join([self._expand(pp) for pp in pl[2:]])
698                            if pl_1 == 'exists':
699                                ok = True
700                                if path.exists(p):
701                                    result = '1'
702                                else:
703                                    result = '0'
704                            elif pl_1 == 'isdir':
705                                ok = True
706                                if path.isdir(p):
707                                    result = '1'
708                                else:
709                                    result = '0'
710                            elif pl_1 == 'isfile':
711                                ok = True
712                                if path.isfile(p):
713                                    result = '1'
714                                else:
715                                    result = '0'
716                    if ok:
717                        s = s.replace(m, result)
718                    else:
719                        self._error('path error: %s' % (' '.join(pl)))
720                    mn = None
721                elif m.startswith('%{pkgconfig '):
722                    pcl = m[11:-1].strip().split()
723                    if len(pcl):
724                        epcl = []
725                        for pc in pcl:
726                            epcl += [self._expand(pc)]
727                        ps = self._pkgconfig(epcl)
728                        s = s.replace(m, ps)
729                        expanded = True
730                    else:
731                        self._error('pkgconfig error: %s' % (m[11:-1].strip()))
732                    mn = None
733                elif m.startswith('%{?') or m.startswith('%{!?'):
734                    if m[2] == '!':
735                        start = 4
736                    else:
737                        start = 3
738                    colon = m[start:].find(':')
739                    if colon < 0:
740                        if not m.endswith('}'):
741                            log.warning(self._name_line_msg("malformed conditional macro '%s'" % (m)))
742                            mn = None
743                        else:
744                            mn = self._label(m[start:-1])
745                    else:
746                        mn = self._label(m[start:start + colon])
747                    if mn:
748                        if m.startswith('%{?'):
749                            istrue = False
750                            if mn in self.macros:
751                                # If defined and 0 or '' then it is false.
752                                istrue = _check_bool(self.macros[mn])
753                                if istrue is None:
754                                    istrue = _check_nil(self.macros[mn])
755                            if colon >= 0 and istrue:
756                                s = s.replace(m, m[start + colon + 1:-1])
757                                expanded = True
758                                mn = None
759                            elif not istrue:
760                                mn = '%{nil}'
761                        else:
762                            isfalse = True
763                            if mn in self.macros:
764                                istrue = _check_bool(self.macros[mn])
765                                if istrue is None or istrue == True:
766                                    isfalse = False
767                            if colon >= 0 and isfalse:
768                                s = s.replace(m, m[start + colon + 1:-1])
769                                expanded = True
770                                mn = None
771                            else:
772                                mn = '%{nil}'
773                if mn:
774                    if mn.lower() in self.macros:
775                        s = s.replace(m, self.macros[mn.lower()])
776                        expanded = True
777                    elif show_warning:
778                        self._error("macro '%s' not found" % (mn))
779        return self._shell(s)
780
781    def _disable(self, config, ls):
782        if len(ls) != 2:
783            log.warning(self._name_line_msg('invalid disable statement'))
784        else:
785            if ls[1] == 'select':
786                self.macros.lock_read_map()
787                log.trace('config: %s: %3d:  _disable_select: %s' % (self.name, self.lc,
788                                                                     ls[1]))
789            else:
790                log.warning(self._name_line_msg('invalid disable statement: %s' % (ls[1])))
791
792    def _select(self, config, ls):
793        if len(ls) != 2:
794            log.warning(self._name_line_msg('invalid select statement'))
795        else:
796            r = self.macros.set_read_map(ls[1])
797            log.trace('config: %s: %3d:  _select: %s %s %r' % \
798                          (self.name, self.lc,
799                           r, ls[1], self.macros.maps()))
800
801    def _sources(self, ls):
802        return sources.process(ls[0][1:], ls[1:], self.macros, self._error)
803
804    def _hash(self, ls):
805        return sources.hash(ls[1:], self.macros, self._error)
806
807    def _define(self, config, ls):
808        if len(ls) <= 1:
809            log.warning(self._name_line_msg('invalid macro definition'))
810        else:
811            d = self._label(ls[1])
812            if self.disable_macro_reassign:
813                if (d not in self.macros) or \
814                        (d in self.macros and len(self.macros[d]) == 0):
815                    if len(ls) == 2:
816                        self.macros[d] = '1'
817                    else:
818                        self.macros[d] = ' '.join([f.strip() for f in ls[2:]])
819                else:
820                    log.warning(self._name_line_msg("macro '%s' already defined" % (d)))
821            else:
822                if len(ls) == 2:
823                    self.macros[d] = '1'
824                else:
825                    self.macros[d] = ' '.join([f.strip() for f in ls[2:]])
826
827    def _undefine(self, config, ls):
828        if len(ls) <= 1:
829            log.warning(self._name_line_msg('invalid macro definition'))
830        else:
831            mn = self._label(ls[1])
832            if mn in self.macros:
833                del self.macros[mn]
834
835    def _ifs(self, config, ls, label, iftrue, isvalid, dir, info):
836        log.trace('config: %s: %3d:  _ifs[%i]: dir=%s %i %r' % \
837                  (self.name, self.lc, self.if_depth, str(dir), len(ls), ls))
838        in_dir = dir
839        in_iftrue = True
840        data = []
841        while True:
842            if isvalid and \
843                    ((iftrue and in_iftrue) or (not iftrue and not in_iftrue)):
844                this_isvalid = True
845            else:
846                this_isvalid = False
847            r = self._parse(config, dir, info, roc = True, isvalid = this_isvalid)
848            if r[0] == 'package':
849                if this_isvalid:
850                    dir, info, data = self._process_package(r, dir, info, data)
851            elif r[0] == 'control':
852                if r[1] == '%end':
853                    self._error(label + ' without %endif')
854                    raise error.general('terminating build')
855                if r[1] == '%endif':
856                    log.trace('config: %s: %3d:  _ifs[%i]: %%endif: dir=%s %s %s %r' % \
857                              (self.name, self.lc, self.if_depth,
858                               str(dir), r[1], this_isvalid, data))
859                    if in_dir is None:
860                        if dir is not None:
861                            dir, info, data = self._process_directive(r, dir, info, data)
862                    else:
863                        if in_dir != dir:
864                            self._error('directives cannot change scope across if statements')
865
866                    return data
867                if r[1] == '%else':
868                    in_iftrue = False
869            elif r[0] == 'directive':
870                if this_isvalid:
871                    if r[1] == '%include':
872                        self.load(r[2][0])
873                        continue
874                    dir, info, data = self._process_directive(r, dir, info, data)
875            elif r[0] == 'data':
876                if this_isvalid:
877                    dir, info, data = self._process_data(r, dir, info, data)
878        # @note is a directive extend missing
879
880    def _if(self, config, ls, isvalid, dir, info, invert = False):
881
882        def add(x, y):
883            return x + ' ' + str(y)
884
885        if len(ls) == 1:
886            self._error('invalid if expression: ' + reduce(add, ls, ''))
887
888        cistrue = True # compound istrue
889        sls = reduce(add, ls[1:], '').split()
890        cls = sls
891
892        log.trace('config: %s: %3d:  _if[%i]: %s' % (self.name, self.lc,
893                                                    self.if_depth, sls))
894
895        self.if_depth += 1
896
897        while len(cls) > 0 and isvalid:
898
899            join_op = 'none'
900
901            if cls[0] == '||' or cls[0] == '&&':
902                if cls[0] == '||':
903                    join_op = 'or'
904                elif cls[0] == '&&':
905                    join_op = 'and'
906                cls = cls[1:]
907                log.trace('config: %s: %3d:  _if[%i]: joining: %s' % (self.name, self.lc,
908                                                                      self.if_depth,
909                                                                      join_op))
910            ori = 0
911            andi = 0
912            i = len(cls)
913            if '||' in cls:
914                ori = cls.index('||')
915                log.trace('config: %s: %3d:  _if[%i}: OR found at %i' % (self.name, self.lc,
916                                                                         self.if_depth,
917                                                                         ori))
918            if '&&' in cls:
919                andi = cls.index('&&')
920                log.trace('config: %s: %3d:  _if[%i]: AND found at %i' % (self.name, self.lc,
921                                                                          self.if_depth,
922                                                                          andi))
923            if ori > 0 or andi > 0:
924                if ori == 0:
925                    i = andi
926                elif andi == 0:
927                    i = ori
928                elif ori < andi:
929                    i = andi
930                else:
931                    i = andi
932                log.trace('config: %s: %3d:  _if[%i]: next OP found at %i' % (self.name, self.lc,
933                                                                              self.if_depth,
934                                                                              i))
935            ls = cls[:i]
936            if len(ls) == 0:
937                self._error('invalid if expression: ' + reduce(add, sls, ''))
938            cls = cls[i:]
939
940            istrue = False
941
942            s = ' '.join(ls)
943            ifls = ls
944
945            if len(ifls) == 1:
946                #
947                # Check if '%if %{x} == %{nil}' has both parts as nothing
948                # which means '%if ==' is always True and '%if !=' is always false.
949                #
950                if ifls[0] == '==':
951                    istrue = True
952                elif ifls[0] == '!=':
953                    istrue = False
954                else:
955                    istrue = _check_bool(ifls[0])
956                    if istrue == None:
957                        self._error('invalid if bool value: ' + reduce(add, ls, ''))
958                        istrue = False
959            elif len(ifls) == 2:
960                if ifls[0] == '!':
961                    istrue = _check_bool(ifls[1])
962                    if istrue == None:
963                        self._error('invalid if bool value: ' + reduce(add, ls, ''))
964                        istrue = False
965                    else:
966                        istrue = not istrue
967                else:
968                    #
969                    # Check is something is being checked against empty,
970                    #   ie '%if %{x} == %{nil}'
971                    # The logic is 'something == nothing' is False and
972                    # 'something != nothing' is True.
973                    #
974                    if ifls[1] == '==':
975                        istrue = False
976                    elif  ifls[1] == '!=':
977                        istrue = True
978                    else:
979                        self._error('invalid if bool operator: ' + reduce(add, ls, ''))
980            else:
981                if len(ifls) >= 3:
982                    for op in ['==', '!=', '>=', '=>', '=<', '<=', '>', '<']:
983                        if op in ifls:
984                            op_pos = ifls.index(op)
985                            ifls = (' '.join(ifls[:op_pos]), op, ' '.join(ifls[op_pos + 1:]))
986                            break
987                if len(ifls) != 3:
988                     self._error('malformed if: ' + reduce(add, ls, ''))
989                if ifls[1] == '==':
990                    if ifls[0] == ifls[2]:
991                        istrue = True
992                    else:
993                        istrue = False
994                elif ifls[1] == '!=' or ifls[1] == '=!':
995                    if ifls[0] != ifls[2]:
996                        istrue = True
997                    else:
998                        istrue = False
999                elif ifls[1] == '>':
1000                    if ifls[0] > ifls[2]:
1001                        istrue = True
1002                    else:
1003                        istrue = False
1004                elif ifls[1] == '>=' or ifls[1] == '=>':
1005                    if ifls[0] >= ifls[2]:
1006                        istrue = True
1007                    else:
1008                        istrue = False
1009                elif ifls[1] == '<=' or ifls[1] == '=<':
1010                    if ifls[0] <= ifls[2]:
1011                        istrue = True
1012                    else:
1013                        istrue = False
1014                elif ifls[1] == '<':
1015                    if ifls[0] < ifls[2]:
1016                        istrue = True
1017                    else:
1018                        istrue = False
1019                else:
1020                    self._error('invalid %if operator: ' + reduce(add, ls, ''))
1021
1022            if join_op == 'or':
1023                if istrue:
1024                    cistrue = True
1025            elif join_op == 'and':
1026                if not istrue:
1027                    cistrue = False
1028            else:
1029                cistrue = istrue
1030
1031            log.trace('config: %s: %3d:  _if[%i]:  %s %s %s %s' % (self.name, self.lc,
1032                                                                   self.if_depth,
1033                                                                   ifls, str(cistrue),
1034                                                                   join_op, str(istrue)))
1035
1036        if invert:
1037            cistrue = not cistrue
1038
1039        ifs_return = self._ifs(config, ls, '%if', cistrue, isvalid, dir, info)
1040
1041        self.if_depth -= 1
1042
1043        log.trace('config: %s: %3d:  _if[%i]: %r' % (self.name, self.lc,
1044                                                     self.if_depth, ifs_return))
1045
1046        return ifs_return
1047
1048    def _ifos(self, config, ls, isvalid, dir, info):
1049        isos = False
1050        if isvalid:
1051            os = self.define('_os')
1052            ls = ' '.join(ls).split()
1053            for l in ls[1:]:
1054                if l in os:
1055                    isos = True
1056                    break
1057        return self._ifs(config, ls, '%ifos', isos, isvalid, dir, info)
1058
1059    def _ifnos(self, config, ls, isvalid, dir, info):
1060        isnos = True
1061        if isvalid:
1062            os = self.define('_os')
1063            ls = ' '.join(ls).split()
1064            for l in ls[1:]:
1065                if l in os:
1066                    isnos = False
1067                    break
1068        return self._ifs(config, ls, '%ifnos', isnos, isvalid, dir, info)
1069
1070    def _ifarch(self, config, positive, ls, isvalid, dir, info):
1071        isarch = False
1072        if isvalid:
1073            arch = self.define('_arch')
1074            ls = ' '.join(ls).split()
1075            for l in ls[1:]:
1076                if l in arch:
1077                    isarch = True
1078                    break
1079        if not positive:
1080            isarch = not isarch
1081        return self._ifs(config, ls, '%ifarch', isarch, isvalid, dir, info)
1082
1083    def _parse(self, config, dir, info, roc = False, isvalid = True):
1084        # roc = return on control
1085
1086        def _clean(line):
1087            line = line[0:-1]
1088            b = line.find('#')
1089            if b >= 0:
1090                line = line[1:b] + ('\\' if line[-1] == '\\' else '')
1091            return line.strip()
1092
1093        def _clean_and_pack(line, last_line):
1094            leading_ws = ' ' if len(line) > 0 and line[0].isspace() else ''
1095            line = _clean(line)
1096            if len(last_line) > 0:
1097                line = last_line + leading_ws + line
1098            return line
1099
1100        #
1101        # Need to add code to count matching '{' and '}' and if they
1102        # do not match get the next line and add to the string until
1103        # they match. This closes an opening '{' that is on another
1104        # line.
1105        #
1106        ll = ''
1107        for l in config:
1108            self.lc += 1
1109            l = _clean_and_pack(l, ll)
1110            if len(l) == 0:
1111                continue
1112            if l[-1] == '\\':
1113                ll = l[0:-1]
1114                continue
1115            ll = ''
1116            if isvalid:
1117                indicator = '>'
1118            else:
1119                indicator = ' '
1120            log.trace('config: %s: %3d:%s%s [%s]' % \
1121                          (self.name, self.lc, indicator, l, str(isvalid)))
1122            lo = l
1123            if isvalid:
1124                l = self._expand(l)
1125            if len(l) == 0:
1126                continue
1127            if l[0] == '%':
1128                ls = self.wss.split(l, 2)
1129                los = self.wss.split(lo, 2)
1130                if ls[0] == '%package':
1131                    if isvalid:
1132                        if ls[1] == '-n':
1133                            name = ls[2]
1134                        else:
1135                            name = self.name + '-' + ls[1]
1136                        return ('package', name)
1137                elif ls[0] == '%disable':
1138                    if isvalid:
1139                        self._disable(config, ls)
1140                elif ls[0] == '%select':
1141                    if isvalid:
1142                        self._select(config, ls)
1143                elif ls[0] == '%source' or ls[0] == '%patch':
1144                    if isvalid:
1145                        d = self._sources(ls)
1146                        if d is not None:
1147                            return ('data', d)
1148                elif ls[0] == '%hash':
1149                    if isvalid:
1150                        d = self._hash(ls)
1151                        if d is not None:
1152                            return ('data', d)
1153                elif ls[0] == '%patch':
1154                    if isvalid:
1155                        self._select(config, ls)
1156                elif ls[0] == '%error':
1157                    if isvalid:
1158                        return ('data', ['%%error %s' % (self._name_line_msg(l[7:]))])
1159                elif ls[0] == '%log':
1160                    if isvalid:
1161                        return ('data', ['%%log %s' % (self._name_line_msg(l[4:]))])
1162                elif ls[0] == '%warning':
1163                    if isvalid:
1164                        return ('data', ['%%warning %s' % (self._name_line_msg(l[9:]))])
1165                elif ls[0] == '%define' or ls[0] == '%global':
1166                    if isvalid:
1167                        self._define(config, ls)
1168                elif ls[0] == '%undefine':
1169                    if isvalid:
1170                        self._undefine(config, ls)
1171                elif ls[0] == '%if':
1172                    d = self._if(config, ls, isvalid, dir, info)
1173                    if len(d):
1174                        log.trace('config: %s: %3d%%if: %s' % (self.name, self.lc, d))
1175                        return ('data', d)
1176                elif ls[0] == '%ifn':
1177                    d = self._if(config, ls, isvalid, dir, info, True)
1178                    if len(d):
1179                        log.trace('config: %s: %3d%%ifn: %s' % (self.name, self.lc, d))
1180                        return ('data', d)
1181                elif ls[0] == '%ifos':
1182                    d = self._ifos(config, ls, isvalid, dir, info)
1183                    if len(d):
1184                        return ('data', d)
1185                elif ls[0] == '%ifnos':
1186                    d = self._ifnos(config, ls, isvalid, dir, info)
1187                    if len(d):
1188                        return ('data', d)
1189                elif ls[0] == '%ifarch':
1190                    d = self._ifarch(config, True, ls, isvalid, dir, info)
1191                    if len(d):
1192                        return ('data', d)
1193                elif ls[0] == '%ifnarch':
1194                    d = self._ifarch(config, False, ls, isvalid, dir, info)
1195                    if len(d):
1196                        return ('data', d)
1197                elif ls[0] == '%endif':
1198                    if roc:
1199                        return ('control', '%endif', '%endif')
1200                    log.warning(self._name_line_msg("unexpected '" + ls[0] + "'"))
1201                elif ls[0] == '%else':
1202                    if roc:
1203                        return ('control', '%else', '%else')
1204                    log.warning(self._name_line_msg("unexpected '" + ls[0] + "'"))
1205                elif ls[0].startswith('%defattr'):
1206                    return ('data', [l])
1207                elif ls[0] == '%bcond_with':
1208                    if isvalid:
1209                        #
1210                        # Check if already defined. Would be by the command line or
1211                        # even a host specific default.
1212                        #
1213                        if self._label('with_' + ls[1]) not in self.macros:
1214                            self._define(config, (ls[0], 'without_' + ls[1]))
1215                elif ls[0] == '%bcond_without':
1216                    if isvalid:
1217                        if self._label('without_' + ls[1]) not in self.macros:
1218                            self._define(config, (ls[0], 'with_' + ls[1]))
1219                else:
1220                    for r in self._ignore:
1221                        if r.match(ls[0]) is not None:
1222                            return ('data', [l])
1223                    if isvalid:
1224                        for d in self._directive:
1225                            if ls[0].strip() == d:
1226                                log.trace('config: %s: %3d:  _parse: directive: %s' % \
1227                                          (self.name, self.lc, ls[0].strip()))
1228                                return ('directive', ls[0].strip(), ls[1:])
1229                        log.warning(self._name_line_msg("unknown directive: '" + ls[0] + "'"))
1230                        return ('data', [lo])
1231            else:
1232                return ('data', [lo])
1233        return ('control', '%end', '%end')
1234
1235    def _process_package(self, results, directive, info, data):
1236        self._set_package(results[1])
1237        directive = None
1238        return (directive, info, data)
1239
1240    def _process_directive(self, results, directive, info, data):
1241        new_data = []
1242        if results[1] == '%description':
1243            new_data = [' '.join(results[2])]
1244            if len(results[2]) == 0:
1245                _package = 'main'
1246            elif len(results[2]) == 1:
1247                _package = results[2][0]
1248            else:
1249                if results[2][0].strip() != '-n':
1250                    log.warning(self._name_line_msg("unknown directive option: '%s'" % (' '.join(results[2]))))
1251                _package = results[2][1].strip()
1252            self._set_package(_package)
1253        if directive and directive != results[1]:
1254            self._directive_extend(directive, data)
1255        directive = results[1]
1256        data = new_data
1257        return (directive, info, data)
1258
1259    def _process_data(self, results, directive, info, data):
1260        log.trace('config: %s: %3d:  _process_data: result=#%r# directive=#%s# info=#%r# data=#%r#' % \
1261                  (self.name, self.lc, results, directive, info, data))
1262        new_data = []
1263        for l in results[1]:
1264            if l.startswith('%error'):
1265                l = self._expand(l)
1266                raise error.general('config error: %s' % (l[7:]))
1267            elif l.startswith('%log'):
1268                l = self._expand(l)
1269                log.output(l[4:])
1270            elif l.startswith('%warning'):
1271                l = self._expand(l)
1272                log.warning(self._name_line_msg(l[9:]))
1273            if not directive:
1274                l = self._expand(l)
1275                ls = self.tags.split(l, 1)
1276                log.trace('config: %s: %3d:  _tag: %s %s' % (self.name, self.lc, l, ls))
1277                if len(ls) > 1:
1278                    info = ls[0].lower()
1279                    if info[-1] == ':':
1280                        info = info[:-1]
1281                    info_data = ls[1].strip()
1282                else:
1283                    info_data = ls[0].strip()
1284                if info is not None:
1285                    self._info_append(info, info_data)
1286                else:
1287                    log.warning(self._name_line_msg("invalid format: '%s'" % (info_data[:-1])))
1288            else:
1289                l = self._expand(l)
1290                log.trace('config: %s: %3d:  _data: %s %s' % (self.name, self.lc, l, new_data))
1291                new_data.append(l)
1292        return (directive, info, data + new_data)
1293
1294    def _set_package(self, _package):
1295        if self.package == 'main' and \
1296                self._packages[self.package].name() != None:
1297            if self._packages[self.package].name() == _package:
1298                return
1299        if _package not in self._packages:
1300            self._packages[_package] = package(_package,
1301                                               self.define('%{_arch}'),
1302                                               self)
1303        self.package = _package
1304
1305    def _directive_extend(self, dir, data):
1306        log.trace('config: %s: %3d:  _directive_extend: %s: %r' % (self.name, self.lc, dir, data))
1307        self._packages[self.package].directive_extend(dir, data)
1308
1309    def _info_append(self, info, data):
1310        self._packages[self.package].info_append(info, data)
1311
1312    def set_macros(self, macros):
1313        if macros is None:
1314            self.macros = opts.defaults
1315        else:
1316            self.macros = macros
1317
1318    def load(self, name):
1319
1320        def common_end(left, right):
1321            end = ''
1322            while len(left) and len(right):
1323                if left[-1] != right[-1]:
1324                    return end
1325                end = left[-1] + end
1326                left = left[:-1]
1327                right = right[:-1]
1328            return end
1329
1330        if self.load_depth == 0:
1331            self._reset(name)
1332            self._packages[self.package] = package(self.package,
1333                                                   self.define('%{_arch}'),
1334                                                   self)
1335
1336        self.load_depth += 1
1337
1338        save_name = self.name
1339        save_lc = self.lc
1340
1341        #
1342        # Locate the config file. Expand any macros then add the
1343        # extension. Check if the file exists, therefore directly
1344        # referenced. If not see if the file contains ':' or the path
1345        # separator. If it does split the path else use the standard config dir
1346        # path in the defaults.
1347        #
1348
1349        exname = self.expand(name)
1350
1351        #
1352        # Macro could add an extension.
1353        #
1354        if exname.endswith('.cfg'):
1355            configname = exname
1356        else:
1357            configname = '%s.cfg' % (exname)
1358            name = '%s.cfg' % (name)
1359
1360        if ':' in configname:
1361            cfgname = path.basename(configname)
1362        else:
1363            cfgname = common_end(configname, name)
1364
1365        if not path.exists(configname):
1366            if ':' in configname:
1367                configdirs = path.dirname(configname).split(':')
1368            else:
1369                configdirs = self.define('_configdir').split(':')
1370            for cp in configdirs:
1371                configname = path.join(path.abspath(cp), cfgname)
1372                if path.exists(configname):
1373                    break
1374                configname = None
1375            if configname is None:
1376                raise error.general('no config file found: %s' % (cfgname))
1377
1378        try:
1379            log.trace('config: %s:  _open: %s' % (self.name, path.host(configname)))
1380            config = open(path.host(configname), 'r')
1381        except IOError as err:
1382            raise error.general('error opening config file: %s' % (path.host(configname)))
1383
1384        self.configpath += [configname]
1385        self._includes += [configname]
1386
1387        self.name = self._relative_path(configname)
1388        self.lc = 0
1389
1390        try:
1391            dir = None
1392            info = None
1393            data = []
1394            while True:
1395                r = self._parse(config, dir, info)
1396                if r[0] == 'package':
1397                    dir, info, data = self._process_package(r, dir, info, data)
1398                elif r[0] == 'control':
1399                    if r[1] == '%end':
1400                        break
1401                    log.warning(self._name_line_msg("unexpected '%s'" % (r[1])))
1402                elif r[0] == 'directive':
1403                    if r[1] == '%include':
1404                        self.load(r[2][0])
1405                        continue
1406                    dir, info, data = self._process_directive(r, dir, info, data)
1407                elif r[0] == 'data':
1408                    dir, info, data = self._process_data(r, dir, info, data)
1409                else:
1410                    self._error("%d: invalid parse state: '%s" % (self.lc, r[0]))
1411            if dir is not None:
1412                self._directive_extend(dir, data)
1413        except:
1414            config.close()
1415            raise
1416
1417        config.close()
1418
1419        self.name = save_name
1420        self.lc = save_lc
1421
1422        self.load_depth -= 1
1423
1424    def defined(self, name):
1425        return name in self.macros
1426
1427    def define(self, name):
1428        if name in self.macros:
1429            d = self.macros[name]
1430        else:
1431            n = self._label(name)
1432            if n in self.macros:
1433                d = self.macros[n]
1434            else:
1435                raise error.general('%d: macro "%s" not found' % (self.lc, name))
1436        return self._expand(d)
1437
1438    def set_define(self, name, value):
1439        self.macros[name] = value
1440
1441    def expand(self, line):
1442        if type(line) == list:
1443            el = []
1444            for l in line:
1445                el += [self._expand(l)]
1446            return el
1447        return self._expand(line)
1448
1449    def macro(self, name):
1450        if name in self.macros:
1451            return self.macros[name]
1452        raise error.general('macro "%s" not found' % (name))
1453
1454    def directive(self, _package, name):
1455        if _package not in self._packages:
1456            raise error.general('package "' + _package + '" not found')
1457        if name not in self._packages[_package].directives:
1458            raise error.general('directive "' + name + \
1459                                    '" not found in package "' + _package + '"')
1460        return self._packages[_package].directives[name]
1461
1462    def abspath(self, rpath):
1463        return path.abspath(self.define(rpath))
1464
1465    def packages(self):
1466        return self._packages
1467
1468    def includes(self):
1469        return self._includes
1470
1471    def file_name(self):
1472        return self.name
1473
1474def run():
1475    import sys
1476    try:
1477        #
1478        # Run where defaults.mc is located
1479        #
1480        opts = options.load(sys.argv, defaults = 'defaults.mc')
1481        log.trace('config: count %d' % (len(opts.config_files())))
1482        for config_file in opts.config_files():
1483            s = open(config_file, opts)
1484            print(s)
1485            del s
1486    except error.general as gerr:
1487        print(gerr)
1488        sys.exit(1)
1489    except error.internal as ierr:
1490        print(ierr)
1491        sys.exit(1)
1492    except KeyboardInterrupt:
1493        log.notice('abort: user terminated')
1494        sys.exit(1)
1495    sys.exit(0)
1496
1497if __name__ == "__main__":
1498    run()
Note: See TracBrowser for help on using the repository browser.