changeset 2854:cdbca3d59518

merge with mpm.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Sat, 12 Aug 2006 11:53:12 -0700
parents 619f1c65384c (diff) e3fb4223e750 (current diff)
children a3c73c9679d2
files hgext/mq.py mercurial/commands.py
diffstat 13 files changed, 193 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/doc/hgrc.5.txt
+++ b/doc/hgrc.5.txt
@@ -306,7 +306,7 @@ http_proxy::
 smtp::
   Configuration for extensions that need to send email messages.
   host;;
-    Optional.  Host name of mail server.  Default: "mail".
+    Host name of mail server, e.g. "mail.example.com".
   port;;
     Optional.  Port to connect to on mail server.  Default: 25.
   tls;;
--- a/hgext/fetch.py
+++ b/hgext/fetch.py
@@ -24,13 +24,13 @@ def fetch(ui, repo, source='default', **
         if modheads == 0:
             return 0
         if modheads == 1:
-            return hg.update(repo, repo.changelog.tip(), wlock=wlock)
+            return hg.clean(repo, repo.changelog.tip(), wlock=wlock)
         newheads = repo.heads(parent)
         newchildren = [n for n in repo.heads(parent) if n != parent]
         newparent = parent
         if newchildren:
             newparent = newchildren[0]
-            hg.update(repo, newparent, wlock=wlock)
+            hg.clean(repo, newparent, wlock=wlock)
         newheads = [n for n in repo.heads() if n != newparent]
         err = False
         if newheads:
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -176,11 +176,11 @@ class queue:
         if exactneg:
             return False, exactneg[0]
         pos = [g for g in patchguards if g[0] == '+']
-        nonpos = [g for g in pos if g[1:] not in guards]
+        exactpos = [g for g in pos if g[1:] in guards]
         if pos:
-            if not nonpos:
-                return True, ''
-            return False, nonpos
+            if exactpos:
+                return True, exactpos[0]
+            return False, pos
         return True, ''
 
     def explain_pushable(self, idx, all_patches=False):
@@ -725,6 +725,8 @@ class queue:
     # 2) a unique substring of the patch name was given
     # 3) patchname[-+]num to indicate an offset in the series file
     def lookup(self, patch, strict=False):
+        patch = patch and str(patch)
+
         def partial_name(s):
             if s in self.series:
                 return s
@@ -1739,7 +1741,7 @@ def select(ui, repo, *args, **opts):
 
     this sets "stable" guard.  mq will skip foo.patch (because it has
     nagative match) but push bar.patch (because it has posative
-    match).  patch is pushed only if all posative guards match and no
+    match).  patch is pushed if any posative guards match and no
     nagative guards match.
 
     with no arguments, default is to print current active guards.
@@ -1749,19 +1751,36 @@ def select(ui, repo, *args, **opts):
     when no guards active, patches with posative guards are skipped,
     patches with nagative guards are pushed.
 
+    qselect can change guards of applied patches. it does not pop
+    guarded patches by default.  use --pop to pop back to last applied
+    patch that is not guarded.  use --reapply (implies --pop) to push
+    back to current patch afterwards, but skip guarded patches.
+
     use -s/--series to print list of all guards in series file (no
     other arguments needed).  use -v for more information.'''
 
     q = repo.mq
     guards = q.active()
     if args or opts['none']:
+        old_unapplied = q.unapplied(repo)
+        old_guarded = [i for i in xrange(len(q.applied)) if
+                       not q.pushable(i)[0]]
         q.set_active(args)
         q.save_dirty()
         if not args:
             ui.status(_('guards deactivated\n'))
-        if q.series:
-            ui.status(_('%d of %d unapplied patches active\n') %
-                      (len(q.unapplied(repo)), len(q.series)))
+        if not opts['pop'] and not opts['reapply']:
+            unapplied = q.unapplied(repo)
+            guarded = [i for i in xrange(len(q.applied))
+                       if not q.pushable(i)[0]]
+            if len(unapplied) != len(old_unapplied):
+                ui.status(_('number of unguarded, unapplied patches has '
+                            'changed from %d to %d\n') %
+                          (len(old_unapplied), len(unapplied)))
+            if len(guarded) != len(old_guarded):
+                ui.status(_('number of guarded, applied patches has changed '
+                            'from %d to %d\n') %
+                          (len(old_guarded), len(guarded)))
     elif opts['series']:
         guards = {}
         noguards = 0
@@ -1789,9 +1808,51 @@ def select(ui, repo, *args, **opts):
                 ui.write(g, '\n')
         else:
             ui.write(_('no active guards\n'))
+    reapply = opts['reapply'] and q.applied and q.appliedname(-1)
+    popped = False
+    if opts['pop'] or opts['reapply']:
+        for i in xrange(len(q.applied)):
+            pushable, reason = q.pushable(i)
+            if not pushable:
+                ui.status(_('popping guarded patches\n'))
+                popped = True
+                if i == 0:
+                    q.pop(repo, all=True)
+                else:
+                    q.pop(repo, i-1)
+                break
+    if popped:
+        try:
+            if reapply:
+                ui.status(_('reapplying unguarded patches\n'))
+                q.push(repo, reapply)
+        finally:
+            q.save_dirty()
 
 def reposetup(ui, repo):
     class mqrepo(repo.__class__):
+        def abort_if_wdir_patched(self, errmsg, force=False):
+            if self.mq.applied and not force:
+                parent = revlog.hex(self.dirstate.parents()[0])
+                if parent in [s.rev for s in self.mq.applied]:
+                    raise util.Abort(errmsg)
+            
+        def commit(self, *args, **opts):
+            if len(args) >= 6:
+                force = args[5]
+            else:
+                force = opts.get('force')
+            self.abort_if_wdir_patched(
+                _('cannot commit over an applied mq patch'),
+                force)
+
+            return super(mqrepo, self).commit(*args, **opts)
+
+        def push(self, remote, force=False, revs=None):
+            if self.mq.applied and not force:
+                raise util.Abort(_('source has mq patches applied'))
+            return super(mqrepo, self).push(remote, force, revs)
+            
         def tags(self):
             if self.tagscache:
                 return self.tagscache
@@ -1813,8 +1874,9 @@ def reposetup(ui, repo):
 
             return tagscache
 
-    repo.__class__ = mqrepo
-    repo.mq = queue(ui, repo.join(""))
+    if repo.local():
+        repo.__class__ = mqrepo
+        repo.mq = queue(ui, repo.join(""))
 
 cmdtable = {
     "qapplied": (applied, [], 'hg qapplied [PATCH]'),
@@ -1906,8 +1968,11 @@ cmdtable = {
          'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
     "qselect": (select,
                 [('n', 'none', None, _('disable all guards')),
-                 ('s', 'series', None, _('list all guards in series file'))],
-                'hg qselect [GUARDS]'),
+                 ('s', 'series', None, _('list all guards in series file')),
+                 ('', 'pop', None,
+                  _('pop to before first guarded applied patch')),
+                 ('', 'reapply', None, _('pop, then reapply patches'))],
+                'hg qselect [OPTION...] [GUARD...]'),
     "qseries":
         (series,
          [('m', 'missing', None, 'print patches not in series'),
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -3545,6 +3545,7 @@ def dispatch(args):
                         mod = sys.modules[name]
                         if hasattr(mod, 'reposetup'):
                             mod.reposetup(u, repo)
+                            hg.repo_setup_hooks.append(mod.reposetup)
                 except hg.RepoError:
                     if cmd not in optionalrepo.split():
                         raise
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -48,9 +48,14 @@ def islocal(repo):
             return False
     return repo.local()
 
+repo_setup_hooks = []
+
 def repository(ui, path=None, create=False):
     """return a repository object for the specified path"""
-    return _lookup(path).instance(ui, path, create)
+    repo = _lookup(path).instance(ui, path, create)
+    for hook in repo_setup_hooks:
+        hook(ui, repo)
+    return repo
 
 def defaultdest(source):
     '''return default destination of clone if none is given'''
--- a/tests/test-abort-checkin
+++ b/tests/test-abort-checkin
@@ -3,6 +3,11 @@
 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
 echo "[extensions]" >> $HGTMP/.hgrc
 echo "mq=" >> $HGTMP/.hgrc
+cat > $HGTMP/false <<EOF
+#!/bin/sh
+exit 1
+EOF
+chmod +x $HGTMP/false
 
 hg init foo
 cd foo
@@ -11,7 +16,7 @@ hg add foo
 
 # mq may keep a reference to the repository so __del__ will not be called
 # and .hg/journal.dirstate will not be deleted:
-HGEDITOR=false hg ci
-HGEDITOR=false hg ci
+HGEDITOR=$HGTMP/false hg ci
+HGEDITOR=$HGTMP/false hg ci
 
 exit 0
--- a/tests/test-globalopts
+++ b/tests/test-globalopts
@@ -45,7 +45,7 @@ hg --cwd c head -v
 hg --cwd b tip --verbose
 
 echo %% --config
-hg --cwd c --config paths.quuxfoo=bar paths | grep -q quuxfoo && echo quuxfoo
+hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /dev/null && echo quuxfoo
 hg --cwd c --config '' tip -q
 hg --cwd c --config a.b tip -q
 hg --cwd c --config a tip -q
--- a/tests/test-import
+++ b/tests/test-import
@@ -72,7 +72,7 @@ rm -rf b
 
 echo % plain diff in email, no subject, no message body, should fail
 hg clone -r0 a b
-grep -v '^\(Subject\|email\)' msg.patch | hg --cwd b import -
+egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
 rm -rf b
 
 echo % hg export in email, should use patch header
@@ -89,9 +89,10 @@ hg --cwd a ci -u someoneelse -d '1 0' -m
 echo % hg import in a subdirectory
 hg clone -r0 a b
 hg --cwd a export tip | sed -e 's/d1\/d2\///' > tip.patch
-pushd b/d1/d2 2>&1 > /dev/null
+dir=`pwd`
+cd b/d1/d2 2>&1 > /dev/null
 hg import  ../../../tip.patch
-popd  2>&1 > /dev/null
+cd $dir
 echo "% message should be 'subdir change'"
 hg --cwd b tip | grep 'subdir change'
 echo "% committer should be 'someoneelse'"
--- a/tests/test-mq
+++ b/tests/test-mq
@@ -10,6 +10,10 @@ hg help mq
 hg init a
 cd a
 echo a > a
+hg ci -Ama
+
+hg clone . ../k
+
 mkdir b
 echo z > b/z
 hg ci -Ama
@@ -48,7 +52,7 @@ echo % qrefresh
 
 echo a >> a
 hg qrefresh
-sed -e "s/\(^diff -r \)\([a-f0-9]* \)/\1 x/" \
+sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \
     -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
     -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch
 
@@ -103,9 +107,19 @@ hg qnext
 hg qprev
 hg qapplied
 
+echo % commit should fail
+hg commit
+
+echo % push should fail
+hg push ../../k
+
 echo % qunapplied
 hg qunapplied
 
+echo % push should succeed
+hg qpop -a
+hg push ../../k
+
 echo % strip
 cd ../../b
 echo x>x
--- a/tests/test-mq-guards
+++ b/tests/test-mq-guards
@@ -63,22 +63,39 @@ echo % should push all
 hg qpush -a
 
 hg qpop -a
-hg qguard a.patch +1 +2
+hg qguard a.patch +1
+hg qguard b.patch +2
 hg qselect 1
+echo % should push a.patch, not b.patch
+hg qpush
+hg qpush
+hg qpop -a
+
+hg qselect 2
 echo % should push b.patch
 hg qpush
 hg qpop -a
 
-hg qselect 2
+hg qselect 1 2
+echo % should push a.patch, b.patch
 hg qpush
-hg qpop -a
-
-hg qselect 1 2
-echo % should push a.patch
 hg qpush
 hg qpop -a
 
 hg qguard a.patch +1 +2 -3
 hg qselect 1 2 3
+echo % list patches and guards
+hg qguard -l
+echo % list series
+hg qseries -v
+echo % list guards
+hg qselect
 echo % should push b.patch
 hg qpush
+
+hg qpush -a
+hg qselect -n --reapply
+echo % guards in series file: +1 +2 -3
+hg qselect -s
+echo % should show c.patch
+hg qapplied
--- a/tests/test-mq-guards.out
+++ b/tests/test-mq-guards.out
@@ -13,7 +13,7 @@ a.patch: +a
 applying b.patch
 Now at: b.patch
 Patch queue now empty
-3 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 2 to 3
 % should push a.patch
 applying a.patch
 Now at: a.patch
@@ -28,27 +28,57 @@ applying c.patch
 Now at: c.patch
 Patch queue now empty
 guards deactivated
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 3 to 2
 % should push all
 applying b.patch
 applying c.patch
 Now at: c.patch
 Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 1 to 2
+% should push a.patch, not b.patch
+applying a.patch
+Now at: a.patch
+applying c.patch
+Now at: c.patch
+Patch queue now empty
 % should push b.patch
 applying b.patch
 Now at: b.patch
 Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 2 to 3
+% should push a.patch, b.patch
+applying a.patch
+Now at: a.patch
 applying b.patch
 Now at: b.patch
 Patch queue now empty
-3 of 3 unapplied patches active
-% should push a.patch
-applying a.patch
-Now at: a.patch
-Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 3 to 2
+% list patches and guards
+a.patch: +1 +2 -3
+b.patch: +2
+c.patch: unguarded
+% list series
+0 G a.patch
+1 U b.patch
+2 U c.patch
+% list guards
+1
+2
+3
 % should push b.patch
 applying b.patch
 Now at: b.patch
+applying c.patch
+Now at: c.patch
+guards deactivated
+popping guarded patches
+Patch queue now empty
+reapplying unguarded patches
+applying c.patch
+Now at: c.patch
+% guards in series file: +1 +2 -3
++1
++2
+-3
+% should show c.patch
+c.patch
--- a/tests/test-mq-qrefresh-replace-log-message
+++ b/tests/test-mq-qrefresh-replace-log-message
@@ -33,7 +33,7 @@ echo " This is the 3rd log message" >> l
 echo bbbb > file
 hg qrefresh -l logfile
 echo =======================
-echo "Should display 'Third commit message\n This is the 3rd log message'"
+printf "Should display 'Third commit message\\\n This is the 3rd log message'\n"
 hg log -l1 -v | sed -n '/description/,$p'
 echo
 
@@ -46,6 +46,6 @@ echo bbbb > file2
 echo " This is the 5th log message" >> logfile) |\
 hg qrefresh -l-
 echo =======================
-echo "Should display 'Fifth commit message\n This is the 5th log message'"
+printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n"
 hg log -l1 -v | sed -n '/description/,$p'
 echo
--- a/tests/test-mq.out
+++ b/tests/test-mq.out
@@ -49,6 +49,7 @@ list of commands (use "hg help -v mq" to
  qunapplied   print the patches not yet applied
  strip        strip a revision and all later revs on the same branch
 adding a
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 adding b/z
 % qinit
 % -R qinit
@@ -102,8 +103,21 @@ Now at: test.patch
 test2.patch
 Only one patch applied
 test.patch
+% commit should fail
+abort: cannot commit over an applied mq patch
+% push should fail
+pushing to ../../k
+abort: source has mq patches applied
 % qunapplied
 test2.patch
+% push should succeed
+Patch queue now empty
+pushing to ../../k
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
 % strip
 adding x
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved