source: rtems-source-builder/source-builder/sb/check.py @ 2ac145a

4.11
Last change on this file since 2ac145a was 2ac145a, checked in by Chris Johns <chrisj@…>, on Jan 18, 2018 at 2:16:47 AM

sb: Add an orphan check to sb-check.

The orphans check lets you see which configuration and build set
files in the RSB are not referernced. You can audit the list and
remove any configuration files not being used. Top level
build set files are included so you need to becareful not to
remove something that is valid and useful. To run:

$ ./source-builder/sb-check --check-orphans

Update #3274

  • Property mode set to 100644
File size: 8.9 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2016 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# Check the defaults for a specific host.
22#
23
24from __future__ import print_function
25
26import os
27
28import error
29import execute
30import fnmatch
31import log
32import options
33import path
34import re
35import version
36
37def _check_none(_opts, macro, value, constraint):
38    return True
39
40
41def _check_triplet(_opts, macro, value, constraint):
42    return True
43
44
45def _check_dir(_opts, macro, value, constraint, silent = False):
46    if constraint != 'none' and not path.isdir(value):
47        if constraint == 'required':
48            if not silent:
49                log.notice('error: dir: not found: (%s) %s' % (macro, value))
50            return False
51        if not silent and _opts.warn_all():
52            log.notice('warning: dir: not found: (%s) %s' % (macro, value))
53    return True
54
55
56def _check_exe(_opts, macro, value, constraint, silent = False):
57
58    if len(value) == 0 or constraint == 'none':
59        return True
60
61    orig_value = value
62
63    if path.isabspath(value):
64        if path.isfile(value):
65            return True
66        if os.name == 'nt':
67            if path.isfile('%s.exe' % (value)):
68                return True
69        value = path.basename(value)
70        absexe = True
71    else:
72        absexe = False
73
74    paths = os.environ['PATH'].split(os.pathsep)
75
76    if _check_paths(value, paths):
77        if absexe:
78            if not silent:
79                log.notice('warning: exe: absolute exe found in path: (%s) %s' % (macro, orig_value))
80        return True
81
82    if constraint == 'optional':
83        if not silent:
84            log.trace('warning: exe: optional exe not found: (%s) %s' % (macro, orig_value))
85        return True
86
87    if not silent:
88        log.notice('error: exe: not found: (%s) %s' % (macro, orig_value))
89    return False
90
91
92def _check_paths(name, paths):
93    for p in paths:
94        exe = path.join(p, name)
95        if path.isfile(exe):
96            return True
97        if os.name == 'nt':
98            if path.isfile('%s.exe' % (exe)):
99                return True
100    return False
101
102
103def path_check(opts, silent = False):
104    if 'PATH' in os.environ:
105        paths = os.environ['PATH'].split(os.pathsep)
106        for p in paths:
107            if len(p.strip()) == 0:
108                if not silent:
109                    log.notice('error: environment PATH contains an empty path')
110                return False
111            elif not options.host_windows and (p.strip() == '.' or p.strip() == '..'):
112                if not silent:
113                    log.notice('error: environment PATH invalid path: %s' % (p))
114                return False
115            elif not path.exists(p):
116                if not silent and opts.warn_all():
117                    log.notice('warning: environment PATH not found: %s' % (p))
118            elif not path.isdir(p):
119                if not silent and opts.warn_all():
120                    log.notice('warning: environment PATH not a directory: %s' % (p))
121    return True
122
123
124def host_setup(opts):
125    """ Basic sanity check. All executables and directories must exist."""
126
127    if not path_check(opts):
128        return False
129
130    checks = { 'none':    _check_none,
131               'triplet': _check_triplet,
132               'dir':     _check_dir,
133               'exe':     _check_exe }
134
135    sane = True
136
137    log.trace('--- check host set up : start"')
138    for d in list(opts.defaults.keys()):
139        try:
140            (test, constraint, value) = opts.defaults.get(d)
141        except:
142            if opts.defaults.get(d) is None:
143                raise error.general('invalid default: %s: not found' % (d))
144            else:
145                raise error.general('invalid default: %s [%r]' % (d, opts.defaults.get(d)))
146        if test != 'none':
147            value = opts.defaults.expand(value)
148            if test not in checks:
149                raise error.general('invalid check test: %s [%r]' % (test, opts.defaults.get(d)))
150            ok = checks[test](opts, d, value, constraint)
151            if ok:
152                tag = ' '
153            else:
154                tag = '*'
155            log.trace('%c %15s: %r -> "%s"' % (tag, d, opts.defaults.get(d), value))
156            if sane and not ok:
157                sane = False
158    log.trace('--- check host set up : end"')
159
160    return sane
161
162
163def check_exe(label, exe):
164    return _check_exe(None, label, exe, None, True)
165
166
167def check_orphans(opts):
168
169    def _find_files(path, globs, excludes = []):
170        ff = []
171        for root, dirs, files in os.walk(path, followlinks = True):
172            for f in files:
173                for g in globs:
174                    if fnmatch.fnmatch(f, g) and f not in excludes:
175                        ff += [os.path.join(root, f)]
176        return sorted(ff)
177
178    def _clean(line):
179        line = line[0:-1]
180        b = line.find('#')
181        if b >= 0:
182            line = line[1:b]
183        return line.strip()
184
185    def _find(name, opts):
186        ename = opts.defaults.expand(name)
187        if ':' in ename:
188            paths = path.dirname(ename).split(':')
189            name = path.basename(name)
190        else:
191            paths = opts.defaults.get_value('_configdir').split(':')
192        for p in paths:
193            n = path.join(opts.defaults.expand(p), name)
194            if path.exists(n):
195                return n
196        return None
197
198    paths = opts.defaults.get_value('_configdir').split(':')
199
200    cfgs = {}
201    for p in paths:
202        ep = opts.defaults.expand(p)
203        print('Scanning: %s (%s)' % (p, ep))
204        for f in _find_files(ep, ['*.cfg', '*.bset']):
205            root, ext = path.splitext(f)
206            cfgs[f] = { 'src': None, 'ext': ext, 'refs': 0, 'errors':[] }
207
208    wss = re.compile(r'\s+')
209
210    for c in cfgs:
211        with open(c, 'r') as f:
212            cfgs[c]['src'] = f.readlines()
213        lc = 0
214        for l in cfgs[c]['src']:
215            lc += 1
216            l = _clean(l)
217            if len(l) == 0:
218                continue
219            if l[0] == '%':
220                ls = wss.split(l, 2)
221                if ls[0] == '%include':
222                    name = _find(ls[1], opts)
223                    if name is None:
224                        cfgs[c]['errors'] += [lc]
225                    elif name not in cfgs:
226                        raise error.general('include: %s: not present' % (ls[1]))
227                    else:
228                        cfgs[name]['refs'] += 1
229            elif cfgs[c]['ext'] == '.bset' and ':' not in l:
230                for ext in ['', '.cfg', '.bset']:
231                    name = _find(l + ext, opts)
232                    if name is not None:
233                        if name not in cfgs:
234                            raise error.general('include: %s: not present' % (ls[1]))
235                        else:
236                            cfgs[name]['refs'] += 1
237                        break
238
239    topdir = opts.defaults.expand('%{_topdir}')
240
241    orphans = []
242    show = True
243
244    for c in cfgs:
245        if cfgs[c]['refs'] == 0:
246            orphans += [c]
247        if len(cfgs[c]['errors']) != 0:
248            if show:
249                print('Warnings:')
250                show = False
251            print(' %s:' % (path.relpath(c)))
252            for l in cfgs[c]['errors']:
253                print(%3d: %s' % (l, cfgs[c]['src'][l - 1][:-1]))
254
255    show = True
256
257    for o in sorted(orphans):
258        if show:
259            print('Orphans:')
260            show = False
261        print(' %s' % (path.relpath(o)))
262
263def run():
264    import sys
265    try:
266        _opts = options.load(args = sys.argv)
267        log.notice('RTEMS Source Builder - Check, %s' % (version.str()))
268
269        orphans = _opts.parse_args('--check-orphans', error = False, extra = False)
270        if orphans:
271            print('Checking for orphans...')
272            check_orphans(_opts)
273        else:
274            if host_setup(_opts):
275                print('Environment is ok')
276            else:
277                print('Environment is not correctly set up')
278    except error.general as gerr:
279        print(gerr)
280        sys.exit(1)
281    except error.internal as ierr:
282        print(ierr)
283        sys.exit(1)
284    except error.exit as eerr:
285        pass
286    except KeyboardInterrupt:
287        log.notice('abort: user terminated')
288        sys.exit(1)
289    sys.exit(0)
290
291
292if __name__ == '__main__':
293    run()
Note: See TracBrowser for help on using the repository browser.