diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/firstheader.py | 30 | ||||
| -rw-r--r-- | python/makefile.py | 100 | ||||
| -rw-r--r-- | python/makevars.py | 50 |
3 files changed, 180 insertions, 0 deletions
diff --git a/python/firstheader.py b/python/firstheader.py new file mode 100644 index 0000000000..19a85b63e5 --- /dev/null +++ b/python/firstheader.py @@ -0,0 +1,30 @@ +# +# check that the first header included in C files is either +# zebra.h or config.h +# + +import sys, os, re, subprocess + +include_re = re.compile('^#\s*include\s+["<]([^ ">]+)[">]', re.M) + +errors = 0 + +files = subprocess.check_output(['git', 'ls-files']).decode('ASCII') +for fn in files.splitlines(): + if not fn.endswith('.c'): + continue + if fn.startswith('tools/'): + continue + with open(fn, 'r') as fd: + data = fd.read() + m = include_re.search(data) + if m is None: + #sys.stderr.write('no #include in %s?\n' % (fn)) + continue + if m.group(1) in ['config.h', 'zebra.h', 'lib/zebra.h']: + continue + sys.stderr.write('%s: %s\n' % (fn, m.group(0))) + errors += 1 + +if errors: + sys.exit(1) diff --git a/python/makefile.py b/python/makefile.py new file mode 100644 index 0000000000..9af397d373 --- /dev/null +++ b/python/makefile.py @@ -0,0 +1,100 @@ +#!/usr/bin/python3 +# +# FRR extended automake/Makefile functionality helper +# +# This script is executed on/after generating Makefile to add some pieces for +# clippy. + +import sys +import os +import subprocess +import re +import argparse +from string import Template + +argp = argparse.ArgumentParser(description = 'FRR Makefile extensions') +argp.add_argument('--dev-build', action = 'store_const', const = True, + help = 'run additional developer checks') +args = argp.parse_args() + +with open('Makefile', 'r') as fd: + before = fd.read() + +nolinecont = before.replace('\\\n', '') +m = re.search('^clippy_scan\s*=([^#]*)(?:#.*)?$', nolinecont, flags=re.MULTILINE) +if m is None: + sys.stderr.write('failed to parse Makefile.in\n') + sys.exit(2) + +clippy_scan = m.group(1).strip().split() +for clippy_file in clippy_scan: + assert clippy_file.endswith('.c') + +# check for files using clippy but not listed in clippy_scan +if args.dev_build: + basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + if os.path.exists(os.path.join(basepath, '.git')): + clippy_ref = subprocess.check_output([ + 'git', '-C', basepath, 'grep', '-l', '-P', '^#\s*include.*_clippy.c', '--', '**.c']).decode('US-ASCII') + + clippy_ref = set(clippy_ref.splitlines()) + missing = clippy_ref - set(clippy_scan) + + if len(missing) > 0: + sys.stderr.write('error: files seem to be using clippy, but not listed in "clippy_scan" in subdir.am:\n\t%s\n' % ('\n\t'.join(sorted(missing)))) + sys.exit(1) + +clippydep = Template(''' +${clippybase}.$$(OBJEXT): ${clippybase}_clippy.c +${clippybase}.lo: ${clippybase}_clippy.c +${clippybase}_clippy.c: $$(CLIPPY_DEPS)''') + +clippyauxdep = Template('''# clippy{ +# auxiliary clippy target +${target}: ${clippybase}_clippy.c +# }clippy''') + +lines = before.splitlines() +autoderp = '#AUTODERP# ' +out_lines = [] +make_rule_re = re.compile('^([^:\s]+):\s*([^:\s]+)\s*($|\n)') + +while lines: + line = lines.pop(0) + if line.startswith(autoderp): + line = line[len(autoderp):] + + if line == '# clippy{': + while lines: + line = lines.pop(0) + if line == '# }clippy': + break + continue + + if line.startswith('#'): + out_lines.append(line) + continue + + m = make_rule_re.match(line) + if m is None: + out_lines.append(line) + continue + + if m.group(2) in clippy_scan: + out_lines.append(clippyauxdep.substitute(target=m.group(1), clippybase=m.group(2)[:-2])) + + out_lines.append(line) + +out_lines.append('# clippy{\n# main clippy targets') +for clippy_file in clippy_scan: + out_lines.append(clippydep.substitute(clippybase = clippy_file[:-2])) +out_lines.append('# }clippy') +out_lines.append('') + +after = '\n'.join(out_lines) +if after == before: + sys.exit(0) + +with open('Makefile.pyout', 'w') as fd: + fd.write(after) +os.rename('Makefile.pyout', 'Makefile') diff --git a/python/makevars.py b/python/makevars.py new file mode 100644 index 0000000000..e0e2031a0d --- /dev/null +++ b/python/makevars.py @@ -0,0 +1,50 @@ +# +# helper class to grab variables from FRR's Makefile +# + +import os +import subprocess + +class MakeVars(object): + ''' + makevars['FOO_CFLAGS'] gets you "FOO_CFLAGS" from Makefile + ''' + def __init__(self): + self._data = dict() + + def getvars(self, varlist): + ''' + get a batch list of variables from make. faster than individual calls. + ''' + rdfd, wrfd = os.pipe() + + shvars = ['shvar-%s' % s for s in varlist] + make = subprocess.Popen(['make', '-s', 'VARFD=%d' % wrfd] + shvars, pass_fds = [wrfd]) + os.close(wrfd) + data = b'' + + rdf = os.fdopen(rdfd, 'rb') + while True: + rdata = rdf.read() + if len(rdata) == 0: + break + data += rdata + + del rdf + make.wait() + + data = data.decode('US-ASCII').strip().split('\n') + for row in data: + k, v = row.split('=', 1) + v = v[1:-1] + self._data[k] = v + + def __getitem__(self, k): + if k not in self._data: + self.getvars([k]) + return self._data[k] + + def get(self, k, defval = None): + if k not in self._data: + self.getvars([k]) + return self._data[k] or defval |
