#!/usr/bin/env python import os, os.path, re, sys from warnings import warn sys.path.append("/usr/share/linux-support-@linux_upstream@@abiname@/lib/python") from debian_linux.patches import PatchSeries, PatchSeriesList _default_home = "/usr/src/kernel-patches/all/@linux_upstream@/debian" revisions = "@revisions@".split() upstream = "@upstream@" class MatchExtra(object): def __init__(self, arch, featureset): self.arch, self.featureset = arch, featureset self.matched_arch = self.matched_featureset = False def __call__(self, obj): if not self: return False data = obj.data match_arch = [] match_featureset = [] for i in data: if i.startswith("arch="): match_arch.append(i[5:]) elif i.startswith("featureset="): match_featureset.append(i[11:]) else: raise RuntimeError('Ignored unknown modifier: %s' % i) ret_arch = ret_featureset = False if match_arch: if self.arch is not None: if self.arch in match_arch: self.matched_arch = True ret_arch = True else: ret_arch = True if match_featureset: if self.featureset is not None: if self.featureset in match_featureset: self.matched_featureset = True ret_featureset = True else: ret_featureset = True return ret_arch and ret_featureset def __nonzero__(self): return self.arch is not None or self.featureset is not None def info(self): ret = [] if self.matched_arch: ret.append("arch=%s" % self.arch) if self.matched_featureset: ret.append("featureset=%s" % self.featureset) return ret _marker = object() class version_file(object): _file = 'version.Debian' extra = None in_progress = False def __init__(self, upstream = None): if os.path.exists(self._file): s = file(self._file).readline().strip() self._read(s) elif upstream: warn('No %s file, assuming Debian Linux %s' % (self._file, upstream)) self.upstream = upstream self.revision = 'orig' else: raise RuntimeError, "Not possible to determine version" def __str__(self): if self.in_progress: return "unstable" ret = [self.upstream, self.revision] if self.extra is not None: ret.extend(self.extra.info()) return ' '.join(ret) def _read(self, s): if s == 'unstable': raise RuntimeError("Tree is in an unstable condition. Can't continue!") list = s.split() self.upstream, self.revision = list[0:2] arch = featureset = None for i in list[2:]: if i.startswith("arch="): arch = i[5:] elif i.startswith("featureset="): featureset = i[11:] else: raise RuntimeError("Can't parse extra information") self.extra = MatchExtra(arch, featureset) def _write(self): if os.path.lexists(self._file): os.unlink(self._file) file(self._file, 'w').write('%s\n' % self) def begin(self): self.in_progress = True self._write() def commit(self, revision, extra = _marker): self.in_progress = False self.revision = revision if extra is not _marker: self.extra = extra self._write() def main(): options, args = parse_options() if len(args) > 1: print "Too much arguments" return home = options.home vfile = version_file(upstream) current_revision = vfile.revision current_extra = vfile.extra if len(args) == 1: target_revision = args[0] else: target_revision = revisions[-1] target_extra = MatchExtra(options.arch, options.featureset) if vfile.upstream != upstream: raise RuntimeError("Upstream version differs between tree (%s) and package (%s)" % (vfile.upstream, upstream)) if current_revision not in revisions: raise RuntimeError, "Current revision is not in our list of revisions" if target_revision not in revisions: raise RuntimeError, "Target revision is not in our list of revisions" if current_revision == target_revision and current_extra == target_extra: print "Nothing to do" return current_index = revisions.index(current_revision) target_index = revisions.index(target_revision) if current_extra: if current_revision != revisions[-1]: raise RuntimeError, "Can't patch from %s with options %s" % (current, ' '.join(current_extra)) consider = ['%s-extra' % i for i in revisions[1:current_index + 1]] s = PatchSeriesList.read(home, consider) vfile.begin() s(cond = current_extra, reverse = True) vfile.commit(current_revision, None) if current_index < target_index: consider = revisions[current_index + 1:target_index + 1] s = PatchSeriesList.read(home, consider) vfile.begin() s() vfile.commit(target_revision) elif current_index > target_index: consider = revisions[target_index + 1:current_index + 1] s = PatchSeriesList.read(home, consider) vfile.begin() s(reverse = True) vfile.commit(target_revision) if target_extra: consider = ['%s-extra' % i for i in revisions[1:target_index + 1]] s = PatchSeriesList.read(home, consider) vfile.begin() s(cond = target_extra) vfile.commit(target_revision, target_extra) def parse_options(): from optparse import OptionParser parser = OptionParser( usage = "%prog [OPTION]... [TARGET]", ) parser.add_option( '-a', '--arch', dest = 'arch', help = "arch", ) parser.add_option( '-f', '--featureset', dest = 'featureset', help = "featureset", ) parser.add_option( '-H', '--overwrite-home', default = _default_home, dest = 'home', help = "overwrite home [default: %default]", ) options, args = parser.parse_args() if options.arch is None and options.featureset is not None: raise RuntimeError('You specified a featureset without an arch, this is not really working') return options, args if __name__ == '__main__': def showwarning(message, category, filename, lineno): sys.stderr.write("Warning: %s\n" % message) import warnings warnings.showwarning = showwarning try: main() except RuntimeError, e: sys.stderr.write("Error: %s\n" % e) raise SystemExit, 1