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 |