comparison mercurial/patch.py @ 10748:fb06e357e698 stable

patch: more precise NoHunk, raised for every file (issue2102)
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Sat, 20 Mar 2010 14:47:05 +0100
parents b010d899665e
children 03225f14c495 196908117c27
comparison
equal deleted inserted replaced
10747:b010d899665e 10748:fb06e357e698
1010 1010
1011 # our states 1011 # our states
1012 BFILE = 1 1012 BFILE = 1
1013 context = None 1013 context = None
1014 lr = linereader(fp) 1014 lr = linereader(fp)
1015 dopatch = True
1016 # gitworkdone is True if a git operation (copy, rename, ...) was 1015 # gitworkdone is True if a git operation (copy, rename, ...) was
1017 # performed already for the current file. Useful when the file 1016 # performed already for the current file. Useful when the file
1018 # section may have no hunk. 1017 # section may have no hunk.
1019 gitworkdone = False 1018 gitworkdone = False
1019 empty = None
1020 1020
1021 while True: 1021 while True:
1022 newfile = newgitfile = False 1022 newfile = newgitfile = False
1023 x = lr.readline() 1023 x = lr.readline()
1024 if not x: 1024 if not x:
1026 if current_hunk: 1026 if current_hunk:
1027 if x.startswith('\ '): 1027 if x.startswith('\ '):
1028 current_hunk.fix_newline() 1028 current_hunk.fix_newline()
1029 yield 'hunk', current_hunk 1029 yield 'hunk', current_hunk
1030 current_hunk = None 1030 current_hunk = None
1031 gitworkdone = False 1031 empty = False
1032 if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or 1032 if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
1033 ((context is not False) and x.startswith('***************')))): 1033 ((context is not False) and x.startswith('***************')))):
1034 try: 1034 try:
1035 if context is None and x.startswith('***************'): 1035 if context is None and x.startswith('***************'):
1036 context = True 1036 context = True
1044 continue 1044 continue
1045 hunknum += 1 1045 hunknum += 1
1046 if emitfile: 1046 if emitfile:
1047 emitfile = False 1047 emitfile = False
1048 yield 'file', (afile, bfile, current_hunk) 1048 yield 'file', (afile, bfile, current_hunk)
1049 empty = False
1049 elif state == BFILE and x.startswith('GIT binary patch'): 1050 elif state == BFILE and x.startswith('GIT binary patch'):
1050 current_hunk = binhunk(changed[bfile]) 1051 current_hunk = binhunk(changed[bfile])
1051 hunknum += 1 1052 hunknum += 1
1052 if emitfile: 1053 if emitfile:
1053 emitfile = False 1054 emitfile = False
1054 yield 'file', ('a/' + afile, 'b/' + bfile, current_hunk) 1055 yield 'file', ('a/' + afile, 'b/' + bfile, current_hunk)
1056 empty = False
1055 current_hunk.extract(lr) 1057 current_hunk.extract(lr)
1056 elif x.startswith('diff --git'): 1058 elif x.startswith('diff --git'):
1057 # check for git diff, scanning the whole patch file if needed 1059 # check for git diff, scanning the whole patch file if needed
1058 m = gitre.match(x) 1060 m = gitre.match(x)
1061 gitworkdone = False
1059 if m: 1062 if m:
1060 afile, bfile = m.group(1, 2) 1063 afile, bfile = m.group(1, 2)
1061 if not git: 1064 if not git:
1062 git = True 1065 git = True
1063 dopatch, gitpatches = scangitpatch(lr, x) 1066 gitpatches = scangitpatch(lr, x)[1]
1064 yield 'git', gitpatches 1067 yield 'git', gitpatches
1065 for gp in gitpatches: 1068 for gp in gitpatches:
1066 changed[gp.path] = gp 1069 changed[gp.path] = gp
1067 # else error? 1070 # else error?
1068 # copy/rename + modify should modify target, not source 1071 # copy/rename + modify should modify target, not source
1069 gp = changed.get(bfile) 1072 gp = changed.get(bfile)
1070 if gp and gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD'): 1073 if gp and (gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD')
1074 or gp.mode):
1071 afile = bfile 1075 afile = bfile
1072 gitworkdone = True 1076 gitworkdone = True
1073 newgitfile = True 1077 newgitfile = True
1074 elif x.startswith('---'): 1078 elif x.startswith('---'):
1075 # check for a unified diff 1079 # check for a unified diff
1095 newfile = True 1099 newfile = True
1096 context = True 1100 context = True
1097 afile = parsefilename(x) 1101 afile = parsefilename(x)
1098 bfile = parsefilename(l2) 1102 bfile = parsefilename(l2)
1099 1103
1104 if newfile:
1105 if empty:
1106 raise NoHunks
1107 empty = not gitworkdone
1108 gitworkdone = False
1109
1100 if newgitfile or newfile: 1110 if newgitfile or newfile:
1101 emitfile = True 1111 emitfile = True
1102 state = BFILE 1112 state = BFILE
1103 hunknum = 0 1113 hunknum = 0
1104 if current_hunk: 1114 if current_hunk:
1105 if current_hunk.complete(): 1115 if current_hunk.complete():
1106 yield 'hunk', current_hunk 1116 yield 'hunk', current_hunk
1117 empty = False
1107 else: 1118 else:
1108 raise PatchError(_("malformed patch %s %s") % (afile, 1119 raise PatchError(_("malformed patch %s %s") % (afile,
1109 current_hunk.desc)) 1120 current_hunk.desc))
1110 1121
1111 if hunknum == 0 and dopatch and not gitworkdone: 1122 if (empty is None and not gitworkdone) or empty:
1112 raise NoHunks 1123 raise NoHunks
1113 1124
1114 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'): 1125 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'):
1115 """ 1126 """
1116 Reads a patch from fp and tries to apply it. 1127 Reads a patch from fp and tries to apply it.