comparison hgext/mq.py @ 10187:fcc15ba18c03

Merge with stable
author Matt Mackall <mpm@selenic.com>
date Fri, 01 Jan 2010 15:33:51 -0600
parents 926c436964b4 296a0b14a686
children 8161127a638f
comparison
equal deleted inserted replaced
10183:572dd10fa308 10187:fcc15ba18c03
223 self.series_path = "series" 223 self.series_path = "series"
224 self.status_path = "status" 224 self.status_path = "status"
225 self.guards_path = "guards" 225 self.guards_path = "guards"
226 self.active_guards = None 226 self.active_guards = None
227 self.guards_dirty = False 227 self.guards_dirty = False
228 self._diffopts = None
229 228
230 @util.propertycache 229 @util.propertycache
231 def applied(self): 230 def applied(self):
232 if os.path.exists(self.join(self.status_path)): 231 if os.path.exists(self.join(self.status_path)):
233 lines = self.opener(self.status_path).read().splitlines() 232 lines = self.opener(self.status_path).read().splitlines()
257 self.applied_dirty = 0 256 self.applied_dirty = 0
258 self.series_dirty = 0 257 self.series_dirty = 0
259 self.guards_dirty = False 258 self.guards_dirty = False
260 self.active_guards = None 259 self.active_guards = None
261 260
262 def diffopts(self): 261 def diffopts(self, opts={}, patchfn=None):
263 if self._diffopts is None: 262 diffopts = patch.diffopts(self.ui, opts)
264 self._diffopts = patch.diffopts(self.ui) 263 if patchfn:
265 return self._diffopts 264 diffopts = self.patchopts(diffopts, patchfn)
265 return diffopts
266
267 def patchopts(self, diffopts, *patches):
268 """Return a copy of input diff options with git set to true if
269 referenced patch is a git patch.
270 """
271 diffopts = diffopts.copy()
272 for patchfn in patches:
273 patchf = self.opener(patchfn, 'r')
274 # if the patch was a git patch, refresh it as a git patch
275 for line in patchf:
276 if line.startswith('diff --git'):
277 diffopts.git = True
278 break
279 patchf.close()
280 return diffopts
266 281
267 def join(self, *p): 282 def join(self, *p):
268 return os.path.join(self.path, *p) 283 return os.path.join(self.path, *p)
269 284
270 def find_series(self, patch): 285 def find_series(self, patch):
416 try: 431 try:
417 os.unlink(undo) 432 os.unlink(undo)
418 except OSError, inst: 433 except OSError, inst:
419 self.ui.warn(_('error removing undo: %s\n') % str(inst)) 434 self.ui.warn(_('error removing undo: %s\n') % str(inst))
420 435
421 def printdiff(self, repo, node1, node2=None, files=None, 436 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
422 fp=None, changes=None, opts={}): 437 fp=None, changes=None, opts={}):
423 stat = opts.get('stat') 438 stat = opts.get('stat')
424 if stat: 439 if stat:
425 opts['unified'] = '0' 440 opts['unified'] = '0'
426 441
427 m = cmdutil.match(repo, files, opts) 442 m = cmdutil.match(repo, files, opts)
428 chunks = patch.diff(repo, node1, node2, m, changes, self.diffopts()) 443 chunks = patch.diff(repo, node1, node2, m, changes, diffopts)
429 write = fp is None and repo.ui.write or fp.write 444 write = fp is None and repo.ui.write or fp.write
430 if stat: 445 if stat:
431 width = self.ui.interactive() and util.termwidth() or 80 446 width = self.ui.interactive() and util.termwidth() or 80
432 write(patch.diffstat(util.iterlines(chunks), width=width, 447 write(patch.diffstat(util.iterlines(chunks), width=width,
433 git=self.diffopts().git)) 448 git=diffopts.git))
434 else: 449 else:
435 for chunk in chunks: 450 for chunk in chunks:
436 write(chunk) 451 write(chunk)
437 452
438 def mergeone(self, repo, mergeq, head, patch, rev): 453 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
439 # first try just applying the patch 454 # first try just applying the patch
440 (err, n) = self.apply(repo, [ patch ], update_status=False, 455 (err, n) = self.apply(repo, [ patch ], update_status=False,
441 strict=True, merge=rev) 456 strict=True, merge=rev)
442 457
443 if err == 0: 458 if err == 0:
462 try: 477 try:
463 ph = patchheader(mergeq.join(patch)) 478 ph = patchheader(mergeq.join(patch))
464 except: 479 except:
465 raise util.Abort(_("unable to read %s") % patch) 480 raise util.Abort(_("unable to read %s") % patch)
466 481
482 diffopts = self.patchopts(diffopts, patch)
467 patchf = self.opener(patch, "w") 483 patchf = self.opener(patch, "w")
468 comments = str(ph) 484 comments = str(ph)
469 if comments: 485 if comments:
470 patchf.write(comments) 486 patchf.write(comments)
471 self.printdiff(repo, head, n, fp=patchf) 487 self.printdiff(repo, diffopts, head, n, fp=patchf)
472 patchf.close() 488 patchf.close()
473 self.removeundo(repo) 489 self.removeundo(repo)
474 return (0, n) 490 return (0, n)
475 491
476 def qparents(self, repo, rev=None): 492 def qparents(self, repo, rev=None):
490 return pp[0] 506 return pp[0]
491 if p1 in arevs: 507 if p1 in arevs:
492 return pp[1] 508 return pp[1]
493 return pp[0] 509 return pp[0]
494 510
495 def mergepatch(self, repo, mergeq, series): 511 def mergepatch(self, repo, mergeq, series, diffopts):
496 if len(self.applied) == 0: 512 if len(self.applied) == 0:
497 # each of the patches merged in will have two parents. This 513 # each of the patches merged in will have two parents. This
498 # can confuse the qrefresh, qdiff, and strip code because it 514 # can confuse the qrefresh, qdiff, and strip code because it
499 # needs to know which parent is actually in the patch queue. 515 # needs to know which parent is actually in the patch queue.
500 # so, we insert a merge marker with only one parent. This way 516 # so, we insert a merge marker with only one parent. This way
520 info = mergeq.isapplied(patch) 536 info = mergeq.isapplied(patch)
521 if not info: 537 if not info:
522 self.ui.warn(_("patch %s is not applied\n") % patch) 538 self.ui.warn(_("patch %s is not applied\n") % patch)
523 return (1, None) 539 return (1, None)
524 rev = bin(info[1]) 540 rev = bin(info[1])
525 (err, head) = self.mergeone(repo, mergeq, head, patch, rev) 541 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
526 if head: 542 if head:
527 self.applied.append(statusentry(hex(head), patch)) 543 self.applied.append(statusentry(hex(head), patch))
528 self.applied_dirty = 1 544 self.applied_dirty = 1
529 if err: 545 if err:
530 return (err, head) 546 return (err, head)
755 force = opts.get('force') 771 force = opts.get('force')
756 user = opts.get('user') 772 user = opts.get('user')
757 date = opts.get('date') 773 date = opts.get('date')
758 if date: 774 if date:
759 date = util.parsedate(date) 775 date = util.parsedate(date)
776 diffopts = self.diffopts({'git': opts.get('git')})
760 self.check_reserved_name(patchfn) 777 self.check_reserved_name(patchfn)
761 if os.path.exists(self.join(patchfn)): 778 if os.path.exists(self.join(patchfn)):
762 raise util.Abort(_('patch "%s" already exists') % patchfn) 779 raise util.Abort(_('patch "%s" already exists') % patchfn)
763 if opts.get('include') or opts.get('exclude') or pats: 780 if opts.get('include') or opts.get('exclude') or pats:
764 match = cmdutil.match(repo, pats, opts) 781 match = cmdutil.match(repo, pats, opts)
804 self.applied_dirty = 1 821 self.applied_dirty = 1
805 if msg: 822 if msg:
806 msg = msg + "\n\n" 823 msg = msg + "\n\n"
807 p.write(msg) 824 p.write(msg)
808 if commitfiles: 825 if commitfiles:
809 diffopts = self.diffopts()
810 if opts.get('git'): diffopts.git = True
811 parent = self.qparents(repo, n) 826 parent = self.qparents(repo, n)
812 chunks = patch.diff(repo, node1=parent, node2=n, 827 chunks = patch.diff(repo, node1=parent, node2=n,
813 match=match, opts=diffopts) 828 match=match, opts=diffopts)
814 for chunk in chunks: 829 for chunk in chunks:
815 p.write(chunk) 830 p.write(chunk)
930 return self.series[i + off] 945 return self.series[i + off]
931 raise util.Abort(_("patch %s not in series") % patch) 946 raise util.Abort(_("patch %s not in series") % patch)
932 947
933 def push(self, repo, patch=None, force=False, list=False, 948 def push(self, repo, patch=None, force=False, list=False,
934 mergeq=None, all=False): 949 mergeq=None, all=False):
950 diffopts = self.diffopts()
935 wlock = repo.wlock() 951 wlock = repo.wlock()
936 try: 952 try:
937 if repo.dirstate.parents()[0] not in repo.heads(): 953 if repo.dirstate.parents()[0] not in repo.heads():
938 self.ui.status(_("(working directory not at a head)\n")) 954 self.ui.status(_("(working directory not at a head)\n"))
939 955
992 1008
993 s = self.series[start:end] 1009 s = self.series[start:end]
994 all_files = {} 1010 all_files = {}
995 try: 1011 try:
996 if mergeq: 1012 if mergeq:
997 ret = self.mergepatch(repo, mergeq, s) 1013 ret = self.mergepatch(repo, mergeq, s, diffopts)
998 else: 1014 else:
999 ret = self.apply(repo, s, list, all_files=all_files) 1015 ret = self.apply(repo, s, list, all_files=all_files)
1000 except: 1016 except:
1001 self.ui.warn(_('cleaning up working directory...')) 1017 self.ui.warn(_('cleaning up working directory...'))
1002 node = repo.dirstate.parents()[0] 1018 node = repo.dirstate.parents()[0]
1135 qp = self.qparents(repo, top) 1151 qp = self.qparents(repo, top)
1136 if opts.get('reverse'): 1152 if opts.get('reverse'):
1137 node1, node2 = None, qp 1153 node1, node2 = None, qp
1138 else: 1154 else:
1139 node1, node2 = qp, None 1155 node1, node2 = qp, None
1140 self._diffopts = patch.diffopts(self.ui, opts) 1156 diffopts = self.diffopts(opts)
1141 self.printdiff(repo, node1, node2, files=pats, opts=opts) 1157 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1142 1158
1143 def refresh(self, repo, pats=None, **opts): 1159 def refresh(self, repo, pats=None, **opts):
1144 if len(self.applied) == 0: 1160 if len(self.applied) == 0:
1145 self.ui.write(_("no patches applied\n")) 1161 self.ui.write(_("no patches applied\n"))
1146 return 1 1162 return 1
1157 if repo.changelog.heads(top) != [top]: 1173 if repo.changelog.heads(top) != [top]:
1158 raise util.Abort(_("cannot refresh a revision with children")) 1174 raise util.Abort(_("cannot refresh a revision with children"))
1159 cparents = repo.changelog.parents(top) 1175 cparents = repo.changelog.parents(top)
1160 patchparent = self.qparents(repo, top) 1176 patchparent = self.qparents(repo, top)
1161 ph = patchheader(self.join(patchfn)) 1177 ph = patchheader(self.join(patchfn))
1178 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1162 if msg: 1179 if msg:
1163 ph.setmessage(msg) 1180 ph.setmessage(msg)
1164 if newuser: 1181 if newuser:
1165 ph.setuser(newuser) 1182 ph.setuser(newuser)
1166 if newdate: 1183 if newdate:
1179 1196
1180 comments = str(ph) 1197 comments = str(ph)
1181 if comments: 1198 if comments:
1182 patchf.write(comments) 1199 patchf.write(comments)
1183 1200
1184 if opts.get('git'):
1185 self.diffopts().git = True
1186 tip = repo.changelog.tip() 1201 tip = repo.changelog.tip()
1187 if top == tip: 1202 if top == tip:
1188 # if the top of our patch queue is also the tip, there is an 1203 # if the top of our patch queue is also the tip, there is an
1189 # optimization here. We update the dirstate in place and strip 1204 # optimization here. We update the dirstate in place and strip
1190 # off the tip commit. Then just commit the current directory 1205 # off the tip commit. Then just commit the current directory
1246 r = list(set(dd)) 1261 r = list(set(dd))
1247 a = list(set(aa)) 1262 a = list(set(aa))
1248 c = [filter(matchfn, l) for l in (m, a, r)] 1263 c = [filter(matchfn, l) for l in (m, a, r)]
1249 match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2])) 1264 match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
1250 chunks = patch.diff(repo, patchparent, match=match, 1265 chunks = patch.diff(repo, patchparent, match=match,
1251 changes=c, opts=self.diffopts()) 1266 changes=c, opts=diffopts)
1252 for chunk in chunks: 1267 for chunk in chunks:
1253 patchf.write(chunk) 1268 patchf.write(chunk)
1254 1269
1255 try: 1270 try:
1256 if self.diffopts().git: 1271 if diffopts.git:
1257 copies = {} 1272 copies = {}
1258 for dst in a: 1273 for dst in a:
1259 src = repo.dirstate.copied(dst) 1274 src = repo.dirstate.copied(dst)
1260 # during qfold, the source file for copies may 1275 # during qfold, the source file for copies may
1261 # be removed. Treat this as a simple add. 1276 # be removed. Treat this as a simple add.
1330 self.save_dirty() 1345 self.save_dirty()
1331 self.ui.warn(_('refresh interrupted while patch was popped! ' 1346 self.ui.warn(_('refresh interrupted while patch was popped! '
1332 '(revert --all, qpush to recover)\n')) 1347 '(revert --all, qpush to recover)\n'))
1333 raise 1348 raise
1334 else: 1349 else:
1335 self.printdiff(repo, patchparent, fp=patchf) 1350 self.printdiff(repo, diffopts, patchparent, fp=patchf)
1336 patchf.rename() 1351 patchf.rename()
1337 added = repo.status()[1] 1352 added = repo.status()[1]
1338 for a in added: 1353 for a in added:
1339 f = repo.wjoin(a) 1354 f = repo.wjoin(a)
1340 try: 1355 try:
1610 if heads != [repo.changelog.node(rev[0])]: 1625 if heads != [repo.changelog.node(rev[0])]:
1611 raise util.Abort(_('revision %d has unmanaged children') 1626 raise util.Abort(_('revision %d has unmanaged children')
1612 % rev[0]) 1627 % rev[0])
1613 lastparent = None 1628 lastparent = None
1614 1629
1615 if git: 1630 diffopts = self.diffopts({'git': git})
1616 self.diffopts().git = True
1617
1618 for r in rev: 1631 for r in rev:
1619 p1, p2 = repo.changelog.parentrevs(r) 1632 p1, p2 = repo.changelog.parentrevs(r)
1620 n = repo.changelog.node(r) 1633 n = repo.changelog.node(r)
1621 if p2 != nullrev: 1634 if p2 != nullrev:
1622 raise util.Abort(_('cannot import merge revision %d') % r) 1635 raise util.Abort(_('cannot import merge revision %d') % r)
1631 checkseries(patchname) 1644 checkseries(patchname)
1632 checkfile(patchname) 1645 checkfile(patchname)
1633 self.full_series.insert(0, patchname) 1646 self.full_series.insert(0, patchname)
1634 1647
1635 patchf = self.opener(patchname, "w") 1648 patchf = self.opener(patchname, "w")
1636 patch.export(repo, [n], fp=patchf, opts=self.diffopts()) 1649 patch.export(repo, [n], fp=patchf, opts=diffopts)
1637 patchf.close() 1650 patchf.close()
1638 1651
1639 se = statusentry(hex(n), patchname) 1652 se = statusentry(hex(n), patchname)
1640 self.applied.insert(0, se) 1653 self.applied.insert(0, se)
1641 1654
2063 message = '\n'.join(message) 2076 message = '\n'.join(message)
2064 2077
2065 if opts['edit']: 2078 if opts['edit']:
2066 message = ui.edit(message, user or ui.username()) 2079 message = ui.edit(message, user or ui.username())
2067 2080
2068 q.refresh(repo, msg=message) 2081 diffopts = q.patchopts(q.diffopts(), *patches)
2082 q.refresh(repo, msg=message, git=diffopts.git)
2069 q.delete(repo, patches, opts) 2083 q.delete(repo, patches, opts)
2070 q.save_dirty() 2084 q.save_dirty()
2071 2085
2072 def goto(ui, repo, patch, **opts): 2086 def goto(ui, repo, patch, **opts):
2073 '''push or pop patches until named patch is at top of stack''' 2087 '''push or pop patches until named patch is at top of stack'''