changeset 19852:57479e0d203d

merge with stable
author Matt Mackall <mpm@selenic.com>
date Tue, 01 Oct 2013 17:00:03 -0700
parents 5c0dc243fe5b (current diff) 4d513f96a565 (diff)
children eddc2a2d57e6
files hgext/histedit.py hgext/rebase.py mercurial/localrepo.py mercurial/util.py
diffstat 11 files changed, 376 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsigs	Tue Oct 01 10:44:59 2013 -0700
+++ b/.hgsigs	Tue Oct 01 17:00:03 2013 -0700
@@ -77,3 +77,4 @@
 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
 335a558f81dc73afeab4d7be63617392b130117f 0 iQIVAwUAUiZrIyBXgaxoKi1yAQK2iw//cquNqqSkc8Re5/TZT9I6NH+lh6DbOKjJP0Xl1Wqq0K+KSIUgZG4G32ovaEb2l5X0uY+3unRPiZ0ebl0YSw4Fb2ZiPIADXLBTOYRrY2Wwd3tpJeGI6wEgZt3SfcITV/g7NJrCjT3FlYoSOIayrExM80InSdcEM0Q3Rx6HKzY2acyxzgZeAtAW5ohFvHilSvY6p5Gcm4+QptMxvw45GPdreUmjeXZxNXNXZ8P+MjMz/QJbai/N7PjmK8lqnhkBsT48Ng/KhhmOkGntNJ2/ImBWLFGcWngSvJ7sfWwnyhndvGhe0Hq1NcCf7I8TjNDxU5TR+m+uW7xjXdLoDbUjBdX4sKXnh8ZjbYiODKBOrrDq25cf8nA/tnpKyE/qsVy60kOk6loY4XKiYmn1V49Ta0emmDx0hqo3HgxHHsHX0NDnGdWGol7cPRET0RzVobKq1A0jnrhPooWidvLh9bPzLonrWDo+ib+DuySoRkuYUK4pgZJ2mbg6daFOBEZygkSyRB8bo1UQUP7EgQDrWe4khb/5GHEfDkrQz3qu/sXvc0Ir1mOUWBFPHC2DjjCn/oMJuUkG1SwM8l2Bfv7h67ssES6YQ2+RjOix4yid7EXS/Ogl45PzCIPSI5+BbNs10JhE0w5uErBHlF53EDTe/TSLc+GU6DB6PP6dH912Njdr3jpNSUQ=
+e7fa36d2ad3a7944a52dca126458d6f482db3524 0 iQIVAwUAUktg4yBXgaxoKi1yAQLO0g//du/2ypYYUfmM/yZ4zztNKIvgMSGTDVbCCGB2y2/wk2EcolpjpGTkcgnJT413ksYtw78ZU+mvv0RjgrFCm8DQ8kroJaQZ2qHmtSUb42hPBPvtg6kL9YaA4yvp87uUBpFRavGS5uX4hhEIyvZKzhXUBvqtL3TfwR7ld21bj8j00wudqELyyU9IrojIY9jkJ3XL/4shBGgP7u6OK5g8yJ6zTnWgysUetxHBPrYjG25lziiiZQFvZqK1B3PUqAOaFPltQs0PB8ipOCAHQgJsjaREj8VmC3+rskmSSy66NHm6gAB9+E8oAgOcU7FzWbdYgnz4kR3M7TQvHX9U61NinPXC6Q9d1VPhO3E6sIGvqJ4YeQOn65V9ezYuIpFSlgQzCHMmLVnOV96Uv1R/Z39I4w7D3S5qoZcQT/siQwGbsZoPMGFYmqOK1da5TZWrrJWkYzc9xvzT9m3q3Wds5pmCmo4b/dIqDifWwYEcNAZ0/YLHwCN5SEZWuunkEwtU5o7TZAv3bvDDA6WxUrrHI/y9/qvvhXxsJnY8IueNhshdmWZfXKz+lJi2Dvk7DUlEQ1zZWSsozi1E+3biMPJO47jsxjoT/jmE5+GHLCgcnXXDVBeaVal99IOaTRFukiz2EMsry1s8fnwEE5XKDKRlU/dOPfsje0gc7bgE0QD/u3E4NJ99g9A=
--- a/.hgtags	Tue Oct 01 10:44:59 2013 -0700
+++ b/.hgtags	Tue Oct 01 17:00:03 2013 -0700
@@ -90,3 +90,4 @@
 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
+e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
--- a/hgext/histedit.py	Tue Oct 01 10:44:59 2013 -0700
+++ b/hgext/histedit.py	Tue Oct 01 17:00:03 2013 -0700
@@ -641,8 +641,7 @@
             # `parentctxnode` should match but no result. This means that
             # currentnode is not a descendant from parentctxnode.
             msg = _('%s is not an ancestor of working directory')
-            hint = _('update to %s or descendant and run "hg histedit '
-                     '--continue" again') % parentctx
+            hint = _('use "histedit --abort" to clear broken state')
             raise util.Abort(msg % parentctx, hint=hint)
         newchildren.pop(0)  # remove parentctxnode
     # Commit dirty working directory if necessary
--- a/hgext/rebase.py	Tue Oct 01 10:44:59 2013 -0700
+++ b/hgext/rebase.py	Tue Oct 01 17:00:03 2013 -0700
@@ -159,8 +159,19 @@
             if opts.get('tool', False):
                 ui.warn(_('tool option will be ignored\n'))
 
-            (originalwd, target, state, skipped, collapsef, keepf,
-                keepbranchesf, external, activebookmark) = restorestatus(repo)
+            try:
+                (originalwd, target, state, skipped, collapsef, keepf,
+                 keepbranchesf, external, activebookmark) = restorestatus(repo)
+            except error.RepoLookupError:
+                if abortf:
+                    clearstatus(repo)
+                    repo.ui.warn(_('rebase aborted (no revision is removed,'
+                                   ' only broken state is cleared)\n'))
+                    return 0
+                else:
+                    msg = _('cannot continue inconsistent rebase')
+                    hint = _('use "hg rebase --abort" to clear borken state')
+                    raise util.Abort(msg, hint=hint)
             if abortf:
                 return abort(repo, originalwd, target, state)
         else:
@@ -801,7 +812,13 @@
 def summaryhook(ui, repo):
     if not os.path.exists(repo.join('rebasestate')):
         return
-    state = restorestatus(repo)[2]
+    try:
+        state = restorestatus(repo)[2]
+    except error.RepoLookupError:
+        # i18n: column positioning for "hg summary"
+        msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
+        ui.write(msg)
+        return
     numrebased = len([i for i in state.itervalues() if i != -1])
     # i18n: column positioning for "hg summary"
     ui.write(_('rebase: %s, %s (rebase --continue)\n') %
--- a/i18n/pt_BR.po	Tue Oct 01 10:44:59 2013 -0700
+++ b/i18n/pt_BR.po	Tue Oct 01 17:00:03 2013 -0700
@@ -4262,6 +4262,12 @@
 msgid "no outgoing ancestors"
 msgstr "nenhum ancestral a ser enviado"
 
+msgid "there are ambiguous outgoing revisions"
+msgstr "algumas revisões a serem enviadas são ambíguas"
+
+msgid "see \"hg help histedit\" for more detail"
+msgstr "veja \"hg help histedit\" para mais detalhes"
+
 msgid "Read history edits from the specified file."
 msgstr "Lê alterações de histórico a partir do arquivo especificado."
 
@@ -4299,12 +4305,33 @@
 msgid ""
 "    With --outgoing, this edits changesets not found in the\n"
 "    destination repository. If URL of the destination is omitted, the\n"
-"    'default-push' (or 'default') path will be used.\n"
-"    "
+"    'default-push' (or 'default') path will be used."
 msgstr ""
 "    Com --outgoing, edita revisões não encontradas no repositório de\n"
 "    destino. Se a URL do destino for omitida, o caminho definido em\n"
-"    'default-push' (ou 'default') será usado.\n"
+"    'default-push' (ou 'default') será usado."
+
+msgid ""
+"    For safety, this command is aborted, also if there are ambiguous\n"
+"    outgoing revisions which may confuse users: for example, there are\n"
+"    multiple branches containing outgoing revisions."
+msgstr ""
+"    Por segurança, este comando também é abortado se o conjunto de\n"
+"    revisões a serem enviadas for ambíguo, pois isso pode confundir\n"
+"    os usuários: por exemplo, se vários ramos possuírem revisões a\n"
+"    serem enviadas."
+
+msgid ""
+"    Use \"min(outgoing() and ::.)\" or similar revset specification\n"
+"    instead of --outgoing to specify edit target revision exactly in\n"
+"    such ambiguous situation. See :hg:`help revsets` for detail about\n"
+"    selecting revisions.\n"
+"    "
+msgstr ""
+"    Ao invés de --outgoing, use \"min(outgoing() and ::.)\" ou outro\n"
+"    revset semelhante para especificar com exatidão as revisões a serem\n"
+"    editadas nessas situações.Veja :hg:`help revsets` para detalhes sobre\n"
+"    seleção de revisões.\n"
 "    "
 
 msgid "source has mq patches applied"
--- a/mercurial/localrepo.py	Tue Oct 01 10:44:59 2013 -0700
+++ b/mercurial/localrepo.py	Tue Oct 01 17:00:03 2013 -0700
@@ -39,9 +39,10 @@
     """propertycache that apply to unfiltered repo only"""
 
     def __get__(self, repo, type=None):
-        if hasunfilteredcache(repo, self.name):
-            return getattr(repo.unfiltered(), self.name)
-        return super(unfilteredpropertycache, self).__get__(repo.unfiltered())
+        unfi = repo.unfiltered()
+        if unfi is repo:
+            return super(unfilteredpropertycache, self).__get__(unfi)
+        return getattr(unfi, self.name)
 
 class filteredpropertycache(propertycache):
     """propertycache that must take filtering in account"""
--- a/mercurial/util.py	Tue Oct 01 10:44:59 2013 -0700
+++ b/mercurial/util.py	Tue Oct 01 17:00:03 2013 -0700
@@ -283,7 +283,8 @@
         return result
 
     def cachevalue(self, obj, value):
-        setattr(obj, self.name, value)
+        # __dict__ assigment required to bypass __setattr__ (eg: repoview)
+        obj.__dict__[self.name] = value
 
 def pipefilter(s, cmd):
     '''filter string S through command CMD, returning its output'''
--- a/tests/test-histedit-arguments.t	Tue Oct 01 10:44:59 2013 -0700
+++ b/tests/test-histedit-arguments.t	Tue Oct 01 17:00:03 2013 -0700
@@ -70,6 +70,35 @@
   [255]
   $ hg up --quiet
 
+Run on a revision not descendants of the initial parent
+--------------------------------------------------------------------
+
+Test the message shown for inconsistent histedit state, which may be
+created (and forgotten) by Mercurial earlier than 2.7. This emulates
+Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
+temporarily.
+
+  $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
+  > edit 08d98a8350f3 4 five
+  > EOF
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  reverting alpha
+  Make changes as needed, you may commit or record as needed now.
+  When you are finished, run hg histedit --continue to resume.
+  [1]
+
+  $ mv .hg/histedit-state .hg/histedit-state.back
+  $ hg update --quiet --clean 2
+  $ mv .hg/histedit-state.back .hg/histedit-state
+
+  $ hg histedit --continue
+  abort: c8e68270e35a is not an ancestor of working directory
+  (use "histedit --abort" to clear broken state)
+  [255]
+
+  $ hg histedit --abort
+  $ hg update --quiet --clean
+
 Test that missing revisions are detected
 ---------------------------------------
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-propertycache.py	Tue Oct 01 17:00:03 2013 -0700
@@ -0,0 +1,179 @@
+"""test behavior of propertycache and unfiltered propertycache
+
+The repoview overlay is quite complexe. We test the behavior of
+property cache of both localrepo and repoview to prevent
+regression."""
+
+import os, subprocess
+import mercurial.localrepo
+import mercurial.repoview
+import mercurial.util
+import mercurial.hg
+import mercurial.ui as uimod
+
+
+# create some special property cache that trace they call
+
+calllog = []
+@mercurial.util.propertycache
+def testcachedfoobar(repo):
+    name = repo.filtername
+    if name is None:
+        name = ''
+    val = len(name)
+    calllog.append(val)
+    return val
+
+unficalllog = []
+@mercurial.localrepo.unfilteredpropertycache
+def testcachedunfifoobar(repo):
+    name = repo.filtername
+    if name is None:
+        name = ''
+    val = 100 + len(name)
+    unficalllog.append(val)
+    return val
+
+#plug them on repo
+mercurial.localrepo.localrepository.testcachedfoobar = testcachedfoobar
+mercurial.localrepo.localrepository.testcachedunfifoobar = testcachedunfifoobar
+
+
+# create an empty repo. and instanciate it. It is important to run
+# those test on the real object to detect regression.
+repopath = os.path.join(os.environ['TESTTMP'], 'repo')
+subprocess.check_call(['hg', 'init', repopath])
+ui = uimod.ui()
+repo = mercurial.hg.repository(ui, path=repopath).unfiltered()
+
+
+print ''
+print '=== property cache ==='
+print ''
+print 'calllog:', calllog
+print 'cached value (unfiltered):',
+print vars(repo).get('testcachedfoobar', 'NOCACHE')
+
+print ''
+print '= first access on unfiltered, should do a call'
+print 'access:', repo.testcachedfoobar
+print 'calllog:', calllog
+print 'cached value (unfiltered):',
+print vars(repo).get('testcachedfoobar', 'NOCACHE')
+
+print ''
+print '= second access on unfiltered, should not do call'
+print 'access', repo.testcachedfoobar
+print 'calllog:', calllog
+print 'cached value (unfiltered):',
+print vars(repo).get('testcachedfoobar', 'NOCACHE')
+
+print ''
+print '= first access on "visible" view, should do a call'
+visibleview = repo.filtered('visible')
+print 'cached value ("visible" view):',
+print vars(visibleview).get('testcachedfoobar', 'NOCACHE')
+print 'access:', visibleview.testcachedfoobar
+print 'calllog:', calllog
+print 'cached value (unfiltered):',
+print vars(repo).get('testcachedfoobar', 'NOCACHE')
+print 'cached value ("visible" view):',
+print vars(visibleview).get('testcachedfoobar', 'NOCACHE')
+
+print ''
+print '= second access on "visible view", should not do call'
+print 'access:', visibleview.testcachedfoobar
+print 'calllog:', calllog
+print 'cached value (unfiltered):',
+print vars(repo).get('testcachedfoobar', 'NOCACHE')
+print 'cached value ("visible" view):',
+print vars(visibleview).get('testcachedfoobar', 'NOCACHE')
+
+print ''
+print '= no effect on other view'
+immutableview = repo.filtered('immutable')
+print 'cached value ("immutable" view):',
+print vars(immutableview).get('testcachedfoobar', 'NOCACHE')
+print 'access:', immutableview.testcachedfoobar
+print 'calllog:', calllog
+print 'cached value (unfiltered):',
+print vars(repo).get('testcachedfoobar', 'NOCACHE')
+print 'cached value ("visible" view):',
+print vars(visibleview).get('testcachedfoobar', 'NOCACHE')
+print 'cached value ("immutable" view):',
+print vars(immutableview).get('testcachedfoobar', 'NOCACHE')
+
+# unfiltered property cache test
+print ''
+print ''
+print '=== unfiltered property cache ==='
+print ''
+print 'unficalllog:', unficalllog
+print 'cached value (unfiltered):      ',
+print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("visible" view):  ',
+print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("immutable" view):',
+print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
+
+print ''
+print '= first access on unfiltered, should do a call'
+print 'access (unfiltered):', repo.testcachedunfifoobar
+print 'unficalllog:', unficalllog
+print 'cached value (unfiltered):      ',
+print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
+
+print ''
+print '= second access on unfiltered, should not do call'
+print 'access (unfiltered):', repo.testcachedunfifoobar
+print 'unficalllog:', unficalllog
+print 'cached value (unfiltered):      ',
+print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
+
+print ''
+print '= access on view should use the unfiltered cache'
+print 'access (unfiltered):      ', repo.testcachedunfifoobar
+print 'access ("visible" view):  ', visibleview.testcachedunfifoobar
+print 'access ("immutable" view):', immutableview.testcachedunfifoobar
+print 'unficalllog:', unficalllog
+print 'cached value (unfiltered):      ',
+print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("visible" view):  ',
+print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("immutable" view):',
+print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
+
+print ''
+print '= even if we clear the unfiltered cache'
+del repo.__dict__['testcachedunfifoobar']
+print 'cached value (unfiltered):      ',
+print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("visible" view):  ',
+print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("immutable" view):',
+print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
+print 'unficalllog:', unficalllog
+print 'access ("visible" view):  ', visibleview.testcachedunfifoobar
+print 'unficalllog:', unficalllog
+print 'cached value (unfiltered):      ',
+print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("visible" view):  ',
+print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("immutable" view):',
+print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
+print 'access ("immutable" view):', immutableview.testcachedunfifoobar
+print 'unficalllog:', unficalllog
+print 'cached value (unfiltered):      ',
+print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("visible" view):  ',
+print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("immutable" view):',
+print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
+print 'access (unfiltered):      ', repo.testcachedunfifoobar
+print 'unficalllog:', unficalllog
+print 'cached value (unfiltered):      ',
+print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("visible" view):  ',
+print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
+print 'cached value ("immutable" view):',
+print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-propertycache.py.out	Tue Oct 01 17:00:03 2013 -0700
@@ -0,0 +1,84 @@
+
+=== property cache ===
+
+calllog: []
+cached value (unfiltered): NOCACHE
+
+= first access on unfiltered, should do a call
+access: 0
+calllog: [0]
+cached value (unfiltered): 0
+
+= second access on unfiltered, should not do call
+access 0
+calllog: [0]
+cached value (unfiltered): 0
+
+= first access on "visible" view, should do a call
+cached value ("visible" view): NOCACHE
+access: 7
+calllog: [0, 7]
+cached value (unfiltered): 0
+cached value ("visible" view): 7
+
+= second access on "visible view", should not do call
+access: 7
+calllog: [0, 7]
+cached value (unfiltered): 0
+cached value ("visible" view): 7
+
+= no effect on other view
+cached value ("immutable" view): NOCACHE
+access: 9
+calllog: [0, 7, 9]
+cached value (unfiltered): 0
+cached value ("visible" view): 7
+cached value ("immutable" view): 9
+
+
+=== unfiltered property cache ===
+
+unficalllog: []
+cached value (unfiltered):       NOCACHE
+cached value ("visible" view):   NOCACHE
+cached value ("immutable" view): NOCACHE
+
+= first access on unfiltered, should do a call
+access (unfiltered): 100
+unficalllog: [100]
+cached value (unfiltered):       100
+
+= second access on unfiltered, should not do call
+access (unfiltered): 100
+unficalllog: [100]
+cached value (unfiltered):       100
+
+= access on view should use the unfiltered cache
+access (unfiltered):       100
+access ("visible" view):   100
+access ("immutable" view): 100
+unficalllog: [100]
+cached value (unfiltered):       100
+cached value ("visible" view):   NOCACHE
+cached value ("immutable" view): NOCACHE
+
+= even if we clear the unfiltered cache
+cached value (unfiltered):       NOCACHE
+cached value ("visible" view):   NOCACHE
+cached value ("immutable" view): NOCACHE
+unficalllog: [100]
+access ("visible" view):   100
+unficalllog: [100, 100]
+cached value (unfiltered):       100
+cached value ("visible" view):   NOCACHE
+cached value ("immutable" view): NOCACHE
+access ("immutable" view): 100
+unficalllog: [100, 100]
+cached value (unfiltered):       100
+cached value ("visible" view):   NOCACHE
+cached value ("immutable" view): NOCACHE
+access (unfiltered):       100
+unficalllog: [100, 100]
+cached value (unfiltered):       100
+cached value ("visible" view):   NOCACHE
+cached value ("immutable" view): NOCACHE
--- a/tests/test-rebase-abort.t	Tue Oct 01 10:44:59 2013 -0700
+++ b/tests/test-rebase-abort.t	Tue Oct 01 17:00:03 2013 -0700
@@ -75,6 +75,31 @@
   |
   o  0:draft 'C1'
   
+Test safety for inconsistent rebase state, which may be created (and
+forgotten) by Mercurial earlier than 2.7. This emulates Mercurial
+earlier than 2.7 by renaming ".hg/rebasestate" temporarily.
+
+  $ hg rebase -s 3 -d 2
+  merging common
+  warning: conflicts during merge.
+  merging common incomplete! (edit conflicts, then use 'hg resolve --mark')
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+
+  $ mv .hg/rebasestate .hg/rebasestate.back
+  $ hg update --quiet --clean 2
+  $ hg --config extensions.mq= strip --quiet "destination()"
+  $ mv .hg/rebasestate.back .hg/rebasestate
+
+  $ hg rebase --continue
+  abort: cannot continue inconsistent rebase
+  (use "hg rebase --abort" to clear borken state)
+  [255]
+  $ hg summary | grep '^rebase: '
+  rebase: (use "hg rebase --abort" to clear broken state)
+  $ hg rebase --abort
+  rebase aborted (no revision is removed, only broken state is cleared)
+
   $ cd ..