Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/patch.py @ 9585:ea1935e2020a
patch: handle symlinks without symlinkhunk
Symlink creations and deletions were handled with a special symlinkhunk object,
working like a binary hunk. However, this model does not support symlink
updates or replacements, so we teach regular hunks how to handle symlinks.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Thu, 15 Oct 2009 23:15:30 +0200 |
parents | b8352a3617f3 |
children | d08099e74b81 |
comparison
equal
deleted
inserted
replaced
9575:5e44d9e562bc | 9585:ea1935e2020a |
---|---|
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 fp = self.opener(fname, 'w') |
303 try: | 305 try: |
304 if self.eol and self.eol != '\n': | 306 if self.eol and self.eol != '\n': |
305 for l in lines: | 307 for l in lines: |
306 if l and l[-1] == '\n': | 308 if l and l[-1] == '\n': |
403 if self.exists and h.createfile(): | 405 if self.exists and h.createfile(): |
404 self.ui.warn(_("file %s already exists\n") % self.fname) | 406 self.ui.warn(_("file %s already exists\n") % self.fname) |
405 self.rej.append(h) | 407 self.rej.append(h) |
406 return -1 | 408 return -1 |
407 | 409 |
408 if isinstance(h, githunk): | 410 if isinstance(h, binhunk): |
409 if h.rmfile(): | 411 if h.rmfile(): |
410 self.unlink(self.fname) | 412 self.unlink(self.fname) |
411 else: | 413 else: |
412 self.lines[:] = h.new() | 414 self.lines[:] = h.new() |
413 self.offset += len(h.new()) | 415 self.offset += len(h.new()) |
694 return res | 696 return res |
695 | 697 |
696 def new(self, fuzz=0, toponly=False): | 698 def new(self, fuzz=0, toponly=False): |
697 return self.fuzzit(self.b, fuzz, toponly) | 699 return self.fuzzit(self.b, fuzz, toponly) |
698 | 700 |
699 class githunk(object): | 701 class binhunk: |
700 """A git hunk""" | 702 'A binary patch file. Only understands literals so far.' |
701 def __init__(self, gitpatch): | 703 def __init__(self, gitpatch): |
702 self.gitpatch = gitpatch | 704 self.gitpatch = gitpatch |
703 self.text = None | 705 self.text = None |
704 self.hunk = [] | 706 self.hunk = ['GIT binary patch\n'] |
705 | 707 |
706 def createfile(self): | 708 def createfile(self): |
707 return self.gitpatch.op in ('ADD', 'RENAME', 'COPY') | 709 return self.gitpatch.op in ('ADD', 'RENAME', 'COPY') |
708 | 710 |
709 def rmfile(self): | 711 def rmfile(self): |
712 def complete(self): | 714 def complete(self): |
713 return self.text is not None | 715 return self.text is not None |
714 | 716 |
715 def new(self): | 717 def new(self): |
716 return [self.text] | 718 return [self.text] |
717 | |
718 class binhunk(githunk): | |
719 'A binary patch file. Only understands literals so far.' | |
720 def __init__(self, gitpatch): | |
721 super(binhunk, self).__init__(gitpatch) | |
722 self.hunk = ['GIT binary patch\n'] | |
723 | 719 |
724 def extract(self, lr): | 720 def extract(self, lr): |
725 line = lr.readline() | 721 line = lr.readline() |
726 self.hunk.append(line) | 722 self.hunk.append(line) |
727 while line and not line.startswith('literal '): | 723 while line and not line.startswith('literal '): |
746 if len(text) != size: | 742 if len(text) != size: |
747 raise PatchError(_('binary patch is %d bytes, not %d') % | 743 raise PatchError(_('binary patch is %d bytes, not %d') % |
748 len(text), size) | 744 len(text), size) |
749 self.text = text | 745 self.text = text |
750 | 746 |
751 class symlinkhunk(githunk): | |
752 """A git symlink hunk""" | |
753 def __init__(self, gitpatch, hunk): | |
754 super(symlinkhunk, self).__init__(gitpatch) | |
755 self.hunk = hunk | |
756 | |
757 def complete(self): | |
758 return True | |
759 | |
760 def fix_newline(self): | |
761 return | |
762 | |
763 def parsefilename(str): | 747 def parsefilename(str): |
764 # --- filename \t|space stuff | 748 # --- filename \t|space stuff |
765 s = str[4:].rstrip('\r\n') | 749 s = str[4:].rstrip('\r\n') |
766 i = s.find('\t') | 750 i = s.find('\t') |
767 if i < 0: | 751 if i < 0: |
895 context = True | 879 context = True |
896 gpatch = changed.get(bfile) | 880 gpatch = changed.get(bfile) |
897 create = afile == '/dev/null' or gpatch and gpatch.op == 'ADD' | 881 create = afile == '/dev/null' or gpatch and gpatch.op == 'ADD' |
898 remove = bfile == '/dev/null' or gpatch and gpatch.op == 'DELETE' | 882 remove = bfile == '/dev/null' or gpatch and gpatch.op == 'DELETE' |
899 current_hunk = hunk(x, hunknum + 1, lr, context, create, remove) | 883 current_hunk = hunk(x, hunknum + 1, lr, context, create, remove) |
900 if remove: | |
901 gpatch = changed.get(afile[2:]) | |
902 if gpatch and gpatch.mode[0]: | |
903 current_hunk = symlinkhunk(gpatch, current_hunk) | |
904 except PatchError, err: | 884 except PatchError, err: |
905 ui.debug(err) | 885 ui.debug(err) |
906 current_hunk = None | 886 current_hunk = None |
907 continue | 887 continue |
908 hunknum += 1 | 888 hunknum += 1 |