Mercurial > public > mercurial-scm > hg
comparison mercurial/patch.py @ 14389:909ac6b9636b
patch: stop modifying gitpatch objects
gitpatch objects emitted by iterhunks() were referencing file paths unmodified
from the input patch. _applydif() made them usable by modifying the gitpatch
objects in-place with specified path strip level. The same modified objects
were then reused by iterhunks() generator. _applydiff() now copies and update
the paths which completely decouples both routines.
As a side effect, the "git" event now receives only metadata about
copies/renames to perform the necessary copies ahead of time. Other actions are
handled in the "file" event.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Thu, 19 May 2011 22:44:01 +0200 |
parents | 37c997d21752 |
children | ce77c275bec3 |
comparison
equal
deleted
inserted
replaced
14388:37c997d21752 | 14389:909ac6b9636b |
---|---|
1155 continue | 1155 continue |
1156 if gitpatches is None: | 1156 if gitpatches is None: |
1157 # scan whole input for git metadata | 1157 # scan whole input for git metadata |
1158 gitpatches = [('b/' + gp.path, gp) for gp | 1158 gitpatches = [('b/' + gp.path, gp) for gp |
1159 in scangitpatch(lr, x)] | 1159 in scangitpatch(lr, x)] |
1160 yield 'git', [g[1] for g in gitpatches] | 1160 yield 'git', [g[1] for g in gitpatches |
1161 if g[1].op in ('COPY', 'RENAME')] | |
1161 gitpatches.reverse() | 1162 gitpatches.reverse() |
1162 afile = 'a/' + m.group(1) | 1163 afile = 'a/' + m.group(1) |
1163 bfile = 'b/' + m.group(2) | 1164 bfile = 'b/' + m.group(2) |
1164 while bfile != gitpatches[-1][0]: | 1165 while bfile != gitpatches[-1][0]: |
1165 gp = gitpatches.pop()[1] | 1166 gp = gitpatches.pop()[1] |
1218 """ | 1219 """ |
1219 return _applydiff(ui, fp, patchfile, backend, changed, strip=strip, | 1220 return _applydiff(ui, fp, patchfile, backend, changed, strip=strip, |
1220 eolmode=eolmode) | 1221 eolmode=eolmode) |
1221 | 1222 |
1222 def _applydiff(ui, fp, patcher, backend, changed, strip=1, eolmode='strict'): | 1223 def _applydiff(ui, fp, patcher, backend, changed, strip=1, eolmode='strict'): |
1224 | |
1225 def pstrip(p): | |
1226 return pathstrip(p, strip - 1)[1] | |
1227 | |
1223 rejects = 0 | 1228 rejects = 0 |
1224 err = 0 | 1229 err = 0 |
1225 current_file = None | 1230 current_file = None |
1226 | 1231 |
1227 for state, values in iterhunks(fp): | 1232 for state, values in iterhunks(fp): |
1237 if current_file: | 1242 if current_file: |
1238 rejects += current_file.close() | 1243 rejects += current_file.close() |
1239 current_file = None | 1244 current_file = None |
1240 afile, bfile, first_hunk, gp = values | 1245 afile, bfile, first_hunk, gp = values |
1241 if gp: | 1246 if gp: |
1242 changed[gp.path] = gp | 1247 path = pstrip(gp.path) |
1248 changed[path] = gp | |
1243 if gp.op == 'DELETE': | 1249 if gp.op == 'DELETE': |
1244 backend.unlink(gp.path) | 1250 backend.unlink(path) |
1245 continue | 1251 continue |
1246 if gp.op == 'RENAME': | 1252 if gp.op == 'RENAME': |
1247 backend.unlink(gp.oldpath) | 1253 backend.unlink(pstrip(gp.oldpath)) |
1248 if gp.mode and not first_hunk: | 1254 if gp.mode and not first_hunk: |
1249 if gp.op == 'ADD': | 1255 if gp.op == 'ADD': |
1250 # Added files without content have no hunk and must be created | 1256 # Added files without content have no hunk and must be created |
1251 backend.writelines(gp.path, [], gp.mode) | 1257 backend.writelines(path, [], gp.mode) |
1252 else: | 1258 else: |
1253 backend.setmode(gp.path, gp.mode[0], gp.mode[1]) | 1259 backend.setmode(path, gp.mode[0], gp.mode[1]) |
1254 if not first_hunk: | 1260 if not first_hunk: |
1255 continue | 1261 continue |
1256 try: | 1262 try: |
1257 mode = gp and gp.mode or None | 1263 mode = gp and gp.mode or None |
1258 current_file, missing = selectfile(backend, afile, bfile, | 1264 current_file, missing = selectfile(backend, afile, bfile, |
1264 current_file = None | 1270 current_file = None |
1265 rejects += 1 | 1271 rejects += 1 |
1266 continue | 1272 continue |
1267 elif state == 'git': | 1273 elif state == 'git': |
1268 for gp in values: | 1274 for gp in values: |
1269 gp.path = pathstrip(gp.path, strip - 1)[1] | 1275 backend.copy(pstrip(gp.oldpath), pstrip(gp.path)) |
1270 if gp.oldpath: | |
1271 gp.oldpath = pathstrip(gp.oldpath, strip - 1)[1] | |
1272 if gp.op in ('COPY', 'RENAME'): | |
1273 backend.copy(gp.oldpath, gp.path) | |
1274 else: | 1276 else: |
1275 raise util.Abort(_('unsupported parser state: %s') % state) | 1277 raise util.Abort(_('unsupported parser state: %s') % state) |
1276 | 1278 |
1277 if current_file: | 1279 if current_file: |
1278 rejects += current_file.close() | 1280 rejects += current_file.close() |
1385 backend = fsbackend(ui, repo.root) | 1387 backend = fsbackend(ui, repo.root) |
1386 fp = open(patchpath, 'rb') | 1388 fp = open(patchpath, 'rb') |
1387 try: | 1389 try: |
1388 changed = set() | 1390 changed = set() |
1389 for state, values in iterhunks(fp): | 1391 for state, values in iterhunks(fp): |
1390 if state == 'hunk': | 1392 if state == 'file': |
1391 continue | |
1392 elif state == 'file': | |
1393 afile, bfile, first_hunk, gp = values | 1393 afile, bfile, first_hunk, gp = values |
1394 if gp: | 1394 if gp: |
1395 changed.add(gp.path) | 1395 changed.add(pathstrip(gp.path, strip - 1)[1]) |
1396 if gp.op == 'RENAME': | 1396 if gp.op == 'RENAME': |
1397 changed.add(gp.oldpath) | 1397 changed.add(pathstrip(gp.oldpath, strip - 1)[1]) |
1398 if not first_hunk: | 1398 if not first_hunk: |
1399 continue | 1399 continue |
1400 current_file, missing = selectfile(backend, afile, bfile, | 1400 current_file, missing = selectfile(backend, afile, bfile, |
1401 first_hunk, strip) | 1401 first_hunk, strip) |
1402 changed.add(current_file) | 1402 changed.add(current_file) |
1403 elif state == 'git': | 1403 elif state not in ('hunk', 'git'): |
1404 for gp in values: | |
1405 gp.path = pathstrip(gp.path, strip - 1)[1] | |
1406 if gp.oldpath: | |
1407 gp.oldpath = pathstrip(gp.oldpath, strip - 1)[1] | |
1408 else: | |
1409 raise util.Abort(_('unsupported parser state: %s') % state) | 1404 raise util.Abort(_('unsupported parser state: %s') % state) |
1410 return changed | 1405 return changed |
1411 finally: | 1406 finally: |
1412 fp.close() | 1407 fp.close() |
1413 | 1408 |