1
2
3
4
5
6
7
8
9
10
11
12
13
14 """
15 Applies unified format diffs
16 """
17
18 from conary.lib import fixeddifflib, log
19 import types
20
22
23
24
25 - def apply(self, src, srcLine):
26 result = []
27 fromLine = srcLine
28 for line in self.lines:
29 if line[0] == " ":
30 if fromLine >= len(src):
31 continue
32
33 result.append(src[fromLine])
34 fromLine = fromLine + 1
35 elif line[0] == "+":
36 result.append(line[1:])
37 elif line[0] == "-":
38 fromLine = fromLine + 1
39
40 return result
41
43
44
45 conflicts = 0
46 srcLen = len(src)
47 srcLine = origSrcLine
48 for line in self.lines:
49 if line[0] == " ":
50 if srcLine >= srcLen:
51 conflicts += 1
52 elif src[srcLine] != line[1:]:
53 conflicts += 1
54 srcLine += 1
55 elif line[0] == "-":
56
57
58
59 if srcLine >= srcLen:
60 conflicts = len(self.lines)
61 elif src[srcLine] != line[1:]:
62 conflicts = len(self.lines)
63 srcLine += 1
64
65 if conflicts:
66
67 applied = True
68 srcLine = origSrcLine
69 for line in self.lines:
70 if line[0] == " " or line[0] == "+":
71 if srcLine >= srcLen:
72 applied = False
73 break
74 elif src[srcLine] != line[1:]:
75 applied = False
76 break
77
78 srcLine += 1
79
80 if applied:
81 return -1
82
83 return conflicts
84
87
89 str = "@@ -%d,%s +%d,%d @@\n" % (self.fromStart, self.fromLen,
90 self.toStart, self.toLen)
91 str += "".join(self.lines)
92 return str
93
94 - def __init__(self, fromStart, fromLen, toStart, toLen, lines, contextCount):
95 self.fromStart = fromStart
96 self.toStart = toStart
97 self.fromLen = fromLen
98 self.toLen = toLen
99 self.lines = lines
100 self.contextCount = contextCount
101
103
104 - def write(self, filename, oldName, newName):
105 f = open(filename, "w")
106 f.write("--- %s\n" % oldName)
107 f.write("+++ %s\n" % newName)
108 for hunk in self:
109 hunk.write(f)
110
111
112
113 -def patch(oldLines, unifiedDiff):
114 i = 0
115
116 if type(unifiedDiff) == types.GeneratorType:
117
118 unifiedDiff = [ l for l in unifiedDiff ]
119
120
121 last = len(unifiedDiff)
122 hunks = []
123 while i < last:
124 (magic1, fromRange, toRange, magic2) = unifiedDiff[i].split()
125 if magic1 != "@@" or magic2 != "@@" or fromRange[0] != "-" or \
126 toRange[0] != "+":
127 raise BadHunkHeader()
128
129 (fromStart, fromLen) = fromRange.split(",")
130 fromStart = int(fromStart[1:]) - 1
131 fromLen = int(fromLen)
132
133 (toStart, toLen) = toRange.split(",")
134 toStart = int(toStart[1:]) - 1
135 toLen = int(toLen)
136
137 fromCount = 0
138 toCount = 0
139 contextCount = 0
140 lines = []
141 i += 1
142 while i < last and unifiedDiff[i][0] != '@':
143 lines.append(unifiedDiff[i])
144 ch = unifiedDiff[i][0]
145 if ch == " ":
146 fromCount += 1
147 toCount += 1
148 contextCount += 1
149 elif ch == "-":
150 fromCount += 1
151 elif ch == "+":
152 toCount += 1
153 elif unifiedDiff[i] == '\ No newline at end of file\n':
154 del lines[-1]
155 lines[-1] = lines[-1][:-1]
156 else:
157 raise BadHunk()
158
159 i += 1
160
161 if toCount != toLen or fromCount != fromLen:
162 raise BadHunk()
163
164 hunks.append(Hunk(fromStart, fromLen, toStart, toLen, lines,
165 contextCount))
166
167 i = 0
168 result = []
169 failedHunks = FailedHunkList()
170
171 fromLine = 0
172 offset = 0
173
174 numHunks = len(hunks)
175 for idx, hunk in enumerate(hunks):
176 log.info('patch: applying hunk %s of %s', idx + 1, numHunks)
177 start = hunk.fromStart + offset
178 conflicts = hunk.countConflicts(oldLines, start)
179 best = (conflicts, 0)
180
181 i = 0
182 while best[0]:
183 i = i + 1
184 tried = 0
185 if (start - abs(i) >= 0):
186 tried = 1
187 conflicts = hunk.countConflicts(oldLines, start - i)
188 if conflicts < best[0]:
189 best = (conflicts, -i)
190
191 if not conflicts:
192 i = -i
193 break
194
195 if ((start + i) <= (len(oldLines) - hunk.fromLen)):
196 tried = 1
197 conflicts = hunk.countConflicts(oldLines, start + i)
198 if conflicts < best[0]:
199 best = (conflicts, i)
200 if not conflicts:
201 break
202
203 if not tried:
204 break
205
206 conflictCount = best[0]
207
208 if conflictCount == -1:
209
210 continue
211
212 if conflictCount and (hunk.contextCount - conflictCount) < 2:
213 failedHunks.append(hunk)
214 continue
215
216 offset = best[1]
217 start += offset
218
219 while (fromLine < start):
220 result.append(oldLines[fromLine])
221 fromLine = fromLine + 1
222
223 result += hunk.apply(oldLines, start)
224 fromLine += hunk.fromLen
225
226 while (fromLine < len(oldLines)):
227 result.append(oldLines[fromLine])
228 fromLine = fromLine + 1
229
230 return (result, failedHunks)
231
235
239
241 for line in lines:
242 if line[0] == " ":
243 yield line
244 elif line[0] == "+":
245 yield "-" + line[1:]
246 elif line[0] == "-":
247 yield "+" + line[1:]
248 elif line[0] == "@":
249 fields = line.split()
250 new = [ fields[0], "-" + fields[2][1:],
251 "+" + fields[1][1:], fields[3] ]
252 yield " ".join(new) + "\n"
253
255
256
257
258 diff = list(fixeddifflib.unified_diff(first, second, *args, **kwargs))
259 missingNewLines = []
260 for i, line in enumerate(diff):
261 if line[-1] != '\n':
262 missingNewLines.append(i)
263
264 for i in reversed(missingNewLines):
265 diff.insert(i + 1, '\ No newline at end of file\n')
266 diff[i] += '\n'
267
268
269 for line in diff:
270 yield line
271