Mercurial > hg
comparison mercurial/patch.py @ 12671:1b4e3152da13
patch: remove internal patcher fallback and NoHunk error
By now the internal patcher is probably more reliable than anything we might
find on the command line.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Sat, 09 Oct 2010 15:13:08 -0500 |
parents | d82d40ff9860 |
children | 9ad16d1bce4b |
comparison
equal
deleted
inserted
replaced
12670:d82d40ff9860 | 12671:1b4e3152da13 |
---|---|
14 import base85, mdiff, util, diffhelpers, copies, encoding | 14 import base85, mdiff, util, diffhelpers, copies, encoding |
15 | 15 |
16 gitre = re.compile('diff --git a/(.*) b/(.*)') | 16 gitre = re.compile('diff --git a/(.*) b/(.*)') |
17 | 17 |
18 class PatchError(Exception): | 18 class PatchError(Exception): |
19 pass | |
20 | |
21 class NoHunks(PatchError): | |
22 pass | 19 pass |
23 | 20 |
24 # helper functions | 21 # helper functions |
25 | 22 |
26 def copyfile(src, dst, basedir): | 23 def copyfile(src, dst, basedir): |
995 lr = linereader(fp) | 992 lr = linereader(fp) |
996 # gitworkdone is True if a git operation (copy, rename, ...) was | 993 # gitworkdone is True if a git operation (copy, rename, ...) was |
997 # performed already for the current file. Useful when the file | 994 # performed already for the current file. Useful when the file |
998 # section may have no hunk. | 995 # section may have no hunk. |
999 gitworkdone = False | 996 gitworkdone = False |
1000 empty = None | |
1001 | 997 |
1002 while True: | 998 while True: |
1003 newfile = newgitfile = False | 999 newfile = newgitfile = False |
1004 x = lr.readline() | 1000 x = lr.readline() |
1005 if not x: | 1001 if not x: |
1007 if current_hunk: | 1003 if current_hunk: |
1008 if x.startswith('\ '): | 1004 if x.startswith('\ '): |
1009 current_hunk.fix_newline() | 1005 current_hunk.fix_newline() |
1010 yield 'hunk', current_hunk | 1006 yield 'hunk', current_hunk |
1011 current_hunk = None | 1007 current_hunk = None |
1012 empty = False | |
1013 if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or | 1008 if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or |
1014 ((context is not False) and x.startswith('***************')))): | 1009 ((context is not False) and x.startswith('***************')))): |
1015 try: | 1010 try: |
1016 if context is None and x.startswith('***************'): | 1011 if context is None and x.startswith('***************'): |
1017 context = True | 1012 context = True |
1025 continue | 1020 continue |
1026 hunknum += 1 | 1021 hunknum += 1 |
1027 if emitfile: | 1022 if emitfile: |
1028 emitfile = False | 1023 emitfile = False |
1029 yield 'file', (afile, bfile, current_hunk) | 1024 yield 'file', (afile, bfile, current_hunk) |
1030 empty = False | |
1031 elif state == BFILE and x.startswith('GIT binary patch'): | 1025 elif state == BFILE and x.startswith('GIT binary patch'): |
1032 current_hunk = binhunk(changed[bfile]) | 1026 current_hunk = binhunk(changed[bfile]) |
1033 hunknum += 1 | 1027 hunknum += 1 |
1034 if emitfile: | 1028 if emitfile: |
1035 emitfile = False | 1029 emitfile = False |
1036 yield 'file', ('a/' + afile, 'b/' + bfile, current_hunk) | 1030 yield 'file', ('a/' + afile, 'b/' + bfile, current_hunk) |
1037 empty = False | |
1038 current_hunk.extract(lr) | 1031 current_hunk.extract(lr) |
1039 elif x.startswith('diff --git'): | 1032 elif x.startswith('diff --git'): |
1040 # check for git diff, scanning the whole patch file if needed | 1033 # check for git diff, scanning the whole patch file if needed |
1041 m = gitre.match(x) | 1034 m = gitre.match(x) |
1042 gitworkdone = False | 1035 gitworkdone = False |
1081 context = True | 1074 context = True |
1082 afile = parsefilename(x) | 1075 afile = parsefilename(x) |
1083 bfile = parsefilename(l2) | 1076 bfile = parsefilename(l2) |
1084 | 1077 |
1085 if newfile: | 1078 if newfile: |
1086 if empty: | |
1087 raise NoHunks | |
1088 empty = not gitworkdone | |
1089 gitworkdone = False | 1079 gitworkdone = False |
1090 | 1080 |
1091 if newgitfile or newfile: | 1081 if newgitfile or newfile: |
1092 emitfile = True | 1082 emitfile = True |
1093 state = BFILE | 1083 state = BFILE |
1094 hunknum = 0 | 1084 hunknum = 0 |
1095 if current_hunk: | 1085 if current_hunk: |
1096 if current_hunk.complete(): | 1086 if current_hunk.complete(): |
1097 yield 'hunk', current_hunk | 1087 yield 'hunk', current_hunk |
1098 empty = False | |
1099 else: | 1088 else: |
1100 raise PatchError(_("malformed patch %s %s") % (afile, | 1089 raise PatchError(_("malformed patch %s %s") % (afile, |
1101 current_hunk.desc)) | 1090 current_hunk.desc)) |
1102 | |
1103 if (empty is None and not gitworkdone) or empty: | |
1104 raise NoHunks | |
1105 | |
1106 | 1091 |
1107 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'): | 1092 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'): |
1108 """Reads a patch from fp and tries to apply it. | 1093 """Reads a patch from fp and tries to apply it. |
1109 | 1094 |
1110 The dict 'changed' is filled in with all of the filenames changed | 1095 The dict 'changed' is filled in with all of the filenames changed |
1268 files = {} | 1253 files = {} |
1269 try: | 1254 try: |
1270 if patcher: | 1255 if patcher: |
1271 return externalpatch(patcher, args, patchname, ui, strip, cwd, | 1256 return externalpatch(patcher, args, patchname, ui, strip, cwd, |
1272 files) | 1257 files) |
1273 else: | 1258 return internalpatch(patchname, ui, strip, cwd, files, eolmode) |
1274 try: | |
1275 return internalpatch(patchname, ui, strip, cwd, files, eolmode) | |
1276 except NoHunks: | |
1277 ui.warn(_('internal patcher failed\n' | |
1278 'please report details to ' | |
1279 'http://mercurial.selenic.com/bts/\n' | |
1280 'or mercurial@selenic.com\n')) | |
1281 patcher = (util.find_exe('gpatch') or util.find_exe('patch') | |
1282 or 'patch') | |
1283 ui.debug('no valid hunks found; trying with %r instead\n' % | |
1284 patcher) | |
1285 if util.needbinarypatch(): | |
1286 args.append('--binary') | |
1287 return externalpatch(patcher, args, patchname, ui, strip, cwd, | |
1288 files) | |
1289 except PatchError, err: | 1259 except PatchError, err: |
1290 s = str(err) | 1260 s = str(err) |
1291 if s: | 1261 if s: |
1292 raise util.Abort(s) | 1262 raise util.Abort(s) |
1293 else: | 1263 else: |