comparison hgext/mq.py @ 5673:dd3ce7515f4d

mq: add --currentuser and --user options to qnew and qrefresh These options make qnew and qrefresh add/update the "From:" header (or, if present, the "# User" header). This allows proper attribution of patches in patch queues with multiple contributors.
author peter.arrenbrecht@gmail.com
date Wed, 19 Dec 2007 22:36:18 +0100
parents 1f044b04fa0a
children 4107e823dc2c
comparison
equal deleted inserted replaced
5653:1b35bc1c1968 5673:dd3ce7515f4d
601 return m, a, r, d 601 return m, a, r, d
602 602
603 def new(self, repo, patch, *pats, **opts): 603 def new(self, repo, patch, *pats, **opts):
604 msg = opts.get('msg') 604 msg = opts.get('msg')
605 force = opts.get('force') 605 force = opts.get('force')
606 user = opts.get('user')
606 if os.path.exists(self.join(patch)): 607 if os.path.exists(self.join(patch)):
607 raise util.Abort(_('patch "%s" already exists') % patch) 608 raise util.Abort(_('patch "%s" already exists') % patch)
608 if opts.get('include') or opts.get('exclude') or pats: 609 if opts.get('include') or opts.get('exclude') or pats:
609 fns, match, anypats = cmdutil.matchpats(repo, pats, opts) 610 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
610 m, a, r, d = repo.status(files=fns, match=match)[:4] 611 m, a, r, d = repo.status(files=fns, match=match)[:4]
615 self.check_toppatch(repo) 616 self.check_toppatch(repo)
616 wlock = repo.wlock() 617 wlock = repo.wlock()
617 try: 618 try:
618 insert = self.full_series_end() 619 insert = self.full_series_end()
619 commitmsg = msg and msg or ("[mq]: %s" % patch) 620 commitmsg = msg and msg or ("[mq]: %s" % patch)
620 n = repo.commit(commitfiles, commitmsg, match=match, force=True) 621 n = repo.commit(commitfiles, commitmsg, user, match=match, force=True)
621 if n == None: 622 if n == None:
622 raise util.Abort(_("repo commit failed")) 623 raise util.Abort(_("repo commit failed"))
623 self.full_series[insert:insert] = [patch] 624 self.full_series[insert:insert] = [patch]
624 self.applied.append(statusentry(revlog.hex(n), patch)) 625 self.applied.append(statusentry(revlog.hex(n), patch))
625 self.parse_series() 626 self.parse_series()
626 self.series_dirty = 1 627 self.series_dirty = 1
627 self.applied_dirty = 1 628 self.applied_dirty = 1
628 p = self.opener(patch, "w") 629 p = self.opener(patch, "w")
630 if user:
631 p.write("From: " + user + "\n\n")
629 if msg: 632 if msg:
630 msg = msg + "\n" 633 msg = msg + "\n"
631 p.write(msg) 634 p.write(msg)
632 p.close() 635 p.close()
633 wlock = None 636 wlock = None
943 ci = 0 946 ci = 0
944 for mi in xrange(len(message)): 947 for mi in xrange(len(message)):
945 while message[mi] != comments[ci]: 948 while message[mi] != comments[ci]:
946 ci += 1 949 ci += 1
947 del comments[ci] 950 del comments[ci]
951
952 newuser = opts.get('user')
953 if newuser:
954 # Update all references to a user in the patch header.
955 # If none found, add "From: " header.
956 needfrom = True
957 for prefix in ['# User ', 'From: ']:
958 for i in xrange(len(comments)):
959 if comments[i].startswith(prefix):
960 comments[i] = prefix + newuser
961 needfrom = False
962 break
963 if needfrom:
964 comments = ['From: ' + newuser, ''] + comments
965 user = newuser
966
948 if msg: 967 if msg:
949 comments.append(msg) 968 comments.append(msg)
950 969
951 patchf.seek(0) 970 patchf.seek(0)
952 patchf.truncate() 971 patchf.truncate()
1068 else: 1087 else:
1069 message = "\n".join(message) 1088 message = "\n".join(message)
1070 else: 1089 else:
1071 message = msg 1090 message = msg
1072 1091
1092 if not user:
1093 user = changes[1]
1094
1073 self.strip(repo, top, update=False, 1095 self.strip(repo, top, update=False,
1074 backup='strip') 1096 backup='strip')
1075 n = repo.commit(filelist, message, changes[1], match=matchfn, 1097 n = repo.commit(filelist, message, user, match=matchfn,
1076 force=1) 1098 force=1)
1077 self.applied[-1] = statusentry(revlog.hex(n), patchfn) 1099 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1078 self.applied_dirty = 1 1100 self.applied_dirty = 1
1079 self.removeundo(repo) 1101 self.removeundo(repo)
1080 else: 1102 else:
1603 ui.write("No patches applied\n") 1625 ui.write("No patches applied\n")
1604 return 1 1626 return 1
1605 return q.qseries(repo, start=l-2, length=1, status='A', 1627 return q.qseries(repo, start=l-2, length=1, status='A',
1606 summary=opts.get('summary')) 1628 summary=opts.get('summary'))
1607 1629
1630 def setupheaderopts(ui, opts):
1631 def do(opt,val):
1632 if not opts[opt] and opts['current' + opt]:
1633 opts[opt] = val
1634 do('user', ui.username())
1635
1608 def new(ui, repo, patch, *args, **opts): 1636 def new(ui, repo, patch, *args, **opts):
1609 """create a new patch 1637 """create a new patch
1610 1638
1611 qnew creates a new patch on top of the currently-applied patch 1639 qnew creates a new patch on top of the currently-applied patch
1612 (if any). It will refuse to run if there are any outstanding 1640 (if any). It will refuse to run if there are any outstanding
1621 q = repo.mq 1649 q = repo.mq
1622 message = cmdutil.logmessage(opts) 1650 message = cmdutil.logmessage(opts)
1623 if opts['edit']: 1651 if opts['edit']:
1624 message = ui.edit(message, ui.username()) 1652 message = ui.edit(message, ui.username())
1625 opts['msg'] = message 1653 opts['msg'] = message
1654 setupheaderopts(ui, opts)
1626 q.new(repo, patch, *args, **opts) 1655 q.new(repo, patch, *args, **opts)
1627 q.save_dirty() 1656 q.save_dirty()
1628 return 0 1657 return 0
1629 1658
1630 def refresh(ui, repo, *pats, **opts): 1659 def refresh(ui, repo, *pats, **opts):
1646 if message: 1675 if message:
1647 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) 1676 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1648 patch = q.applied[-1].name 1677 patch = q.applied[-1].name
1649 (message, comment, user, date, hasdiff) = q.readheaders(patch) 1678 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1650 message = ui.edit('\n'.join(message), user or ui.username()) 1679 message = ui.edit('\n'.join(message), user or ui.username())
1680 setupheaderopts(ui, opts)
1651 ret = q.refresh(repo, pats, msg=message, **opts) 1681 ret = q.refresh(repo, pats, msg=message, **opts)
1652 q.save_dirty() 1682 q.save_dirty()
1653 return ret 1683 return ret
1654 1684
1655 def diff(ui, repo, *pats, **opts): 1685 def diff(ui, repo, *pats, **opts):
2136 repo.__class__ = mqrepo 2166 repo.__class__ = mqrepo
2137 repo.mq = queue(ui, repo.join("")) 2167 repo.mq = queue(ui, repo.join(""))
2138 2168
2139 seriesopts = [('s', 'summary', None, _('print first line of patch header'))] 2169 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2140 2170
2171 headeropts = [
2172 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2173 ('u', 'user', '', _('add "From: <given user>" to patch'))]
2174
2141 cmdtable = { 2175 cmdtable = {
2142 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')), 2176 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2143 "qclone": 2177 "qclone":
2144 (clone, 2178 (clone,
2145 [('', 'pull', None, _('use pull protocol to copy metadata')), 2179 [('', 'pull', None, _('use pull protocol to copy metadata')),
2194 "qnew": 2228 "qnew":
2195 (new, 2229 (new,
2196 [('e', 'edit', None, _('edit commit message')), 2230 [('e', 'edit', None, _('edit commit message')),
2197 ('f', 'force', None, _('import uncommitted changes into patch')), 2231 ('f', 'force', None, _('import uncommitted changes into patch')),
2198 ('g', 'git', None, _('use git extended diff format')), 2232 ('g', 'git', None, _('use git extended diff format')),
2199 ] + commands.walkopts + commands.commitopts, 2233 ] + commands.walkopts + commands.commitopts + headeropts,
2200 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')), 2234 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2201 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')), 2235 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2202 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')), 2236 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2203 "^qpop": 2237 "^qpop":
2204 (pop, 2238 (pop,
2217 "^qrefresh": 2251 "^qrefresh":
2218 (refresh, 2252 (refresh,
2219 [('e', 'edit', None, _('edit commit message')), 2253 [('e', 'edit', None, _('edit commit message')),
2220 ('g', 'git', None, _('use git extended diff format')), 2254 ('g', 'git', None, _('use git extended diff format')),
2221 ('s', 'short', None, _('refresh only files already in the patch')), 2255 ('s', 'short', None, _('refresh only files already in the patch')),
2222 ] + commands.walkopts + commands.commitopts, 2256 ] + commands.walkopts + commands.commitopts + headeropts,
2223 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')), 2257 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2224 'qrename|qmv': 2258 'qrename|qmv':
2225 (rename, [], _('hg qrename PATCH1 [PATCH2]')), 2259 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2226 "qrestore": 2260 "qrestore":
2227 (restore, 2261 (restore,