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

4.104.114.95
Last change on this file since c5b5493 was c5b5493, checked in by Chris Johns <chrisj@…>, on 02/11/14 at 03:06:45

config: Change pkgconfig to check.

Add the extra actions: ccflags, cflags, ldflags and libs to allow the
fetching of these from pkg-config files.

  • Property mode set to 100644
File size: 39.4 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2013 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
28import copy
29import os
30import re
31import sys
32
33try:
34    import error
35    import execute
36    import log
37    import options
38    import path
39    import pkgconfig
40except KeyboardInterrupt:
41    print 'user terminated'
42    sys.exit(1)
43except:
44    print 'error: unknown application load error'
45    sys.exit(1)
46
47def _check_bool(value):
48    if value.isdigit():
49        if int(value) == 0:
50            istrue = False
51        else:
52            istrue = True
53    else:
54        istrue = None
55    return istrue
56
57class package:
58
59    def __init__(self, name, arch, config):
60        self._name = name
61        self._arch = arch
62        self.config = config
63        self.directives = {}
64        self.infos = {}
65
66    def __str__(self):
67
68        def _dictlist(dl):
69            s = ''
70            dll = dl.keys()
71            dll.sort()
72            for d in dll:
73                if d:
74                    s += '  ' + d + ':\n'
75                    for l in dl[d]:
76                        s += '    ' + l + '\n'
77            return s
78
79        s = '\npackage: ' + self._name + \
80            '\n directives:\n' + _dictlist(self.directives) + \
81            '\n infos:\n' + _dictlist(self.infos)
82
83        return s
84
85    def _macro_override(self, info, macro):
86        '''See if a macro overrides this setting.'''
87        overridden = self.config.macros.overridden(macro)
88        if overridden:
89            return self.config.macros.expand(macro)
90        return info
91
92    def directive_extend(self, dir, data):
93        if dir not in self.directives:
94            self.directives[dir] = []
95        for i in range(0, len(data)):
96            data[i] = data[i].strip()
97        self.directives[dir].extend(data)
98        self.config.macros[dir] = '\n'.join(self.directives[dir])
99
100    def info_append(self, info, data):
101        if info not in self.infos:
102            self.infos[info] = []
103        self.infos[info].append(data)
104        self.config.macros[info] = '\n'.join(self.infos[info])
105
106    def get_info(self, info, expand = True):
107        if info in self.config.macros:
108            _info = self.config.macros[info].split('\n')
109            if expand:
110                return self.config.expand(_info)
111            else:
112                return _info
113        return None
114
115    def extract_info(self, label, expand = True):
116        ll = label.lower()
117        infos = {}
118        keys = self.config.macros.find('%s.*' % (ll))
119        for k in keys:
120            if k == ll:
121                k = '%s0' % (ll)
122            elif not k[len(ll):].isdigit():
123                continue
124            infos[k] = [self.config.expand(self.config.macros[k])]
125        return infos
126
127    def _find_macro(self, label, expand = True):
128        if label in self.config.macros:
129            macro = self.config.macros[label].split('\n')
130            if expand:
131                return self.config.expand(macro)
132            else:
133                return macro
134        return None
135
136    def find_info(self, label, expand = True):
137        return self._find_macro(label, expand)
138
139    def find_directive(self, label, expand = True):
140        return self._find_macro(label, expand)
141
142    def name(self):
143        info = self.find_info('name')
144        if info:
145            n = info[0]
146        else:
147            n = self._name
148        return self._macro_override(n, 'name')
149
150    def summary(self):
151        info = self.find_info('summary')
152        if info:
153            return info[0]
154        return ''
155
156    def url(self):
157        info = self.find_info('url')
158        if info:
159            return info[0]
160        return ''
161
162    def version(self):
163        info = self.find_info('version')
164        if not info:
165            return None
166        return info[0]
167
168    def release(self):
169        info = self.find_info('release')
170        if not info:
171            return None
172        return info[0]
173
174    def buildarch(self):
175        info = self.find_info('buildarch')
176        if not info:
177            return self._arch
178        return info[0]
179
180    def sources(self):
181        return self.extract_info('source')
182
183    def patches(self):
184        return self.extract_info('patch')
185
186    def prep(self):
187        return self.find_directive('%prep')
188
189    def build(self):
190        return self.find_directive('%build')
191
192    def install(self):
193        return self.find_directive('%install')
194
195    def clean(self):
196        return self.find_directive('%clean')
197
198    def include(self):
199        return self.find_directive('%include')
200
201    def testing(self):
202        return self.find_directive('%testing')
203
204    def long_name(self):
205        return self.name()
206
207    def disabled(self):
208        return len(self.name()) == 0
209
210class file:
211    """Parse a config file."""
212
213    _directive = [ '%description',
214                   '%prep',
215                   '%build',
216                   '%clean',
217                   '%install',
218                   '%include',
219                   '%install',
220                   '%testing' ]
221
222    _ignore = [ re.compile('%setup'),
223                re.compile('%configure'),
224                re.compile('%source[0-9]*'),
225                re.compile('%patch[0-9]*'),
226                re.compile('%select'),
227                re.compile('%disable') ]
228
229    def __init__(self, name, opts, macros = None):
230        self.opts = opts
231        if macros is None:
232            self.macros = opts.defaults
233        else:
234            self.macros = macros
235        self.init_name = name
236        log.trace('config: %s' % (name))
237        self.disable_macro_reassign = False
238        self.configpath = []
239        self.wss = re.compile(r'\s+')
240        self.tags = re.compile(r':+')
241        self.sf = re.compile(r'%\([^\)]+\)')
242        for arg in self.opts.args:
243            if arg.startswith('--with-') or arg.startswith('--without-'):
244                label = arg[2:].lower().replace('-', '_')
245                self.macros.define(label)
246        self._includes = []
247        self.load_depth = 0
248        self.load(name)
249
250    def __str__(self):
251
252        def _dict(dd):
253            s = ''
254            ddl = dd.keys()
255            ddl.sort()
256            for d in ddl:
257                s += '  ' + d + ': ' + dd[d] + '\n'
258            return s
259
260        s = 'config: %s' % ('.'.join(self.configpath)) + \
261            '\n' + str(self.opts) + \
262            '\nlines parsed: %d' % (self.lc) + \
263            '\nname: ' + self.name + \
264            '\nmacros:\n' + str(self.macros)
265        for _package in self._packages:
266            s += str(self._packages[_package])
267        return s
268
269    def _name_line_msg(self,  msg):
270        return '%s:%d: %s' % (path.basename(self.init_name), self.lc,  msg)
271
272    def _output(self, text):
273        if not self.opts.quiet():
274            log.output(text)
275
276    def _error(self, msg):
277        err = 'error: %s' % (self._name_line_msg(msg))
278        log.stderr(err)
279        log.output(err)
280        self.in_error = True
281        if not self.opts.dry_run():
282            log.stderr('warning: switched to dry run due to errors')
283            self.opts.set_dry_run()
284
285    def _label(self, name):
286        if name.startswith('%{') and name[-1] is '}':
287            return name
288        return '%{' + name.lower() + '}'
289
290    def _macro_split(self, s):
291        '''Split the string (s) up by macros. Only split on the
292           outter level. Nested levels will need to split with futher calls.'''
293        trace_me = False
294        if trace_me:
295            print '------------------------------------------------------'
296        macros = []
297        nesting = []
298        has_braces = False
299        c = 0
300        while c < len(s):
301            if trace_me:
302                print 'ms:', c, '"' + s[c:] + '"', has_braces, len(nesting), nesting
303            #
304            # We need to watch for shell type variables or the form '${var}' because
305            # they can upset the brace matching.
306            #
307            if s[c] == '%' or s[c] == '$':
308                start = s[c]
309                c += 1
310                if c == len(s):
311                    continue
312                #
313                # Do we have '%%' or '%(' or '$%' or '$(' or not '${' ?
314                #
315                if s[c] == '%' or s[c] == '(' or (start == '$' and s[c] != '{'):
316                    continue
317                elif not s[c].isspace():
318                    #
319                    # If this is a shell macro and we are at the outter
320                    # level or is '$var' forget it and move on.
321                    #
322                    if start == '$' and (s[c] != '{' or len(nesting) == 0):
323                        continue
324                    if s[c] == '{':
325                        this_has_braces = True
326                    else:
327                        this_has_braces = False
328                    nesting.append((c - 1, has_braces))
329                    has_braces = this_has_braces
330            elif len(nesting) > 0:
331                if s[c] == '}' or (s[c].isspace() and not has_braces):
332                    #
333                    # Can have '%{?test: something %more}' where the
334                    # nested %more ends with the '}' which also ends
335                    # the outter macro.
336                    #
337                    if not has_braces:
338                        if s[c] == '}':
339                            macro_start, has_braces = nesting[len(nesting) - 1]
340                            nesting = nesting[:-1]
341                            if len(nesting) == 0:
342                                macros.append(s[macro_start:c].strip())
343                    if len(nesting) > 0:
344                        macro_start, has_braces = nesting[len(nesting) - 1]
345                        nesting = nesting[:-1]
346                        if len(nesting) == 0:
347                            macros.append(s[macro_start:c + 1].strip())
348            c += 1
349        if trace_me:
350            print 'ms:', macros
351        if trace_me:
352            print '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-='
353        return macros
354
355    def _shell(self, line):
356        sl = self.sf.findall(line)
357        if len(sl):
358            e = execute.capture_execution()
359            for s in sl:
360                if options.host_windows:
361                    cmd = '%s -c "%s"' % (self.macros.expand('%{__sh}'), s[2:-1])
362                else:
363                    cmd = s[2:-1]
364                exit_code, proc, output = e.shell(cmd)
365                if exit_code == 0:
366                    line = line.replace(s, output)
367                else:
368                    raise error.general('shell macro failed: %s:%d: %s' % (s, exit_code, output))
369        return line
370
371    def _pkgconfig_check(self, test):
372        ts = test.split()
373        ok = False
374        pkg = pkgconfig.package(ts[0], output = log.output)
375        if len(ts) != 1 and len(ts) != 3:
376            self._error('malformed check')
377        else:
378            op = '>='
379            ver = '0'
380            if len(ts) == 3:
381                op = ts[1]
382                ver = self.macros.expand(ts[2])
383            try:
384                ok = pkg.check(op, ver)
385            except pkgconfig.error, pe:
386                self._error('check: %s' % (pe))
387            except:
388                raise error.interal('pkgconfig failure')
389        return ok
390
391    def _pkgconfig_flags(self, package, flags):
392        pkg_flags = None
393        pkg = pkgconfig.package(package, output = log.output)
394        try:
395            pkg_flags = pkg.get(flags)
396        except pkgconfig.error, pe:
397            self._error('flags:%s: %s' % (flags, pe))
398        except:
399            raise error.interal('pkgconfig failure')
400        return pkg_flags
401
402    def _expand(self, s):
403        expand_count = 0
404        expanded = True
405        while expanded:
406            expand_count += 1
407            if expand_count > 500:
408                raise error.general('macro expand looping: %s' % (s))
409            expanded = False
410            ms = self._macro_split(s)
411            for m in ms:
412                mn = m
413                #
414                # A macro can be '%{macro}' or '%macro'. Turn the later into
415                # the former.
416                #
417                show_warning = True
418                if mn[1] != '{':
419                    for r in self._ignore:
420                        if r.match(mn) is not None:
421                            mn = None
422                            break
423                    else:
424                        mn = self._label(mn[1:])
425                        show_warning = False
426                elif m.startswith('%{expand'):
427                    colon = m.find(':')
428                    if colon < 8:
429                        log.warning('malformed expand macro, no colon found')
430                    else:
431                        e = self._expand(m[colon + 1:-1].strip())
432                        s = s.replace(m, e)
433                        expanded = True
434                        mn = None
435                elif m.startswith('%{with '):
436                    #
437                    # Change the ' ' to '_' because the macros have no spaces.
438                    #
439                    n = self._label('with_' + m[7:-1].strip())
440                    if n in self.macros:
441                        s = s.replace(m, '1')
442                    else:
443                        s = s.replace(m, '0')
444                    expanded = True
445                    mn = None
446                elif m.startswith('%{echo'):
447                    if not m.endswith('}'):
448                        log.warning("malformed conditional macro '%s'" % (m))
449                        mn = None
450                    else:
451                        e = self._expand(m[6:-1].strip())
452                        log.output('%s' % (self._name_line_msg(e)))
453                        s = ''
454                        expanded = True
455                        mn = None
456                elif m.startswith('%{defined'):
457                    n = self._label(m[9:-1].strip())
458                    if n in self.macros:
459                        s = s.replace(m, '1')
460                    else:
461                        s = s.replace(m, '0')
462                    expanded = True
463                    mn = None
464                elif m.startswith('%{check'):
465                    if self._pkgconfig_check(m[7:-1].strip()):
466                        s = s.replace(m, '1')
467                    else:
468                        s = s.replace(m, '0')
469                    expanded = True
470                    mn = None
471                elif m.startswith('%{ccflags'):
472                    flags = self._pkgconfig_flags(m[9:-1].strip(), 'ccflags')
473                    if flags:
474                        s = s.replace(m, flags)
475                    else:
476                        self._error('ccflags error: %s' % (m[9:-1].strip()))
477                    expanded = True
478                    mn = None
479                elif m.startswith('%{cflags'):
480                    flags = self._pkgconfig_flags(m[8:-1].strip(), 'cflags')
481                    if flags:
482                        s = s.replace(m, flags)
483                    else:
484                        self._error('cflags error: %s' % (m[8:-1].strip()))
485                    expanded = True
486                    mn = None
487                elif m.startswith('%{ldflags'):
488                    flags = self._pkgconfig_flags(m[9:-1].strip(), 'ldflags')
489                    if flags:
490                        s = s.replace(m, flags)
491                    else:
492                        self._error('ldflags error: %s' % (m[9:-1].strip()))
493                    expanded = True
494                    mn = None
495                elif m.startswith('%{libs'):
496                    flags = self._pkgconfig_flags(m[6:-1].strip(), 'libs')
497                    if flags:
498                        s = s.replace(m, flags)
499                    else:
500                        self._error('libs error: %s' % (m[6:-1].strip()))
501                    expanded = True
502                    mn = None
503                elif m.startswith('%{?') or m.startswith('%{!?'):
504                    if m[2] == '!':
505                        start = 4
506                    else:
507                        start = 3
508                    colon = m[start:].find(':')
509                    if colon < 0:
510                        if not m.endswith('}'):
511                            log.warning("malformed conditional macro '%s'" % (m))
512                            mn = None
513                        else:
514                            mn = self._label(m[start:-1])
515                    else:
516                        mn = self._label(m[start:start + colon])
517                    if mn:
518                        if m.startswith('%{?'):
519                            istrue = False
520                            if mn in self.macros:
521                                # If defined and 0 then it is false.
522                                istrue = _check_bool(self.macros[mn])
523                                if istrue is None:
524                                    istrue = True
525                            if colon >= 0 and istrue:
526                                s = s.replace(m, m[start + colon + 1:-1])
527                                expanded = True
528                                mn = None
529                            elif not istrue:
530                                mn = '%{nil}'
531                        else:
532                            isfalse = True
533                            if mn in self.macros:
534                                istrue = _check_bool(self.macros[mn])
535                                if istrue is None or istrue == True:
536                                    isfalse = False
537                            if colon >= 0 and isfalse:
538                                s = s.replace(m, m[start + colon + 1:-1])
539                                expanded = True
540                                mn = None
541                            else:
542                                mn = '%{nil}'
543                if mn:
544                    if mn.lower() in self.macros:
545                        s = s.replace(m, self.macros[mn.lower()])
546                        expanded = True
547                    elif show_warning:
548                        self._error("macro '%s' not found" % (mn))
549        return self._shell(s)
550
551    def _disable(self, config, ls):
552        if len(ls) != 2:
553            log.warning('invalid disable statement')
554        else:
555            if ls[1] == 'select':
556                self.macros.lock_read_map()
557                log.trace('config: %s: _disable_select: %s' % (self.init_name, ls[1]))
558            else:
559                log.warning('invalid disable statement: %s' % (ls[1]))
560
561    def _select(self, config, ls):
562        if len(ls) != 2:
563            log.warning('invalid select statement')
564        else:
565            r = self.macros.set_read_map(ls[1])
566            log.trace('config: %s: _select: %s %s %r' % \
567                          (self.init_name, r, ls[1], self.macros.maps()))
568
569    def _define(self, config, ls):
570        if len(ls) <= 1:
571            log.warning('invalid macro definition')
572        else:
573            d = self._label(ls[1])
574            if self.disable_macro_reassign:
575                if (d not in self.macros) or \
576                        (d in self.macros and len(self.macros[d]) == 0):
577                    if len(ls) == 2:
578                        self.macros[d] = '1'
579                    else:
580                        self.macros[d] = ' '.join([f.strip() for f in ls[2:]])
581                else:
582                    log.warning("macro '%s' already defined" % (d))
583            else:
584                if len(ls) == 2:
585                    self.macros[d] = '1'
586                else:
587                    self.macros[d] = ' '.join([f.strip() for f in ls[2:]])
588
589    def _undefine(self, config, ls):
590        if len(ls) <= 1:
591            log.warning('invalid macro definition')
592        else:
593            mn = self._label(ls[1])
594            if mn in self.macros:
595                del self.macros[mn]
596            else:
597                log.warning("macro '%s' not defined" % (mn))
598
599    def _ifs(self, config, ls, label, iftrue, isvalid, dir, info):
600        in_iftrue = True
601        data = []
602        while True:
603            if isvalid and \
604                    ((iftrue and in_iftrue) or (not iftrue and not in_iftrue)):
605                this_isvalid = True
606            else:
607                this_isvalid = False
608            r = self._parse(config, dir, info, roc = True, isvalid = this_isvalid)
609            if r[0] == 'package':
610                if this_isvalid:
611                    dir, info, data = self._process_package(r, dir, info, data)
612            elif r[0] == 'control':
613                if r[1] == '%end':
614                    self._error(label + ' without %endif')
615                    raise error.general('terminating build')
616                if r[1] == '%endif':
617                    log.trace('config: %s: _ifs: %s %s' % (self.init_name, r[1], this_isvalid))
618                    return data
619                if r[1] == '%else':
620                    in_iftrue = False
621            elif r[0] == 'directive':
622                if this_isvalid:
623                    if r[1] == '%include':
624                        self.load(r[2][0])
625                        continue
626                    dir, info, data = self._process_directive(r, dir, info, data)
627            elif r[0] == 'data':
628                if this_isvalid:
629                    dir, info, data = self._process_data(r, dir, info, data)
630        # @note is a directive extend missing
631
632    def _if(self, config, ls, isvalid, dir, info, invert = False):
633
634        def add(x, y):
635            return x + ' ' + str(y)
636
637        istrue = False
638        if isvalid:
639            if len(ls) == 2:
640                s = ls[1]
641            else:
642                s = (ls[1] + ' ' + ls[2])
643            ifls = s.split()
644            if len(ifls) == 1:
645                #
646                # Check if '%if %{x} == %{nil}' has both parts as nothing
647                # which means '%if ==' is always True and '%if !=' is always false.
648                #
649                if ifls[0] == '==':
650                    istrue = True
651                elif ifls[0] == '!=':
652                    istrue = False
653                else:
654                    istrue = _check_bool(ifls[0])
655                    if istrue == None:
656                        self._error('invalid if bool value: ' + reduce(add, ls, ''))
657                        istrue = False
658            elif len(ifls) == 2:
659                if ifls[0] == '!':
660                    istrue = _check_bool(ifls[1])
661                    if istrue == None:
662                        self._error('invalid if bool value: ' + reduce(add, ls, ''))
663                        istrue = False
664                    else:
665                        istrue = not istrue
666                else:
667                    #
668                    # Check is something is being checked against empty,
669                    #   ie '%if %{x} == %{nil}'
670                    # The logic is 'something == nothing' is False and
671                    # 'something != nothing' is True.
672                    #
673                    if ifls[1] == '==':
674                        istrue = False
675                    elif  ifls[1] == '!=':
676                        istrue = True
677                    else:
678                        self._error('invalid if bool operator: ' + reduce(add, ls, ''))
679            elif len(ifls) == 3:
680                if ifls[1] == '==':
681                    if ifls[0] == ifls[2]:
682                        istrue = True
683                    else:
684                        istrue = False
685                elif ifls[1] == '!=' or ifls[1] == '=!':
686                    if ifls[0] != ifls[2]:
687                        istrue = True
688                    else:
689                        istrue = False
690                elif ifls[1] == '>':
691                    if ifls[0] > ifls[2]:
692                        istrue = True
693                    else:
694                        istrue = False
695                elif ifls[1] == '>=' or ifls[1] == '=>':
696                    if ifls[0] >= ifls[2]:
697                        istrue = True
698                    else:
699                        istrue = False
700                elif ifls[1] == '<=' or ifls[1] == '=<':
701                    if ifls[0] <= ifls[2]:
702                        istrue = True
703                    else:
704                        istrue = False
705                elif ifls[1] == '<':
706                    if ifls[0] < ifls[2]:
707                        istrue = True
708                    else:
709                        istrue = False
710                else:
711                    self._error('invalid %if operator: ' + reduce(add, ls, ''))
712            else:
713                self._error('malformed if: ' + reduce(add, ls, ''))
714            if invert:
715                istrue = not istrue
716            log.trace('config: %s: _if:  %s %s' % (self.init_name, ifls, str(istrue)))
717        return self._ifs(config, ls, '%if', istrue, isvalid, dir, info)
718
719    def _ifos(self, config, ls, isvalid, dir, info):
720        isos = False
721        if isvalid:
722            os = self.define('_os')
723            for l in ls:
724                if l in os:
725                    isos = True
726                    break
727        return self._ifs(config, ls, '%ifos', isos, isvalid, dir, info)
728
729    def _ifarch(self, config, positive, ls, isvalid, dir, info):
730        isarch = False
731        if isvalid:
732            arch = self.define('_arch')
733            for l in ls:
734                if l in arch:
735                    isarch = True
736                    break
737        if not positive:
738            isarch = not isarch
739        return self._ifs(config, ls, '%ifarch', isarch, isvalid, dir, info)
740
741    def _parse(self, config, dir, info, roc = False, isvalid = True):
742        # roc = return on control
743
744        def _clean(line):
745            line = line[0:-1]
746            b = line.find('#')
747            if b >= 0:
748                line = line[1:b]
749            return line.strip()
750
751        #
752        # Need to add code to count matching '{' and '}' and if they
753        # do not match get the next line and add to the string until
754        # they match. This closes an opening '{' that is on another
755        # line.
756        #
757        for l in config:
758            self.lc += 1
759            l = _clean(l)
760            if len(l) == 0:
761                continue
762            log.trace('config: %s: %03d: %s %s' % \
763                          (self.init_name, self.lc, str(isvalid), l))
764            lo = l
765            if isvalid:
766                l = self._expand(l)
767            if len(l) == 0:
768                continue
769            if l[0] == '%':
770                ls = self.wss.split(l, 2)
771                los = self.wss.split(lo, 2)
772                if ls[0] == '%package':
773                    if isvalid:
774                        if ls[1] == '-n':
775                            name = ls[2]
776                        else:
777                            name = self.name + '-' + ls[1]
778                        return ('package', name)
779                elif ls[0] == '%disable':
780                    if isvalid:
781                        self._disable(config, ls)
782                elif ls[0] == '%select':
783                    if isvalid:
784                        self._select(config, ls)
785                elif ls[0] == '%error':
786                    if isvalid:
787                        return ('data', ['%%error %s' % (self._name_line_msg(l[7:]))])
788                elif ls[0] == '%warning':
789                    if isvalid:
790                        return ('data', ['%%warning %s' % (self._name_line_msg(l[9:]))])
791                elif ls[0] == '%define' or ls[0] == '%global':
792                    if isvalid:
793                        self._define(config, ls)
794                elif ls[0] == '%undefine':
795                    if isvalid:
796                        self._undefine(config, ls)
797                elif ls[0] == '%if':
798                    d = self._if(config, ls, isvalid, dir, info)
799                    if len(d):
800                        log.trace('config: %s: %%if: %s' % (self.init_name, d))
801                        return ('data', d)
802                elif ls[0] == '%ifn':
803                    d = self._if(config, ls, isvalid, dir, info, True)
804                    if len(d):
805                        log.trace('config: %s: %%ifn: %s' % (self.init_name, d))
806                        return ('data', d)
807                elif ls[0] == '%ifos':
808                    d = self._ifos(config, ls, isvalid, dir, info)
809                    if len(d):
810                        return ('data', d)
811                elif ls[0] == '%ifarch':
812                    d = self._ifarch(config, True, ls, isvalid, dir, info)
813                    if len(d):
814                        return ('data', d)
815                elif ls[0] == '%ifnarch':
816                    d = self._ifarch(config, False, ls, isvalid, dir, info)
817                    if len(d):
818                        return ('data', d)
819                elif ls[0] == '%endif':
820                    if roc:
821                        return ('control', '%endif', '%endif')
822                    log.warning("unexpected '" + ls[0] + "'")
823                elif ls[0] == '%else':
824                    if roc:
825                        return ('control', '%else', '%else')
826                    log.warning("unexpected '" + ls[0] + "'")
827                elif ls[0].startswith('%defattr'):
828                    return ('data', [l])
829                elif ls[0] == '%bcond_with':
830                    if isvalid:
831                        #
832                        # Check if already defined. Would be by the command line or
833                        # even a host specific default.
834                        #
835                        if self._label('with_' + ls[1]) not in self.macros:
836                            self._define(config, (ls[0], 'without_' + ls[1]))
837                elif ls[0] == '%bcond_without':
838                    if isvalid:
839                        if self._label('without_' + ls[1]) not in self.macros:
840                            self._define(config, (ls[0], 'with_' + ls[1]))
841                else:
842                    for r in self._ignore:
843                        if r.match(ls[0]) is not None:
844                            return ('data', [l])
845                    if isvalid:
846                        for d in self._directive:
847                            if ls[0].strip() == d:
848                                return ('directive', ls[0].strip(), ls[1:])
849                        log.warning("unknown directive: '" + ls[0] + "'")
850                        return ('data', [lo])
851            else:
852                return ('data', [lo])
853        return ('control', '%end', '%end')
854
855    def _process_package(self, results, directive, info, data):
856        self._set_package(results[1])
857        directive = None
858        return (directive, info, data)
859
860    def _process_directive(self, results, directive, info, data):
861        new_data = []
862        if results[1] == '%description':
863            new_data = [' '.join(results[2])]
864            if len(results[2]) == 0:
865                _package = 'main'
866            elif len(results[2]) == 1:
867                _package = results[2][0]
868            else:
869                if results[2][0].strip() != '-n':
870                    log.warning("unknown directive option: '%s'" % (' '.join(results[2])))
871                _package = results[2][1].strip()
872            self._set_package(_package)
873        if directive and directive != results[1]:
874            self._directive_extend(directive, data)
875        directive = results[1]
876        data = new_data
877        return (directive, info, data)
878
879    def _process_data(self, results, directive, info, data):
880        new_data = []
881        for l in results[1]:
882            if l.startswith('%error'):
883                l = self._expand(l)
884                raise error.general('config error: %s' % (l[7:]))
885            elif l.startswith('%warning'):
886                l = self._expand(l)
887                log.stderr('warning: %s' % (l[9:]))
888                log.warning(l[9:])
889            if not directive:
890                l = self._expand(l)
891                ls = self.tags.split(l, 1)
892                log.trace('config: %s: _tag: %s %s' % (self.init_name, l, ls))
893                if len(ls) > 1:
894                    info = ls[0].lower()
895                    if info[-1] == ':':
896                        info = info[:-1]
897                    info_data = ls[1].strip()
898                else:
899                    info_data = ls[0].strip()
900                if info is not None:
901                    self._info_append(info, info_data)
902                else:
903                    log.warning("invalid format: '%s'" % (info_data[:-1]))
904            else:
905                log.trace('config: %s: _data: %s %s' % (self.init_name, l, new_data))
906                new_data.append(l)
907        return (directive, info, data + new_data)
908
909    def _set_package(self, _package):
910        if self.package == 'main' and \
911                self._packages[self.package].name() != None:
912            if self._packages[self.package].name() == _package:
913                return
914        if _package not in self._packages:
915            self._packages[_package] = package(_package,
916                                               self.define('%{_arch}'),
917                                               self)
918        self.package = _package
919
920    def _directive_extend(self, dir, data):
921        self._packages[self.package].directive_extend(dir, data)
922
923    def _info_append(self, info, data):
924        self._packages[self.package].info_append(info, data)
925
926    def load(self, name):
927
928        def common_end(left, right):
929            end = ''
930            while len(left) and len(right):
931                if left[-1] != right[-1]:
932                    return end
933                end = left[-1] + end
934                left = left[:-1]
935                right = right[:-1]
936            return end
937
938        if self.load_depth == 0:
939            self.in_error = False
940            self.lc = 0
941            self.name = name
942            self.conditionals = {}
943            self._packages = {}
944            self.package = 'main'
945            self._packages[self.package] = package(self.package,
946                                                   self.define('%{_arch}'),
947                                                   self)
948
949        self.load_depth += 1
950
951        save_name = self.name
952        save_lc = self.lc
953
954        self.name = name
955        self.lc = 0
956
957        #
958        # Locate the config file. Expand any macros then add the
959        # extension. Check if the file exists, therefore directly
960        # referenced. If not see if the file contains ':' or the path
961        # separator. If it does split the path else use the standard config dir
962        # path in the defaults.
963        #
964
965        exname = self.expand(name)
966
967        #
968        # Macro could add an extension.
969        #
970        if exname.endswith('.cfg'):
971            configname = exname
972        else:
973            configname = '%s.cfg' % (exname)
974            name = '%s.cfg' % (name)
975
976        if ':' in configname:
977            cfgname = path.basename(configname)
978        else:
979            cfgname = common_end(configname, name)
980
981        if not path.exists(configname):
982            if ':' in configname:
983                configdirs = path.dirname(configname).split(':')
984            else:
985                configdirs = self.define('_configdir').split(':')
986            for cp in configdirs:
987                configname = path.join(path.abspath(cp), cfgname)
988                if path.exists(configname):
989                    break
990                configname = None
991            if configname is None:
992                raise error.general('no config file found: %s' % (cfgname))
993
994        try:
995            log.trace('config: %s: _open: %s' % (self.init_name, path.host(configname)))
996            config = open(path.host(configname), 'r')
997        except IOError, err:
998            raise error.general('error opening config file: %s' % (path.host(configname)))
999        self.configpath += [configname]
1000
1001        self._includes += [configname]
1002
1003        try:
1004            dir = None
1005            info = None
1006            data = []
1007            while True:
1008                r = self._parse(config, dir, info)
1009                if r[0] == 'package':
1010                    dir, info, data = self._process_package(r, dir, info, data)
1011                elif r[0] == 'control':
1012                    if r[1] == '%end':
1013                        break
1014                    log.warning("unexpected '%s'" % (r[1]))
1015                elif r[0] == 'directive':
1016                    if r[1] == '%include':
1017                        self.load(r[2][0])
1018                        continue
1019                    dir, info, data = self._process_directive(r, dir, info, data)
1020                elif r[0] == 'data':
1021                    dir, info, data = self._process_data(r, dir, info, data)
1022                else:
1023                    self._error("%d: invalid parse state: '%s" % (self.lc, r[0]))
1024            if dir is not None:
1025                self._directive_extend(dir, data)
1026        except:
1027            config.close()
1028            raise
1029
1030        config.close()
1031
1032        self.name = save_name
1033        self.lc = save_lc
1034
1035        self.load_depth -= 1
1036
1037    def defined(self, name):
1038        return self.macros.has_key(name)
1039
1040    def define(self, name):
1041        if name in self.macros:
1042            d = self.macros[name]
1043        else:
1044            n = self._label(name)
1045            if n in self.macros:
1046                d = self.macros[n]
1047            else:
1048                raise error.general('%d: macro "%s" not found' % (self.lc, name))
1049        return self._expand(d)
1050
1051    def set_define(self, name, value):
1052        self.macros[name] = value
1053
1054    def expand(self, line):
1055        if type(line) == list:
1056            el = []
1057            for l in line:
1058                el += [self._expand(l)]
1059            return el
1060        return self._expand(line)
1061
1062    def macro(self, name):
1063        if name in self.macros:
1064            return self.macros[name]
1065        raise error.general('macro "%s" not found' % (name))
1066
1067    def directive(self, _package, name):
1068        if _package not in self._packages:
1069            raise error.general('package "' + _package + '" not found')
1070        if name not in self._packages[_package].directives:
1071            raise error.general('directive "' + name + \
1072                                    '" not found in package "' + _package + '"')
1073        return self._packages[_package].directives[name]
1074
1075    def abspath(self, rpath):
1076        return path.abspath(self.define(rpath))
1077
1078    def packages(self):
1079        return self._packages
1080
1081    def includes(self):
1082        return self._includes
1083
1084    def file_name(self):
1085        return self.init_name
1086
1087def run():
1088    import sys
1089    try:
1090        #
1091        # Run where defaults.mc is located
1092        #
1093        opts = options.load(sys.argv, defaults = 'defaults.mc')
1094        log.trace('config: count %d' % (len(opts.config_files())))
1095        for config_file in opts.config_files():
1096            s = file(config_file, opts)
1097            print s
1098            del s
1099    except error.general, gerr:
1100        print gerr
1101        sys.exit(1)
1102    except error.internal, ierr:
1103        print ierr
1104        sys.exit(1)
1105    except KeyboardInterrupt:
1106        log.notice('abort: user terminated')
1107        sys.exit(1)
1108    sys.exit(0)
1109
1110if __name__ == "__main__":
1111    run()
Note: See TracBrowser for help on using the repository browser.