diff hgext3rd/topic/__init__.py @ 6752:44e41905b289 mercurial-6.6

test-compat: merge stable into mercurial-6.6
author Anton Shestakov <av6@dwimlabs.net>
date Thu, 11 Apr 2024 01:58:03 -0300
parents 107c5af631a7
children bdf99d434b06 2d2da4f7742a
line wrap: on
line diff
--- a/hgext3rd/topic/__init__.py	Thu Feb 29 14:18:08 2024 -0300
+++ b/hgext3rd/topic/__init__.py	Thu Apr 11 01:58:03 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"""