changeset 19097:3f5e75c22585 stable

push: make locking of source optional (issue3684) Having the permission to lock the source repo on push is now optional. When the repo cannot be locked, phase are not changed locally. A status message is issue when some actual phase movement are skipped: cannot lock source repo, skipping local public phase update A debug message with the exact reason of the locking failure is issued in all case.
author Pierre-Yves David <pierre-yves.david@logilab.fr>
date Tue, 30 Apr 2013 21:19:56 +0200
parents 0e4af72cbd7f
children f01ae031f84c
files mercurial/localrepo.py tests/test-phases-exchange.t
diffstat 2 files changed, 62 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/localrepo.py	Tue Apr 30 10:51:25 2013 +0200
+++ b/mercurial/localrepo.py	Tue Apr 30 21:19:56 2013 +0200
@@ -1764,9 +1764,29 @@
         unfi = self.unfiltered()
         def localphasemove(nodes, phase=phases.public):
             """move <nodes> to <phase> in the local source repo"""
-            phases.advanceboundary(self, phase, nodes)
+            if locallock is not None:
+                phases.advanceboundary(self, phase, nodes)
+            else:
+                # repo is not locked, do not change any phases!
+                # Informs the user that phases should have been moved when
+                # applicable.
+                actualmoves = [n for n in nodes if phase < self[n].phase()]
+                phasestr = phases.phasenames[phase]
+                if actualmoves:
+                    self.ui.status(_('cannot lock source repo, skipping local'
+                                     ' %s phase update\n') % phasestr)
         # get local lock as we might write phase data
-        locallock = self.lock()
+        locallock = None
+        try:
+            locallock = self.lock()
+        except IOError, err:
+            if err.errno != errno.EACCES:
+                raise
+            # source repo cannot be locked.
+            # We do not abort the push, but just disable the local phase
+            # synchronisation.
+            msg = 'cannot lock source repository: %s\n' % err
+            self.ui.debug(msg)
         try:
             self.checkpush(force, revs)
             lock = None
@@ -1918,7 +1938,8 @@
                 if lock is not None:
                     lock.release()
         finally:
-            locallock.release()
+            if locallock is not None:
+                locallock.release()
 
         self.ui.debug("checking for updated bookmarks\n")
         rb = remote.listkeys('bookmarks')
--- a/tests/test-phases-exchange.t	Tue Apr 30 10:51:25 2013 +0200
+++ b/tests/test-phases-exchange.t	Tue Apr 30 21:19:56 2013 +0200
@@ -1062,5 +1062,43 @@
   |
   o  0 public a-A - 054250a37db4
   
+
+Pushing From an unlockable repo
+--------------------------------
+(issue3684)
+
+Unability to lock the source repo should not prevent the push. It will prevent
+the retrieval of remote phase during push. For example, pushing to a publishing
+server won't turn changeset public.
+
+1. Test that push is not prevented
+
+  $ hg init Phi
+  $ cd Upsilon
+  $ chmod -R -w .hg
+  $ hg push ../Phi
+  pushing to ../Phi
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 14 changesets with 14 changes to 14 files (+3 heads)
+  $ chmod -R +w .hg
+
+2. Test that failed phases movement are reported
+
+  $ hg phase --force --draft 3
+  $ chmod -R -w .hg
+  $ hg push ../Phi
+  pushing to ../Phi
+  searching for changes
+  no changes found
+  cannot lock source repo, skipping local public phase update
+  [1]
+  $ chmod -R +w .hg
+  $ hgph Upsilon
+
+  $ cd ..
+
   $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS