linux/debian/templates/patch.apply.in

296 lines
8.3 KiB
Python

#!/usr/bin/env python
import os, os.path, re, sys
from warnings import warn
from debian_linux.patches import PatchSeries
_default_home = "@home@"
_default_revisions = "@revisions@"
_default_source = "@source@"
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):
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:])
ret_arch = ret_featureset = False
if self.arch is not None:
if match_arch:
if self.arch in match_arch:
self.matched_arch = True
ret_arch = True
else:
ret_arch = True
if not match_featureset:
ret_featureset = ret_arch
if self.featureset is not None:
if match_featureset:
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
class SeriesList(list):
def __call__(self, cond = bool, reverse = False):
for i in self:
i(cond = cond, reverse = reverse)
if reverse:
print "--> %s fully unapplied." % i.name
else:
print "--> %s fully applied." % i.name
@classmethod
def read(cls, revisions, home):
ret = cls()
for i in revisions:
try:
fp = file(os.path.join(home, 'series', i))
ret.append(PatchSeries(i, home, fp))
except IOError:
pass
return ret
@classmethod
def read_extra(cls, revisions, home):
return cls.read((i + '-extra' for i in revisions), home)
class version(object):
__slots__ = "upstream", "revision"
def __init__(self, string = None):
if string is not None:
self.upstream, self.revision = self.parse(string)
def __str__(self):
return "%s-%s" % (self.upstream, self.revision)
_re = r"""
^
(
\d+\.\d+\.\d+
(?:
-.+?
)?
)
-
([^-]+)
$
"""
def parse(self, version):
match = re.match(self._re, version, re.X)
if match is None:
raise ValueError
return match.groups()
class version_file(object):
_file = 'version.Debian'
extra = None
in_progress = False
def __init__(self, ver = None, overwrite = False):
if overwrite:
self._read(ver)
elif os.path.exists(self._file):
s = file(self._file).readline().strip()
self._read(s)
elif ver:
warn('No %s file, assuming pristine Linux %s' % (self._file, ver.upstream))
self.version = version()
self.version.upstream = ver.upstream
self.version.revision = '0'
else:
raise RuntimeError, "Not possible to determine version"
def __str__(self):
if self.in_progress:
return "unstable"
if self.extra is not None:
return ' '.join([str(self.version)] + self.extra.info())
return str(self.version)
def _read(self, s):
list = s.split()
try:
self.version = version(list[0])
except ValueError:
raise RuntimeError, 'Can\'t read version in %s: "%s"' % (self._file, list[0])
arch = featureset = None
for i in list[1:]:
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, version = None, extra = None):
self.in_progress = False
if version is not None:
self.version = version
if extra is not None:
self.extra = extra
self._write()
def main():
options, args = parse_options()
if len(args) > 1:
print "Too much arguments"
return
home = options.home
revisions = ['0'] + options.revisions.split()
source = version(options.source)
if len(args) == 1:
target = version(args[0])
else:
target = source
if options.current is not None:
vfile = version_file(options.current, True)
else:
vfile = version_file(source)
current = vfile.version
current_extra = vfile.extra
target_extra = MatchExtra(options.arch, options.featureset)
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)
source_index = revisions.index(source.revision)
target_index = revisions.index(target.revision)
if current_extra:
if current_index != source_index:
raise RuntimeError, "Can't patch from %s with options %s" % (current, ' '.join(current_extra))
consider = revisions[1:current_index + 1]
s = SeriesList.read_extra(consider, home)
vfile.begin()
s(cond = current_extra, reverse = True)
vfile.commit(current)
if current_index < target_index:
consider = revisions[current_index + 1:target_index + 1]
s = SeriesList.read(consider, home)
vfile.begin()
s()
vfile.commit(target)
elif current_index > target_index:
consider = revisions[current_index + 1:target_index + 1]
s = SeriesList.read(consider, home)
vfile.begin()
s(reverse = True)
vfile.commit(target)
if target_extra:
consider = revisions[1:target_index + 1]
s = SeriesList.read_extra(consider, home)
vfile.begin()
s(cond = target_extra)
vfile.commit(target, 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(
'-C', '--overwrite-current',
dest = 'current',
help = "overwrite current",
)
parser.add_option(
'-H', '--overwrite-home',
default = _default_home, dest = 'home',
help = "overwrite home [default: %default]",
)
parser.add_option(
'-R', '--overwrite-revisions',
default = _default_revisions, dest = 'revisions',
help = "overwrite revisions [default: %default]",
)
parser.add_option(
'-S', '--overwrite-source',
default = _default_source, dest = 'source',
help = "overwrite source [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