1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
#!/usr/bin/env python
# vim: set fileencoding=UTF-8:
# Copyright 2013 Red Hat, Inc.
# Author: Jan Pokorný <jpokorny at redhat dot com>
# Licensed under MIT license
import sys
import re
import getopt
from os import environ
from subprocess import Popen, PIPE
from threading import Thread
# svn checkout http://python-patch.googlecode.com/svn/trunk/ python-patch
# pushd python-patch
# patch <../python-patch-allow-for-externalizing-hunk-again.patch
# popd
# ln -s python-patch/patch .
import patch
re_h = re.compile(
r'^Hunk \#(\d+) succeeded at (\d+)(?: with fuzz (\d+))? \(offset (-?\d+) lines?\)\.$',
re.MULTILINE
)
use_threading = True
#use_threading = False
def adjustment(ret, stderrdata):
print >>sys.stderr, "ret = {0}\nstderrdata = {1}".format(ret, stderrdata)
for match in re_h.finditer(stderrdata):
print >>sys.stderr, match.groups()
ret = int(match.groups()[3])
break
else:
ret = 0
return ret
def hunk_worker(hunk, header, tres, i, cmd, **kwargs):
proc = Popen(cmd, **kwargs)
str_hunk = str(hunk)
partial_patch = header + '\n' + str_hunk
_, stderrdata = proc.communicate(partial_patch)
delta = adjustment(proc.wait(), stderrdata)
tres[i] = delta
def proceed(opts, args):
if not args:
args.append('-')
cmd_args = reduce(lambda a, x: a + list(x), opts, [])
#print >>sys.stderr, "cmdargs: {0}, opts: {1}".format(cmd_args, opts)
null = open('/dev/null', 'a')
cmd = (lambda *a: a)('/usr/bin/patch', '-o-', *cmd_args)
e = dict(LC='C')
for name, value in environ.iteritems():
if name in ('TMPDIR', 'TMP', 'TEMP'):
e[name] = value
kwargs = dict(stdin=PIPE, stdout=null, stderr=PIPE, env=e)
for arg in args:
arg = arg if arg != '-' else '/dev/stdin'
ps = patch.fromfile(arg)
if not ps:
print >>sys.stderr, "Bad patch file: {0}".format(arg)
continue
for p in ps.items:
header = '{0}--- {1}\n+++ {2}'.format('\n'.join(p.header),
p.source, p.target)
print header
tres = [0 for hunk in p.hunks]
ts = [True for hunk in p.hunks]
tmax = 10
avg = 0.0
cnt = 0
avg_limit = 50.0
len_ts = len(ts)
while any(ts):
# ts[i] = False if not to continue with that or bool(x) == True
# otherwise (None is a temporary local state!)
for i in xrange(len_ts):
if not ts[i]:
continue
if not use_threading:
hunk_worker(p.hunks[i], header, tres, i, cmd, **kwargs)
ts[i] = None
continue
if i >= tmax:
blockers = filter(lambda (x, y): bool(y), enumerate(ts[:i]))
while len(blockers) >= tmax:
for ii, it in blockers:
it.join(0.001)
if not it.is_alive():
ts[ii] = None
break
else:
continue
break
t = Thread(target=hunk_worker, args=(p.hunks[i], header, tres, i, cmd),
kwargs=kwargs)
ts[i] = t
t.start()
for i in xrange(len_ts):
t = ts[i]
if t and use_threading:
t.join()
ts[i] = None
if ts[i] is None:
avg = (avg * cnt + tres[i])
cnt += 1
avg /= cnt
ts[i] = False
for i in xrange(len_ts):
hunk = p.hunks[i]
if i > 0 and hunk.startsrc < p.hunks[i-1].startsrc: #+ p.hunks[i-1].linessrc:
#print >>sys.stderr, "Critical adjustment: {0}".format(i+1)
p.hunks[i-1].startsrc = hunk.startsrc - p.hunks[i-1].linessrc
for ii in xrange(i-1, len_ts):
ts[i] = True
break
ts[i] = ts[i] or abs(tres[i] - avg) > avg_limit
if i > 0:
ts[i] = ts[i] or abs(tres[i] - tres[i-1]) > (avg_limit/2)
if i < len_ts - 1:
ts[i] = ts[i] or abs(tres[i] - tres[i+1]) > (avg_limit/2)
if ts[i]:
delta = int(tres[i] + (tres[i] - avg) / 1.25)
hunk.startsrc += delta
hunk.starttgt += delta
else:
continue
avg_limit *= 1.25
for i in xrange(len_ts):
delta = tres[i]
hunk = p.hunks[i]
if delta:
hunk.startsrc += delta
hunk.starttgt += delta
print str(hunk),
null.close()
if __name__ == '__main__':
# see PATCH(1)
opts, args = getopt.getopt(sys.argv[1:], 'p:f:h', ['strip=', 'fuzz='])
if ('-h', '') in opts:
print >>sys.stderr, "Usage: {0} {{[-p|-f]}} [patch-or-stdin]" \
.format(sys.argv[0])
sys.exit(0)
sys.exit(proceed(opts, args))
|