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