# HG changeset patch # User Anton Shestakov # Date 1712859026 10800 # Node ID 80d5e11713f593958fdd93f02fa42de5c78057cc # Parent 0ac82f1858f7c0eb7fef24181b4eb13783cdcede# Parent 890a1b249cf7893c32ba9c30923f1d817d96fbef test-compat: merge mercurial-5.2 into mercurial-5.1 diff -r 0ac82f1858f7 -r 80d5e11713f5 .gitlab-ci.yml --- a/.gitlab-ci.yml Fri Mar 01 16:41:12 2024 -0300 +++ b/.gitlab-ci.yml Thu Apr 11 15:10:26 2024 -0300 @@ -27,14 +27,14 @@ - (cd tests; ls -1 test-check-*.t > /tmp/check-tests.txt) script: - *prepare_hg - - ("$PYTHON" --version) - - (cd tests; set -x; HGMODULEPOLICY="$TEST_HGMODULEPOLICY" "$PYTHON" /ci/repos/mercurial/tests/run-tests.py --color=always $RUNTEST_ARGS) + - ($PYTHON --version) + - (cd tests; set -x; HGMODULEPOLICY="$TEST_HGMODULEPOLICY" $PYTHON /ci/repos/mercurial/tests/run-tests.py --color=always $RUNTEST_ARGS) checks-py2: <<: *runtests variables: PY: py2 - PYTHON: python2 + PYTHON: prlimit --nofile=1024:1024 python2 RUNTEST_ARGS: "--test-list /tmp/check-tests.txt" checks-py3: @@ -46,7 +46,7 @@ <<: *runtests variables: PY: py2 - PYTHON: python2 + PYTHON: prlimit --nofile=1024:1024 python2 RUNTEST_ARGS: "--blacklist /tmp/check-tests.txt" TEST_HGMODULEPOLICY: "c" @@ -54,7 +54,7 @@ <<: *runtests variables: PY: py2 - PYTHON: python2 + PYTHON: prlimit --nofile=1024:1024 python2 RUNTEST_ARGS: "--pure --blacklist /tmp/check-tests.txt" TEST_HGMODULEPOLICY: "py" diff -r 0ac82f1858f7 -r 80d5e11713f5 .hgtags --- a/.hgtags Fri Mar 01 16:41:12 2024 -0300 +++ b/.hgtags Thu Apr 11 15:10:26 2024 -0300 @@ -108,3 +108,4 @@ b9355f6f3093c0cf9698215f05059321880f28da 11.0.2 a625eb5acea4d682becd21759170306ab769afb2 11.1.0 369e248b6312cc3b0777033a4632f2c9e18a0897 11.1.1 +c31c6638381080bc5905fad37545610fde3b98bc 11.1.2 diff -r 0ac82f1858f7 -r 80d5e11713f5 CHANGELOG --- a/CHANGELOG Fri Mar 01 16:41:12 2024 -0300 +++ b/CHANGELOG Thu Apr 11 15:10:26 2024 -0300 @@ -1,7 +1,23 @@ Changelog ========= -11.1.2 - in progress +11.1.3 - in progress +-------------------- + +topic (1.1.3) + + * topic namespaces: add hg debug-default-topic-namespace command that can + list changesets with problematic topic namespaces (i.e. "none" and + "default") and rewrite them + + * topic namespaces: new experimental.tns-reject-push config to make servers + reject pushes that contain changesets with any topic namespace in commit + extras + + * topic namespaces: slightly change .hg/topic-namespace cleanup code to be + executed on acquiring a wlock instead of on reading .hg/topic-namespace + +11.1.2 -- 2024-03-03 -------------------- * compatibility with Mercurial 6.7 diff -r 0ac82f1858f7 -r 80d5e11713f5 debian/changelog --- a/debian/changelog Fri Mar 01 16:41:12 2024 -0300 +++ b/debian/changelog Thu Apr 11 15:10:26 2024 -0300 @@ -1,3 +1,9 @@ +mercurial-evolve (11.1.2-1) unstable; urgency=medium + + * new upstream release + + -- Anton Shestakov Sun, 03 Mar 2024 15:09:28 -0300 + mercurial-evolve (11.1.1-1) unstable; urgency=medium * new upstream release diff -r 0ac82f1858f7 -r 80d5e11713f5 hgext3rd/evolve/metadata.py --- a/hgext3rd/evolve/metadata.py Fri Mar 01 16:41:12 2024 -0300 +++ b/hgext3rd/evolve/metadata.py Thu Apr 11 15:10:26 2024 -0300 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -__version__ = b'11.1.2.dev0' +__version__ = b'11.1.3.dev0' testedwith = b'4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6.0 6.1 6.2 6.3 6.4 6.5 6.6 6.7' minimumhgversion = b'4.9' buglink = b'https://bz.mercurial-scm.org/' diff -r 0ac82f1858f7 -r 80d5e11713f5 hgext3rd/topic/__init__.py --- a/hgext3rd/topic/__init__.py Fri Mar 01 16:41:12 2024 -0300 +++ b/hgext3rd/topic/__init__.py Thu Apr 11 15:10:26 2024 -0300 @@ -179,6 +179,7 @@ hg, localrepo, lock as lockmod, + logcmdutil, merge, namespaces, node, @@ -237,7 +238,7 @@ b'log.topic': b'green_background', } -__version__ = b'1.1.2.dev0' +__version__ = b'1.1.3.dev0' testedwith = b'4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6.0 6.1 6.2 6.3 6.4 6.5 6.6 6.7' minimumhgversion = b'4.9' @@ -295,6 +296,9 @@ configitem(b'experimental', b'tns-default-pull-namespaces', default=configitems.dynamicdefault, ) +configitem(b'experimental', b'tns-reject-push', + default=False, +) configitem(b'experimental', b'topic-mode.server', default=configitems.dynamicdefault, ) @@ -715,31 +719,23 @@ self._topic_namespaces = namespaces return namespaces - @property - def currenttns(self): - tns = self.vfs.tryread(b'topic-namespace') + def wlock(self, wait=True): + wlock = super(topicrepo, self).wlock(wait=wait) # we should definitely drop this at some point, but it depends on # our own release schedule, not core's, so here's hg 1.0 # hg <= 1.0 (cfa08c88a5c4) - if tns == b'none': + if wlock is not None and wlock.held: try: - with self.wlock(wait=False): - try: - # we make sure the file contains what we expect - if self.vfs.read(b'topic-namespace') == b'none': - repo.vfs.unlinkpath(b'topic-namespace') - except IOError as err: - if err.errno != errno.ENOENT: - raise - except error.LockError: - # if we cannot acquire wdir lock, then we shouldn't do - # anything at all, since it'd be unsafe to modify wdir - pass - elif tns == b'': - # technically, if user creates an empty file, it should be - # handled differently than non-existing file, but the - # distinction is probably not that important - tns = b'none' + if self.vfs.read(b'topic-namespace') == b'none': + repo.vfs.unlinkpath(b'topic-namespace') + except IOError as err: + if err.errno != errno.ENOENT: + raise + return wlock + + @property + def currenttns(self): + tns = self.vfs.tryread(b'topic-namespace') or b'none' return encoding.tolocal(tns) @util.propertycache @@ -921,6 +917,25 @@ else: tr.addvalidator(b'000-reject-publish', _validate_publish) + if self.ui.configbool(b'experimental', b'tns-reject-push'): + if util.safehasattr(tr, '_validator'): + # hg <= 5.3 (36f08ae87ef6) + origvalidator_publish = tr._validator + + def _validate_csets_with_tns(tr2): + repo = reporef() + flow.reject_csets_with_tns(repo, tr2) + + def validator(tr2): + _validate_csets_with_tns(tr2) + return origvalidator_publish(tr2) + + if util.safehasattr(tr, '_validator'): + # hg <= 5.3 (36f08ae87ef6) + tr._validator = validator + else: + tr.addvalidator(b'000-reject-csets-with-tns', _validate_csets_with_tns) + if util.safehasattr(tr, '_validator'): # hg <= 5.3 (36f08ae87ef6) origvalidator_affected_tns = tr._validator @@ -1911,6 +1926,73 @@ for tns in repo.topic_namespaces: ui.write(b'%s\n' % (tns,)) +@command(b'debug-default-topic-namespace', [ + (b'', b'none', True, b'find changesets with topic-namespace=none'), + (b'', b'default', False, b'find changesets with topic-namespace=default'), + (b'', b'clear', False, b'remove topic namespace from commit extras'), + ] + commands.formatteropts) +def debugdefaulttns(ui, repo, **opts): + """list changesets with the default topic namespace in commit extras""" + opts = pycompat.byteskwargs(opts) + condition = [] + if opts[b'none']: + condition += [b'extra("topic-namespace", "none")'] + if opts[b'default']: + condition += [b'extra("topic-namespace", "default")'] + if not condition: + condition = [b'none()'] + revs = repo.revs(b'not public() and not obsolete() and (%lr)', condition) + if opts[b'clear']: + with repo.wlock(), repo.lock(), repo.transaction(b'debug-default-topic-namespace'): + successors = {} + for rev in revs: + _clear_tns_extras(ui, repo, rev, successors) + scmutil.cleanupnodes(repo, successors, b'debug-default-topic-namespace') + return + displayer = logcmdutil.changesetdisplayer(ui, repo, opts) + logcmdutil.displayrevs(ui, repo, revs, displayer, None) + +def _clear_tns_extras(ui, repo, rev, successors): + ctx = repo[rev] + + if len(ctx.parents()) > 1: + # ctx.files() isn't reliable for merges, so fall back to the + # slower repo.status() method + st = ctx.p1().status(ctx) + files = set(st.modified) | set(st.added) | set(st.removed) + else: + files = set(ctx.files()) + + def filectxfn(repo, unused, path): + try: + return ctx[path] + except error.ManifestLookupError: + return None + + extra = ctx.extra().copy() + del extra[b'topic-namespace'] + + p1 = ctx.p1().node() + p2 = ctx.p2().node() + if p1 in successors: + p1 = successors[p1][0] + if p2 in successors: + p2 = successors[p2][0] + mc = context.memctx(repo, + (p1, p2), + ctx.description(), + files, + filectxfn, + user=ctx.user(), + date=ctx.date(), + extra=extra) + + overrides = {(b'phases', b'new-commit'): ctx.phase()} + with repo.ui.configoverride(overrides, b'debug-default-topic-namespace'): + newnode = repo.commitctx(mc) + + successors[ctx.node()] = (newnode,) + @command(b'debug-parse-fqbn', commands.formatteropts, _(b'FQBN'), optionalrepo=True) def debugparsefqbn(ui, repo, fqbn, **opts): """parse branch//namespace/topic string into its components""" diff -r 0ac82f1858f7 -r 80d5e11713f5 hgext3rd/topic/flow.py --- a/hgext3rd/topic/flow.py Fri Mar 01 16:41:12 2024 -0300 +++ b/hgext3rd/topic/flow.py Thu Apr 11 15:10:26 2024 -0300 @@ -47,7 +47,8 @@ untopiced = repo.revs(b'not public() and (%n:) - hidden() - topic()', startnode) if untopiced: num = len(untopiced) - fnode = repo[untopiced.first()].hex()[:10] + cl = repo.changelog + fnode = node.short(cl.node(untopiced.first())) if num == 1: msg = _(b"%s") % fnode else: @@ -82,6 +83,29 @@ msg += b' and %d others' % (len(published) - 1) raise error.Abort(msg) +def reject_csets_with_tns(repo, tr): + """Reject the push if there are changesets with any topic namespace""" + if b'node' not in tr.hookargs: # no new revs + return + + reject = repo.ui.config(b'experimental', b'tns-reject-push') + if not reject: + return + + startnode = node.bin(tr.hookargs[b'node']) + repo = repo.unfiltered() + with_tns = repo.revs(b'not public() and extra("topic-namespace") and (%n:) - hidden()', startnode) + if with_tns: + num = len(with_tns) + cl = repo.changelog + fnode = node.short(cl.node(with_tns.first())) + if num == 1: + msg = _(b"%s") % fnode + else: + msg = _(b"%s and %d more") % (fnode, num - 1) + fullmsg = _(b"rejecting draft changesets with topic namespace: %s") + raise error.Abort(fullmsg % msg) + def wrappush(orig, repo, remote, *args, **kwargs): """interpret the --publish flag and pass it to the push operation""" newargs = kwargs.copy() diff -r 0ac82f1858f7 -r 80d5e11713f5 tests/test-namespaces-reject.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-namespaces-reject.t Thu Apr 11 15:10:26 2024 -0300 @@ -0,0 +1,81 @@ +Rejecting changesets with any topic namespaces during push + + $ . "$TESTDIR/testlib/common.sh" + + $ cat >> $HGRCPATH << EOF + > [extensions] + > topic = + > [phases] + > publish = no + > [devel] + > tns-report-transactions = push + > [ui] + > logtemplate = "{rev}: {desc} {fqbn} ({phase})\n" + > EOF + + $ hg init orig + $ hg clone orig clone -q + + $ cd clone + +changesets without topic namespace are freely exchanged + + $ echo apple > a + $ hg debug-topic-namespace --clear + $ hg topic apple + marked working directory as topic: apple + $ hg ci -qAm apple + + $ hg log -r . -T '{rev}: {join(extras, " ")}\n' + 0: branch=default topic=apple + + $ hg push + pushing to * (glob) + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + +changesets with topic namespaces are rejected when server configuration disallows + + $ cat >> ../orig/.hg/hgrc << EOF + > [experimental] + > tns-reject-push = yes + > EOF + + $ echo banana > b + $ hg debug-topic-namespace bob + marked working directory as topic namespace: bob + $ hg topic banana + $ hg ci -qAm 'banana' + + $ hg push + pushing to $TESTTMP/orig + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + transaction abort! + rollback completed + abort: rejecting draft changesets with topic namespace: ed9751f04a18 + [255] + +changesets with topic namespaces are only exchanged if server configuration allows + + $ cat >> ../orig/.hg/hgrc << EOF + > [experimental] + > tns-reject-push = no + > EOF + + $ hg push + pushing to $TESTTMP/orig + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + topic namespaces affected: bob + + $ cd .. diff -r 0ac82f1858f7 -r 80d5e11713f5 tests/test-namespaces.t --- a/tests/test-namespaces.t Fri Mar 01 16:41:12 2024 -0300 +++ b/tests/test-namespaces.t Thu Apr 11 15:10:26 2024 -0300 @@ -286,6 +286,58 @@ abort: topic namespace 'nonsense' does not exist! [255] +Debug command related to the default/empty topic namespace + + $ hg debug-topic-namespace --clear + + $ echo none > none + $ hg ci -qAm 'tns=none' \ + > --config extensions.topic=! \ + > --config extensions.commitextras= \ + > --extra topic-namespace=none + + + $ echo default > default + $ hg ci -qAm 'tns=default' \ + > --config extensions.topic=! \ + > --config extensions.commitextras= \ + > --extra topic-namespace=default + + $ hg debug-default-topic-namespace \ + > --debug \ + > | grep extra + extra: branch=stable + extra: topic-namespace=none + + $ hg debug-default-topic-namespace \ + > --no-none \ + > --default \ + > --debug \ + > | grep extra + extra: branch=stable + extra: topic-namespace=default + + $ hg debug-default-topic-namespace \ + > --default \ + > -T '{rev}:{node|short} {join(extras, " ")}\n' + 4:29a2d0acd473 branch=stable topic-namespace=none + 5:16d6061fce0c branch=stable topic-namespace=default + + $ hg debug-default-topic-namespace --none --default --clear + + $ hg debug-default-topic-namespace --none --default + + $ hg evolve --config extensions.evolve= --list + + $ hg evolve --config extensions.evolve= --any + update:[7] tns=default + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + working directory is now at 38c9ea9d27a7 + + $ hg debug-default-topic-namespace --none --default + + $ hg verify --quiet + Parsing $ hg debug-parse-fqbn foo/bar//user26/feature -T '[{branch}] <{topic_namespace}> ({topic})\n' diff -r 0ac82f1858f7 -r 80d5e11713f5 tests/test-topic-flow-reject-untopiced.t --- a/tests/test-topic-flow-reject-untopiced.t Fri Mar 01 16:41:12 2024 -0300 +++ b/tests/test-topic-flow-reject-untopiced.t Thu Apr 11 15:10:26 2024 -0300 @@ -76,7 +76,7 @@ added 1 changesets with 1 changes to 1 files transaction abort! rollback completed - abort: rejecting draft changesets: 4e8b0e0237 + abort: rejecting draft changesets: 4e8b0e0237c6 [255] $ hg push ../server -f @@ -88,7 +88,7 @@ added 1 changesets with 1 changes to 1 files transaction abort! rollback completed - abort: rejecting draft changesets: 4e8b0e0237 + abort: rejecting draft changesets: 4e8b0e0237c6 [255] Grow the stack with more changesets having topic @@ -124,7 +124,7 @@ added 4 changesets with 4 changes to 4 files transaction abort! rollback completed - abort: rejecting draft changesets: 4e8b0e0237 + abort: rejecting draft changesets: 4e8b0e0237c6 [255] Testing case when both experimental.topic-mode.server and @@ -142,7 +142,7 @@ added 4 changesets with 4 changes to 4 files transaction abort! rollback completed - abort: rejecting draft changesets: 4e8b0e0237 + abort: rejecting draft changesets: 4e8b0e0237c6 [255] Turning the changeset public and testing push