comparison mercurial/patch.py @ 9598:a981ddb16b80

Merge with crew-stable
author Patrick Mezard <pmezard@gmail.com>
date Fri, 16 Oct 2009 00:06:23 +0200
parents c156bf947e26 d08099e74b81
children 5384a22ab698
comparison
equal deleted inserted replaced
9597:fbed59b61a1c 9598:a981ddb16b80
290 self.fileprinted = False 290 self.fileprinted = False
291 self.printfile(False) 291 self.printfile(False)
292 self.hunks = 0 292 self.hunks = 0
293 293
294 def readlines(self, fname): 294 def readlines(self, fname):
295 if os.path.islink(fname):
296 return [os.readlink(fname)]
295 fp = self.opener(fname, 'r') 297 fp = self.opener(fname, 'r')
296 try: 298 try:
297 return list(linereader(fp, self.eol is not None)) 299 return list(linereader(fp, self.eol is not None))
298 finally: 300 finally:
299 fp.close() 301 fp.close()
300 302
301 def writelines(self, fname, lines): 303 def writelines(self, fname, lines):
302 fp = self.opener(fname, 'w') 304 # Ensure supplied data ends in fname, being a regular file or
305 # a symlink. updatedir() will -too magically- take care of
306 # setting it to the proper type afterwards.
307 islink = os.path.islink(fname)
308 if islink:
309 fp = cStringIO.StringIO()
310 else:
311 fp = self.opener(fname, 'w')
303 try: 312 try:
304 if self.eol and self.eol != '\n': 313 if self.eol and self.eol != '\n':
305 for l in lines: 314 for l in lines:
306 if l and l[-1] == '\n': 315 if l and l[-1] == '\n':
307 l = l[:-1] + self.eol 316 l = l[:-1] + self.eol
308 fp.write(l) 317 fp.write(l)
309 else: 318 else:
310 fp.writelines(lines) 319 fp.writelines(lines)
320 if islink:
321 self.opener.symlink(fp.getvalue(), fname)
311 finally: 322 finally:
312 fp.close() 323 fp.close()
313 324
314 def unlink(self, fname): 325 def unlink(self, fname):
315 os.unlink(fname) 326 os.unlink(fname)
397 if self.exists and h.createfile(): 408 if self.exists and h.createfile():
398 self.ui.warn(_("file %s already exists\n") % self.fname) 409 self.ui.warn(_("file %s already exists\n") % self.fname)
399 self.rej.append(h) 410 self.rej.append(h)
400 return -1 411 return -1
401 412
402 if isinstance(h, githunk): 413 if isinstance(h, binhunk):
403 if h.rmfile(): 414 if h.rmfile():
404 self.unlink(self.fname) 415 self.unlink(self.fname)
405 else: 416 else:
406 self.lines[:] = h.new() 417 self.lines[:] = h.new()
407 self.offset += len(h.new()) 418 self.offset += len(h.new())
663 return res 674 return res
664 675
665 def new(self, fuzz=0, toponly=False): 676 def new(self, fuzz=0, toponly=False):
666 return self.fuzzit(self.b, fuzz, toponly) 677 return self.fuzzit(self.b, fuzz, toponly)
667 678
668 class githunk(object): 679 class binhunk:
669 """A git hunk""" 680 'A binary patch file. Only understands literals so far.'
670 def __init__(self, gitpatch): 681 def __init__(self, gitpatch):
671 self.gitpatch = gitpatch 682 self.gitpatch = gitpatch
672 self.text = None 683 self.text = None
673 self.hunk = [] 684 self.hunk = ['GIT binary patch\n']
674 685
675 def createfile(self): 686 def createfile(self):
676 return self.gitpatch.op in ('ADD', 'RENAME', 'COPY') 687 return self.gitpatch.op in ('ADD', 'RENAME', 'COPY')
677 688
678 def rmfile(self): 689 def rmfile(self):
681 def complete(self): 692 def complete(self):
682 return self.text is not None 693 return self.text is not None
683 694
684 def new(self): 695 def new(self):
685 return [self.text] 696 return [self.text]
686
687 class binhunk(githunk):
688 'A binary patch file. Only understands literals so far.'
689 def __init__(self, gitpatch):
690 super(binhunk, self).__init__(gitpatch)
691 self.hunk = ['GIT binary patch\n']
692 697
693 def extract(self, lr): 698 def extract(self, lr):
694 line = lr.readline() 699 line = lr.readline()
695 self.hunk.append(line) 700 self.hunk.append(line)
696 while line and not line.startswith('literal '): 701 while line and not line.startswith('literal '):
715 if len(text) != size: 720 if len(text) != size:
716 raise PatchError(_('binary patch is %d bytes, not %d') % 721 raise PatchError(_('binary patch is %d bytes, not %d') %
717 len(text), size) 722 len(text), size)
718 self.text = text 723 self.text = text
719 724
720 class symlinkhunk(githunk):
721 """A git symlink hunk"""
722 def __init__(self, gitpatch, hunk):
723 super(symlinkhunk, self).__init__(gitpatch)
724 self.hunk = hunk
725
726 def complete(self):
727 return True
728
729 def fix_newline(self):
730 return
731
732 def parsefilename(str): 725 def parsefilename(str):
733 # --- filename \t|space stuff 726 # --- filename \t|space stuff
734 s = str[4:].rstrip('\r\n') 727 s = str[4:].rstrip('\r\n')
735 i = s.find('\t') 728 i = s.find('\t')
736 if i < 0: 729 if i < 0:
873 context = True 866 context = True
874 gpatch = changed.get(bfile) 867 gpatch = changed.get(bfile)
875 create = afile == '/dev/null' or gpatch and gpatch.op == 'ADD' 868 create = afile == '/dev/null' or gpatch and gpatch.op == 'ADD'
876 remove = bfile == '/dev/null' or gpatch and gpatch.op == 'DELETE' 869 remove = bfile == '/dev/null' or gpatch and gpatch.op == 'DELETE'
877 current_hunk = hunk(x, hunknum + 1, lr, context, create, remove) 870 current_hunk = hunk(x, hunknum + 1, lr, context, create, remove)
878 if remove:
879 gpatch = changed.get(afile[2:])
880 if gpatch and gpatch.mode[0]:
881 current_hunk = symlinkhunk(gpatch, current_hunk)
882 except PatchError, err: 871 except PatchError, err:
883 ui.debug(err) 872 ui.debug(err)
884 current_hunk = None 873 current_hunk = None
885 continue 874 continue
886 hunknum += 1 875 hunknum += 1