mercurial/patch.py
changeset 10101 155fe35534d3
parent 9725 3f522d2fa633
child 10102 1720d70cd6d4
equal deleted inserted replaced
10100:be442c7d84b4 10101:155fe35534d3
   262             yield l
   262             yield l
   263 
   263 
   264 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
   264 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
   265 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
   265 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
   266 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
   266 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
       
   267 eolmodes = ['strict', 'crlf', 'lf']
   267 
   268 
   268 class patchfile(object):
   269 class patchfile(object):
   269     def __init__(self, ui, fname, opener, missing=False, eol=None):
   270     def __init__(self, ui, fname, opener, missing=False, eolmode='strict'):
   270         self.fname = fname
   271         self.fname = fname
   271         self.eol = eol
   272         self.eolmode = eolmode
       
   273         self.eol = {'strict': None, 'crlf': '\r\n', 'lf': '\n'}[eolmode]
   272         self.opener = opener
   274         self.opener = opener
   273         self.ui = ui
   275         self.ui = ui
   274         self.lines = []
   276         self.lines = []
   275         self.exists = False
   277         self.exists = False
   276         self.missing = missing
   278         self.missing = missing
   294     def readlines(self, fname):
   296     def readlines(self, fname):
   295         if os.path.islink(fname):
   297         if os.path.islink(fname):
   296             return [os.readlink(fname)]
   298             return [os.readlink(fname)]
   297         fp = self.opener(fname, 'r')
   299         fp = self.opener(fname, 'r')
   298         try:
   300         try:
   299             return list(linereader(fp, self.eol is not None))
   301             return list(linereader(fp, self.eolmode != 'strict'))
   300         finally:
   302         finally:
   301             fp.close()
   303             fp.close()
   302 
   304 
   303     def writelines(self, fname, lines):
   305     def writelines(self, fname, lines):
   304         # Ensure supplied data ends in fname, being a regular file or
   306         # Ensure supplied data ends in fname, being a regular file or
   937                              current_hunk.desc))
   939                              current_hunk.desc))
   938 
   940 
   939     if hunknum == 0 and dopatch and not gitworkdone:
   941     if hunknum == 0 and dopatch and not gitworkdone:
   940         raise NoHunks
   942         raise NoHunks
   941 
   943 
   942 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eol=None):
   944 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'):
   943     """
   945     """
   944     Reads a patch from fp and tries to apply it.
   946     Reads a patch from fp and tries to apply it.
   945 
   947 
   946     The dict 'changed' is filled in with all of the filenames changed
   948     The dict 'changed' is filled in with all of the filenames changed
   947     by the patch. Returns 0 for a clean patch, -1 if any rejects were
   949     by the patch. Returns 0 for a clean patch, -1 if any rejects were
   948     found and 1 if there was any fuzz.
   950     found and 1 if there was any fuzz.
   949 
   951 
   950     If 'eol' is None, the patch content and patched file are read in
   952     If 'eolmode' is 'strict', the patch content and patched file are
   951     binary mode. Otherwise, line endings are ignored when patching then
   953     read in binary mode. Otherwise, line endings are ignored when
   952     normalized to 'eol' (usually '\n' or \r\n').
   954     patching then normalized according to 'eolmode'.
   953     """
   955     """
   954     rejects = 0
   956     rejects = 0
   955     err = 0
   957     err = 0
   956     current_file = None
   958     current_file = None
   957     gitpatches = None
   959     gitpatches = None
   958     opener = util.opener(os.getcwd())
   960     opener = util.opener(os.getcwd())
   959     textmode = eol is not None
   961     textmode = eolmode != 'strict'
   960 
   962 
   961     def closefile():
   963     def closefile():
   962         if not current_file:
   964         if not current_file:
   963             return 0
   965             return 0
   964         current_file.close()
   966         current_file.close()
   977         elif state == 'file':
   979         elif state == 'file':
   978             rejects += closefile()
   980             rejects += closefile()
   979             afile, bfile, first_hunk = values
   981             afile, bfile, first_hunk = values
   980             try:
   982             try:
   981                 if sourcefile:
   983                 if sourcefile:
   982                     current_file = patchfile(ui, sourcefile, opener, eol=eol)
   984                     current_file = patchfile(ui, sourcefile, opener, eolmode=eolmode)
   983                 else:
   985                 else:
   984                     current_file, missing = selectfile(afile, bfile, first_hunk,
   986                     current_file, missing = selectfile(afile, bfile, first_hunk,
   985                                             strip)
   987                                             strip)
   986                     current_file = patchfile(ui, current_file, opener, missing, eol)
   988                     current_file = patchfile(ui, current_file, opener, missing, eolmode)
   987             except PatchError, err:
   989             except PatchError, err:
   988                 ui.warn(str(err) + '\n')
   990                 ui.warn(str(err) + '\n')
   989                 current_file, current_hunk = None, None
   991                 current_file, current_hunk = None, None
   990                 rejects += 1
   992                 rejects += 1
   991                 continue
   993                 continue
  1102 
  1104 
  1103     if files is None:
  1105     if files is None:
  1104         files = {}
  1106         files = {}
  1105     if eolmode is None:
  1107     if eolmode is None:
  1106         eolmode = ui.config('patch', 'eol', 'strict')
  1108         eolmode = ui.config('patch', 'eol', 'strict')
  1107     try:
  1109     if eolmode.lower() not in eolmodes:
  1108         eol = {'strict': None, 'crlf': '\r\n', 'lf': '\n'}[eolmode.lower()]
       
  1109     except KeyError:
       
  1110         raise util.Abort(_('Unsupported line endings type: %s') % eolmode)
  1110         raise util.Abort(_('Unsupported line endings type: %s') % eolmode)
       
  1111     eolmode = eolmode.lower()
  1111 
  1112 
  1112     try:
  1113     try:
  1113         fp = open(patchobj, 'rb')
  1114         fp = open(patchobj, 'rb')
  1114     except TypeError:
  1115     except TypeError:
  1115         fp = patchobj
  1116         fp = patchobj
  1116     if cwd:
  1117     if cwd:
  1117         curdir = os.getcwd()
  1118         curdir = os.getcwd()
  1118         os.chdir(cwd)
  1119         os.chdir(cwd)
  1119     try:
  1120     try:
  1120         ret = applydiff(ui, fp, files, strip=strip, eol=eol)
  1121         ret = applydiff(ui, fp, files, strip=strip, eolmode=eolmode)
  1121     finally:
  1122     finally:
  1122         if cwd:
  1123         if cwd:
  1123             os.chdir(curdir)
  1124             os.chdir(curdir)
  1124     if ret < 0:
  1125     if ret < 0:
  1125         raise PatchError
  1126         raise PatchError