##// END OF EJS Templates
patch: generalize the use of patchmeta in applydiff()...
Patrick Mezard -
r14566:d0c2cc11 default
parent child Browse files
Show More
@@ -595,12 +595,10 b' def reposetup(ui, repo):'
595 595 wlock.release()
596 596
597 597 # monkeypatches
598 def kwpatchfile_init(orig, self, ui, fname, backend, store, mode, create,
599 remove, eolmode=None, copysource=None):
598 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None):
600 599 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
601 600 rejects or conflicts due to expanded keywords in working dir.'''
602 orig(self, ui, fname, backend, store, mode, create, remove,
603 eolmode, copysource)
601 orig(self, ui, gp, backend, store, eolmode)
604 602 # shrink keywords read from working dir
605 603 self.lines = kwt.shrinklines(self.fname, self.lines)
606 604
@@ -281,6 +281,14 b' class patchmeta(object):'
281 281 isexec = mode & 0100
282 282 self.mode = (islink, isexec)
283 283
284 def copy(self):
285 other = patchmeta(self.path)
286 other.oldpath = self.oldpath
287 other.mode = self.mode
288 other.op = self.op
289 other.binary = self.binary
290 return other
291
284 292 def __repr__(self):
285 293 return "<patchmeta %s %r>" % (self.op, self.path)
286 294
@@ -509,9 +517,8 b" contextdesc = re.compile('(---|\\*\\*\\*) ("
509 517 eolmodes = ['strict', 'crlf', 'lf', 'auto']
510 518
511 519 class patchfile(object):
512 def __init__(self, ui, fname, backend, store, mode, create, remove,
513 eolmode='strict', copysource=None):
514 self.fname = fname
520 def __init__(self, ui, gp, backend, store, eolmode='strict'):
521 self.fname = gp.path
515 522 self.eolmode = eolmode
516 523 self.eol = None
517 524 self.backend = backend
@@ -519,17 +526,17 b' class patchfile(object):'
519 526 self.lines = []
520 527 self.exists = False
521 528 self.missing = True
522 self.mode = mode
523 self.copysource = copysource
524 self.create = create
525 self.remove = remove
529 self.mode = gp.mode
530 self.copysource = gp.oldpath
531 self.create = gp.op in ('ADD', 'COPY', 'RENAME')
532 self.remove = gp.op == 'DELETE'
526 533 try:
527 if copysource is None:
528 data, mode = backend.getfile(fname)
534 if self.copysource is None:
535 data, mode = backend.getfile(self.fname)
529 536 self.exists = True
530 537 else:
531 data, mode = store.getfile(copysource)
532 self.exists = backend.exists(fname)
538 data, mode = store.getfile(self.copysource)
539 self.exists = backend.exists(self.fname)
533 540 self.missing = False
534 541 if data:
535 542 self.lines = data.splitlines(True)
@@ -549,7 +556,7 b' class patchfile(object):'
549 556 nlines.append(l)
550 557 self.lines = nlines
551 558 except IOError:
552 if create:
559 if self.create:
553 560 self.missing = False
554 561 if self.mode is None:
555 562 self.mode = (False, False)
@@ -1016,14 +1023,7 b' def pathstrip(path, strip):'
1016 1023 count -= 1
1017 1024 return path[:i].lstrip(), path[i:].rstrip()
1018 1025
1019 def selectfile(backend, afile_orig, bfile_orig, hunk, strip, gp):
1020 if gp:
1021 # Git patches do not play games. Excluding copies from the
1022 # following heuristic avoids a lot of confusion
1023 fname = pathstrip(gp.path, strip - 1)[1]
1024 create = gp.op in ('ADD', 'COPY', 'RENAME')
1025 remove = gp.op == 'DELETE'
1026 return fname, create, remove
1026 def makepatchmeta(backend, afile_orig, bfile_orig, hunk, strip):
1027 1027 nulla = afile_orig == "/dev/null"
1028 1028 nullb = bfile_orig == "/dev/null"
1029 1029 create = nulla and hunk.starta == 0 and hunk.lena == 0
@@ -1065,7 +1065,12 b' def selectfile(backend, afile_orig, bfil'
1065 1065 else:
1066 1066 raise PatchError(_("undefined source and destination files"))
1067 1067
1068 return fname, create, remove
1068 gp = patchmeta(fname)
1069 if create:
1070 gp.op = 'ADD'
1071 elif remove:
1072 gp.op = 'DELETE'
1073 return gp
1069 1074
1070 1075 def scangitpatch(lr, firstline):
1071 1076 """
@@ -1134,7 +1139,7 b' def iterhunks(fp):'
1134 1139 hunknum += 1
1135 1140 if emitfile:
1136 1141 emitfile = False
1137 yield 'file', (afile, bfile, h, gp)
1142 yield 'file', (afile, bfile, h, gp and gp.copy() or None)
1138 1143 yield 'hunk', h
1139 1144 elif x.startswith('diff --git'):
1140 1145 m = gitre.match(x)
@@ -1144,14 +1149,14 b' def iterhunks(fp):'
1144 1149 # scan whole input for git metadata
1145 1150 gitpatches = [('a/' + gp.path, 'b/' + gp.path, gp) for gp
1146 1151 in scangitpatch(lr, x)]
1147 yield 'git', [g[2] for g in gitpatches
1152 yield 'git', [g[2].copy() for g in gitpatches
1148 1153 if g[2].op in ('COPY', 'RENAME')]
1149 1154 gitpatches.reverse()
1150 1155 afile = 'a/' + m.group(1)
1151 1156 bfile = 'b/' + m.group(2)
1152 1157 while afile != gitpatches[-1][0] and bfile != gitpatches[-1][1]:
1153 1158 gp = gitpatches.pop()[2]
1154 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp)
1159 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
1155 1160 gp = gitpatches[-1][2]
1156 1161 # copy/rename + modify should modify target, not source
1157 1162 if gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD') or gp.mode:
@@ -1191,7 +1196,7 b' def iterhunks(fp):'
1191 1196
1192 1197 while gitpatches:
1193 1198 gp = gitpatches.pop()[2]
1194 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp)
1199 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
1195 1200
1196 1201 def applydiff(ui, fp, backend, store, strip=1, eolmode='strict'):
1197 1202 """Reads a patch from fp and tries to apply it.
@@ -1228,41 +1233,38 b' def _applydiff(ui, fp, patcher, backend,'
1228 1233 rejects += current_file.close()
1229 1234 current_file = None
1230 1235 afile, bfile, first_hunk, gp = values
1231 copysource = None
1232 1236 if gp:
1233 1237 path = pstrip(gp.path)
1238 gp.path = pstrip(gp.path)
1234 1239 if gp.oldpath:
1235 copysource = pstrip(gp.oldpath)
1236 if gp.op == 'RENAME':
1237 backend.unlink(copysource)
1238 if not first_hunk:
1239 if gp.op == 'DELETE':
1240 backend.unlink(path)
1241 continue
1242 data, mode = None, None
1243 if gp.op in ('RENAME', 'COPY'):
1244 data, mode = store.getfile(copysource)
1245 if gp.mode:
1246 mode = gp.mode
1247 if gp.op == 'ADD':
1248 # Added files without content have no hunk and
1249 # must be created
1250 data = ''
1251 if data or mode:
1252 if (gp.op in ('ADD', 'RENAME', 'COPY')
1253 and backend.exists(path)):
1254 raise PatchError(_("cannot create %s: destination "
1255 "already exists") % path)
1256 backend.setfile(path, data, mode, copysource)
1240 gp.oldpath = pstrip(gp.oldpath)
1241 else:
1242 gp = makepatchmeta(backend, afile, bfile, first_hunk, strip)
1243 if gp.op == 'RENAME':
1244 backend.unlink(gp.oldpath)
1257 1245 if not first_hunk:
1246 if gp.op == 'DELETE':
1247 backend.unlink(gp.path)
1248 continue
1249 data, mode = None, None
1250 if gp.op in ('RENAME', 'COPY'):
1251 data, mode = store.getfile(gp.oldpath)
1252 if gp.mode:
1253 mode = gp.mode
1254 if gp.op == 'ADD':
1255 # Added files without content have no hunk and
1256 # must be created
1257 data = ''
1258 if data or mode:
1259 if (gp.op in ('ADD', 'RENAME', 'COPY')
1260 and backend.exists(gp.path)):
1261 raise PatchError(_("cannot create %s: destination "
1262 "already exists") % gp.path)
1263 backend.setfile(gp.path, data, mode, gp.oldpath)
1258 1264 continue
1259 1265 try:
1260 mode = gp and gp.mode or None
1261 current_file, create, remove = selectfile(
1262 backend, afile, bfile, first_hunk, strip, gp)
1263 current_file = patcher(ui, current_file, backend, store, mode,
1264 create, remove, eolmode=eolmode,
1265 copysource=copysource)
1266 current_file = patcher(ui, gp, backend, store,
1267 eolmode=eolmode)
1266 1268 except PatchError, inst:
1267 1269 ui.warn(str(inst) + '\n')
1268 1270 current_file = None
@@ -1395,14 +1397,14 b' def changedfiles(ui, repo, patchpath, st'
1395 1397 if state == 'file':
1396 1398 afile, bfile, first_hunk, gp = values
1397 1399 if gp:
1398 changed.add(pathstrip(gp.path, strip - 1)[1])
1399 if gp.op == 'RENAME':
1400 changed.add(pathstrip(gp.oldpath, strip - 1)[1])
1401 if not first_hunk:
1402 continue
1403 current_file, create, remove = selectfile(
1404 backend, afile, bfile, first_hunk, strip, gp)
1405 changed.add(current_file)
1400 gp.path = pathstrip(gp.path, strip - 1)[1]
1401 if gp.oldpath:
1402 gp.oldpath = pathstrip(gp.oldpath, strip - 1)[1]
1403 else:
1404 gp = makepatchmeta(backend, afile, bfile, first_hunk, strip)
1405 changed.add(gp.path)
1406 if gp.op == 'RENAME':
1407 changed.add(gp.oldpath)
1406 1408 elif state not in ('hunk', 'git'):
1407 1409 raise util.Abort(_('unsupported parser state: %s') % state)
1408 1410 return changed
General Comments 0
You need to be logged in to leave comments. Login now