branching: merge stable into default
authorRaphaël Gomès <rgomes@octobus.net>
Fri, 15 Mar 2024 10:52:51 +0100
changeset 51508 0239ebdd0740
parent 51496 79a7616a82b8 (current diff)
parent 51507 4976aacae424 (diff)
child 51515 16d93adddce7
branching: merge stable into default
mercurial/branchmap.py
mercurial/localrepo.py
tests/test-branches.t
--- a/.hgsigs	Sun Mar 10 03:29:12 2024 +0100
+++ b/.hgsigs	Fri Mar 15 10:52:51 2024 +0100
@@ -257,3 +257,4 @@
 136902b3a95db38854ebaf5198a627641065c2ea 0 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
+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
--- a/.hgtags	Sun Mar 10 03:29:12 2024 +0100
+++ b/.hgtags	Fri Mar 15 10:52:51 2024 +0100
@@ -273,3 +273,4 @@
 136902b3a95db38854ebaf5198a627641065c2ea 6.6.2
 3fd1efb3ad124e6686c0fb66e6943cd8aeea5681 6.6.3
 d1d48d18db37106b801ef6cb90955536458e7ffc 6.7rc0
+c9ceb4f6025690167bdb245e530de6bac8baae95 6.7
--- a/hgext/chainsaw.py	Sun Mar 10 03:29:12 2024 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-# chainsaw.py
-#
-# Copyright 2022 Georges Racinet <georges.racinet@octobus.net>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-"""chainsaw is a collection of single-minded and dangerous tools. (EXPERIMENTAL)
-
-  "Don't use a chainsaw to cut your food!"
-
-The chainsaw extension provides commands that are so much geared towards a
-specific use case in a specific context or environment that they are totally
-inappropriate and **really dangerous** in other contexts.
-
-The help text of each command explicitly summarizes its context of application
-and the wanted end result.
-
-It is recommended to run these commands with the ``HGPLAIN`` environment
-variable (see :hg:`help scripting`).
-"""
-
-import shutil
-
-from mercurial.i18n import _
-from mercurial import (
-    cmdutil,
-    commands,
-    error,
-    localrepo,
-    registrar,
-)
-from mercurial.utils import (
-    urlutil,
-)
-
-cmdtable = {}
-command = registrar.command(cmdtable)
-# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
-# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
-# be specifying the version(s) of Mercurial they are tested with, or
-# leave the attribute unspecified.
-testedwith = b'ships-with-hg-core'
-
-
-@command(
-    b'admin::chainsaw-update',
-    [
-        (
-            b'',
-            b'purge-unknown',
-            True,
-            _(
-                b'Remove unversioned files before update. Disabling this can '
-                b'in some cases interfere with the update.'
-                b'See also :hg:`purge`.'
-            ),
-        ),
-        (
-            b'',
-            b'purge-ignored',
-            True,
-            _(
-                b'Remove ignored files before update. Disable this for '
-                b'instance to reuse previous compiler object files. '
-                b'See also :hg:`purge`.'
-            ),
-        ),
-        (
-            b'',
-            b'rev',
-            b'',
-            _(b'revision to update to'),
-        ),
-        (
-            b'',
-            b'source',
-            b'',
-            _(b'repository to clone from'),
-        ),
-        (
-            b'',
-            b'dest',
-            b'',
-            _(b'repository to update to REV (possibly cloning)'),
-        ),
-        (
-            b'',
-            b'initial-clone-minimal',
-            False,
-            _(
-                b'Pull only the prescribed revision upon initial cloning. '
-                b'This has the side effect of ignoring clone-bundles, '
-                b'which if often slower on the client side and stressful '
-                b'to the server than applying available clone bundles.'
-            ),
-        ),
-    ],
-    _(
-        b'hg admin::chainsaw-update [OPTION] --rev REV --source SOURCE --dest DEST'
-    ),
-    helpbasic=True,
-    norepo=True,
-)
-def update(ui, **opts):
-    """pull and update to a given revision, no matter what, (EXPERIMENTAL)
-
-    Context of application: *some* Continuous Integration (CI) systems,
-    packaging or deployment tools.
-
-    Wanted end result: local repository at the given REPO_PATH, having the
-    latest changes to the given revision and with a clean working directory
-    updated at the given revision.
-
-    chainsaw-update pulls from one source, then updates the working directory
-    to the given revision, overcoming anything that would stand in the way.
-
-    By default, it will:
-
-    - clone if the local repo does not exist yet, **removing any directory
-      at the given path** that would not be a Mercurial repository.
-      The initial clone is full by default, so that clonebundles can be
-      applied. Use the --initial-clone-minimal flag to avoid this.
-    - break locks if needed, leading to possible corruption if there
-      is a concurrent write access.
-    - perform recovery actions if needed
-    - revert any local modification.
-    - purge unknown and ignored files.
-    - go as far as to reclone if everything else failed (not implemented yet).
-
-    DO NOT use it for anything else than performing a series
-    of unattended updates, with full exclusive repository access each time
-    and without any other local work than running build scripts.
-    In case the local repository is a share (see :hg:`help share`), exclusive
-    write access to the share source is also mandatory.
-
-    It is recommended to run these commands with the ``HGPLAIN`` environment
-    variable (see :hg:`scripting`).
-
-    Motivation: in Continuous Integration and Delivery systems (CI/CD), the
-    occasional remnant or bogus lock are common sources of waste of time (both
-    working time and calendar time). CI/CD scripts tend to grow with counter-
-    measures, often done in urgency. Also, whilst it is neat to keep
-    repositories from one job to the next (especially with large
-    repositories), an exceptional recloning is better than missing a release
-    deadline.
-    """
-    rev = opts['rev']
-    source = opts['source']
-    repo_path = opts['dest']
-    if not rev:
-        raise error.InputError(_(b'specify a target revision with --rev'))
-    if not source:
-        raise error.InputError(_(b'specify a pull path with --source'))
-    if not repo_path:
-        raise error.InputError(_(b'specify a repo path with --dest'))
-    repo_path = urlutil.urllocalpath(repo_path)
-
-    try:
-        repo = localrepo.instance(ui, repo_path, create=False)
-        repo_created = False
-        ui.status(_(b'loaded repository at "%s"\n' % repo_path))
-    except error.RepoError:
-        try:
-            shutil.rmtree(repo_path)
-        except FileNotFoundError:
-            ui.status(_(b'no such directory: "%s"\n' % repo_path))
-        else:
-            ui.status(
-                _(
-                    b'removed non-repository file or directory '
-                    b'at "%s"' % repo_path
-                )
-            )
-
-        ui.status(_(b'creating repository at "%s"\n' % repo_path))
-        repo = localrepo.instance(ui, repo_path, create=True)
-        repo_created = True
-
-    if repo.svfs.tryunlink(b'lock'):
-        ui.status(_(b'had to break store lock\n'))
-    if repo.vfs.tryunlink(b'wlock'):
-        ui.status(_(b'had to break working copy lock\n'))
-    # If another process relock after the breacking above, the next locking
-    # will have to wait.
-    with repo.wlock(), repo.lock():
-        ui.status(_(b'recovering after interrupted transaction, if any\n'))
-        repo.recover()
-
-        ui.status(_(b'pulling from %s\n') % source)
-        if repo_created and not opts.get('initial_clone_minimal'):
-            pull_revs = []
-        else:
-            pull_revs = [rev]
-        overrides = {(b'ui', b'quiet'): True}
-        with repo.ui.configoverride(overrides, b'chainsaw-update'):
-            pull = cmdutil.findcmd(b'pull', commands.table)[1][0]
-            ret = pull(
-                repo.ui,
-                repo,
-                source,
-                rev=pull_revs,
-                remote_hidden=False,
-            )
-            if ret:
-                return ret
-
-        purge = cmdutil.findcmd(b'purge', commands.table)[1][0]
-        ret = purge(
-            ui,
-            repo,
-            dirs=True,
-            all=opts.get('purge_ignored'),
-            files=opts.get('purge_unknown'),
-            confirm=False,
-        )
-        if ret:
-            return ret
-
-        ui.status(_(b'updating to revision \'%s\'\n') % rev)
-        update = cmdutil.findcmd(b'update', commands.table)[1][0]
-        ret = update(ui, repo, rev=rev, clean=True)
-        if ret:
-            return ret
-
-        ui.status(
-            _(
-                b'chainsaw-update to revision \'%s\' '
-                b'for repository at \'%s\' done\n'
-            )
-            % (rev, repo.root)
-        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/admin/chainsaw.py	Fri Mar 15 10:52:51 2024 +0100
@@ -0,0 +1,226 @@
+# chainsaw.py
+#
+# Copyright 2022 Georges Racinet <georges.racinet@octobus.net>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+"""chainsaw is a collection of single-minded and dangerous tools. (EXPERIMENTAL)
+
+  "Don't use a chainsaw to cut your food!"
+
+The chainsaw is a collection of commands that are so much geared towards a
+specific use case in a specific context or environment that they are totally
+inappropriate and **really dangerous** in other contexts.
+
+The help text of each command explicitly summarizes its context of application
+and the wanted end result.
+
+It is recommended to run these commands with the ``HGPLAIN`` environment
+variable (see :hg:`help scripting`).
+"""
+
+import shutil
+
+from ..i18n import _
+from .. import (
+    cmdutil,
+    commands,
+    error,
+    localrepo,
+    registrar,
+)
+from ..utils import (
+    urlutil,
+)
+
+cmdtable = {}
+command = registrar.command(cmdtable)
+
+
+@command(
+    b'admin::chainsaw-update',
+    [
+        (
+            b'',
+            b'purge-unknown',
+            True,
+            _(
+                b'Remove unversioned files before update. Disabling this can '
+                b'in some cases interfere with the update.'
+                b'See also :hg:`purge`.'
+            ),
+        ),
+        (
+            b'',
+            b'purge-ignored',
+            True,
+            _(
+                b'Remove ignored files before update. Disable this for '
+                b'instance to reuse previous compiler object files. '
+                b'See also :hg:`purge`.'
+            ),
+        ),
+        (
+            b'',
+            b'rev',
+            b'',
+            _(b'revision to update to'),
+        ),
+        (
+            b'',
+            b'source',
+            b'',
+            _(b'repository to clone from'),
+        ),
+        (
+            b'',
+            b'dest',
+            b'',
+            _(b'repository to update to REV (possibly cloning)'),
+        ),
+        (
+            b'',
+            b'initial-clone-minimal',
+            False,
+            _(
+                b'Pull only the prescribed revision upon initial cloning. '
+                b'This has the side effect of ignoring clone-bundles, '
+                b'which if often slower on the client side and stressful '
+                b'to the server than applying available clone bundles.'
+            ),
+        ),
+    ],
+    _(
+        b'hg admin::chainsaw-update [OPTION] --rev REV --source SOURCE --dest DEST'
+    ),
+    helpbasic=True,
+    norepo=True,
+)
+def update(ui, **opts):
+    """pull and update to a given revision, no matter what, (EXPERIMENTAL)
+
+    Context of application: *some* Continuous Integration (CI) systems,
+    packaging or deployment tools.
+
+    Wanted end result: local repository at the given REPO_PATH, having the
+    latest changes to the given revision and with a clean working directory
+    updated at the given revision.
+
+    chainsaw-update pulls from one source, then updates the working directory
+    to the given revision, overcoming anything that would stand in the way.
+
+    By default, it will:
+
+    - clone if the local repo does not exist yet, **removing any directory
+      at the given path** that would not be a Mercurial repository.
+      The initial clone is full by default, so that clonebundles can be
+      applied. Use the --initial-clone-minimal flag to avoid this.
+    - break locks if needed, leading to possible corruption if there
+      is a concurrent write access.
+    - perform recovery actions if needed
+    - revert any local modification.
+    - purge unknown and ignored files.
+    - go as far as to reclone if everything else failed (not implemented yet).
+
+    DO NOT use it for anything else than performing a series
+    of unattended updates, with full exclusive repository access each time
+    and without any other local work than running build scripts.
+    In case the local repository is a share (see :hg:`help share`), exclusive
+    write access to the share source is also mandatory.
+
+    It is recommended to run these commands with the ``HGPLAIN`` environment
+    variable (see :hg:`scripting`).
+
+    Motivation: in Continuous Integration and Delivery systems (CI/CD), the
+    occasional remnant or bogus lock are common sources of waste of time (both
+    working time and calendar time). CI/CD scripts tend to grow with counter-
+    measures, often done in urgency. Also, whilst it is neat to keep
+    repositories from one job to the next (especially with large
+    repositories), an exceptional recloning is better than missing a release
+    deadline.
+    """
+    rev = opts['rev']
+    source = opts['source']
+    repo_path = opts['dest']
+    if not rev:
+        raise error.InputError(_(b'specify a target revision with --rev'))
+    if not source:
+        raise error.InputError(_(b'specify a pull path with --source'))
+    if not repo_path:
+        raise error.InputError(_(b'specify a repo path with --dest'))
+    repo_path = urlutil.urllocalpath(repo_path)
+
+    try:
+        repo = localrepo.instance(ui, repo_path, create=False)
+        repo_created = False
+        ui.status(_(b'loaded repository at "%s"\n' % repo_path))
+    except error.RepoError:
+        try:
+            shutil.rmtree(repo_path)
+        except FileNotFoundError:
+            ui.status(_(b'no such directory: "%s"\n' % repo_path))
+        else:
+            ui.status(
+                _(
+                    b'removed non-repository file or directory '
+                    b'at "%s"' % repo_path
+                )
+            )
+
+        ui.status(_(b'creating repository at "%s"\n' % repo_path))
+        repo = localrepo.instance(ui, repo_path, create=True)
+        repo_created = True
+
+    if repo.svfs.tryunlink(b'lock'):
+        ui.status(_(b'had to break store lock\n'))
+    if repo.vfs.tryunlink(b'wlock'):
+        ui.status(_(b'had to break working copy lock\n'))
+    # If another process relock after the breacking above, the next locking
+    # will have to wait.
+    with repo.wlock(), repo.lock():
+        ui.status(_(b'recovering after interrupted transaction, if any\n'))
+        repo.recover()
+
+        ui.status(_(b'pulling from %s\n') % source)
+        if repo_created and not opts.get('initial_clone_minimal'):
+            pull_revs = []
+        else:
+            pull_revs = [rev]
+        overrides = {(b'ui', b'quiet'): True}
+        with repo.ui.configoverride(overrides, b'chainsaw-update'):
+            pull = cmdutil.findcmd(b'pull', commands.table)[1][0]
+            ret = pull(
+                repo.ui,
+                repo,
+                source,
+                rev=pull_revs,
+                remote_hidden=False,
+            )
+            if ret:
+                return ret
+
+        purge = cmdutil.findcmd(b'purge', commands.table)[1][0]
+        ret = purge(
+            ui,
+            repo,
+            dirs=True,
+            all=opts.get('purge_ignored'),
+            files=opts.get('purge_unknown'),
+            confirm=False,
+        )
+        if ret:
+            return ret
+
+        ui.status(_(b'updating to revision \'%s\'\n') % rev)
+        update = cmdutil.findcmd(b'update', commands.table)[1][0]
+        ret = update(ui, repo, rev=rev, clean=True)
+        if ret:
+            return ret
+
+        ui.status(
+            _(
+                b'chainsaw-update to revision \'%s\' '
+                b'for repository at \'%s\' done\n'
+            )
+            % (rev, repo.root)
+        )
--- a/mercurial/admin_commands.py	Sun Mar 10 03:29:12 2024 +0100
+++ b/mercurial/admin_commands.py	Fri Mar 15 10:52:51 2024 +0100
@@ -6,11 +6,12 @@
 # GNU General Public License version 2 or any later version.
 
 from .i18n import _
-from .admin import verify
+from .admin import chainsaw, verify
 from . import error, registrar, transaction
 
 
 table = {}
+table.update(chainsaw.command._table)
 command = registrar.command(table)
 
 
--- a/mercurial/branchmap.py	Sun Mar 10 03:29:12 2024 +0100
+++ b/mercurial/branchmap.py	Fri Mar 15 10:52:51 2024 +0100
@@ -880,7 +880,7 @@
 
         if self._names:
             try:
-                if repo.ui.configbool(b'format', b'mmap-revbranchcache'):
+                if repo.ui.configbool(b'storage', b'revbranchcache.mmap'):
                     with repo.cachevfs(_rbcrevs) as fp:
                         data = util.buffer(util.mmapread(fp))
                 else:
--- a/mercurial/configitems.toml	Sun Mar 10 03:29:12 2024 +0100
+++ b/mercurial/configitems.toml	Fri Mar 15 10:52:51 2024 +0100
@@ -583,6 +583,11 @@
 
 [[items]]
 section = "devel"
+name = "lock-wait-sync-file"
+default = ""
+
+[[items]]
+section = "devel"
 name = "persistent-nodemap"
 default = false
 documentation = """When true, revlogs use a special reference version of the \
@@ -1160,6 +1165,19 @@
 default = false
 generic = true
 
+
+# The format section is dedicated to control of the repository on disk format
+# and constraints.
+#
+# A format change affects which data is expected to be stored in the repository
+# and how. It impacts other client whichever their version are, format change
+# often comes with an associated entry in the requirements.
+#
+# The option are usually in the form `use-xxx-yyy` (with xxx-yy the feature name).
+#
+# To configure details of how the repository is accessed, without affect the
+# repository formats, see the `storage section`.
+
 [[items]]
 section = "format"
 name = "bookmarks-in-store"
@@ -2102,6 +2120,15 @@
 default = true
 experimental = true
 
+
+# The "storage" section house config options that change how the repository
+# data are accessed by  the current process but does not affects the on disk
+# format. They can also adjust how the storage is computed, but without affect
+# compatibility wither other clients.
+#
+# For deeper format change, see the `format` section.
+
+
 [[items]]
 section = "storage"
 name = "dirstate-v2.slow-path"
@@ -2110,6 +2137,11 @@
 
 [[items]]
 section = "storage"
+name = "revbranchcache.mmap"
+default = true
+
+[[items]]
+section = "storage"
 name = "new-repo-backend"
 default = "revlogv1"
 experimental = true
@@ -2913,8 +2945,3 @@
 name = "date-format"
 default = ""
 in_core_extension = "blackbox"
-
-[[items]]
-section = "format"
-name = "mmap-revbranchcache"
-default = false
--- a/mercurial/crecord.py	Sun Mar 10 03:29:12 2024 +0100
+++ b/mercurial/crecord.py	Fri Mar 15 10:52:51 2024 +0100
@@ -1563,7 +1563,6 @@
     def sigwinchhandler(self, n, frame):
         """handle window resizing"""
         try:
-            curses.endwin()
             self.xscreensize, self.yscreensize = scmutil.termsize(self.ui)
             self.statuswin.resize(self.numstatuslines, self.xscreensize)
             self.numpadlines = self.getnumlinesdisplayed(ignorefolding=True) + 1
@@ -1694,7 +1693,6 @@
 
         curses.raw()
         curses.def_prog_mode()
-        curses.endwin()
         self.commenttext = self.ui.edit(self.commenttext, self.ui.username())
         curses.cbreak()
         self.stdscr.refresh()
--- a/mercurial/localrepo.py	Sun Mar 10 03:29:12 2024 +0100
+++ b/mercurial/localrepo.py	Fri Mar 15 10:52:51 2024 +0100
@@ -3072,6 +3072,9 @@
             warntimeout = self.ui.configint(b"ui", b"timeout.warn")
         # internal config: ui.signal-safe-lock
         signalsafe = self.ui.configbool(b'ui', b'signal-safe-lock')
+        sync_file = self.ui.config(b'devel', b'lock-wait-sync-file')
+        if not sync_file:
+            sync_file = None
 
         l = lockmod.trylock(
             self.ui,
@@ -3083,6 +3086,7 @@
             acquirefn=acquirefn,
             desc=desc,
             signalsafe=signalsafe,
+            devel_wait_sync_file=sync_file,
         )
         return l
 
--- a/mercurial/lock.py	Sun Mar 10 03:29:12 2024 +0100
+++ b/mercurial/lock.py	Fri Mar 15 10:52:51 2024 +0100
@@ -115,6 +115,7 @@
 
     This function is responsible to issue warnings and or debug messages about
     the held lock while trying to acquires it."""
+    devel_wait_file = kwargs.pop("devel_wait_sync_file", None)
 
     def printwarning(printer, locker):
         """issue the usual "waiting on lock" message through any channel"""
@@ -150,6 +151,11 @@
             l._trylock()
             break
         except error.LockHeld as inst:
+            if devel_wait_file is not None:
+                # create the file to signal we are waiting
+                with open(devel_wait_file, 'w'):
+                    pass
+
             if delay == debugidx:
                 printwarning(ui.debug, inst.locker)
             if delay == warningidx:
--- a/mercurial/obsutil.py	Sun Mar 10 03:29:12 2024 +0100
+++ b/mercurial/obsutil.py	Fri Mar 15 10:52:51 2024 +0100
@@ -468,10 +468,10 @@
 
         # Check if other meta has changed
         changeextra = changectx.extra().items()
-        ctxmeta = list(filter(metanotblacklisted, changeextra))
+        ctxmeta = sorted(filter(metanotblacklisted, changeextra))
 
         sourceextra = source.extra().items()
-        srcmeta = list(filter(metanotblacklisted, sourceextra))
+        srcmeta = sorted(filter(metanotblacklisted, sourceextra))
 
         if ctxmeta != srcmeta:
             effects |= METACHANGED
--- a/mercurial/phases.py	Sun Mar 10 03:29:12 2024 +0100
+++ b/mercurial/phases.py	Fri Mar 15 10:52:51 2024 +0100
@@ -703,6 +703,7 @@
             return set()
 
         # search for affected high phase changesets and roots
+        seen = set(new_revs)
         push = heapq.heappush
         pop = heapq.heappop
         parents = cl.parentrevs
@@ -735,9 +736,11 @@
                 # higher phases
                 delroots.add(current)
             # schedule a walk down if needed
-            if p1_phase > targetphase:
+            if p1_phase > targetphase and p1 not in seen:
+                seen.add(p1)
                 push(revs, -p1)
-            if p2_phase > targetphase:
+            if p2_phase > targetphase and p2 not in seen:
+                seen.add(p2)
                 push(revs, -p2)
             if p1_phase < targetphase and p2_phase < targetphase:
                 new_target_roots.add(current)
--- a/relnotes/6.7	Sun Mar 10 03:29:12 2024 +0100
+++ b/relnotes/6.7	Fri Mar 15 10:52:51 2024 +0100
@@ -1,7 +1,4 @@
-= Mercurial 6.7rc0 =
-
-/!\ These are **tentative** release notes for the upcoming Mercurial 6.7.
-Anything can be added or removed before the actual release.
+= Mercurial 6.7 =
 
 As usual, a *lot* of patches don't make it to this list.
 
@@ -20,6 +17,7 @@
  * annotate: limit output to range of lines
  * unbundle: faster computation of changed heads
  * Large improvements of some of the phases code (23950e39281f)
+ * rust-filepatterns: export glob_to_re function
 
 == New Experimental Features ==
 
@@ -41,6 +39,11 @@
  * cext: fix potential memory leaks of list items appended with PyList_Append
  * doc: document that labels must have a dot in them to have an effect
  * debugformat: fix formatting for compression level
+ * obsutil: sort metadata before comparing in geteffectflag()
+ * crecord: drop calls to `curses.endwin()`
+ * rust-index: don't use mutable borrow for head-diff computation
+ * rust-index: don't use mutable borrow to computed filtered heads
+
 
 == Backwards Compatibility Changes ==
 
--- a/rust/hg-core/src/filepatterns.rs	Sun Mar 10 03:29:12 2024 +0100
+++ b/rust/hg-core/src/filepatterns.rs	Fri Mar 15 10:52:51 2024 +0100
@@ -73,7 +73,7 @@
 }
 
 /// Transforms a glob pattern into a regex
-fn glob_to_re(pat: &[u8]) -> Vec<u8> {
+pub fn glob_to_re(pat: &[u8]) -> Vec<u8> {
     let mut input = pat;
     let mut res: Vec<u8> = vec![];
     let mut group_depth = 0;
--- a/rust/hg-core/src/matchers.rs	Sun Mar 10 03:29:12 2024 +0100
+++ b/rust/hg-core/src/matchers.rs	Fri Mar 15 10:52:51 2024 +0100
@@ -737,14 +737,11 @@
     }
 }
 
-/// Returns a function that matches an `HgPath` against the given regex
-/// pattern.
+/// Return a `RegexBuilder` from a bytes pattern
 ///
-/// This can fail when the pattern is invalid or not supported by the
-/// underlying engine (the `regex` crate), for instance anything with
-/// back-references.
-#[logging_timer::time("trace")]
-fn re_matcher(pattern: &[u8]) -> PatternResult<RegexMatcher> {
+/// This works around the fact that even if it works on byte haysacks,
+/// [`regex::bytes::Regex`] still uses UTF-8 patterns.
+pub fn re_bytes_builder(pattern: &[u8]) -> regex::bytes::RegexBuilder {
     use std::io::Write;
 
     // The `regex` crate adds `.*` to the start and end of expressions if there
@@ -764,7 +761,18 @@
     // # Safety
     // This is safe because we escaped all non-ASCII bytes.
     let pattern_string = unsafe { String::from_utf8_unchecked(escaped_bytes) };
-    let re = regex::bytes::RegexBuilder::new(&pattern_string)
+    regex::bytes::RegexBuilder::new(&pattern_string)
+}
+
+/// Returns a function that matches an `HgPath` against the given regex
+/// pattern.
+///
+/// This can fail when the pattern is invalid or not supported by the
+/// underlying engine (the `regex` crate), for instance anything with
+/// back-references.
+#[logging_timer::time("trace")]
+fn re_matcher(pattern: &[u8]) -> PatternResult<RegexMatcher> {
+    let re = re_bytes_builder(pattern)
         .unicode(false)
         // Big repos with big `.hgignore` will hit the default limit and
         // incur a significant performance hit. One repo's `hg status` hit
--- a/rust/hg-cpython/src/revlog.rs	Sun Mar 10 03:29:12 2024 +0100
+++ b/rust/hg-cpython/src/revlog.rs	Fri Mar 15 10:52:51 2024 +0100
@@ -854,7 +854,7 @@
     ) -> PyResult<PyObject> {
         let begin = begin.extract::<BaseRevision>(py)?;
         let end = end.extract::<BaseRevision>(py)?;
-        let index = &mut *self.index(py).borrow_mut();
+        let index = &*self.index(py).borrow();
         let begin =
             Self::check_revision(index, UncheckedRevision(begin - 1), py)?;
         let end = Self::check_revision(index, UncheckedRevision(end - 1), py)?;
@@ -873,7 +873,7 @@
         py: Python,
         filtered_revs: &PyObject,
     ) -> PyResult<PyObject> {
-        let index = &mut *self.index(py).borrow_mut();
+        let index = &*self.index(py).borrow();
         let filtered_revs = rev_pyiter_collect(py, filtered_revs, index)?;
 
         if let Some(new_heads) = index
--- a/tests/test-branches.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-branches.t	Fri Mar 15 10:52:51 2024 +0100
@@ -2,8 +2,8 @@
 
 #if mmap
   $ cat <<EOF >> $HGRCPATH
-  > [format]
-  > mmap-revbranchcache=true
+  > [storage]
+  > revbranchcache.mmap=true
   > EOF
 #endif
 
--- a/tests/test-chainsaw-update.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-chainsaw-update.t	Fri Mar 15 10:52:51 2024 +0100
@@ -5,11 +5,6 @@
 setup
 =====
 
-  $ cat >> $HGRCPATH << EOF
-  > [extensions]
-  > chainsaw=
-  > EOF
-
   $ hg init src
   $ cd src
   $ echo 1 > root
--- a/tests/test-chg.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-chg.t	Fri Mar 15 10:52:51 2024 +0100
@@ -288,7 +288,9 @@
 preserved (since setprocname isn't available on py3 and pure version,
 the 10th-most-recent line is different when using py3):
 
-  $ cat log/server.log.1 log/server.log | tail -10 | filterlog
+(the "worker process exited" line is matched independently as it order is unstable with the "exiting" line, the worker might exit before the server decide to exit).
+
+  $ cat log/server.log.1 log/server.log | tail -10 | grep -v "worker process exited" | filterlog
   YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ... (no-setprocname !)
   YYYY/MM/DD HH:MM:SS (PID)> forked worker process (pid=...)
   YYYY/MM/DD HH:MM:SS (PID)> setprocname: ... (setprocname !)
@@ -298,8 +300,9 @@
   YYYY/MM/DD HH:MM:SS (PID)> setenv: ...
   YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ...
   YYYY/MM/DD HH:MM:SS (PID)> validate: []
+  YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
+  $ cat log/server.log.1 log/server.log | tail -10 | grep "worker process exited" | filterlog
   YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
-  YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
 
 global data mutated by schems
 -----------------------------
--- a/tests/test-completion.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-completion.t	Fri Mar 15 10:52:51 2024 +0100
@@ -3,6 +3,7 @@
   abort
   add
   addremove
+  admin::chainsaw-update
   admin::verify
   annotate
   archive
@@ -66,6 +67,7 @@
   abort
   add
   addremove
+  admin::chainsaw-update
   admin::verify
   annotate
   archive
@@ -260,6 +262,7 @@
   abort: dry-run
   add: include, exclude, subrepos, dry-run
   addremove: similarity, subrepos, include, exclude, dry-run
+  admin::chainsaw-update: purge-unknown, purge-ignored, rev, source, dest, initial-clone-minimal
   admin::verify: check, option
   annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, line-range, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
   archive: no-decode, prefix, rev, type, subrepos, include, exclude
--- a/tests/test-generaldelta.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-generaldelta.t	Fri Mar 15 10:52:51 2024 +0100
@@ -5,9 +5,12 @@
 implementation of parentdelta: third manifest revision would be fully
 inserted due to big distance from its paren revision (zero).
 
+(We disable the revlog compression to avoid the annoying instability in the chunk size that depends on the compressors implementation)
+
   $ cat << EOF >> $HGRCPATH
   > [format]
   > sparse-revlog = no
+  > revlog-compression = none
   > EOF
 
   $ hg init repo --config format.generaldelta=no --config format.usegeneraldelta=no
@@ -138,12 +141,12 @@
 
 - Verify non-aggressive merge uses p1 (commit 1) as delta parent
   $ hg merge -q 0
-  $ hg commit -q -m merge
+  $ hg commit -q -m merge --config storage.revlog.optimize-delta-parent-choice=no
   $ hg debugdeltachain -m
       rev      p1      p2  chain# chainlen     prev   delta
         0      -1      -1       1        1       -1    base
-        1      -1      -1       1        2        0    prev
-        2       1       0       1        2        0      p2
+        1      -1      -1       2        1       -1    base
+        2       1       0       2        2        1      p1
 
   $ hg strip -q -r . --config extensions.strip=
 
@@ -154,7 +157,7 @@
   $ hg debugdeltachain -m
       rev      p1      p2  chain# chainlen     prev   delta
         0      -1      -1       1        1       -1    base
-        1      -1      -1       1        2        0    prev
+        1      -1      -1       2        1       -1    base
         2       1       0       1        2        0      p2
 
 Test that strip bundle use bundle2
@@ -266,13 +269,13 @@
        46      45      -1       3       29       45      p1         58       1334       1671   1.25262      1671         0    0.00000
        47      46      -1       3       30       46      p1         58       1380       1729   1.25290      1729         0    0.00000
        48      47      -1       3       31       47      p1         58       1426       1787   1.25316      1787         0    0.00000
-       49       5      -1       4        1       -1    base        ???        316        ???   0.6????       ???         0    0.00000 (glob)
-       50      49      -1       4        2       49      p1         58        362        2??   0.7????       2??         0    0.00000 (glob)
-       51      17      -1       4        3       50    prev        3??        5??        6??   1.0????       6??         0    0.00000 (glob)
-       52      51      -1       4        4       51      p1         58        640        6??   1.0????       6??         0    0.00000 (glob)
-       53      52      -1       5        1       -1    base          0          0          0   0.00000         0         0    0.00000
-       54      53      -1       5        2       53      p1        3??        640        3??   0.5????       3??         0    0.00000 (glob)
-  $ hg clone --pull source-repo --config experimental.maxdeltachainspan=2800 relax-chain --config format.generaldelta=yes
+       49       5      -1       4        1       -1    base        317        316        317   1.00316       317         0    0.00000
+       50      49      -1       4        2       49      p1         58        362        375   1.03591       375         0    0.00000
+       51      17      -1       5        1       -1    base        595        594        595   1.00168       595         0    0.00000
+       52      51      -1       5        2       51      p1         58        640        653   1.02031       653         0    0.00000
+       53      52      -1       6        1       -1    base          0          0          0   0.00000         0         0    0.00000
+       54      53      -1       7        1       -1    base        641        640        641   1.00156       641         0    0.00000
+  $ hg clone --pull source-repo --config experimental.maxdeltachainspan=2900 relax-chain --config format.generaldelta=yes
   requesting all changes
   adding changesets
   adding manifests
@@ -332,12 +335,12 @@
        46      45      -1       3       29       45      p1         58       1334       1671   1.25262      1671         0    0.00000
        47      46      -1       3       30       46      p1         58       1380       1729   1.25290      1729         0    0.00000
        48      47      -1       3       31       47      p1         58       1426       1787   1.25316      1787         0    0.00000
-       49       5      -1       4        1       -1    base        ???        316        ???   0.6????       ???         0    0.00000 (glob)
-       50      49      -1       4        2       49      p1         58        362        2??   0.7????       2??         0    0.00000 (glob)
-       51      17      -1       2       13       17      p1         58        594        739   1.24411      278?      20??    2.7???? (glob)
-       52      51      -1       5        1       -1    base        3??        640        3??   0.5????       3??         0    0.00000 (glob)
+       49       5      -1       1        7        5      p1         58        316        389   1.23101      2857      2468    6.34447
+       50      49      -1       4        1       -1    base        363        362        363   1.00276       363         0    0.00000
+       51      17      -1       5        1       -1    base        595        594        595   1.00168       595         0    0.00000
+       52      51      -1       5        2       51      p1         58        640        653   1.02031       653         0    0.00000
        53      52      -1       6        1       -1    base          0          0          0   0.00000         0         0    0.00000
-       54      53      -1       7        1       -1    base        3??        640        3??   0.5????       3??         0    0.00000 (glob)
+       54      53      -1       7        1       -1    base        641        640        641   1.00156       641         0    0.00000
   $ hg clone --pull source-repo --config experimental.maxdeltachainspan=0 noconst-chain --config format.usegeneraldelta=yes --config storage.revlog.reuse-external-delta-parent=no
   requesting all changes
   adding changesets
@@ -403,4 +406,4 @@
        51      17      -1       2       13       17      p1         58        594        739   1.24411      2642      1903    2.57510
        52      51      -1       2       14       51      p1         58        640        797   1.24531      2700      1903    2.38770
        53      52      -1       4        1       -1    base          0          0          0   0.00000         0         0    0.00000
-       54      53      -1       5        1       -1    base        3??        640        3??   0.5????       3??         0    0.00000 (glob)
+       54      53      -1       5        1       -1    base        641        640        641   1.00156       641         0    0.00000
--- a/tests/test-help.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-help.t	Fri Mar 15 10:52:51 2024 +0100
@@ -412,6 +412,9 @@
   
    abort         abort an unfinished operation (EXPERIMENTAL)
    add           add the specified files on the next commit
+   admin::chainsaw-update, admin::chainsawupdate
+                 pull and update to a given revision, no matter what,
+                 (EXPERIMENTAL)
    annotate, blame
                  show changeset information by line for each file
    clone         make a copy of an existing repository
@@ -2535,6 +2538,13 @@
   add the specified files on the next commit
   </td></tr>
   <tr><td>
+  <a href="/help/admin::chainsaw-update">
+  admin::chainsaw-update
+  </a>
+  </td><td>
+  pull and update to a given revision, no matter what, (EXPERIMENTAL)
+  </td></tr>
+  <tr><td>
   <a href="/help/annotate">
   annotate
   </a>
--- a/tests/test-hgweb-json.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-hgweb-json.t	Fri Mar 15 10:52:51 2024 +0100
@@ -2038,6 +2038,10 @@
         "topic": "add"
       },
       {
+        "summary": "pull and update to a given revision, no matter what, (EXPERIMENTAL)",
+        "topic": "admin::chainsaw-update"
+      },
+      {
         "summary": "show changeset information by line for each file",
         "topic": "annotate"
       },
--- a/tests/test-lock-badness.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-lock-badness.t	Fri Mar 15 10:52:51 2024 +0100
@@ -49,15 +49,32 @@
 
 One process waiting for another
 
-  $ cat > hooks.py << EOF
-  > import time
-  > def sleepone(**x): time.sleep(1)
-  > def sleephalf(**x): time.sleep(0.5)
+  $ SYNC_FILE_LOCKED="$TESTTMP/sync-file-locked"
+  $ export SYNC_FILE_LOCKED
+  $ SYNC_FILE_TRYING_LOCK="$TESTTMP/sync-file-trying-lock"
+  $ export SYNC_FILE_TRYING_LOCK
+  $ cat << EOF > locker.sh
+  > $RUNTESTDIR/testlib/wait-on-file 10 $SYNC_FILE_TRYING_LOCK $SYNC_FILE_LOCKED;
+  > EOF
+  $ cat << EOF > waiter.sh
+  > $RUNTESTDIR/testlib/wait-on-file 10 $SYNC_FILE_LOCKED;
   > EOF
+  $ clean_sync() {
+  >   rm -f "$SYNC_FILE_LOCKED"
+  >   rm -f "$SYNC_FILE_TRYING_LOCK"
+  > }
+
+
+  $ clean_sync
   $ echo b > b/b
-  $ hg -R b ci -A -m b --config hooks.precommit="python:`pwd`/hooks.py:sleepone" > stdout &
-  $ hg -R b up -q --config ui.timeout.warn=0 --config hooks.pre-update="python:`pwd`/hooks.py:sleephalf" \
-  > > preup-stdout 2>preup-stderr
+  $ hg -R b ci -A -m b \
+  >   --config hooks.precommit="sh $TESTTMP/locker.sh" \
+  >   > stdout &
+  $ hg -R b up -q \
+  >   --config ui.timeout.warn=0 \
+  >   --config hooks.pre-update="sh $TESTTMP/waiter.sh" \
+  >   --config devel.lock-wait-sync-file="$SYNC_FILE_TRYING_LOCK" \
+  >   > preup-stdout 2> preup-stderr
   $ wait
   $ cat preup-stdout
   $ cat preup-stderr
@@ -68,11 +85,16 @@
 
 On processs waiting on another, warning after a long time.
 
+  $ clean_sync
   $ echo b > b/c
-  $ hg -R b ci -A -m b --config hooks.precommit="python:`pwd`/hooks.py:sleepone" > stdout &
-  $ hg -R b up -q --config hooks.pre-update="python:`pwd`/hooks.py:sleephalf" \
-  > --config ui.timeout.warn=250 \
-  > > preup-stdout 2>preup-stderr
+  $ hg -R b ci -A -m b \
+  >   --config hooks.precommit="sh $TESTTMP/locker.sh" \
+  >   > stdout &
+  $ hg -R b up -q \
+  >   --config hooks.pre-update="sh $TESTTMP/waiter.sh" \
+  >   --config devel.lock-wait-sync-file="$SYNC_FILE_TRYING_LOCK" \
+  >   --config ui.timeout.warn=250 \
+  >   > preup-stdout 2> preup-stderr
   $ wait
   $ cat preup-stdout
   $ cat preup-stderr
@@ -81,11 +103,16 @@
 
 On processs waiting on another, warning disabled.
 
+  $ clean_sync
   $ echo b > b/d
-  $ hg -R b ci -A -m b --config hooks.precommit="python:`pwd`/hooks.py:sleepone" > stdout &
-  $ hg -R b up -q --config hooks.pre-update="python:`pwd`/hooks.py:sleephalf" \
-  > --config ui.timeout.warn=-1 \
-  > > preup-stdout 2>preup-stderr
+  $ hg -R b ci -A -m b \
+  >   --config hooks.precommit="sh $TESTTMP/locker.sh" \
+  >   > stdout &
+  $ hg -R b up -q \
+  >   --config hooks.pre-update="sh $TESTTMP/waiter.sh" \
+  >   --config devel.lock-wait-sync-file="$SYNC_FILE_TRYING_LOCK" \
+  >   --config ui.timeout.warn=-1 \
+  >   > preup-stdout 2>preup-stderr
   $ wait
   $ cat preup-stdout
   $ cat preup-stderr
@@ -96,14 +123,19 @@
 
 On processs waiting on another, warning after a long time (debug output on)
 
+  $ clean_sync
   $ echo b > b/e
-  $ hg -R b ci -A -m b --config hooks.precommit="python:`pwd`/hooks.py:sleepone" > stdout &
-  $ hg -R b up --config hooks.pre-update="python:`pwd`/hooks.py:sleephalf" \
-  > --config ui.timeout.warn=250 --debug\
-  > > preup-stdout 2>preup-stderr
+  $ hg -R b ci -A -m b \
+  >   --config hooks.precommit="sh $TESTTMP/locker.sh" \
+  >   > stdout &
+  $ hg -R b up \
+  >   --config hooks.pre-update="sh $TESTTMP/waiter.sh" \
+  >   --config devel.lock-wait-sync-file="$SYNC_FILE_TRYING_LOCK" \
+  >   --config ui.timeout.warn=250 --debug \
+  >   > preup-stdout 2>preup-stderr
   $ wait
   $ cat preup-stdout
-  calling hook pre-update: hghook_pre-update.sleephalf
+  running hook pre-update: sh $TESTTMP/waiter.sh
   waiting for lock on working directory of b held by process '*' on host '*' (glob)
   got lock after * seconds (glob)
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -113,14 +145,19 @@
 
 On processs waiting on another, warning disabled, (debug output on)
 
+  $ clean_sync
   $ echo b > b/f
-  $ hg -R b ci -A -m b --config hooks.precommit="python:`pwd`/hooks.py:sleepone" > stdout &
-  $ hg -R b up --config hooks.pre-update="python:`pwd`/hooks.py:sleephalf" \
-  > --config ui.timeout.warn=-1 --debug\
-  > > preup-stdout 2>preup-stderr
+  $ hg -R b ci -A -m b \
+  >   --config hooks.precommit="sh $TESTTMP/locker.sh" \
+  >   > stdout &
+  $ hg -R b up \
+  >   --config hooks.pre-update="sh $TESTTMP/waiter.sh" \
+  >   --config devel.lock-wait-sync-file="$SYNC_FILE_TRYING_LOCK" \
+  >   --config ui.timeout.warn=-1 --debug\
+  >   > preup-stdout 2>preup-stderr
   $ wait
   $ cat preup-stdout
-  calling hook pre-update: hghook_pre-update.sleephalf
+  running hook pre-update: sh $TESTTMP/waiter.sh
   waiting for lock on working directory of b held by process '*' on host '*' (glob)
   got lock after * seconds (glob)
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-patchbomb-tls.t	Sun Mar 10 03:29:12 2024 +0100
+++ b/tests/test-patchbomb-tls.t	Fri Mar 15 10:52:51 2024 +0100
@@ -1,5 +1,15 @@
 #require serve ssl
 
+  $ wait_log() {
+  >     pattern="$1"
+  >     for s in $TESTDIR/seq.py 10; do
+  >         if grep "$pattern" $TESTTMP/log > /dev/null ; then
+  >             break
+  >         fi
+  >         sleep 1
+  >     done
+  > }
+
 Set up SMTP server:
 
   $ CERTSDIR="$TESTDIR/sslcerts"
@@ -47,6 +57,7 @@
   (?i)abort: .*?certificate.verify.failed.* (re)
   [255]
 
+  $ wait_log "ssl error:"
   $ cat ../log
   * ssl error: * (glob)
   $ : > ../log
@@ -62,6 +73,7 @@
   (?i)abort: .*?certificate.verify.failed.* (re)
   [255]
 
+  $ wait_log "ssl error:"
   $ cat ../log
   * ssl error: * (glob)
   $ : > ../log
@@ -83,6 +95,7 @@
   (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
   [150]
 
+  $ wait_log "no hello:"
   $ cat ../log
   connection from * (glob)
   no hello: b''
@@ -143,6 +156,7 @@
   (?i)abort: .*?certificate.verify.failed.* (re)
   [255]
 
+  $ wait_log "ssl error:"
   $ cat ../log
   * ssl error: * (glob)
   $ : > ../log