[PATCH] mq: add --currentuser and --user options to qnew and qrefresh

Peter Arrenbrecht peter.arrenbrecht at gmail.com
Tue Dec 18 02:59:54 CST 2007


Brendan,

I have started the separate patch for the date part. Turns out mq does
not read a plain "Date: " tag, only the "# Date " line within an "# HG
changeset patch". However, some people would be happy if they could
set/update the date when they do qnew/qrefresh and have mq use that
date when they do qpush.

I could

(a) read "Date: " too, but I don't think people really want to read
email dates as commit dates automatically,

(b) only support updating existing "# Date " lines in qrefresh and
write an "#HG changeset patch" header in qnew when -d or -D is
specified; I would then also write "# User " rather than "From:" when
-u or -U is also specified.

(c) switch to "#HG changeset patch" style when -d or -D is specified
to qrefresh, clobbering other headers (they are not read anyway); this
is what you initially suggested even for -u and -U.

I favor (b). It would mean you only get to update dates on patches
that you started with a proper hg patch header (using qnew -D). Since
I expect people to set

[defaults]
qnew = -D -U
qrefresh = -D

that should pan out. It does, however, mean that -d and -D on qrefresh
are only advisory. I cannot let them fail if there is no "# HG
changeset patch" header exactly because they will be used as defaults
and so be active even for non-conforming patches. I might issue a
warning, but I don't really think I should.

Unless you guys object, I'll continue with (b), as outlined above, in
a few days.

-peter


On Dec 18, 2007 8:57 AM, Peter Arrenbrecht <peter.arrenbrecht at gmail.com> wrote:
> # HG changeset patch
> # User peter.arrenbrecht at gmail.com
> # Date 1197963907 -3600
> # Node ID 10fa9311ee977ac413e0575cf9c02004f0ba565f
> # Parent  812dbb08d59a6ccfdb873bb50f752c4e0272c518
> 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.
>
> diff --git a/hgext/mq.py b/hgext/mq.py
> --- a/hgext/mq.py
> +++ b/hgext/mq.py
> @@ -603,6 +603,7 @@ class queue:
>      def new(self, repo, patch, *pats, **opts):
>          msg = opts.get('msg')
>          force = opts.get('force')
> +        user = opts.get('user')
>          if os.path.exists(self.join(patch)):
>              raise util.Abort(_('patch "%s" already exists') % patch)
>          if opts.get('include') or opts.get('exclude') or pats:
> @@ -617,7 +618,7 @@ class queue:
>          try:
>              insert = self.full_series_end()
>              commitmsg = msg and msg or ("[mq]: %s" % patch)
> -            n = repo.commit(commitfiles, commitmsg, match=match, force=True)
> +            n = repo.commit(commitfiles, commitmsg, user, match=match, force=True)
>              if n == None:
>                  raise util.Abort(_("repo commit failed"))
>              self.full_series[insert:insert] = [patch]
> @@ -626,6 +627,8 @@ class queue:
>              self.series_dirty = 1
>              self.applied_dirty = 1
>              p = self.opener(patch, "w")
> +            if user:
> +                p.write("From: " + user + "\n\n")
>              if msg:
>                  msg = msg + "\n"
>                  p.write(msg)
> @@ -945,6 +948,22 @@ class queue:
>                      while message[mi] != comments[ci]:
>                          ci += 1
>                      del comments[ci]
> +
> +            newuser = opts.get('user')
> +            if newuser:
> +                # Update all references to a user in the patch header.
> +                # If none found, add "From: " header.
> +                needfrom = True
> +                for prefix in ['# User ', 'From: ']:
> +                    for i in xrange(len(comments)):
> +                        if comments[i].startswith(prefix):
> +                            comments[i] = prefix + newuser
> +                            needfrom = False
> +                            break
> +                if needfrom:
> +                    comments = ['From: ' + newuser, ''] + comments
> +                user = newuser
> +
>              if msg:
>                  comments.append(msg)
>
> @@ -1070,9 +1089,12 @@ class queue:
>                  else:
>                      message = msg
>
> +                if not user:
> +                    user = changes[1]
> +
>                  self.strip(repo, top, update=False,
>                             backup='strip')
> -                n = repo.commit(filelist, message, changes[1], match=matchfn,
> +                n = repo.commit(filelist, message, user, match=matchfn,
>                                  force=1)
>                  self.applied[-1] = statusentry(revlog.hex(n), patchfn)
>                  self.applied_dirty = 1
> @@ -1605,6 +1627,12 @@ def prev(ui, repo, **opts):
>      return q.qseries(repo, start=l-2, length=1, status='A',
>                       summary=opts.get('summary'))
>
> +def setupheaderopts(ui, opts):
> +    def do(opt,val):
> +        if not opts[opt] and opts['current' + opt]:
> +            opts[opt] = val
> +    do('user', ui.username())
> +
>  def new(ui, repo, patch, *args, **opts):
>      """create a new patch
>
> @@ -1623,6 +1651,7 @@ def new(ui, repo, patch, *args, **opts):
>      if opts['edit']:
>          message = ui.edit(message, ui.username())
>      opts['msg'] = message
> +    setupheaderopts(ui, opts)
>      q.new(repo, patch, *args, **opts)
>      q.save_dirty()
>      return 0
> @@ -1648,6 +1677,7 @@ def refresh(ui, repo, *pats, **opts):
>          patch = q.applied[-1].name
>          (message, comment, user, date, hasdiff) = q.readheaders(patch)
>          message = ui.edit('\n'.join(message), user or ui.username())
> +    setupheaderopts(ui, opts)
>      ret = q.refresh(repo, pats, msg=message, **opts)
>      q.save_dirty()
>      return ret
> @@ -2138,6 +2168,10 @@ def reposetup(ui, repo):
>
>  seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
>
> +headeropts = [
> +    ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
> +    ('u', 'user', '', _('add "From: <given user>" to patch'))]
> +
>  cmdtable = {
>      "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
>      "qclone":
> @@ -2196,7 +2230,7 @@ cmdtable = {
>           [('e', 'edit', None, _('edit commit message')),
>            ('f', 'force', None, _('import uncommitted changes into patch')),
>            ('g', 'git', None, _('use git extended diff format')),
> -          ] + commands.walkopts + commands.commitopts,
> +          ] + commands.walkopts + commands.commitopts + headeropts,
>           _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
>      "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
>      "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
> @@ -2219,7 +2253,7 @@ cmdtable = {
>           [('e', 'edit', None, _('edit commit message')),
>            ('g', 'git', None, _('use git extended diff format')),
>            ('s', 'short', None, _('refresh only files already in the patch')),
> -          ] + commands.walkopts + commands.commitopts,
> +          ] + commands.walkopts + commands.commitopts + headeropts,
>           _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
>      'qrename|qmv':
>          (rename, [], _('hg qrename PATCH1 [PATCH2]')),
> diff --git a/tests/test-mq-header-from b/tests/test-mq-header-from
> new file mode 100755
> --- /dev/null
> +++ b/tests/test-mq-header-from
> @@ -0,0 +1,107 @@
> +#!/bin/sh
> +
> +echo "[extensions]" >> $HGRCPATH
> +echo "mq=" >> $HGRCPATH
> +echo "[diff]" >> $HGRCPATH
> +echo "nodates=true" >> $HGRCPATH
> +
> +
> +catlog() {
> +    cat .hg/patches/$1.patch | sed -e "s/^diff \-r [0-9a-f]* /diff -r ... /"
> +    hg log --template "{rev}: {desc} - {author}\n"
> +}
> +
> +
> +echo ==== init
> +hg init a
> +cd a
> +hg qinit
> +
> +
> +echo ==== qnew -U
> +hg qnew -U 1.patch
> +catlog 1
> +
> +echo ==== qref
> +echo "1" >1
> +hg add
> +hg qref
> +catlog 1
> +
> +echo ==== qref -u
> +hg qref -u mary
> +catlog 1
> +
> +echo ==== qnew
> +hg qnew 2.patch
> +echo "2" >2
> +hg add
> +hg qref
> +catlog 2
> +
> +echo ==== qref -u
> +hg qref -u jane
> +catlog 2
> +
> +
> +echo ==== qnew -U -m
> +hg qnew -U -m "Three" 3.patch
> +catlog 3
> +
> +echo ==== qref
> +echo "3" >3
> +hg add
> +hg qref
> +catlog 3
> +
> +echo ==== qref -m
> +hg qref -m "Drei"
> +catlog 3
> +
> +echo ==== qref -u
> +hg qref -u mary
> +catlog 3
> +
> +echo ==== qref -u -m
> +hg qref -u maria -m "Three (again)"
> +catlog 3
> +
> +echo ==== qnew -m
> +hg qnew -m "Four" 4.patch
> +echo "4" >4
> +hg add
> +hg qref
> +catlog 4
> +
> +echo ==== qref -u
> +hg qref -u jane
> +catlog 4
> +
> +
> +echo ==== qnew with HG header
> +hg qnew 5.patch
> +hg qpop
> +echo "# HG changeset patch" >>.hg/patches/5.patch
> +echo "# User johndoe" >>.hg/patches/5.patch
> +hg qpush
> +catlog 5
> +
> +echo ==== hg qref
> +echo "5" >5
> +hg add
> +hg qref
> +catlog 5
> +
> +echo ==== hg qref -U
> +hg qref -U
> +catlog 5
> +
> +echo ==== hg qref -u
> +hg qref -u johndeere
> +catlog 5
> +
> +
> +echo ==== "qpop -a / qpush -a"
> +hg qpop -a
> +hg qpush -a
> +hg log --template "{rev}: {desc} - {author}\n"
> diff --git a/tests/test-mq-header-from.out b/tests/test-mq-header-from.out
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-mq-header-from.out
> @@ -0,0 +1,201 @@
> +==== init
> +==== qnew -U
> +From: test
> +
> +0: [mq]: 1.patch - test
> +==== qref
> +adding 1
> +From: test
> +
> +diff -r ... 1
> +--- /dev/null
> ++++ b/1
> +@@ -0,0 +1,1 @@
> ++1
> +0: [mq]: 1.patch - test
> +==== qref -u
> +From: mary
> +
> +diff -r ... 1
> +--- /dev/null
> ++++ b/1
> +@@ -0,0 +1,1 @@
> ++1
> +0: [mq]: 1.patch - mary
> +==== qnew
> +adding 2
> +diff -r ... 2
> +--- /dev/null
> ++++ b/2
> +@@ -0,0 +1,1 @@
> ++2
> +1: [mq]: 2.patch - test
> +0: [mq]: 1.patch - mary
> +==== qref -u
> +From: jane
> +
> +
> +diff -r ... 2
> +--- /dev/null
> ++++ b/2
> +@@ -0,0 +1,1 @@
> ++2
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qnew -U -m
> +From: test
> +
> +Three
> +2: Three - test
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qref
> +adding 3
> +From: test
> +
> +Three
> +
> +diff -r ... 3
> +--- /dev/null
> ++++ b/3
> +@@ -0,0 +1,1 @@
> ++3
> +2: Three - test
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qref -m
> +From: test
> +
> +Drei
> +
> +diff -r ... 3
> +--- /dev/null
> ++++ b/3
> +@@ -0,0 +1,1 @@
> ++3
> +2: Drei - test
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qref -u
> +From: mary
> +
> +Drei
> +
> +diff -r ... 3
> +--- /dev/null
> ++++ b/3
> +@@ -0,0 +1,1 @@
> ++3
> +2: Drei - mary
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qref -u -m
> +From: maria
> +
> +Three (again)
> +
> +diff -r ... 3
> +--- /dev/null
> ++++ b/3
> +@@ -0,0 +1,1 @@
> ++3
> +2: Three (again) - maria
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qnew -m
> +adding 4
> +Four
> +
> +diff -r ... 4
> +--- /dev/null
> ++++ b/4
> +@@ -0,0 +1,1 @@
> ++4
> +3: Four - test
> +2: Three (again) - maria
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qref -u
> +From: jane
> +
> +Four
> +
> +diff -r ... 4
> +--- /dev/null
> ++++ b/4
> +@@ -0,0 +1,1 @@
> ++4
> +3: Four - jane
> +2: Three (again) - maria
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qnew with HG header
> +Now at: 4.patch
> +applying 5.patch
> +/usr/bin/patch: **** Only garbage was found in the patch input.
> +patch failed, unable to continue (try -v)
> +patch 5.patch is empty
> +Now at: 5.patch
> +# HG changeset patch
> +# User johndoe
> +4: imported patch 5.patch - johndoe
> +3: Four - jane
> +2: Three (again) - maria
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== hg qref
> +adding 5
> +# HG changeset patch
> +# User johndoe
> +
> +diff -r ... 5
> +--- /dev/null
> ++++ b/5
> +@@ -0,0 +1,1 @@
> ++5
> +4: [mq]: 5.patch - johndoe
> +3: Four - jane
> +2: Three (again) - maria
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== hg qref -U
> +# HG changeset patch
> +# User test
> +
> +diff -r ... 5
> +--- /dev/null
> ++++ b/5
> +@@ -0,0 +1,1 @@
> ++5
> +4: [mq]: 5.patch - test
> +3: Four - jane
> +2: Three (again) - maria
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== hg qref -u
> +# HG changeset patch
> +# User johndeere
> +
> +diff -r ... 5
> +--- /dev/null
> ++++ b/5
> +@@ -0,0 +1,1 @@
> ++5
> +4: [mq]: 5.patch - johndeere
> +3: Four - jane
> +2: Three (again) - maria
> +1: [mq]: 2.patch - jane
> +0: [mq]: 1.patch - mary
> +==== qpop -a / qpush -a
> +Patch queue now empty
> +applying 1.patch
> +applying 2.patch
> +applying 3.patch
> +applying 4.patch
> +applying 5.patch
> +Now at: 5.patch
> +4: imported patch 5.patch - johndeere
> +3: Four - jane
> +2: Three (again) - maria
> +1: imported patch 2.patch - jane
> +0: imported patch 1.patch - mary
>


More information about the Mercurial-devel mailing list