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 = False |
1022 newfile = newgitfile = False |
1023 x = lr.readline() |
1023 x = lr.readline() |
1024 if not x: |
1024 if not x: |
1025 break |
1025 break |
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 newfile = True |
1077 newgitfile = True |
1074 elif x.startswith('---'): |
1078 elif x.startswith('---'): |
1075 # check for a unified diff |
1079 # check for a unified diff |
1076 l2 = lr.readline() |
1080 l2 = lr.readline() |
1077 if not l2.startswith('+++'): |
1081 if not l2.startswith('+++'): |
1078 lr.push(l2) |
1082 lr.push(l2) |
1096 context = True |
1100 context = True |
1097 afile = parsefilename(x) |
1101 afile = parsefilename(x) |
1098 bfile = parsefilename(l2) |
1102 bfile = parsefilename(l2) |
1099 |
1103 |
1100 if newfile: |
1104 if newfile: |
|
1105 if empty: |
|
1106 raise NoHunks |
|
1107 empty = not gitworkdone |
|
1108 gitworkdone = False |
|
1109 |
|
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. |