##// END OF EJS Templates
Add git-1.4 binary patch support
Brendan Cully -
r3367:7f486971 default
parent child Browse files
Show More
@@ -8,9 +8,9 b''
8 from demandload import demandload
8 from demandload import demandload
9 from i18n import gettext as _
9 from i18n import gettext as _
10 from node import *
10 from node import *
11 demandload(globals(), "cmdutil mdiff util")
11 demandload(globals(), "base85 cmdutil mdiff util")
12 demandload(globals(), '''cStringIO email.Parser errno os re shutil sys tempfile
12 demandload(globals(), "cStringIO email.Parser errno os re shutil sha sys")
13 popen2''')
13 demandload(globals(), "tempfile zlib")
14
14
15 # helper functions
15 # helper functions
16
16
@@ -128,6 +128,7 b' def readgitpatch(patchname):'
128 self.op = 'MODIFY'
128 self.op = 'MODIFY'
129 self.copymod = False
129 self.copymod = False
130 self.lineno = 0
130 self.lineno = 0
131 self.binary = False
131
132
132 # Filter patch for git information
133 # Filter patch for git information
133 gitre = re.compile('diff --git a/(.*) b/(.*)')
134 gitre = re.compile('diff --git a/(.*) b/(.*)')
@@ -175,6 +176,10 b' def readgitpatch(patchname):'
175 gp.mode = int(line.rstrip()[-3:], 8)
176 gp.mode = int(line.rstrip()[-3:], 8)
176 elif line.startswith('new mode '):
177 elif line.startswith('new mode '):
177 gp.mode = int(line.rstrip()[-3:], 8)
178 gp.mode = int(line.rstrip()[-3:], 8)
179 elif line.startswith('GIT binary patch'):
180 if not dopatch:
181 dopatch = 'binary'
182 gp.binary = True
178 if gp:
183 if gp:
179 gitpatches.append(gp)
184 gitpatches.append(gp)
180
185
@@ -185,6 +190,25 b' def readgitpatch(patchname):'
185
190
186 def dogitpatch(patchname, gitpatches, cwd=None):
191 def dogitpatch(patchname, gitpatches, cwd=None):
187 """Preprocess git patch so that vanilla patch can handle it"""
192 """Preprocess git patch so that vanilla patch can handle it"""
193 def extractbin(fp):
194 line = fp.readline()
195 while line and not line.startswith('literal '):
196 line = fp.readline()
197 if not line:
198 return
199 size = int(line[8:].rstrip())
200 dec = []
201 line = fp.readline()
202 while line:
203 line = line[1:-1]
204 dec.append(base85.b85decode(line))
205 line = fp.readline()
206 text = zlib.decompress(''.join(dec))
207 if len(text) != size:
208 raise util.Abort(_('binary patch is %d bytes, not %d') %
209 (len(text), size))
210 return text
211
188 pf = file(patchname)
212 pf = file(patchname)
189 pfline = 1
213 pfline = 1
190
214
@@ -194,23 +218,37 b' def dogitpatch(patchname, gitpatches, cw'
194 try:
218 try:
195 for i in range(len(gitpatches)):
219 for i in range(len(gitpatches)):
196 p = gitpatches[i]
220 p = gitpatches[i]
197 if not p.copymod:
221 if not p.copymod and not p.binary:
198 continue
222 continue
199
223
200 copyfile(p.oldpath, p.path, basedir=cwd)
201
202 # rewrite patch hunk
224 # rewrite patch hunk
203 while pfline < p.lineno:
225 while pfline < p.lineno:
204 tmpfp.write(pf.readline())
226 tmpfp.write(pf.readline())
205 pfline += 1
227 pfline += 1
206 tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
228
207 line = pf.readline()
229 if p.binary:
208 pfline += 1
230 text = extractbin(pf)
209 while not line.startswith('--- a/'):
231 if not text:
210 tmpfp.write(line)
232 raise util.Abort(_('binary patch extraction failed'))
233 if not cwd:
234 cwd = os.getcwd()
235 absdst = os.path.join(cwd, p.path)
236 basedir = os.path.dirname(absdst)
237 if not os.path.isdir(basedir):
238 os.makedirs(basedir)
239 out = file(absdst, 'wb')
240 out.write(text)
241 out.close()
242 elif p.copymod:
243 copyfile(p.oldpath, p.path, basedir=cwd)
244 tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
211 line = pf.readline()
245 line = pf.readline()
212 pfline += 1
246 pfline += 1
213 tmpfp.write('--- a/%s\n' % p.path)
247 while not line.startswith('--- a/'):
248 tmpfp.write(line)
249 line = pf.readline()
250 pfline += 1
251 tmpfp.write('--- a/%s\n' % p.path)
214
252
215 line = pf.readline()
253 line = pf.readline()
216 while line:
254 while line:
@@ -270,16 +308,16 b' def patch(patchname, ui, strip=1, cwd=No'
270
308
271 (dopatch, gitpatches) = readgitpatch(patchname)
309 (dopatch, gitpatches) = readgitpatch(patchname)
272
310
311 files, fuzz = {}, False
273 if dopatch:
312 if dopatch:
274 if dopatch == 'filter':
313 if dopatch in ('filter', 'binary'):
275 patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
314 patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
276 try:
315 try:
277 files, fuzz = __patch(patchname)
316 if dopatch != 'binary':
317 files, fuzz = __patch(patchname)
278 finally:
318 finally:
279 if dopatch == 'filter':
319 if dopatch == 'filter':
280 os.unlink(patchname)
320 os.unlink(patchname)
281 else:
282 files, fuzz = {}, False
283
321
284 for gp in gitpatches:
322 for gp in gitpatches:
285 files[gp.path] = (gp.op, gp)
323 files[gp.path] = (gp.op, gp)
@@ -340,6 +378,40 b' def updatedir(ui, repo, patches, wlock=N'
340
378
341 return files
379 return files
342
380
381 def b85diff(fp, to, tn):
382 '''print base85-encoded binary diff'''
383 def gitindex(text):
384 if not text:
385 return '0' * 40
386 l = len(text)
387 s = sha.new('blob %d\0' % l)
388 s.update(text)
389 return s.hexdigest()
390
391 def fmtline(line):
392 l = len(line)
393 if l <= 26:
394 l = chr(ord('A') + l - 1)
395 else:
396 l = chr(l - 26 + ord('a') - 1)
397 return '%c%s\n' % (l, base85.b85encode(line, True))
398
399 def chunk(text, csize=52):
400 l = len(text)
401 i = 0
402 while i < l:
403 yield text[i:i+csize]
404 i += csize
405
406 # TODO: deltas
407 l = len(tn)
408 fp.write('index %s..%s\nGIT binary patch\nliteral %s\n' %
409 (gitindex(to), gitindex(tn), len(tn)))
410
411 tn = ''.join([fmtline(l) for l in chunk(zlib.compress(tn))])
412 fp.write(tn)
413 fp.write('\n')
414
343 def diff(repo, node1=None, node2=None, files=None, match=util.always,
415 def diff(repo, node1=None, node2=None, files=None, match=util.always,
344 fp=None, changes=None, opts=None):
416 fp=None, changes=None, opts=None):
345 '''print diff of changes to files between two nodes, or node and
417 '''print diff of changes to files between two nodes, or node and
@@ -496,6 +568,8 b' def diff(repo, node1=None, node2=None, f'
496 to = getfile(a).read(arev)
568 to = getfile(a).read(arev)
497 else:
569 else:
498 header.append('new file mode %s\n' % mode)
570 header.append('new file mode %s\n' % mode)
571 if util.binary(tn):
572 dodiff = 'binary'
499 elif f in removed:
573 elif f in removed:
500 if f in srcs:
574 if f in srcs:
501 dodiff = False
575 dodiff = False
@@ -509,9 +583,14 b' def diff(repo, node1=None, node2=None, f'
509 else:
583 else:
510 nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
584 nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
511 addmodehdr(header, omode, nmode)
585 addmodehdr(header, omode, nmode)
586 if util.binary(to) or util.binary(tn):
587 dodiff = 'binary'
512 r = None
588 r = None
513 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
589 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
514 if dodiff:
590 if dodiff == 'binary':
591 fp.write(''.join(header))
592 b85diff(fp, to, tn)
593 elif dodiff:
515 text = mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts)
594 text = mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts)
516 if text or len(header) > 1:
595 if text or len(header) > 1:
517 fp.write(''.join(header))
596 fp.write(''.join(header))
General Comments 0
You need to be logged in to leave comments. Login now