linux/debian/lib/python/debian_linux/patches.py

181 lines
4.6 KiB
Python

from __future__ import print_function
import glob
import os
import shutil
import subprocess
class Operation(object):
def __init__(self, name, data):
self.name, self.data = name, data
def __call__(self, dir='.', reverse=False):
try:
if not reverse:
self.do(dir)
else:
self.do_reverse(dir)
self._log(True)
except:
self._log(False)
raise
def _log(self, result):
if result:
s = "OK"
else:
s = "FAIL"
print(""" (%s) %-4s %s""" % (self.operation, s, self.name))
def do(self, dir):
raise NotImplementedError
def do_reverse(self, dir):
raise NotImplementedError
class OperationPatch(Operation):
def __init__(self, name, filename, data):
super(OperationPatch, self).__init__(name, data)
self.filename = filename
def _call(self, dir, *extraargs):
with open(self.filename) as f:
subprocess.check_call(
("patch", "-p1", "-f", "-s", "-t", "--no-backup-if-mismatch") + extraargs,
cwd=dir,
stdin=f,
)
def patch_push(self, dir):
self._call(dir, '--fuzz=1')
def patch_pop(self, dir):
self._call(dir, '-R')
class OperationPatchPush(OperationPatch):
operation = '+'
do = OperationPatch.patch_push
do_reverse = OperationPatch.patch_pop
class OperationPatchPop(OperationPatch):
operation = '-'
do = OperationPatch.patch_pop
do_reverse = OperationPatch.patch_push
class SubOperation(Operation):
def _log(self, result):
if result:
s = "OK"
else:
s = "FAIL"
print(""" %-10s %-4s %s""" % ('(%s)' % self.operation, s, self.name))
class SubOperationFilesRemove(SubOperation):
operation = "remove"
def do(self, dir):
name = os.path.join(dir, self.name)
for n in glob.iglob(name):
if os.path.isdir(n):
shutil.rmtree(n)
else:
os.unlink(n)
class SubOperationFilesUnifdef(SubOperation):
operation = "unifdef"
def do(self, dir):
filename = os.path.join(dir, self.name)
ret = subprocess.call(("unifdef", "-o", filename, filename) + tuple(self.data))
if ret == 0:
raise RuntimeError("unifdef of %s removed nothing" % self.name)
elif ret != 1:
raise RuntimeError("unifdef failed")
class OperationFiles(Operation):
operation = 'X'
suboperations = {
'remove': SubOperationFilesRemove,
'rm': SubOperationFilesRemove,
'unifdef': SubOperationFilesUnifdef,
}
def __init__(self, name, filename, data):
super(OperationFiles, self).__init__(name, data)
ops = []
with open(filename) as f:
for line in f:
line = line.strip()
if not line or line[0] == '#':
continue
items = line.split()
operation, filename = items[:2]
data = items[2:]
if operation not in self.suboperations:
raise RuntimeError('Undefined operation "%s" in series %s' % (operation, name))
ops.append(self.suboperations[operation](filename, data))
self.ops = ops
def do(self, dir):
for i in self.ops:
i(dir=dir)
class PatchSeries(list):
operations = {
'+': OperationPatchPush,
'-': OperationPatchPop,
'X': OperationFiles,
}
def __init__(self, name, root, fp):
self.name, self.root = name, root
for line in fp:
line = line.strip()
if not len(line) or line[0] == '#':
continue
items = line.split(' ')
operation, filename = items[:2]
data = items[2:]
if operation in self.operations:
f = os.path.join(self.root, filename)
if os.path.exists(f):
self.append(self.operations[operation](filename, f, data))
else:
raise RuntimeError("Can't find patch %s for series %s" % (filename, self.name))
else:
raise RuntimeError('Undefined operation "%s" in series %s' % (operation, name))
def __call__(self, cond=bool, dir='.', reverse=False):
if not reverse:
l = self
else:
l = self[::-1]
for i in l:
if cond(i):
i(dir=dir, reverse=reverse)
def __repr__(self):
return '<%s object for %s>' % (self.__class__.__name__, self.name)