mercurial/patch.py
changeset 9598 a981ddb16b80
parent 9576 c156bf947e26
parent 9586 d08099e74b81
child 9639 5384a22ab698
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