# HG changeset patch # User Matt Mackall # Date 2013-10-02 00:00:03 # Node ID 57479e0d203d0006b09bf386f538424ca74d8509 # Parent 5c0dc243fe5b921589688633a6d2fbe4756d5d1c # Parent 4d513f96a565639c0879086b68cf72a1e01e596c merge with stable diff --git a/.hgsigs b/.hgsigs --- a/.hgsigs +++ b/.hgsigs @@ -77,3 +77,4 @@ 009794acc6e37a650f0fae37872e733382ac1c0c 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= diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -90,3 +90,4 @@ 009794acc6e37a650f0fae37872e733382ac1c0c f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7 335a558f81dc73afeab4d7be63617392b130117f 2.7.1 +e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2 diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -641,8 +641,7 @@ def bootstrapcontinue(ui, repo, parentct # `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 diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -159,8 +159,19 @@ def rebase(ui, repo, **opts): 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 pullrebase(orig, ui, repo, *args, ** 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') % diff --git a/i18n/pt_BR.po b/i18n/pt_BR.po --- a/i18n/pt_BR.po +++ b/i18n/pt_BR.po @@ -4262,6 +4262,12 @@ msgstr "comparando com %s\n" 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 @@ msgstr "" 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" diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -39,9 +39,10 @@ class unfilteredpropertycache(propertyca """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""" diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -283,7 +283,8 @@ class propertycache(object): 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''' diff --git a/tests/test-histedit-arguments.t b/tests/test-histedit-arguments.t --- a/tests/test-histedit-arguments.t +++ b/tests/test-histedit-arguments.t @@ -70,6 +70,35 @@ Run on a revision not ancestors of the c [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 --------------------------------------- diff --git a/tests/test-propertycache.py b/tests/test-propertycache.py new file mode 100644 --- /dev/null +++ b/tests/test-propertycache.py @@ -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') diff --git a/tests/test-propertycache.py.out b/tests/test-propertycache.py.out new file mode 100644 --- /dev/null +++ b/tests/test-propertycache.py.out @@ -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 diff --git a/tests/test-rebase-abort.t b/tests/test-rebase-abort.t --- a/tests/test-rebase-abort.t +++ b/tests/test-rebase-abort.t @@ -75,6 +75,31 @@ Abort: | 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 ..