comparison mercurial/patch.py @ 10101:155fe35534d3

patch: propagate eolmode down to patchfile The old code mapped the value of eolmode ('strict', 'crlf' or 'lf') to eol (None, '\r\n' or '\n') at the entry point in internalpatch. The value of eol was then used directly as the desired EOL in patchfile. We now delay the mapping and let patchfile do it instead. This allows for more complicated behavior where it does not make sense to map eolmode directly to the target EOLs.
author Martin Geisler <mg@lazybytes.net>
date Sun, 20 Dec 2009 17:18:02 +0100
parents 3f522d2fa633
children 1720d70cd6d4
comparison
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