comparison hgext/mq.py @ 3098:fe9b13e35e46

Merge with crew
author Matt Mackall <mpm@selenic.com>
date Fri, 15 Sep 2006 15:22:45 -0500
parents 7fa3d38a99b6
children 15fde1970003
comparison
equal deleted inserted replaced
3097:1b738357bba9 3098:fe9b13e35e46
29 refresh contents of top applied patch qrefresh 29 refresh contents of top applied patch qrefresh
30 ''' 30 '''
31 31
32 from mercurial.demandload import * 32 from mercurial.demandload import *
33 from mercurial.i18n import gettext as _ 33 from mercurial.i18n import gettext as _
34 from mercurial import commands
34 demandload(globals(), "os sys re struct traceback errno bz2") 35 demandload(globals(), "os sys re struct traceback errno bz2")
35 demandload(globals(), "mercurial:cmdutil,commands,hg,patch,revlog,ui,util") 36 demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,ui,util")
36 37
37 commands.norepo += " qclone qversion" 38 commands.norepo += " qclone qversion"
38 39
39 class statusentry: 40 class statusentry:
40 def __init__(self, rev, name=None): 41 def __init__(self, rev, name=None):
41 if not name: 42 if not name:
42 fields = rev.split(':') 43 fields = rev.split(':', 1)
43 if len(fields) == 2: 44 if len(fields) == 2:
44 self.rev, self.name = fields 45 self.rev, self.name = fields
45 else: 46 else:
46 self.rev, self.name = None, None 47 self.rev, self.name = None, None
47 else: 48 else:
480 err = 1 481 err = 1
481 break 482 break
482 tr.close() 483 tr.close()
483 return (err, n) 484 return (err, n)
484 485
485 def delete(self, repo, patches, keep=False): 486 def delete(self, repo, patches, opts):
486 realpatches = [] 487 realpatches = []
488 appliedbase = 0
489 forget = opts.get('forget')
487 for patch in patches: 490 for patch in patches:
488 patch = self.lookup(patch, strict=True) 491 patch = self.lookup(patch, strict=True)
489 info = self.isapplied(patch) 492 info = self.isapplied(patch)
490 if info: 493 if info and not forget:
491 raise util.Abort(_("cannot delete applied patch %s") % patch) 494 raise util.Abort(_("cannot delete applied patch %s") % patch)
492 if patch not in self.series: 495 if patch not in self.series:
493 raise util.Abort(_("patch %s not in series file") % patch) 496 raise util.Abort(_("patch %s not in series file") % patch)
497 if forget:
498 if not info:
499 raise util.Abort(_("cannot forget unapplied patch %s") % patch)
500 if info[0] != appliedbase:
501 raise util.Abort(_("patch %s not at base") % patch)
502 appliedbase += 1
494 realpatches.append(patch) 503 realpatches.append(patch)
495 504
496 if not keep: 505 if not opts.get('keep'):
497 r = self.qrepo() 506 r = self.qrepo()
498 if r: 507 if r:
499 r.remove(realpatches, True) 508 r.remove(realpatches, True)
500 else: 509 else:
501 os.unlink(self.join(patch)) 510 os.unlink(self.join(patch))
502 511
512 if forget:
513 del self.applied[:appliedbase]
514 self.applied_dirty = 1
503 indices = [self.find_series(p) for p in realpatches] 515 indices = [self.find_series(p) for p in realpatches]
504 indices.sort() 516 indices.sort()
505 for i in indices[-1::-1]: 517 for i in indices[-1::-1]:
506 del self.full_series[i] 518 del self.full_series[i]
507 self.parse_series() 519 self.parse_series()
691 chgrpfile = bundle(backupch) 703 chgrpfile = bundle(backupch)
692 704
693 stripall(rev, revnum) 705 stripall(rev, revnum)
694 706
695 change = chlog.read(rev) 707 change = chlog.read(rev)
708 chlog.strip(revnum, revnum)
696 repo.manifest.strip(repo.manifest.rev(change[0]), revnum) 709 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
697 chlog.strip(revnum, revnum)
698 if saveheads: 710 if saveheads:
699 self.ui.status("adding branch\n") 711 self.ui.status("adding branch\n")
700 commands.unbundle(self.ui, repo, chgrpfile, update=False) 712 commands.unbundle(self.ui, repo, chgrpfile, update=False)
701 if backup != "strip": 713 if backup != "strip":
702 os.unlink(chgrpfile) 714 os.unlink(chgrpfile)
754 return self.series[sno] 766 return self.series[sno]
755 if not strict: 767 if not strict:
756 # return any partial match made above 768 # return any partial match made above
757 if res: 769 if res:
758 return res 770 return res
759 minus = patch.rsplit('-', 1) 771 minus = patch.rfind('-')
760 if len(minus) > 1: 772 if minus >= 0:
761 res = partial_name(minus[0]) 773 res = partial_name(patch[:minus])
762 if res: 774 if res:
763 i = self.series.index(res) 775 i = self.series.index(res)
764 try: 776 try:
765 off = int(minus[1] or 1) 777 off = int(patch[minus+1:] or 1)
766 except(ValueError, OverflowError): 778 except(ValueError, OverflowError):
767 pass 779 pass
768 else: 780 else:
769 if i - off >= 0: 781 if i - off >= 0:
770 return self.series[i - off] 782 return self.series[i - off]
771 plus = patch.rsplit('+', 1) 783 plus = patch.rfind('+')
772 if len(plus) > 1: 784 if plus >= 0:
773 res = partial_name(plus[0]) 785 res = partial_name(patch[:plus])
774 if res: 786 if res:
775 i = self.series.index(res) 787 i = self.series.index(res)
776 try: 788 try:
777 off = int(plus[1] or 1) 789 off = int(patch[plus+1:] or 1)
778 except(ValueError, OverflowError): 790 except(ValueError, OverflowError):
779 pass 791 pass
780 else: 792 else:
781 if i + off < len(self.series): 793 if i + off < len(self.series):
782 return self.series[i + off] 794 return self.series[i + off]
913 self.printdiff(repo, qp, files=pats, opts=opts) 925 self.printdiff(repo, qp, files=pats, opts=opts)
914 926
915 def refresh(self, repo, pats=None, **opts): 927 def refresh(self, repo, pats=None, **opts):
916 if len(self.applied) == 0: 928 if len(self.applied) == 0:
917 self.ui.write("No patches applied\n") 929 self.ui.write("No patches applied\n")
918 return 930 return 1
919 wlock = repo.wlock() 931 wlock = repo.wlock()
920 self.check_toppatch(repo) 932 self.check_toppatch(repo)
921 (top, patch) = (self.applied[-1].rev, self.applied[-1].name) 933 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
922 top = revlog.bin(top) 934 top = revlog.bin(top)
923 cparents = repo.changelog.parents(top) 935 cparents = repo.changelog.parents(top)
924 patchparent = self.qparents(repo, top) 936 patchparent = self.qparents(repo, top)
925 message, comments, user, date, patchfound = self.readheaders(patch) 937 message, comments, user, date, patchfound = self.readheaders(patchfn)
926 938
927 patchf = self.opener(patch, "w") 939 patchf = self.opener(patchfn, "w")
928 msg = opts.get('msg', '').rstrip() 940 msg = opts.get('msg', '').rstrip()
929 if msg: 941 if msg:
930 if comments: 942 if comments:
931 # Remove existing message. 943 # Remove existing message.
932 ci = 0 944 ci = 0
992 1004
993 m = list(util.unique(mm)) 1005 m = list(util.unique(mm))
994 r = list(util.unique(dd)) 1006 r = list(util.unique(dd))
995 a = list(util.unique(aa)) 1007 a = list(util.unique(aa))
996 filelist = filter(matchfn, util.unique(m + r + a)) 1008 filelist = filter(matchfn, util.unique(m + r + a))
997 self.printdiff(repo, patchparent, files=filelist, 1009 if opts.get('git'):
998 changes=(m, a, r, [], u), fp=patchf) 1010 self.diffopts().git = True
1011 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1012 fp=patchf, changes=(m, a, r, [], u),
1013 opts=self.diffopts())
999 patchf.close() 1014 patchf.close()
1000 1015
1001 changes = repo.changelog.read(tip) 1016 changes = repo.changelog.read(tip)
1002 repo.dirstate.setparents(*cparents) 1017 repo.dirstate.setparents(*cparents)
1003 copies = [(f, repo.dirstate.copied(f)) for f in a] 1018 copies = [(f, repo.dirstate.copied(f)) for f in a]
1016 repo.dirstate.update(mm, 'n', st_mtime=0) 1031 repo.dirstate.update(mm, 'n', st_mtime=0)
1017 repo.dirstate.forget(forget) 1032 repo.dirstate.forget(forget)
1018 1033
1019 if not msg: 1034 if not msg:
1020 if not message: 1035 if not message:
1021 message = "patch queue: %s\n" % patch 1036 message = "patch queue: %s\n" % patchfn
1022 else: 1037 else:
1023 message = "\n".join(message) 1038 message = "\n".join(message)
1024 else: 1039 else:
1025 message = msg 1040 message = msg
1026 1041
1027 self.strip(repo, top, update=False, backup='strip', wlock=wlock) 1042 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1028 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) 1043 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
1029 self.applied[-1] = statusentry(revlog.hex(n), patch) 1044 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1030 self.applied_dirty = 1 1045 self.applied_dirty = 1
1031 else: 1046 else:
1032 self.printdiff(repo, patchparent, fp=patchf) 1047 self.printdiff(repo, patchparent, fp=patchf)
1033 patchf.close() 1048 patchf.close()
1034 self.pop(repo, force=True, wlock=wlock) 1049 self.pop(repo, force=True, wlock=wlock)
1235 if len(self.applied): 1250 if len(self.applied):
1236 p = self.appliedname(-1) 1251 p = self.appliedname(-1)
1237 self.ui.write(p + '\n') 1252 self.ui.write(p + '\n')
1238 else: 1253 else:
1239 self.ui.write("No patches applied\n") 1254 self.ui.write("No patches applied\n")
1255 return 1
1240 1256
1241 def next(self, repo): 1257 def next(self, repo):
1242 end = self.series_end() 1258 end = self.series_end()
1243 if end == len(self.series): 1259 if end == len(self.series):
1244 self.ui.write("All patches applied\n") 1260 self.ui.write("All patches applied\n")
1261 return 1
1245 else: 1262 else:
1246 p = self.series[end] 1263 p = self.series[end]
1247 if self.ui.verbose: 1264 if self.ui.verbose:
1248 self.ui.write("%d " % self.series.index(p)) 1265 self.ui.write("%d " % self.series.index(p))
1249 self.ui.write(p + '\n') 1266 self.ui.write(p + '\n')
1252 if len(self.applied) > 1: 1269 if len(self.applied) > 1:
1253 p = self.appliedname(-2) 1270 p = self.appliedname(-2)
1254 self.ui.write(p + '\n') 1271 self.ui.write(p + '\n')
1255 elif len(self.applied) == 1: 1272 elif len(self.applied) == 1:
1256 self.ui.write("Only one patch applied\n") 1273 self.ui.write("Only one patch applied\n")
1274 return 1
1257 else: 1275 else:
1258 self.ui.write("No patches applied\n") 1276 self.ui.write("No patches applied\n")
1277 return 1
1259 1278
1260 def qimport(self, repo, files, patch=None, existing=None, force=None): 1279 def qimport(self, repo, files, patch=None, existing=None, force=None):
1261 if len(files) > 1 and patch: 1280 if len(files) > 1 and patch:
1262 raise util.Abort(_('option "-n" not valid when importing multiple ' 1281 raise util.Abort(_('option "-n" not valid when importing multiple '
1263 'files')) 1282 'files'))
1296 qrepo.add(added) 1315 qrepo.add(added)
1297 1316
1298 def delete(ui, repo, patch, *patches, **opts): 1317 def delete(ui, repo, patch, *patches, **opts):
1299 """remove patches from queue 1318 """remove patches from queue
1300 1319
1301 The patches must not be applied. 1320 With --forget, mq will stop managing the named patches. The
1302 With -k, the patch files are preserved in the patch directory.""" 1321 patches must be applied and at the base of the stack. This option
1322 is useful when the patches have been applied upstream.
1323
1324 Otherwise, the patches must not be applied.
1325
1326 With --keep, the patch files are preserved in the patch directory."""
1303 q = repo.mq 1327 q = repo.mq
1304 q.delete(repo, (patch,) + patches, keep=opts.get('keep')) 1328 q.delete(repo, (patch,) + patches, opts)
1305 q.save_dirty() 1329 q.save_dirty()
1306 return 0 1330 return 0
1307 1331
1308 def applied(ui, repo, patch=None, **opts): 1332 def applied(ui, repo, patch=None, **opts):
1309 """print the patches already applied""" 1333 """print the patches already applied"""
1400 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary']) 1424 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1401 return 0 1425 return 0
1402 1426
1403 def top(ui, repo, **opts): 1427 def top(ui, repo, **opts):
1404 """print the name of the current patch""" 1428 """print the name of the current patch"""
1405 repo.mq.top(repo) 1429 return repo.mq.top(repo)
1406 return 0
1407 1430
1408 def next(ui, repo, **opts): 1431 def next(ui, repo, **opts):
1409 """print the name of the next patch""" 1432 """print the name of the next patch"""
1410 repo.mq.next(repo) 1433 return repo.mq.next(repo)
1411 return 0
1412 1434
1413 def prev(ui, repo, **opts): 1435 def prev(ui, repo, **opts):
1414 """print the name of the previous patch""" 1436 """print the name of the previous patch"""
1415 repo.mq.prev(repo) 1437 return repo.mq.prev(repo)
1416 return 0
1417 1438
1418 def new(ui, repo, patch, **opts): 1439 def new(ui, repo, patch, **opts):
1419 """create a new patch 1440 """create a new patch
1420 1441
1421 qnew creates a new patch on top of the currently-applied patch 1442 qnew creates a new patch on top of the currently-applied patch
1447 if message: 1468 if message:
1448 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) 1469 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1449 patch = q.applied[-1].name 1470 patch = q.applied[-1].name
1450 (message, comment, user, date, hasdiff) = q.readheaders(patch) 1471 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1451 message = ui.edit('\n'.join(message), user or ui.username()) 1472 message = ui.edit('\n'.join(message), user or ui.username())
1452 q.refresh(repo, pats, msg=message, **opts) 1473 ret = q.refresh(repo, pats, msg=message, **opts)
1453 q.save_dirty() 1474 q.save_dirty()
1454 return 0 1475 return ret
1455 1476
1456 def diff(ui, repo, *pats, **opts): 1477 def diff(ui, repo, *pats, **opts):
1457 """diff of the current patch""" 1478 """diff of the current patch"""
1458 repo.mq.diff(repo, pats, opts) 1479 repo.mq.diff(repo, pats, opts)
1459 return 0 1480 return 0
1474 q = repo.mq 1495 q = repo.mq
1475 1496
1476 if not files: 1497 if not files:
1477 raise util.Abort(_('qfold requires at least one patch name')) 1498 raise util.Abort(_('qfold requires at least one patch name'))
1478 if not q.check_toppatch(repo): 1499 if not q.check_toppatch(repo):
1479 raise util.Abort(_('No patches applied\n')) 1500 raise util.Abort(_('No patches applied'))
1480 1501
1481 message = commands.logmessage(opts) 1502 message = commands.logmessage(opts)
1482 if opts['edit']: 1503 if opts['edit']:
1483 if message: 1504 if message:
1484 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) 1505 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1569 if patch: 1590 if patch:
1570 patch = q.lookup(patch) 1591 patch = q.lookup(patch)
1571 else: 1592 else:
1572 if not q.applied: 1593 if not q.applied:
1573 ui.write('No patches applied\n') 1594 ui.write('No patches applied\n')
1574 return 1595 return 1
1575 patch = q.lookup('qtip') 1596 patch = q.lookup('qtip')
1576 message = repo.mq.readheaders(patch)[0] 1597 message = repo.mq.readheaders(patch)[0]
1577 1598
1578 ui.write('\n'.join(message) + '\n') 1599 ui.write('\n'.join(message) + '\n')
1579 1600
1646 1667
1647 if not name: 1668 if not name:
1648 name = patch 1669 name = patch
1649 patch = None 1670 patch = None
1650 1671
1651 if name in q.series:
1652 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1653
1654 absdest = q.join(name)
1655 if os.path.exists(absdest):
1656 raise util.Abort(_('%s already exists') % absdest)
1657
1658 if patch: 1672 if patch:
1659 patch = q.lookup(patch) 1673 patch = q.lookup(patch)
1660 else: 1674 else:
1661 if not q.applied: 1675 if not q.applied:
1662 ui.write(_('No patches applied\n')) 1676 ui.write(_('No patches applied\n'))
1663 return 1677 return
1664 patch = q.lookup('qtip') 1678 patch = q.lookup('qtip')
1679 absdest = q.join(name)
1680 if os.path.isdir(absdest):
1681 name = os.path.join(name, os.path.basename(patch))
1682 absdest = q.join(name)
1683 if os.path.exists(absdest):
1684 raise util.Abort(_('%s already exists') % absdest)
1685
1686 if name in q.series:
1687 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1665 1688
1666 if ui.verbose: 1689 if ui.verbose:
1667 ui.write('Renaming %s to %s\n' % (patch, name)) 1690 ui.write('Renaming %s to %s\n' % (patch, name))
1668 i = q.find_series(patch) 1691 i = q.find_series(patch)
1669 q.full_series[i] = name 1692 q.full_series[i] = name
1731 backup = 'all' 1754 backup = 'all'
1732 if opts['backup']: 1755 if opts['backup']:
1733 backup = 'strip' 1756 backup = 'strip'
1734 elif opts['nobackup']: 1757 elif opts['nobackup']:
1735 backup = 'none' 1758 backup = 'none'
1736 repo.mq.strip(repo, rev, backup=backup) 1759 update = repo.dirstate.parents()[0] != revlog.nullid
1760 repo.mq.strip(repo, rev, backup=backup, update=update)
1737 return 0 1761 return 0
1738 1762
1739 def select(ui, repo, *args, **opts): 1763 def select(ui, repo, *args, **opts):
1740 '''set or print guarded patches to push 1764 '''set or print guarded patches to push
1741 1765
1907 [('I', 'include', [], _('include names matching the given patterns')), 1931 [('I', 'include', [], _('include names matching the given patterns')),
1908 ('X', 'exclude', [], _('exclude names matching the given patterns'))], 1932 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
1909 'hg qdiff [-I] [-X] [FILE]...'), 1933 'hg qdiff [-I] [-X] [FILE]...'),
1910 "qdelete|qremove|qrm": 1934 "qdelete|qremove|qrm":
1911 (delete, 1935 (delete,
1912 [('k', 'keep', None, _('keep patch file'))], 1936 [('f', 'forget', None, _('stop managing an applied patch')),
1913 'hg qdelete [-k] PATCH'), 1937 ('k', 'keep', None, _('keep patch file'))],
1938 'hg qdelete [-f] [-k] PATCH'),
1914 'qfold': 1939 'qfold':
1915 (fold, 1940 (fold,
1916 [('e', 'edit', None, _('edit patch header')), 1941 [('e', 'edit', None, _('edit patch header')),
1917 ('k', 'keep', None, _('keep folded patch files')), 1942 ('k', 'keep', None, _('keep folded patch files')),
1918 ('m', 'message', '', _('set patch header to <text>')), 1943 ('m', 'message', '', _('set patch header to <text>')),
1959 "^qrefresh": 1984 "^qrefresh":
1960 (refresh, 1985 (refresh,
1961 [('e', 'edit', None, _('edit commit message')), 1986 [('e', 'edit', None, _('edit commit message')),
1962 ('m', 'message', '', _('change commit message with <text>')), 1987 ('m', 'message', '', _('change commit message with <text>')),
1963 ('l', 'logfile', '', _('change commit message with <file> content')), 1988 ('l', 'logfile', '', _('change commit message with <file> content')),
1989 ('g', 'git', None, _('use git extended diff format')),
1964 ('s', 'short', None, 'short refresh'), 1990 ('s', 'short', None, 'short refresh'),
1965 ('I', 'include', [], _('include names matching the given patterns')), 1991 ('I', 'include', [], _('include names matching the given patterns')),
1966 ('X', 'exclude', [], _('exclude names matching the given patterns'))], 1992 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
1967 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'), 1993 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'),
1968 'qrename|qmv': 1994 'qrename|qmv':
1990 'hg qselect [OPTION...] [GUARD...]'), 2016 'hg qselect [OPTION...] [GUARD...]'),
1991 "qseries": 2017 "qseries":
1992 (series, 2018 (series,
1993 [('m', 'missing', None, 'print patches not in series'), 2019 [('m', 'missing', None, 'print patches not in series'),
1994 ('s', 'summary', None, _('print first line of patch header'))], 2020 ('s', 'summary', None, _('print first line of patch header'))],
1995 'hg qseries [-m]'), 2021 'hg qseries [-ms]'),
1996 "^strip": 2022 "^strip":
1997 (strip, 2023 (strip,
1998 [('f', 'force', None, 'force multi-head removal'), 2024 [('f', 'force', None, 'force multi-head removal'),
1999 ('b', 'backup', None, 'bundle unrelated changesets'), 2025 ('b', 'backup', None, 'bundle unrelated changesets'),
2000 ('n', 'nobackup', None, 'no backups')], 2026 ('n', 'nobackup', None, 'no backups')],