summaryrefslogtreecommitdiffstats
path: root/bin/buildcheck.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/buildcheck.py')
-rwxr-xr-xbin/buildcheck.py211
1 files changed, 211 insertions, 0 deletions
diff --git a/bin/buildcheck.py b/bin/buildcheck.py
new file mode 100755
index 0000000..16a1fd2
--- /dev/null
+++ b/bin/buildcheck.py
@@ -0,0 +1,211 @@
+#!/usr/bin/python
+
+import sys
+sys.path.append('debian/lib/python')
+
+import fnmatch
+import stat
+
+from debian_linux.abi import Symbols
+from debian_linux.config import ConfigCoreDump
+from debian_linux.debian import *
+
+
+class CheckAbi(object):
+ class SymbolInfo(object):
+ def __init__(self, symbol):
+ self.symbol = symbol
+
+ def write(self, out, ignored):
+ info = []
+ if ignored:
+ info.append("ignored")
+ for i in ('module', 'version', 'export'):
+ info.append("%s: %s" % (i, getattr(self.symbol, i)))
+ out.write("%-48s %s\n" % (self.symbol.name, ", ".join(info)))
+
+ class SymbolChangeInfo(object):
+ def __init__(self, symbol_ref, symbol_new):
+ self.symbol_ref, self.symbol_new = symbol_ref, symbol_new
+
+ def write(self, out, ignored):
+ info = []
+ if ignored:
+ info.append("ignored")
+ for i in ('module', 'version', 'export'):
+ d_ref = getattr(self.symbol_ref, i)
+ d_new = getattr(self.symbol_new, i)
+ if d_ref != d_new:
+ info.append("%s: %s -> %s" % (i, d_ref, d_new))
+ else:
+ info.append("%s: %s" % (i, d_new))
+ out.write("%-48s %s\n" % (self.symbol_new.name, ", ".join(info)))
+
+ def __init__(self, config, dir, arch, featureset, flavour):
+ self.config = config
+ self.arch, self.featureset, self.flavour = arch, featureset, flavour
+
+ self.filename_new = "%s/Module.symvers" % dir
+
+ changelog = Changelog(version=VersionLinux)[0]
+ version = changelog.version.linux_version
+ abiname = self.config['abi',]['abiname']
+ self.filename_ref = "debian/abi/%s-%s/%s_%s_%s" % (version, abiname, arch, featureset, flavour)
+
+ def __call__(self, out):
+ ret = 0
+
+ new = Symbols(open(self.filename_new))
+ try:
+ ref = Symbols(open(self.filename_ref))
+ except IOError:
+ out.write("Can't read ABI reference. ABI not checked! Continuing.\n")
+ return 0
+
+ symbols, add, change, remove = self._cmp(ref, new)
+
+ ignore = self._ignore(symbols.keys())
+
+ add_effective = add - ignore
+ change_effective = change - ignore
+ remove_effective = remove - ignore
+
+ if change_effective or remove_effective:
+ out.write("ABI has changed! Refusing to continue.\n")
+ ret = 1
+ elif change or remove:
+ out.write("ABI has changed but all changes have been ignored. Continuing.\n")
+ elif add_effective:
+ out.write("New symbols have been added. Continuing.\n")
+ elif add:
+ out.write("New symbols have been added but have been ignored. Continuing.\n")
+ else:
+ out.write("No ABI changes.\n")
+
+ if add:
+ out.write("\nAdded symbols:\n")
+ t = list(add)
+ t.sort()
+ for name in t:
+ symbols[name].write(out, name in ignore)
+
+ if change:
+ out.write("\nChanged symbols:\n")
+ t = list(change)
+ t.sort()
+ for name in t:
+ symbols[name].write(out, name in ignore)
+
+ if remove:
+ out.write("\nRemoved symbols:\n")
+ t = list(remove)
+ t.sort()
+ for name in t:
+ symbols[name].write(out, name in ignore)
+
+ return ret
+
+ def _cmp(self, ref, new):
+ ref_names = set(ref.keys())
+ new_names = set(new.keys())
+
+ add = set()
+ change = set()
+ remove = set()
+
+ symbols = {}
+
+ for name in new_names - ref_names:
+ add.add(name)
+ symbols[name] = self.SymbolInfo(new[name])
+
+ for name in ref_names.intersection(new_names):
+ s_ref = ref[name]
+ s_new = new[name]
+
+ if s_ref != s_new:
+ print "cmp", s_ref.__dict__, s_new.__dict__
+ change.add(name)
+ symbols[name] = self.SymbolChangeInfo(s_ref, s_new)
+
+ for name in ref_names - new_names:
+ remove.add(name)
+ symbols[name] = self.SymbolInfo(ref[name])
+
+ return symbols, add, change, remove
+
+ def _ignore(self, all):
+ # TODO: let config merge this lists
+ configs = []
+ configs.append(self.config.get(('abi', self.arch, self.featureset, self.flavour), {}))
+ configs.append(self.config.get(('abi', self.arch, None, self.flavour), {}))
+ configs.append(self.config.get(('abi', self.arch, self.featureset), {}))
+ configs.append(self.config.get(('abi', self.arch), {}))
+ configs.append(self.config.get(('abi',), {}))
+ ignores = set()
+ for config in configs:
+ ignores.update(config.get('ignore-changes', []))
+ filtered = set()
+ for m in ignores:
+ filtered.update(fnmatch.filter(all, m))
+ return filtered
+
+
+class CheckImage(object):
+ def __init__(self, config, dir, arch, featureset, flavour):
+ self.dir = dir
+ self.arch, self.featureset, self.flavour = arch, featureset, flavour
+
+ self.config_entry_build = config.merge('build', arch, featureset, flavour)
+ self.config_entry_image = config.merge('image', arch, featureset, flavour)
+
+ def __call__(self, out):
+ image = self.config_entry_build.get('image-file')
+
+ if not image:
+ # TODO: Bail out
+ return 0
+
+ image = os.path.join(self.dir, image)
+
+ fail = 0
+
+ fail |= self.check_size(out, image)
+
+ return fail
+
+ def check_size(self, out, image):
+ value = self.config_entry_image.get('check-size')
+
+ if not value:
+ return 0
+
+ value = int(value)
+
+ size = os.stat(image)[stat.ST_SIZE]
+
+ if size > value:
+ out.write('Image too large (%d > %d)! Refusing to continue.\n' % (size, value))
+ return 1
+
+ out.write('Image fits (%d <= %d). Continuing.\n' % (size, value))
+ return 0
+
+
+class Main(object):
+ def __init__(self, dir, arch, featureset, flavour):
+ self.args = dir, arch, featureset, flavour
+
+ self.config = ConfigCoreDump(fp=file("debian/config.defines.dump"))
+
+ def __call__(self):
+ fail = 0
+
+ for c in CheckAbi, CheckImage:
+ fail |= c(self.config, *self.args)(sys.stdout)
+
+ return fail
+
+
+if __name__ == '__main__':
+ sys.exit(Main(*sys.argv[1:])())