changeset 47859:155a2ec8a9dc

merge with stable
author Matt Harbison <matt_harbison@yahoo.com>
date Sun, 22 Aug 2021 16:32:06 -0400
parents de2e04fe4897 (current diff) df94c13ddf60 (diff)
children 08f16b3331df
files hgext/fix.py mercurial/configitems.py
diffstat 67 files changed, 2277 insertions(+), 305 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsigs	Tue Jul 20 17:20:19 2021 +0200
+++ b/.hgsigs	Sun Aug 22 16:32:06 2021 -0400
@@ -211,3 +211,7 @@
 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAmB+71MQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91Vj+EADBa/tHfgyymKmXXl9DSlzwEhX1DkCE0aRcsbfXujnpOQrDi09pfHvtYEbgJfl6m8JEUOjuRRcxofnIWOC9UJCGC3ZfW5tTcHomCFlqjHhUxGKsvQ1Wcec1IH3mmzhqLnd0X57EgnNC6APwgxNVRmC0q7M7rSlNiE8BkHEUuyCau5FvpgdF31Aqa9IQP95pmmeDwL4ByPR1Nssu2/8N5vbcQm55gdjcggNjBvNEbaFHDS9NlGS8quvCMwRZkr3meDfTeCs9d2MveXXvV8GVOFq+WHMoURVijTjON+HuXB7HLegyhVOcigfbU5zxGY/IAJ/tAYEzBLWSYW6wjsN5uuZP267XhKpd2FT8Cfe9t3OnN1K21ndltlaMSdGyAynuepzVE0IELOCiKlgBZkdnft2XkUt2DDg/TqhOeXmUBzIFVze5KULSgrFvjkx71iV22LUGkIxzIuW5ieBMeZotKHzI+ZXO7xNSDIdoSfERKUqfYJKbksnBQLRxYUO77KetjocsMMYyB4Dpzu05+eWpYtZs2u5PsqP/Jv84Mz3QR0szAI1h3KlhmbkvKxnWnFYasAdFPMluX4G4X+9+MulODCwgw/RvQhh13M2QP0vGb1Xzu/JOuxRr3zuliTUfszd7YHVJoROzuT9PlcZ4criwZwv+fvbCN+F9LRbeI/BQBVZi6w==
 8d2b62d716b095507effaa8d56f87cd27ba659ab 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAmCAO3gQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91YvWD/4kn4nLsu6W6hpSmB6qZB7y9adX8mqwzpSfnt0hwesk5FiBmGnDWHT5IvGHRTq0B3+peG9NH5R0h1WgtCdyh6YxGg0CZwNoarv64U8llS+PTXp8YZo/bVex7QGKQJr45Xik4ZH6htJ0muJUhzpHa6wkthTxK2OuaTTJvJ53lY8dR4lmefxSYPAwWs/jOzkmPwIeK8EnG0ZcBtmheJESOzKnmmOF6N4GnUGFFz/W5q8Gfeqj9xKKDt+zdPHXCEZUYivBcMPL7UNti2kvrp3R7VXBzbw/bPAJTrq68M4Z9mFb0qRZ88ubGXu+LEufsG2Dls/ZF0GnBPeReuFFrg9jimQqo6Rf/+4vV+GtFBY71aofFDDex9/s0q7skNEBxLP6r/KfsachYzvdciRS46zLelrL/NhpDvM6mHOLWmuycCeYShYctGbc2zDK7vD136Da6xlWU5Qci/+6zTtAjaKqdIpJuIzBfKdhaakri8vlpplpNLIDMfTTLyYKVAuHUtZcwHcHWmx54b2ulAmNXtc5yB/JqRIUined+Z6KlYc7c7MKEo2FB2/0okIbx7bIiXbV2of4j3ufv+NPIQel1qsnX58vbYL1spdfynNMTHQ+TYc9lUvuq31znu2LLJ9ZhTOiLEt1QZB28lTukzNuH2MEpGWtrOBIC9AcXjyyZ8HlIwEWMA==
 067f2c53fb24506c9e9fb4639871b13b19a85f8a 0 iQJJBAABCgAzFiEEgY2HzRrBgMOUyG5jOjPeRg2ew58FAmCQMXEVHDc4OTVwdWxraXRAZ21haWwuY29tAAoJEDoz3kYNnsOfpJgP/isIDkbMuhot376RY2SwilSCkjJRoKRCDyLjJReBUF29t+DPWs8h971t2v5DIasfuQZthMv9A6DYcyEs1Q3NTKvT4TMKTTrqQfIe8UMmUa9PI1SIuTShiWbwonrN8rrVMVVcjPO/gookMV8/uoYW3wn/SThkBEYYauONBBVKbQ/Bt31/OPbEeAEdb/IEJ9X9PL1sfQkf+/DA/cwawS+xn01GAxWybx8eJkcJFdGdUcl/PYWgX76RSUhGvD6aHRJTZ1+sXy7+ligfpdPkNrQ248mVEEQkmZaCQ39dQPMX5zLa2hEX6eW9b1BEhNjHzbDfyqwc+F5czLw+R56vjPUyRCkxAZ6Q5Q3vkgLPBlZ2Ay0Lta/5+qGWcX+nDzfKfr2FhBLAnRZG/M+M2ckzR+8twyKg7/vdD8e/B3+Oxmu5QTS8xuj1628Brf9IehedQHoEPDe2M5ynhlEcybkbLz1R7zWKrh2h76OGQtspcjF997W1uZFx+DH6kHSznIm/8zEXy13R2nZk/0YtGX2UjZDv9bZ5X3B7T1673uscx3VpiT8YLJVKX7FyFLMgUbVY9ZGFlQ/pzUP3gTGa5rAB8b72U45jlXdKKvCn9B3hbS4j9OzJKpjsspWDmFHl2/a01ZOL/SZtMlm7FeYymUXKc10dndXlXTlGxHFUJQsii6t3dDyf
+411dc27fd9fd076d6a031a08fcaace659afe2fe3 0 iQJJBAABCgAzFiEEgY2HzRrBgMOUyG5jOjPeRg2ew58FAmDnSgwVHDc4OTVwdWxraXRAZ21haWwuY29tAAoJEDoz3kYNnsOftvQP/j1mvheFHsv5TSJ2IEKgEK4G/cIxt+taoWpecEUVN5JAk7q4Y1xnzcoyqQdAyvZcTu7m4ESx865XW6Jvc0I2pG+uKcmO7ZfwrAOugoXXxrlXtopVfDDFZOLlk72x+Z5tQpL9QcBUgetkuOZLFhT+1ETjnFd2H4P4pwPjdTpn+YBmDmh1tWTMzllTDDzvZeE6iAjIpM9IQKL4jKxcEjPAX2XDa1xWhd/o9NZC9kYSTIBQvbFWAz3A0PSAudz0lu5YDXKJNtIHlzZtMFmcUlqJGM4MlD6v9tm8EQbCWTgOm0+wB5miDqv05aC6axD3LnSgrlPsmRDZCIRAws1JHEjKYFob7VRMxpivW7GDSd6QrmUbTHYN5eY0v1YB62dCa8W9qk2E7R5VdLRi4haFTv42u7jOZT0tSzRv/R0QppoVQ7/Fpqpps+aoZBM6EGj/pAxRgBTHeyI9WTFUAYDbhRuN9EoJAqRUCpXn39oR+TsaD9COENAJroX2WLIY8XFD3UzrpA9NPt7JE9mufWoNipNqLdLY7k3p3UxX0/SDboVlax6ORpQN+YzYhCesJaAOhlTAXMRMyXsfw/ScYttXxmIJ7BINYEMSXM55uiUPYFjE/GuZjbjgqk3dmJr7ceAyGa5v+m5Hr6efPSRHKUAxkEcDsXpcTHyEOVt3l7Qwfd+oUumK
+d7515d29761d5ada7d9c765f517db67db75dea9a 0 iQJJBAABCgAzFiEEgY2HzRrBgMOUyG5jOjPeRg2ew58FAmD4lQMVHDc4OTVwdWxraXRAZ21haWwuY29tAAoJEDoz3kYNnsOfVsMP/19G6aZBokNRdErXcT86ahVy82IquR/CmLJcdj/4nehmBXToLCmdeqKe17ZKgZ7bnPnevhO07zPub7RUhDixnb7OxpbXiyP7x67FAqAfKvi8rZggmeWZT5kpiltoBIvHDlOlQhsgtfea0REULyn4zNB6dLED5zh2Ddr5LcWIjfOvIWo1F0eFMcRszL8f2u2ei2dERDuG8MSzMsiFHMAPRMHJjm+YukJBuz78CH4qT/Inkq52ao+3GCh4fFBhPG5+IABeCn1J4cAAK06mPcJqa7fbv7NfUCN9MeDNQUsUGGfIhKzGHJTb7PwXkKJ3qpLPs4FYGV1ZTucrIU1i65hXuf66QcYGlAQmKavS7xDOfZhzrZrAKe65dLpWdEH5mpTMcjaMBS+mhfMJT7DQg9T/9jISiKeqiFNkNOy1cobpJWes8iFwihEBtEhCtiVgnf7i7IzZY/spmSmP4ot/MEBi3jMjvAEaH1HyDGOPuBuqRSIRU+Mf5o1yB2kZmGL9vHWUzm/ySjQFYte061OyE9bZrbF9daOTdRip/CXPApOneVBIMwXc7fWDu45cKyVg7kYo8a0gcFfg39Ceja3Z8iJSFtJTuj1Sd9q8YU6pxqDrfPm1byJJlb7SvAoZfIGQPFk+DF6UVEcWRC0MYRm2bHXlaZwNVpgmFv6ZOVja3jxCJkw8
+2813d406b03607cdb8c06cb04c44efcc9a79d9a2 0 iQJJBAABCgAzFiEEgY2HzRrBgMOUyG5jOjPeRg2ew58FAmESg/wVHDc4OTVwdWxraXRAZ21haWwuY29tAAoJEDoz3kYNnsOf6kAP/1w3elvhAYQcK9hkEVCg4sQgnvcatOafCNaK0dVW9OOFbt+8DNUcHbtUHZtR6ETmSAMlWilIr/1vRMjy0Zic6afJ30oq8i+4f6DgLyTsLQL/QdwJQIwi2fZmHebv1PSrhT9tJAwtH6oG3cNhSq8KMme4l7sVR7ekB34Cmzk3fa5udMOuQG9xWbGTmeEsx0kYb+1oag+NnnZJqVTi68gGGxRW8TYZ1APXJcrZVfkldtaIWx6U1UdkWSTqWHV4fnnctp/1M+IgXCLT0iupY5LnxqGKQcMte7WKRPPdfhGF1ta+LN+QPHbwXhDRDIWPBVbDeHxjKcjz3h+DOeF0b7c5vKDADgo9LtHui9QhBJiCDHwsM+8gA+kNEDbtvIYYQ6CLxX9m1TttxI4ASIzFGIQF6nBr3mjQCzmOoWtgVh7R4dsQ9YZgm4twjsIg3g0MDhmgs71jn6Gp4BficF25nY8J6Ct8YopkPs2sfiBYJmyh9NJLDjwqNnjq3MBervPX3B+7p1dfIsK4JoSuop5A4lc4OOEhrwm5BKIxm30R4NtB15RZ7nI0DcRFcwNQiTYPG+nOaPsFzeZD6lj8+YnuLyo2aCnf4K26/1YTlE1wOFkCb1reL99++i8FP94poHBKZ7+6HT6gk4Mmnfb52II4yWlh/CYLeKEzFFfAiOTvfhzpIvqg
+53221078e0de65d1a821ce5311dec45a7a978301 0 iQJJBAABCgAzFiEEgY2HzRrBgMOUyG5jOjPeRg2ew58FAmEeqLUVHDc4OTVwdWxraXRAZ21haWwuY29tAAoJEDoz3kYNnsOfMb4P/R4oPBjSKrlGbuxYClNdP0lV4C1NUU1SPa+Il4QwGQteKD+RDfvp8z8+c45rVIEGiUNzaSJP/ZEyhBVW657rYzIhBnZgqnpwBzOViqe4Q3lHiq6wPKjEDIRJafcqMb6MaViPS6iRn6hhMlAcPcoabwhXrUgv8QyxVSTFlJm0RGbUVekQLIWKEAnwcWLHKt0d2DrB0/706xXtKxdJ8N/2WCVOOkr7UvpdLXo3quOz1S930/o1iF/csggsi9q4oZYj2XBdBGHayoqkhKAQMyBfXH19RqW3SWZafY8whrZDCz+9AAmJJk8hjQl6xrT/ZVweRfqvRoMJBgjQdFTi58wjC8995ZXKEC7jsJCEblyRJkc23opuAArPEkJXLDR+oK1vOfikaRjmQoMPAMDjbxTUyVOuHcX+PxMtq9NAO0MKcnSr+D2Xc28TGY9PkBhRkEnN3nlZH5z7DvF8GfOnUt5SGhFiQHhXnL6jDBCQVDKAoCJn0WKDG9+29I6st2eGEwKaIjZQ9NCtaLASiauopMOyWWbHeM58bCl80TBXuj+3W+mo+zDSLoGwWJc5oFdFpmnGGTQtkxPDiV4ksIgJAMb/KHkGY+RxnEsWgX1VcR2c1sYD4nzOjrt4RuvX1i+cfzRjLOchPiru7BbrBQRTXGhrvNzsS9laTCxCH2oDazIudia4
--- a/.hgtags	Tue Jul 20 17:20:19 2021 +0200
+++ b/.hgtags	Sun Aug 22 16:32:06 2021 -0400
@@ -224,3 +224,7 @@
 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0
 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1
 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8
+411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1
+d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0
+2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1
+53221078e0de65d1a821ce5311dec45a7a978301 5.9
--- a/Makefile	Tue Jul 20 17:20:19 2021 +0200
+++ b/Makefile	Sun Aug 22 16:32:06 2021 -0400
@@ -270,9 +270,27 @@
 pyoxidizer:
 	$(PYOXIDIZER) build --path ./rust/hgcli --release
 
+
+PYOX_DIR=build/pyoxidizer/x86_64-pc-windows-msvc/release/app
+
+# a temporary target to setup all we need for run-tests.py --pyoxidizer
+# (should go away as the run-tests implementation improves
+pyoxidizer-windows-tests: pyoxidizer
+	rm -rf $(PYOX_DIR)/templates
+	cp -ar $(PYOX_DIR)/lib/mercurial/templates $(PYOX_DIR)/templates
+	rm -rf $(PYOX_DIR)/helptext
+	cp -ar $(PYOX_DIR)/lib/mercurial/helptext $(PYOX_DIR)/helptext
+	rm -rf $(PYOX_DIR)/defaultrc
+	cp -ar $(PYOX_DIR)/lib/mercurial/defaultrc $(PYOX_DIR)/defaultrc
+	rm -rf $(PYOX_DIR)/contrib
+	cp -ar contrib $(PYOX_DIR)/contrib
+	rm -rf $(PYOX_DIR)/doc
+	cp -ar doc $(PYOX_DIR)/doc
+
+
 .PHONY: help all local build doc cleanbutpackages clean install install-bin \
 	install-doc install-home install-home-bin install-home-doc \
 	dist dist-notests check tests rust-tests check-code format-c \
-	update-pot pyoxidizer \
+	update-pot pyoxidizer pyoxidizer-windows-tests \
 	$(packaging_targets) \
 	osx
--- a/contrib/check-code.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/contrib/check-code.py	Sun Aug 22 16:32:06 2021 -0400
@@ -340,11 +340,6 @@
         (r'[^\n]\Z', "no trailing newline"),
         (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
         (
-            r'^\s+(self\.)?[A-Za-z][a-z0-9]+[A-Z]\w* = ',
-            "don't use camelcase in identifiers",
-            r'#.*camelcase-required',
-        ),
-        (
             r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
             "linebreak after :",
         ),
--- a/contrib/heptapod-ci.yml	Tue Jul 20 17:20:19 2021 +0200
+++ b/contrib/heptapod-ci.yml	Sun Aug 22 16:32:06 2021 -0400
@@ -10,7 +10,11 @@
     HG_CI_IMAGE_TAG: "latest"
     TEST_HGTESTS_ALLOW_NETIO: "0"
 
+.all_template: &all
+  when: always
+
 .runtests_template: &runtests
+    <<: *all
     stage: tests
     # The runner made a clone as root.
     # We make a new clone owned by user used to run the step.
@@ -38,6 +42,7 @@
         PYTHON: python3
 
 rust-cargo-test-py2: &rust_cargo_test
+    <<: *all
     stage: tests
     script:
         - echo "python used, $PYTHON"
@@ -50,6 +55,7 @@
         PYTHON: python3
 
 phabricator-refresh:
+    <<: *all
     stage: phabricator
     variables:
       DEFAULT_COMMENT: ":white_check_mark: refresh by Heptapod after a successful CI run (:octopus: :green_heart:)"
@@ -128,7 +134,6 @@
 
 check-pytype-py3:
     extends: .runtests_template
-    when: manual
     before_script:
       - hg clone . /tmp/mercurial-ci/ --noupdate --config phases.publish=no
       - hg -R /tmp/mercurial-ci/ update `hg log --rev '.' --template '{node}'`
@@ -137,6 +142,7 @@
       - $PYTHON -m pip install --user -U pytype==2021.04.15
     variables:
         RUNTEST_ARGS: " --allow-slow-tests tests/test-check-pytype.t"
+        HGTEST_TIMEOUT: "3600"
         PYTHON: python3
         TEST_HGMODULEPOLICY: "c"
 
@@ -146,11 +152,10 @@
 # run-tests.py- it is needed to make run-tests.py generate a `python3` script
 # that satisfies the various shebang lines and delegates to `py -3`.
 .window_runtests_template: &windows_runtests
+    <<: *all
     stage: tests
     before_script:
-      # Temporary until this is adjusted in the environment
-      - $Env:TEMP="C:/Temp"
-      - $Env:TMP="C:/Temp"
+      - C:/MinGW/msys/1.0/bin/sh.exe --login -c 'cd "$OLDPWD" && ls -1 tests/test-check-*.* > C:/Temp/check-tests.txt'
       # TODO: find/install cvs, bzr, perforce, gpg, sqlite3
 
     script:
@@ -159,16 +164,25 @@
         - Invoke-Expression "$Env:PYTHON -V"
         - Invoke-Expression "$Env:PYTHON -m black --version"
         - echo "$Env:RUNTEST_ARGS"
+        - echo "$Env:TMP"
+        - echo "$Env:TEMP"
 
         - C:/MinGW/msys/1.0/bin/sh.exe --login -c 'cd "$OLDPWD" && HGTESTS_ALLOW_NETIO="$TEST_HGTESTS_ALLOW_NETIO" HGMODULEPOLICY="$TEST_HGMODULEPOLICY" $PYTHON tests/run-tests.py --color=always $RUNTEST_ARGS'
 
 windows-py3:
     <<: *windows_runtests
-    when: manual
     tags:
       - windows
-    timeout: 2h
     variables:
         TEST_HGMODULEPOLICY: "c"
-        RUNTEST_ARGS: "--blacklist /tmp/check-tests.txt"
+        RUNTEST_ARGS: "--blacklist C:/Temp/check-tests.txt"
         PYTHON: py -3
+
+windows-py3-pyox:
+    <<: *windows_runtests
+    tags:
+      - windows
+    variables:
+        TEST_HGMODULEPOLICY: "c"
+        RUNTEST_ARGS: "--blacklist C:/Temp/check-tests.txt --pyoxidized"
+        PYTHON: py -3
--- a/contrib/import-checker.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/contrib/import-checker.py	Sun Aug 22 16:32:06 2021 -0400
@@ -278,6 +278,8 @@
         ):
             continue
         for top, dirs, files in os.walk(libpath):
+            if 'dist-packages' in top.split(os.path.sep):
+                continue
             for i, d in reversed(list(enumerate(dirs))):
                 if (
                     not os.path.exists(os.path.join(top, d, '__init__.py'))
--- a/contrib/install-windows-dependencies.ps1	Tue Jul 20 17:20:19 2021 +0200
+++ b/contrib/install-windows-dependencies.ps1	Sun Aug 22 16:32:06 2021 -0400
@@ -19,14 +19,6 @@
 $VS_BUILD_TOOLS_URL = "https://download.visualstudio.microsoft.com/download/pr/a1603c02-8a66-4b83-b821-811e3610a7c4/aa2db8bb39e0cbd23e9940d8951e0bc3/vs_buildtools.exe"
 $VS_BUILD_TOOLS_SHA256 = "911E292B8E6E5F46CBC17003BDCD2D27A70E616E8D5E6E69D5D489A605CAA139"
 
-$VC9_PYTHON_URL = "https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi"
-$VC9_PYTHON_SHA256 = "070474db76a2e625513a5835df4595df9324d820f9cc97eab2a596dcbc2f5cbf"
-
-$PYTHON27_x64_URL = "https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi"
-$PYTHON27_x64_SHA256 = "b74a3afa1e0bf2a6fc566a7b70d15c9bfabba3756fb077797d16fffa27800c05"
-$PYTHON27_X86_URL = "https://www.python.org/ftp/python/2.7.18/python-2.7.18.msi"
-$PYTHON27_X86_SHA256 = "d901802e90026e9bad76b8a81f8dd7e43c7d7e8269d9281c9e9df7a9c40480a9"
-
 $PYTHON37_x86_URL = "https://www.python.org/ftp/python/3.7.9/python-3.7.9.exe"
 $PYTHON37_x86_SHA256 = "769bb7c74ad1df6d7d74071cc16a984ff6182e4016e11b8949b93db487977220"
 $PYTHON37_X64_URL = "https://www.python.org/ftp/python/3.7.9/python-3.7.9-amd64.exe"
@@ -46,18 +38,15 @@
 $PIP_URL = "https://github.com/pypa/get-pip/raw/309a56c5fd94bd1134053a541cb4657a4e47e09d/get-pip.py"
 $PIP_SHA256 = "57e3643ff19f018f8a00dfaa6b7e4620e3c1a7a2171fd218425366ec006b3bfe"
 
-$VIRTUALENV_URL = "https://files.pythonhosted.org/packages/66/f0/6867af06d2e2f511e4e1d7094ff663acdebc4f15d4a0cb0fed1007395124/virtualenv-16.7.5.tar.gz"
-$VIRTUALENV_SHA256 = "f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2"
-
 $INNO_SETUP_URL = "http://files.jrsoftware.org/is/5/innosetup-5.6.1-unicode.exe"
 $INNO_SETUP_SHA256 = "27D49E9BC769E9D1B214C153011978DB90DC01C2ACD1DDCD9ED7B3FE3B96B538"
 
 $MINGW_BIN_URL = "https://osdn.net/frs/redir.php?m=constant&f=mingw%2F68260%2Fmingw-get-0.6.3-mingw32-pre-20170905-1-bin.zip"
 $MINGW_BIN_SHA256 = "2AB8EFD7C7D1FC8EAF8B2FA4DA4EEF8F3E47768284C021599BC7435839A046DF"
 
-$MERCURIAL_WHEEL_FILENAME = "mercurial-5.1.2-cp27-cp27m-win_amd64.whl"
-$MERCURIAL_WHEEL_URL = "https://files.pythonhosted.org/packages/6d/47/e031e47f7fe9b16e4e3383da47e2b0a7eae6e603996bc67a03ec4fa1b3f4/$MERCURIAL_WHEEL_FILENAME"
-$MERCURIAL_WHEEL_SHA256 = "1d18c7f6ca1456f0f62ee65c9a50c14cbba48ce6e924930cdb10537f5c9eaf5f"
+$MERCURIAL_WHEEL_FILENAME = "mercurial-5.8.1-cp39-cp39-win_amd64.whl"
+$MERCURIAL_WHEEL_URL = "https://files.pythonhosted.org/packages/5c/b5/a5fa664761eef29b6c90eb24cb09ab8fe2c9b4b86af41d42c17476aff29b/$MERCURIAL_WHEEL_FILENAME"
+$MERCURIAL_WHEEL_SHA256 = "cbf3efa68fd7ebf94691bd00d2c86bbd47ca73620c8faa4f18b6c394bf5f82b0"
 
 $RUSTUP_INIT_URL = "https://static.rust-lang.org/rustup/archive/1.21.1/x86_64-pc-windows-gnu/rustup-init.exe"
 $RUSTUP_INIT_SHA256 = "d17df34ba974b9b19cf5c75883a95475aa22ddc364591d75d174090d55711c72"
@@ -91,6 +80,8 @@
 }
 
 function Invoke-Process($path, $arguments) {
+    echo "$path $arguments"
+
     $p = Start-Process -FilePath $path -ArgumentList $arguments -Wait -PassThru -WindowStyle Hidden
 
     if ($p.ExitCode -ne 0) {
@@ -135,9 +126,6 @@
 
     $pip = "${prefix}\assets\get-pip.py"
 
-    Secure-Download $VC9_PYTHON_URL ${prefix}\assets\VCForPython27.msi $VC9_PYTHON_SHA256
-    Secure-Download $PYTHON27_x86_URL ${prefix}\assets\python27-x86.msi $PYTHON27_x86_SHA256
-    Secure-Download $PYTHON27_x64_URL ${prefix}\assets\python27-x64.msi $PYTHON27_x64_SHA256
     Secure-Download $PYTHON37_x86_URL ${prefix}\assets\python37-x86.exe $PYTHON37_x86_SHA256
     Secure-Download $PYTHON37_x64_URL ${prefix}\assets\python37-x64.exe $PYTHON37_x64_SHA256
     Secure-Download $PYTHON38_x86_URL ${prefix}\assets\python38-x86.exe $PYTHON38_x86_SHA256
@@ -145,7 +133,6 @@
     Secure-Download $PYTHON39_x86_URL ${prefix}\assets\python39-x86.exe $PYTHON39_x86_SHA256
     Secure-Download $PYTHON39_x64_URL ${prefix}\assets\python39-x64.exe $PYTHON39_x64_SHA256
     Secure-Download $PIP_URL ${pip} $PIP_SHA256
-    Secure-Download $VIRTUALENV_URL ${prefix}\assets\virtualenv.tar.gz $VIRTUALENV_SHA256
     Secure-Download $VS_BUILD_TOOLS_URL ${prefix}\assets\vs_buildtools.exe $VS_BUILD_TOOLS_SHA256
     Secure-Download $INNO_SETUP_URL ${prefix}\assets\InnoSetup.exe $INNO_SETUP_SHA256
     Secure-Download $MINGW_BIN_URL ${prefix}\assets\mingw-get-bin.zip $MINGW_BIN_SHA256
@@ -153,20 +140,10 @@
     Secure-Download $RUSTUP_INIT_URL ${prefix}\assets\rustup-init.exe $RUSTUP_INIT_SHA256
     Secure-Download $PYOXIDIZER_URL ${prefix}\assets\PyOxidizer.msi $PYOXIDIZER_SHA256
 
-    Write-Output "installing Python 2.7 32-bit"
-    Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x86.msi /l* ${prefix}\assets\python27-x86.log /q TARGETDIR=${prefix}\python27-x86 ALLUSERS="
-    Invoke-Process ${prefix}\python27-x86\python.exe ${prefix}\assets\get-pip.py
-    Invoke-Process ${prefix}\python27-x86\Scripts\pip.exe "install ${prefix}\assets\virtualenv.tar.gz"
-
-    Write-Output "installing Python 2.7 64-bit"
-    Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x64.msi /l* ${prefix}\assets\python27-x64.log /q TARGETDIR=${prefix}\python27-x64 ALLUSERS="
-    Invoke-Process ${prefix}\python27-x64\python.exe ${prefix}\assets\get-pip.py
-    Invoke-Process ${prefix}\python27-x64\Scripts\pip.exe "install ${prefix}\assets\virtualenv.tar.gz"
-
     Install-Python3 "Python 3.7 32-bit" ${prefix}\assets\python37-x86.exe ${prefix}\python37-x86 ${pip}
     Install-Python3 "Python 3.7 64-bit" ${prefix}\assets\python37-x64.exe ${prefix}\python37-x64 ${pip}
     Install-Python3 "Python 3.8 32-bit" ${prefix}\assets\python38-x86.exe ${prefix}\python38-x86 ${pip}
-    Install-Python3 "Python 3.8 64-bit" ${prefix}\assets\python38-x64.exe ${prefix}\python38-x64 ${pip}
+#    Install-Python3 "Python 3.8 64-bit" ${prefix}\assets\python38-x64.exe ${prefix}\python38-x64 ${pip}
     Install-Python3 "Python 3.9 32-bit" ${prefix}\assets\python39-x86.exe ${prefix}\python39-x86 ${pip}
     Install-Python3 "Python 3.9 64-bit" ${prefix}\assets\python39-x64.exe ${prefix}\python39-x64 ${pip}
 
@@ -178,9 +155,6 @@
 
     Install-Rust ${prefix}
 
-    Write-Output "installing Visual C++ 9.0 for Python 2.7"
-    Invoke-Process msiexec.exe "/i ${prefix}\assets\VCForPython27.msi /l* ${prefix}\assets\VCForPython27.log /q"
-
     Write-Output "installing Inno Setup"
     Invoke-Process ${prefix}\assets\InnoSetup.exe "/SP- /VERYSILENT /SUPPRESSMSGBOXES"
 
@@ -196,7 +170,7 @@
     # Construct a virtualenv useful for bootstrapping. It conveniently contains a
     # Mercurial install.
     Write-Output "creating bootstrap virtualenv with Mercurial"
-    Invoke-Process "$prefix\python27-x64\Scripts\virtualenv.exe" "${prefix}\venv-bootstrap"
+    Invoke-Process "$prefix\python39-x64\python.exe" "-m venv ${prefix}\venv-bootstrap"
     Invoke-Process "${prefix}\venv-bootstrap\Scripts\pip.exe" "install ${prefix}\assets\${MERCURIAL_WHEEL_FILENAME}"
 }
 
@@ -204,7 +178,7 @@
     Write-Output "cloning $repo_url to $dest"
     # TODO Figure out why CA verification isn't working in EC2 and remove
     # --insecure.
-    Invoke-Process "${prefix}\venv-bootstrap\Scripts\hg.exe" "clone --insecure $repo_url $dest"
+    Invoke-Process "${prefix}\venv-bootstrap\Scripts\python.exe" "${prefix}\venv-bootstrap\Scripts\hg clone --insecure $repo_url $dest"
 
     # Mark repo as non-publishing by default for convenience.
     Add-Content -Path "$dest\.hg\hgrc" -Value "`n[phases]`npublish = false"
--- a/contrib/packaging/requirements-windows-py3.txt	Tue Jul 20 17:20:19 2021 +0200
+++ b/contrib/packaging/requirements-windows-py3.txt	Sun Aug 22 16:32:06 2021 -0400
@@ -4,6 +4,14 @@
 #
 #    pip-compile --generate-hashes --output-file=contrib/packaging/requirements-windows-py3.txt contrib/packaging/requirements-windows.txt.in
 #
+atomicwrites==1.4.0 \
+    --hash=sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197 \
+    --hash=sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a \
+    # via pytest
+attrs==21.2.0 \
+    --hash=sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1 \
+    --hash=sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb \
+    # via pytest
 cached-property==1.5.2 \
     --hash=sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130 \
     --hash=sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0 \
@@ -48,6 +56,10 @@
     --hash=sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b \
     --hash=sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f \
     # via pygit2
+colorama==0.4.4 \
+    --hash=sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b \
+    --hash=sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2 \
+    # via pytest
 docutils==0.16 \
     --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \
     --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc \
@@ -67,14 +79,76 @@
     --hash=sha256:e5871b86a079e9e290f52ab14559cea1b694a0b8ed2b9ebb898f6ced7f14a406 \
     --hash=sha256:e593f514b8ac740b4ceeb047745b4719bfc9f334904245c6edcb3a9d002f577b \
     # via -r contrib/packaging/requirements-windows.txt.in
+fuzzywuzzy==0.18.0 \
+    --hash=sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8 \
+    # via -r contrib/packaging/requirements-windows.txt.in
+idna==3.2 \
+    --hash=sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a \
+    --hash=sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3 \
+    # via yarl
 importlib-metadata==3.1.0 \
     --hash=sha256:590690d61efdd716ff82c39ca9a9d4209252adfe288a4b5721181050acbd4175 \
     --hash=sha256:d9b8a46a0885337627a6430db287176970fff18ad421becec1d64cfc763c2099 \
-    # via keyring
+    # via keyring, pluggy, pytest
+iniconfig==1.1.1 \
+    --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \
+    --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32 \
+    # via pytest
 keyring==21.4.0 \
     --hash=sha256:4e34ea2fdec90c1c43d6610b5a5fafa1b9097db1802948e90caf5763974b8f8d \
     --hash=sha256:9aeadd006a852b78f4b4ef7c7556c2774d2432bbef8ee538a3e9089ac8b11466 \
     # via -r contrib/packaging/requirements-windows.txt.in
+multidict==5.1.0 \
+    --hash=sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a \
+    --hash=sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93 \
+    --hash=sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632 \
+    --hash=sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656 \
+    --hash=sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79 \
+    --hash=sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7 \
+    --hash=sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d \
+    --hash=sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5 \
+    --hash=sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224 \
+    --hash=sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26 \
+    --hash=sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea \
+    --hash=sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348 \
+    --hash=sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6 \
+    --hash=sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76 \
+    --hash=sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1 \
+    --hash=sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f \
+    --hash=sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952 \
+    --hash=sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a \
+    --hash=sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37 \
+    --hash=sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9 \
+    --hash=sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359 \
+    --hash=sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8 \
+    --hash=sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da \
+    --hash=sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3 \
+    --hash=sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d \
+    --hash=sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf \
+    --hash=sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841 \
+    --hash=sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d \
+    --hash=sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93 \
+    --hash=sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f \
+    --hash=sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647 \
+    --hash=sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635 \
+    --hash=sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456 \
+    --hash=sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda \
+    --hash=sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5 \
+    --hash=sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281 \
+    --hash=sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80 \
+    # via yarl
+packaging==21.0 \
+    --hash=sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7 \
+    --hash=sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14 \
+    # via pytest
+pluggy==0.13.1 \
+    --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \
+    --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d \
+    # via pytest
+py==1.10.0 \
+    --hash=sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3 \
+    --hash=sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a \
+    # via pytest
 pycparser==2.20 \
     --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \
     --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 \
@@ -102,14 +176,73 @@
     --hash=sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998 \
     --hash=sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7 \
     # via -r contrib/packaging/requirements-windows.txt.in
+pyparsing==2.4.7 \
+    --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \
+    --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b \
+    # via packaging
+pytest-vcr==1.0.2 \
+    --hash=sha256:23ee51b75abbcc43d926272773aae4f39f93aceb75ed56852d0bf618f92e1896 \
+    # via -r contrib/packaging/requirements-windows.txt.in
+pytest==6.2.4 \
+    --hash=sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b \
+    --hash=sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890 \
+    # via pytest-vcr
 pywin32-ctypes==0.2.0 \
     --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
     --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \
     # via -r contrib/packaging/requirements-windows.txt.in, keyring
+pyyaml==5.4.1 \
+    --hash=sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf \
+    --hash=sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696 \
+    --hash=sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393 \
+    --hash=sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77 \
+    --hash=sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922 \
+    --hash=sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5 \
+    --hash=sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8 \
+    --hash=sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10 \
+    --hash=sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc \
+    --hash=sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018 \
+    --hash=sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e \
+    --hash=sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253 \
+    --hash=sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347 \
+    --hash=sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183 \
+    --hash=sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541 \
+    --hash=sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb \
+    --hash=sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185 \
+    --hash=sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc \
+    --hash=sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db \
+    --hash=sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa \
+    --hash=sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46 \
+    --hash=sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122 \
+    --hash=sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b \
+    --hash=sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63 \
+    --hash=sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df \
+    --hash=sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc \
+    --hash=sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247 \
+    --hash=sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6 \
+    --hash=sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0 \
+    # via vcrpy
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 \
+    # via vcrpy
+toml==0.10.2 \
+    --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \
+    --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f \
+    # via pytest
+typing-extensions==3.10.0.0 \
+    --hash=sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497 \
+    --hash=sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342 \
+    --hash=sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84 \
+    # via yarl
 urllib3==1.25.11 \
     --hash=sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2 \
     --hash=sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e \
     # via dulwich
+vcrpy==4.1.1 \
+    --hash=sha256:12c3fcdae7b88ecf11fc0d3e6d77586549d4575a2ceee18e82eee75c1f626162 \
+    --hash=sha256:57095bf22fc0a2d99ee9674cdafebed0f3ba763018582450706f7d3a74fff599 \
+    # via pytest-vcr
 windows-curses==2.2.0 \
     --hash=sha256:1452d771ec6f9b3fef037da2b169196a9a12be4e86a6c27dd579adac70c42028 \
     --hash=sha256:267544e4f60c09af6505e50a69d7f01d7f8a281cf4bd4fc7efc3b32b9a4ef64e \
@@ -120,6 +253,48 @@
     --hash=sha256:c5cd032bc7d0f03224ab55c925059d98e81795098d59bbd10f7d05c7ea9677ce \
     --hash=sha256:fc0be372fe6da3c39d7093154ce029115a927bf287f34b4c615e2b3f8c23dfaa \
     # via -r contrib/packaging/requirements-windows.txt.in
+wrapt==1.12.1 \
+    --hash=sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7 \
+    # via vcrpy
+yarl==1.6.3 \
+    --hash=sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e \
+    --hash=sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434 \
+    --hash=sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366 \
+    --hash=sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3 \
+    --hash=sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec \
+    --hash=sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959 \
+    --hash=sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e \
+    --hash=sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c \
+    --hash=sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6 \
+    --hash=sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a \
+    --hash=sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6 \
+    --hash=sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424 \
+    --hash=sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e \
+    --hash=sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f \
+    --hash=sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50 \
+    --hash=sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2 \
+    --hash=sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc \
+    --hash=sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4 \
+    --hash=sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970 \
+    --hash=sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10 \
+    --hash=sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0 \
+    --hash=sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406 \
+    --hash=sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896 \
+    --hash=sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643 \
+    --hash=sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721 \
+    --hash=sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478 \
+    --hash=sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724 \
+    --hash=sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e \
+    --hash=sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8 \
+    --hash=sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96 \
+    --hash=sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25 \
+    --hash=sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76 \
+    --hash=sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2 \
+    --hash=sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2 \
+    --hash=sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c \
+    --hash=sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a \
+    --hash=sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71 \
+    # via vcrpy
 zipp==3.4.0 \
     --hash=sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108 \
     --hash=sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb \
--- a/contrib/packaging/requirements-windows.txt.in	Tue Jul 20 17:20:19 2021 +0200
+++ b/contrib/packaging/requirements-windows.txt.in	Sun Aug 22 16:32:06 2021 -0400
@@ -2,9 +2,17 @@
 # Pinned to an old version because 0.20 drops Python 3 compatibility.
 dulwich < 0.20 ; python_version <= '2.7'
 dulwich ; python_version >= '3'
+
+# Needed by the release note tooling
+fuzzywuzzy
+
 keyring
 pygit2 ; python_version >= '3'
 pygments
+
+# Needed by the phabricator tests
+pytest-vcr
+
 # Need to list explicitly so dependency gets pulled in when
 # not running on Windows.
 pywin32-ctypes
--- a/hgext/fix.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/hgext/fix.py	Sun Aug 22 16:32:06 2021 -0400
@@ -132,6 +132,7 @@
 
 from mercurial.i18n import _
 from mercurial.node import (
+    nullid,
     nullrev,
     wdirrev,
 )
@@ -751,16 +752,17 @@
 
     Directly updates the dirstate for the affected files.
     """
+    assert repo.dirstate.p2() == nullid
+
     for path, data in pycompat.iteritems(filedata):
         fctx = ctx[path]
         fctx.write(data, fctx.flags())
-        if repo.dirstate[path] == b'n':
-            repo.dirstate.set_possibly_dirty(path)
 
-    oldparentnodes = repo.dirstate.parents()
-    newparentnodes = [replacements.get(n, n) for n in oldparentnodes]
-    if newparentnodes != oldparentnodes:
-        repo.setparents(*newparentnodes)
+    oldp1 = repo.dirstate.p1()
+    newp1 = replacements.get(oldp1, oldp1)
+    if newp1 != oldp1:
+        with repo.dirstate.parentchange():
+            scmutil.movedirstate(repo, repo[newp1])
 
 
 def replacerev(ui, repo, ctx, filedata, replacements):
--- a/hgext/git/dirstate.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/hgext/git/dirstate.py	Sun Aug 22 16:32:06 2021 -0400
@@ -74,6 +74,8 @@
         self._root = os.path.dirname(root)
         self.git = gitrepo
         self._plchangecallbacks = {}
+        # TODO: context.poststatusfixup is bad and uses this attribute
+        self._dirty = False
 
     def p1(self):
         try:
@@ -255,12 +257,12 @@
             if match(p):
                 yield p
 
-    def normal(self, f, parentfiledata=None):
+    def set_clean(self, f, parentfiledata=None):
         """Mark a file normal and clean."""
         # TODO: for now we just let libgit2 re-stat the file. We can
         # clearly do better.
 
-    def normallookup(self, f):
+    def set_possibly_dirty(self, f):
         """Mark a file normal, but possibly dirty."""
         # TODO: for now we just let libgit2 re-stat the file. We can
         # clearly do better.
@@ -296,6 +298,16 @@
         # TODO: figure out a strategy for saving index backups.
         pass
 
+    def set_tracked(self, f):
+        uf = pycompat.fsdecode(f)
+        if uf in self.git.index:
+            return False
+        index = self.git.index
+        index.read()
+        index.add(uf)
+        index.write()
+        return True
+
     def add(self, f):
         index = self.git.index
         index.read()
@@ -310,6 +322,16 @@
             index.remove(fs)
             index.write()
 
+    def set_untracked(self, f):
+        index = self.git.index
+        index.read()
+        fs = pycompat.fsdecode(f)
+        if fs in index:
+            index.remove(fs)
+            index.write()
+            return True
+        return False
+
     def remove(self, f):
         index = self.git.index
         index.read()
@@ -324,6 +346,10 @@
         # TODO
         pass
 
+    def update_file(self, *args, **kwargs):
+        # TODO
+        pass
+
     @contextlib.contextmanager
     def parentchange(self):
         # TODO: track this maybe?
--- a/hgext/releasenotes.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/hgext/releasenotes.py	Sun Aug 22 16:32:06 2021 -0400
@@ -39,9 +39,22 @@
 command = registrar.command(cmdtable)
 
 try:
-    import fuzzywuzzy.fuzz as fuzz
+    # Silence a warning about python-Levenshtein.
+    #
+    # We don't need the the performance that much and it get anoying in tests.
+    import warnings
 
-    fuzz.token_set_ratio
+    with warnings.catch_warnings():
+        warnings.filterwarnings(
+            action="ignore",
+            message=".*python-Levenshtein.*",
+            category=UserWarning,
+            module="fuzzywuzzy.fuzz",
+        )
+
+        import fuzzywuzzy.fuzz as fuzz
+
+        fuzz.token_set_ratio
 except ImportError:
     fuzz = None
 
--- a/hgext/remotefilelog/remotefilelogserver.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/hgext/remotefilelog/remotefilelogserver.py	Sun Aug 22 16:32:06 2021 -0400
@@ -186,7 +186,7 @@
                         yield (t, u, e, s)
 
             for x in repo.store.topfiles():
-                if state.noflatmf and x[0][:11] == b'00manifest.':
+                if state.noflatmf and x[1][:11] == b'00manifest.':
                     continue
                 yield x
 
--- a/mercurial/commands.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/commands.py	Sun Aug 22 16:32:06 2021 -0400
@@ -75,12 +75,6 @@
     urlutil,
 )
 
-if pycompat.TYPE_CHECKING:
-    from typing import (
-        List,
-    )
-
-
 table = {}
 table.update(debugcommandsmod.command._table)
 
@@ -3341,7 +3335,8 @@
                 )
             # checking that newnodes exist because old state files won't have it
             elif statedata.get(b'newnodes') is not None:
-                nn = statedata[b'newnodes']  # type: List[bytes]
+                nn = statedata[b'newnodes']
+                assert isinstance(nn, list)  # list of bytes
                 nn.append(node)
 
     # remove state when we complete successfully
--- a/mercurial/configitems.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/configitems.py	Sun Aug 22 16:32:06 2021 -0400
@@ -1897,6 +1897,11 @@
     default=True,
     alias=[(b'format', b'aggressivemergedeltas')],
 )
+coreconfigitem(
+    b'storage',
+    b'revlog.issue6528.fix-incoming',
+    default=True,
+)
 # experimental as long as rust is experimental (or a C version is implemented)
 coreconfigitem(
     b'storage',
--- a/mercurial/debugcommands.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/debugcommands.py	Sun Aug 22 16:32:06 2021 -0400
@@ -71,6 +71,7 @@
     registrar,
     repair,
     repoview,
+    requirements,
     revlog,
     revset,
     revsetlang,
@@ -105,6 +106,7 @@
 from .revlogutils import (
     deltas as deltautil,
     nodemap,
+    rewrite,
     sidedata,
 )
 
@@ -1451,6 +1453,80 @@
         ui.write(b"%s\n" % f)
 
 
+@command(
+    b"debug-repair-issue6528",
+    [
+        (
+            b'',
+            b'to-report',
+            b'',
+            _(b'build a report of affected revisions to this file'),
+            _(b'FILE'),
+        ),
+        (
+            b'',
+            b'from-report',
+            b'',
+            _(b'repair revisions listed in this report file'),
+            _(b'FILE'),
+        ),
+        (
+            b'',
+            b'paranoid',
+            False,
+            _(b'check that both detection methods do the same thing'),
+        ),
+    ]
+    + cmdutil.dryrunopts,
+)
+def debug_repair_issue6528(ui, repo, **opts):
+    """find affected revisions and repair them. See issue6528 for more details.
+
+    The `--to-report` and `--from-report` flags allow you to cache and reuse the
+    computation of affected revisions for a given repository across clones.
+    The report format is line-based (with empty lines ignored):
+
+    ```
+    <ascii-hex of the affected revision>,... <unencoded filelog index filename>
+    ```
+
+    There can be multiple broken revisions per filelog, they are separated by
+    a comma with no spaces. The only space is between the revision(s) and the
+    filename.
+
+    Note that this does *not* mean that this repairs future affected revisions,
+    that needs a separate fix at the exchange level that hasn't been written yet
+    (as of 5.9rc0).
+
+    There is a `--paranoid` flag to test that the fast implementation is correct
+    by checking it against the slow implementation. Since this matter is quite
+    urgent and testing every edge-case is probably quite costly, we use this
+    method to test on large repositories as a fuzzing method of sorts.
+    """
+    cmdutil.check_incompatible_arguments(
+        opts, 'to_report', ['from_report', 'dry_run']
+    )
+    dry_run = opts.get('dry_run')
+    to_report = opts.get('to_report')
+    from_report = opts.get('from_report')
+    paranoid = opts.get('paranoid')
+    # TODO maybe add filelog pattern and revision pattern parameters to help
+    # narrow down the search for users that know what they're looking for?
+
+    if requirements.REVLOGV1_REQUIREMENT not in repo.requirements:
+        msg = b"can only repair revlogv1 repositories, v2 is not affected"
+        raise error.Abort(_(msg))
+
+    rewrite.repair_issue6528(
+        ui,
+        repo,
+        dry_run=dry_run,
+        to_report=to_report,
+        from_report=from_report,
+        paranoid=paranoid,
+    )
+
+
 @command(b'debugformat', [] + cmdutil.formatteropts)
 def debugformat(ui, repo, **opts):
     """display format information about the current repository
--- a/mercurial/dirstate.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/dirstate.py	Sun Aug 22 16:32:06 2021 -0400
@@ -599,7 +599,7 @@
 
         This function must be called within a `dirstate.parentchange` context.
 
-        note: the API is at an early stage and we might need to ajust it
+        note: the API is at an early stage and we might need to adjust it
         depending of what information ends up being relevant and useful to
         other processing.
         """
@@ -828,7 +828,7 @@
             )
         else:
             util.nouideprecwarn(
-                b"do not use `remove` outside of update/merge context."
+                b"do not use `add` outside of update/merge context."
                 b" Use `set_tracked`",
                 b'6.0',
                 stacklevel=2,
--- a/mercurial/filelog.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/filelog.py	Sun Aug 22 16:32:06 2021 -0400
@@ -20,6 +20,7 @@
 from .utils import storageutil
 from .revlogutils import (
     constants as revlog_constants,
+    rewrite,
 )
 
 
@@ -37,6 +38,8 @@
         # Used by LFS.
         self._revlog.filename = path
         self.nullid = self._revlog.nullid
+        opts = opener.options
+        self._fix_issue6528 = opts.get(b'issue6528.fix-incoming', True)
 
     def __len__(self):
         return len(self._revlog)
@@ -157,13 +160,18 @@
                 )
             )
 
-        return self._revlog.addgroup(
-            deltas,
-            linkmapper,
-            transaction,
-            addrevisioncb=addrevisioncb,
-            duplicaterevisioncb=duplicaterevisioncb,
-        )
+        with self._revlog._writing(transaction):
+
+            if self._fix_issue6528:
+                deltas = rewrite.filter_delta_issue6528(self._revlog, deltas)
+
+            return self._revlog.addgroup(
+                deltas,
+                linkmapper,
+                transaction,
+                addrevisioncb=addrevisioncb,
+                duplicaterevisioncb=duplicaterevisioncb,
+            )
 
     def getstrippoint(self, minlink):
         return self._revlog.getstrippoint(minlink)
--- a/mercurial/helptext/config.txt	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/helptext/config.txt	Sun Aug 22 16:32:06 2021 -0400
@@ -906,13 +906,21 @@
     with the Rust part  might actually suffer some slowdown. For this reason,
     Such version will by default refuse to access such repositories. That
     behavior can be controlled by configuration. Check
-    :hg:`help config.storage.revlog.persistent-nodemap.slowpath` for details.
+    :hg:`help config.storage.revlog.persistent-nodemap.slow-path` for details.
 
     Repository with this on-disk format require Mercurial version 5.4 or above.
 
     By default this format variant is disabled if fast implementation is not
     available and enabled by default if the fast implementation is available.
 
+    To accomodate install of Mercurial without the fast implementation you can
+    downgrade your repository. To do so run the following command:
+
+    $ hg debugupgraderepo \
+          --run \
+          --config format.use-persistent-nodemap=False \
+          --config storage.revlog.persistent-nodemap.slow-path=allow
+
 ``use-share-safe``
     Enforce "safe" behaviors for all "shares" that access this repository.
 
@@ -1838,7 +1846,7 @@
     ``json``
       Render profiling data as JSON.
 
-``frequency``
+``freq``
     Sampling frequency.  Specific to the ``stat`` sampling profiler.
     (default: 1000)
 
@@ -2035,6 +2043,21 @@
 Control the strategy Mercurial uses internally to store history. Options in this
 category impact performance and repository size.
 
+``revlog.issue6528.fix-incoming``
+    Version 5.8 of Mercurial had a bug leading to altering the parent of file
+    revision with copy information (or any other metadata) on exchange. This
+    leads to the copy metadata to be overlooked by various internal logic. The
+    issue was fixed in Mercurial 5.8.1.
+    (See https://bz.mercurial-scm.org/show_bug.cgi?id=6528 for details)
+
+    As a result Mercurial is now checking and fixing incoming file revisions to
+    make sure there parents are in the right order. This behavior can be
+    disabled by setting this option to `no`. This apply to revisions added
+    through push, pull, clone and unbundle.
+
+    To fix affected revisions that already exist within the repository, one can
+    use :hg:`debug-repair-issue-6528`.
+
 ``revlog.optimize-delta-parent-choice``
     When storing a merge revision, both parents will be equally considered as
     a possible delta base. This results in better delta selection and improved
--- a/mercurial/localrepo.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/localrepo.py	Sun Aug 22 16:32:06 2021 -0400
@@ -1043,6 +1043,9 @@
     )
     options[b'deltabothparents'] = deltabothparents
 
+    issue6528 = ui.configbool(b'storage', b'revlog.issue6528.fix-incoming')
+    options[b'issue6528.fix-incoming'] = issue6528
+
     lazydelta = ui.configbool(b'storage', b'revlog.reuse-external-delta')
     lazydeltabase = False
     if lazydelta:
--- a/mercurial/pycompat.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/pycompat.py	Sun Aug 22 16:32:06 2021 -0400
@@ -40,6 +40,8 @@
     def future_set_exception_info(f, exc_info):
         f.set_exception_info(*exc_info)
 
+    # this is close enough for our usage
+    FileNotFoundError = OSError
 
 else:
     import concurrent.futures as futures
@@ -53,6 +55,8 @@
     def future_set_exception_info(f, exc_info):
         f.set_exception(exc_info[0])
 
+    FileNotFoundError = __builtins__['FileNotFoundError']
+
 
 def identity(a):
     return a
--- a/mercurial/revlog.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/revlog.py	Sun Aug 22 16:32:06 2021 -0400
@@ -897,10 +897,8 @@
             if rev == wdirrev:
                 raise error.WdirUnsupported
             raise
-        if entry[5] == nullrev:
-            return entry[6], entry[5]
-        else:
-            return entry[5], entry[6]
+
+        return entry[5], entry[6]
 
     # fast parentrevs(rev) where rev isn't filtered
     _uncheckedparentrevs = parentrevs
@@ -921,11 +919,7 @@
     def parents(self, node):
         i = self.index
         d = i[self.rev(node)]
-        # inline node() to avoid function call overhead
-        if d[5] == self.nullid:
-            return i[d[6]][7], i[d[5]][7]
-        else:
-            return i[d[5]][7], i[d[6]][7]
+        return i[d[5]][7], i[d[6]][7]  # map revisions to nodes inline
 
     def chainlen(self, rev):
         return self._chaininfo(rev)[0]
@@ -2122,6 +2116,8 @@
                         dfh = self._datafp(b"w+")
                     transaction.add(self._datafile, dsize)
                 if self._sidedatafile is not None:
+                    # revlog-v2 does not inline, help Pytype
+                    assert dfh is not None
                     try:
                         sdfh = self.opener(self._sidedatafile, mode=b"r+")
                         dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
@@ -2584,6 +2580,8 @@
             assert not sidedata
             self._enforceinlinesize(transaction)
         if self._docket is not None:
+            # revlog-v2 always has 3 writing handles, help Pytype
+            assert self._writinghandles[2] is not None
             self._docket.index_end = self._writinghandles[0].tell()
             self._docket.data_end = self._writinghandles[1].tell()
             self._docket.sidedata_end = self._writinghandles[2].tell()
--- a/mercurial/revlogutils/rewrite.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/revlogutils/rewrite.py	Sun Aug 22 16:32:06 2021 -0400
@@ -7,8 +7,10 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+import binascii
 import contextlib
 import os
+import struct
 
 from ..node import (
     nullrev,
@@ -27,6 +29,7 @@
     ENTRY_SIDEDATA_COMPRESSED_LENGTH,
     ENTRY_SIDEDATA_COMPRESSION_MODE,
     ENTRY_SIDEDATA_OFFSET,
+    REVIDX_ISCENSORED,
     REVLOGV0,
     REVLOGV1,
 )
@@ -34,6 +37,7 @@
 
 from .. import (
     error,
+    mdiff,
     pycompat,
     revlogutils,
     util,
@@ -472,3 +476,411 @@
     new_index_file.write(entry_bin)
     revlog._docket.index_end = new_index_file.tell()
     revlog._docket.data_end = new_data_file.tell()
+
+
+def _get_filename_from_filelog_index(path):
+    # Drop the extension and the `data/` prefix
+    path_part = path.rsplit(b'.', 1)[0].split(b'/', 1)
+    if len(path_part) < 2:
+        msg = _(b"cannot recognize filelog from filename: '%s'")
+        msg %= path
+        raise error.Abort(msg)
+
+    return path_part[1]
+
+
+def _filelog_from_filename(repo, path):
+    """Returns the filelog for the given `path`. Stolen from `engine.py`"""
+
+    from .. import filelog  # avoid cycle
+
+    fl = filelog.filelog(repo.svfs, path)
+    return fl
+
+
+def _write_swapped_parents(repo, rl, rev, offset, fp):
+    """Swaps p1 and p2 and overwrites the revlog entry for `rev` in `fp`"""
+    from ..pure import parsers  # avoid cycle
+
+    if repo._currentlock(repo._lockref) is None:
+        # Let's be paranoid about it
+        msg = "repo needs to be locked to rewrite parents"
+        raise error.ProgrammingError(msg)
+
+    index_format = parsers.IndexObject.index_format
+    entry = rl.index[rev]
+    new_entry = list(entry)
+    new_entry[5], new_entry[6] = entry[6], entry[5]
+    packed = index_format.pack(*new_entry[:8])
+    fp.seek(offset)
+    fp.write(packed)
+
+
+def _reorder_filelog_parents(repo, fl, to_fix):
+    """
+    Swaps p1 and p2 for all `to_fix` revisions of filelog `fl` and writes the
+    new version to disk, overwriting the old one with a rename.
+    """
+    from ..pure import parsers  # avoid cycle
+
+    ui = repo.ui
+    assert len(to_fix) > 0
+    rl = fl._revlog
+    if rl._format_version != constants.REVLOGV1:
+        msg = "expected version 1 revlog, got version '%d'" % rl._format_version
+        raise error.ProgrammingError(msg)
+
+    index_file = rl._indexfile
+    new_file_path = index_file + b'.tmp-parents-fix'
+    repaired_msg = _(b"repaired revision %d of 'filelog %s'\n")
+
+    with ui.uninterruptible():
+        try:
+            util.copyfile(
+                rl.opener.join(index_file),
+                rl.opener.join(new_file_path),
+                checkambig=rl._checkambig,
+            )
+
+            with rl.opener(new_file_path, mode=b"r+") as fp:
+                if rl._inline:
+                    index = parsers.InlinedIndexObject(fp.read())
+                    for rev in fl.revs():
+                        if rev in to_fix:
+                            offset = index._calculate_index(rev)
+                            _write_swapped_parents(repo, rl, rev, offset, fp)
+                            ui.write(repaired_msg % (rev, index_file))
+                else:
+                    index_format = parsers.IndexObject.index_format
+                    for rev in to_fix:
+                        offset = rev * index_format.size
+                        _write_swapped_parents(repo, rl, rev, offset, fp)
+                        ui.write(repaired_msg % (rev, index_file))
+
+            rl.opener.rename(new_file_path, index_file)
+            rl.clearcaches()
+            rl._loadindex()
+        finally:
+            util.tryunlink(new_file_path)
+
+
+def _is_revision_affected(fl, filerev, metadata_cache=None):
+    full_text = lambda: fl._revlog.rawdata(filerev)
+    parent_revs = lambda: fl._revlog.parentrevs(filerev)
+    return _is_revision_affected_inner(
+        full_text, parent_revs, filerev, metadata_cache
+    )
+
+
+def _is_revision_affected_inner(
+    full_text,
+    parents_revs,
+    filerev,
+    metadata_cache=None,
+):
+    """Mercurial currently (5.9rc0) uses `p1 == nullrev and p2 != nullrev` as a
+    special meaning compared to the reverse in the context of filelog-based
+    copytracing. issue6528 exists because new code assumed that parent ordering
+    didn't matter, so this detects if the revision contains metadata (since
+    it's only used for filelog-based copytracing) and its parents are in the
+    "wrong" order."""
+    try:
+        raw_text = full_text()
+    except error.CensoredNodeError:
+        # We don't care about censored nodes as they never carry metadata
+        return False
+    has_meta = raw_text.startswith(b'\x01\n')
+    if metadata_cache is not None:
+        metadata_cache[filerev] = has_meta
+    if has_meta:
+        (p1, p2) = parents_revs()
+        if p1 != nullrev and p2 == nullrev:
+            return True
+    return False
+
+
+def _is_revision_affected_fast(repo, fl, filerev, metadata_cache):
+    rl = fl._revlog
+    is_censored = lambda: rl.iscensored(filerev)
+    delta_base = lambda: rl.deltaparent(filerev)
+    delta = lambda: rl._chunk(filerev)
+    full_text = lambda: rl.rawdata(filerev)
+    parent_revs = lambda: rl.parentrevs(filerev)
+    return _is_revision_affected_fast_inner(
+        is_censored,
+        delta_base,
+        delta,
+        full_text,
+        parent_revs,
+        filerev,
+        metadata_cache,
+    )
+
+
+def _is_revision_affected_fast_inner(
+    is_censored,
+    delta_base,
+    delta,
+    full_text,
+    parent_revs,
+    filerev,
+    metadata_cache,
+):
+    """Optimization fast-path for `_is_revision_affected`.
+
+    `metadata_cache` is a dict of `{rev: has_metadata}` which allows any
+    revision to check if its base has metadata, saving computation of the full
+    text, instead looking at the current delta.
+
+    This optimization only works if the revisions are looked at in order."""
+
+    if is_censored():
+        # Censored revisions don't contain metadata, so they cannot be affected
+        metadata_cache[filerev] = False
+        return False
+
+    p1, p2 = parent_revs()
+    if p1 == nullrev or p2 != nullrev:
+        return False
+
+    delta_parent = delta_base()
+    parent_has_metadata = metadata_cache.get(delta_parent)
+    if parent_has_metadata is None:
+        return _is_revision_affected_inner(
+            full_text,
+            parent_revs,
+            filerev,
+            metadata_cache,
+        )
+
+    chunk = delta()
+    if not len(chunk):
+        # No diff for this revision
+        return parent_has_metadata
+
+    header_length = 12
+    if len(chunk) < header_length:
+        raise error.Abort(_(b"patch cannot be decoded"))
+
+    start, _end, _length = struct.unpack(b">lll", chunk[:header_length])
+
+    if start < 2:  # len(b'\x01\n') == 2
+        # This delta does *something* to the metadata marker (if any).
+        # Check it the slow way
+        is_affected = _is_revision_affected_inner(
+            full_text,
+            parent_revs,
+            filerev,
+            metadata_cache,
+        )
+        return is_affected
+
+    # The diff did not remove or add the metadata header, it's then in the same
+    # situation as its parent
+    metadata_cache[filerev] = parent_has_metadata
+    return parent_has_metadata
+
+
+def _from_report(ui, repo, context, from_report, dry_run):
+    """
+    Fix the revisions given in the `from_report` file, but still checks if the
+    revisions are indeed affected to prevent an unfortunate cyclic situation
+    where we'd swap well-ordered parents again.
+
+    See the doc for `debug_fix_issue6528` for the format documentation.
+    """
+    ui.write(_(b"loading report file '%s'\n") % from_report)
+
+    with context(), open(from_report, mode='rb') as f:
+        for line in f.read().split(b'\n'):
+            if not line:
+                continue
+            filenodes, filename = line.split(b' ', 1)
+            fl = _filelog_from_filename(repo, filename)
+            to_fix = set(
+                fl.rev(binascii.unhexlify(n)) for n in filenodes.split(b',')
+            )
+            excluded = set()
+
+            for filerev in to_fix:
+                if _is_revision_affected(fl, filerev):
+                    msg = b"found affected revision %d for filelog '%s'\n"
+                    ui.warn(msg % (filerev, filename))
+                else:
+                    msg = _(b"revision %s of file '%s' is not affected\n")
+                    msg %= (binascii.hexlify(fl.node(filerev)), filename)
+                    ui.warn(msg)
+                    excluded.add(filerev)
+
+            to_fix = to_fix - excluded
+            if not to_fix:
+                msg = _(b"no affected revisions were found for '%s'\n")
+                ui.write(msg % filename)
+                continue
+            if not dry_run:
+                _reorder_filelog_parents(repo, fl, sorted(to_fix))
+
+
+def filter_delta_issue6528(revlog, deltas_iter):
+    """filter incomind deltas to repaire issue 6528 on the fly"""
+    metadata_cache = {}
+
+    deltacomputer = deltas.deltacomputer(revlog)
+
+    for rev, d in enumerate(deltas_iter, len(revlog)):
+        (
+            node,
+            p1_node,
+            p2_node,
+            linknode,
+            deltabase,
+            delta,
+            flags,
+            sidedata,
+        ) = d
+
+        if not revlog.index.has_node(deltabase):
+            raise error.LookupError(
+                deltabase, revlog.radix, _(b'unknown parent')
+            )
+        base_rev = revlog.rev(deltabase)
+        if not revlog.index.has_node(p1_node):
+            raise error.LookupError(p1_node, revlog.radix, _(b'unknown parent'))
+        p1_rev = revlog.rev(p1_node)
+        if not revlog.index.has_node(p2_node):
+            raise error.LookupError(p2_node, revlog.radix, _(b'unknown parent'))
+        p2_rev = revlog.rev(p2_node)
+
+        is_censored = lambda: bool(flags & REVIDX_ISCENSORED)
+        delta_base = lambda: revlog.rev(delta_base)
+        delta_base = lambda: base_rev
+        parent_revs = lambda: (p1_rev, p2_rev)
+
+        def full_text():
+            # note: being able to reuse the full text computation in the
+            # underlying addrevision would be useful however this is a bit too
+            # intrusive the for the "quick" issue6528 we are writing before the
+            # 5.8 release
+            textlen = mdiff.patchedsize(revlog.size(base_rev), delta)
+
+            revinfo = revlogutils.revisioninfo(
+                node,
+                p1_node,
+                p2_node,
+                [None],
+                textlen,
+                (base_rev, delta),
+                flags,
+            )
+            # cached by the global "writing" context
+            assert revlog._writinghandles is not None
+            if revlog._inline:
+                fh = revlog._writinghandles[0]
+            else:
+                fh = revlog._writinghandles[1]
+            return deltacomputer.buildtext(revinfo, fh)
+
+        is_affected = _is_revision_affected_fast_inner(
+            is_censored,
+            delta_base,
+            lambda: delta,
+            full_text,
+            parent_revs,
+            rev,
+            metadata_cache,
+        )
+        if is_affected:
+            d = (
+                node,
+                p2_node,
+                p1_node,
+                linknode,
+                deltabase,
+                delta,
+                flags,
+                sidedata,
+            )
+        yield d
+
+
+def repair_issue6528(
+    ui, repo, dry_run=False, to_report=None, from_report=None, paranoid=False
+):
+    from .. import store  # avoid cycle
+
+    @contextlib.contextmanager
+    def context():
+        if dry_run or to_report:  # No need for locking
+            yield
+        else:
+            with repo.wlock(), repo.lock():
+                yield
+
+    if from_report:
+        return _from_report(ui, repo, context, from_report, dry_run)
+
+    report_entries = []
+
+    with context():
+        files = list(
+            (file_type, path)
+            for (file_type, path, _e, _s) in repo.store.datafiles()
+            if path.endswith(b'.i') and file_type & store.FILEFLAGS_FILELOG
+        )
+
+        progress = ui.makeprogress(
+            _(b"looking for affected revisions"),
+            unit=_(b"filelogs"),
+            total=len(files),
+        )
+        found_nothing = True
+
+        for file_type, path in files:
+            if (
+                not path.endswith(b'.i')
+                or not file_type & store.FILEFLAGS_FILELOG
+            ):
+                continue
+            progress.increment()
+            filename = _get_filename_from_filelog_index(path)
+            fl = _filelog_from_filename(repo, filename)
+
+            # Set of filerevs (or hex filenodes if `to_report`) that need fixing
+            to_fix = set()
+            metadata_cache = {}
+            for filerev in fl.revs():
+                affected = _is_revision_affected_fast(
+                    repo, fl, filerev, metadata_cache
+                )
+                if paranoid:
+                    slow = _is_revision_affected(fl, filerev)
+                    if slow != affected:
+                        msg = _(b"paranoid check failed for '%s' at node %s")
+                        node = binascii.hexlify(fl.node(filerev))
+                        raise error.Abort(msg % (filename, node))
+                if affected:
+                    msg = b"found affected revision %d for filelog '%s'\n"
+                    ui.warn(msg % (filerev, path))
+                    found_nothing = False
+                    if not dry_run:
+                        if to_report:
+                            to_fix.add(binascii.hexlify(fl.node(filerev)))
+                        else:
+                            to_fix.add(filerev)
+
+            if to_fix:
+                to_fix = sorted(to_fix)
+                if to_report:
+                    report_entries.append((filename, to_fix))
+                else:
+                    _reorder_filelog_parents(repo, fl, to_fix)
+
+        if found_nothing:
+            ui.write(_(b"no affected revisions were found\n"))
+
+        if to_report and report_entries:
+            with open(to_report, mode="wb") as f:
+                for path, to_fix in report_entries:
+                    f.write(b"%s %s\n" % (b",".join(to_fix), path))
+
+        progress.complete()
--- a/mercurial/rewriteutil.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/rewriteutil.py	Sun Aug 22 16:32:06 2021 -0400
@@ -207,7 +207,12 @@
     hashes = re.findall(NODE_RE, commitmsg)
     unfi = repo.unfiltered()
     for h in hashes:
-        fullnode = scmutil.resolvehexnodeidprefix(unfi, h)
+        try:
+            fullnode = scmutil.resolvehexnodeidprefix(unfi, h)
+        except error.WdirUnsupported:
+            # Someone has an fffff... in a commit message we're
+            # rewriting. Don't try rewriting that.
+            continue
         if fullnode is None:
             continue
         ctx = unfi[fullnode]
--- a/mercurial/store.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/store.py	Sun Aug 22 16:32:06 2021 -0400
@@ -569,6 +569,11 @@
         self.vfs = vfsmod.filtervfs(vfs, encodefilename)
         self.opener = self.vfs
 
+    # note: topfiles would also need a decode phase. It is just that in
+    # practice we do not have any file outside of `data/` that needs encoding.
+    # However that might change so we should probably add a test and encoding
+    # decoding for it too. see issue6548
+
     def datafiles(self, matcher=None):
         for t, a, b, size in super(encodedstore, self).datafiles():
             try:
--- a/mercurial/streamclone.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/streamclone.py	Sun Aug 22 16:32:06 2021 -0400
@@ -565,6 +565,16 @@
 def _emit2(repo, entries, totalfilesize):
     """actually emit the stream bundle"""
     vfsmap = _makemap(repo)
+    # we keep repo.vfs out of the on purpose, ther are too many danger there
+    # (eg: .hg/hgrc),
+    #
+    # this assert is duplicated (from _makemap) as author might think this is
+    # fine, while this is really not fine.
+    if repo.vfs in vfsmap.values():
+        raise error.ProgrammingError(
+            b'repo.vfs must not be added to vfsmap for security reasons'
+        )
+
     progress = repo.ui.makeprogress(
         _(b'bundle'), total=totalfilesize, unit=_(b'bytes')
     )
@@ -573,7 +583,7 @@
         # copy is delayed until we are in the try
         entries = [_filterfull(e, copy, vfsmap) for e in entries]
         yield None  # this release the lock on the repository
-        seen = 0
+        totalbytecount = 0
 
         for src, name, ftype, data in entries:
             vfs = vfsmap[src]
@@ -585,6 +595,7 @@
             elif ftype == _filefull:
                 fp = open(data, b'rb')
                 size = util.fstat(fp).st_size
+            bytecount = 0
             try:
                 yield util.uvarintencode(size)
                 yield name
@@ -593,9 +604,20 @@
                 else:
                     chunks = util.filechunkiter(fp, limit=size)
                 for chunk in chunks:
-                    seen += len(chunk)
-                    progress.update(seen)
+                    bytecount += len(chunk)
+                    totalbytecount += len(chunk)
+                    progress.update(totalbytecount)
                     yield chunk
+                if bytecount != size:
+                    # Would most likely be caused by a race due to `hg strip` or
+                    # a revlog split
+                    raise error.Abort(
+                        _(
+                            b'clone could only read %d bytes from %s, but '
+                            b'expected %d bytes'
+                        )
+                        % (bytecount, name, size)
+                    )
             finally:
                 fp.close()
 
@@ -713,6 +735,15 @@
         progress.update(0)
 
         vfsmap = _makemap(repo)
+        # we keep repo.vfs out of the on purpose, ther are too many danger
+        # there (eg: .hg/hgrc),
+        #
+        # this assert is duplicated (from _makemap) as author might think this
+        # is fine, while this is really not fine.
+        if repo.vfs in vfsmap.values():
+            raise error.ProgrammingError(
+                b'repo.vfs must not be added to vfsmap for security reasons'
+            )
 
         with repo.transaction(b'clone'):
             ctxs = (vfs.backgroundclosing(repo.ui) for vfs in vfsmap.values())
--- a/mercurial/subrepo.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/subrepo.py	Sun Aug 22 16:32:06 2021 -0400
@@ -458,12 +458,14 @@
         create = allowcreate and not r.wvfs.exists(b'%s/.hg' % path)
         # repository constructor does expand variables in path, which is
         # unsafe since subrepo path might come from untrusted source.
-        if os.path.realpath(util.expandpath(root)) != root:
+        norm_root = os.path.normcase(root)
+        real_root = os.path.normcase(os.path.realpath(util.expandpath(root)))
+        if real_root != norm_root:
             raise error.Abort(
                 _(b'subrepo path contains illegal component: %s') % path
             )
         self._repo = hg.repository(r.baseui, root, create=create)
-        if self._repo.root != root:
+        if os.path.normcase(self._repo.root) != os.path.normcase(root):
             raise error.ProgrammingError(
                 b'failed to reject unsafe subrepo '
                 b'path: %s (expanded to %s)' % (root, self._repo.root)
--- a/mercurial/templater.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/templater.py	Sun Aug 22 16:32:06 2021 -0400
@@ -71,7 +71,10 @@
 import os
 
 from .i18n import _
-from .pycompat import getattr
+from .pycompat import (
+    FileNotFoundError,
+    getattr,
+)
 from . import (
     config,
     encoding,
@@ -833,6 +836,13 @@
 
 def _readmapfile(fp, mapfile):
     """Load template elements from the given map file"""
+    if pycompat.iswindows:
+        # quick hack to make sure we can process '/' in the code dealing with
+        # ressource. Ideally we would make sure we use `/` instead of `ossep`
+        # in the templater code, but that seems a bigger and less certain
+        # change that we better left for the default branch.
+        name_paths = mapfile.split(pycompat.ossep)
+        mapfile = b'/'.join(name_paths)
     base = os.path.dirname(mapfile)
     conf = config.config()
 
@@ -845,9 +855,12 @@
         if not subresource:
             if pycompat.ossep not in rel:
                 abs = rel
-                subresource = resourceutil.open_resource(
-                    b'mercurial.templates', rel
-                )
+                try:
+                    subresource = resourceutil.open_resource(
+                        b'mercurial.templates', rel
+                    )
+                except FileNotFoundError:
+                    subresource = None
             else:
                 dir = templatedir()
                 if dir:
@@ -1117,6 +1130,13 @@
         return f, open(f, mode='rb')
 
     # Otherwise try to read it using the resources API
+    if pycompat.iswindows:
+        # quick hack to make sure we can process '/' in the code dealing with
+        # ressource. Ideally we would make sure we use `/` instead of `ossep`
+        # in the templater code, but that seems a bigger and less certain
+        # change that we better left for the default branch.
+        name_paths = name.split(pycompat.ossep)
+        name = b'/'.join(name_paths)
     name_parts = name.split(b'/')
     package_name = b'.'.join([b'mercurial', b'templates'] + name_parts[:-1])
     return (
--- a/mercurial/testing/__init__.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/testing/__init__.py	Sun Aug 22 16:32:06 2021 -0400
@@ -33,5 +33,11 @@
 
 
 def write_file(path, content=b''):
-    with open(path, 'wb') as f:
+    if content:
+        write_path = b'%s.tmp' % path
+    else:
+        write_path = path
+    with open(write_path, 'wb') as f:
         f.write(content)
+    if path != write_path:
+        os.rename(write_path, path)
--- a/mercurial/upgrade_utils/engine.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/upgrade_utils/engine.py	Sun Aug 22 16:32:06 2021 -0400
@@ -66,7 +66,7 @@
         # drop the extension and the `data/` prefix
         path_part = path.rsplit(b'.', 1)[0].split(b'/', 1)
         if len(path_part) < 2:
-            msg = _('cannot recognize revlog from filename: %s')
+            msg = _(b'cannot recognize revlog from filename: %s')
             msg %= path
             raise error.Abort(msg)
         path = path_part[1]
--- a/mercurial/vfs.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/vfs.py	Sun Aug 22 16:32:06 2021 -0400
@@ -50,6 +50,14 @@
 class abstractvfs(object):
     """Abstract base class; cannot be instantiated"""
 
+    # default directory separator for vfs
+    #
+    # Other vfs code always use `/` and this works fine because python file API
+    # abstract the use of `/` and make it work transparently. For consistency
+    # vfs will always use `/` when joining. This avoid some confusion in
+    # encoded vfs (see issue6546)
+    _dir_sep = b'/'
+
     def __init__(self, *args, **kwargs):
         '''Prevent instantiation; don't call this from subclasses.'''
         raise NotImplementedError('attempted instantiating ' + str(type(self)))
@@ -152,12 +160,22 @@
         mode = st.st_mode
         return stat.S_ISREG(mode) or stat.S_ISLNK(mode)
 
+    def _join(self, *paths):
+        root_idx = 0
+        for idx, p in enumerate(paths):
+            if os.path.isabs(p) or p.startswith(self._dir_sep):
+                root_idx = idx
+        if root_idx != 0:
+            paths = paths[root_idx:]
+        paths = [p for p in paths if p]
+        return self._dir_sep.join(paths)
+
     def reljoin(self, *paths):
         """join various elements of a path together (as os.path.join would do)
 
         The vfs base is not injected so that path stay relative. This exists
         to allow handling of strange encoding if needed."""
-        return os.path.join(*paths)
+        return self._join(*paths)
 
     def split(self, path):
         """split top-most element of a path (as os.path.split would do)
@@ -528,7 +546,9 @@
 
     def join(self, path, *insidef):
         if path:
-            return os.path.join(self.base, path, *insidef)
+            parts = [self.base, path]
+            parts.extend(insidef)
+            return self._join(*parts)
         else:
             return self.base
 
--- a/mercurial/windows.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/mercurial/windows.py	Sun Aug 22 16:32:06 2021 -0400
@@ -200,20 +200,20 @@
     This shouldn't be called directly- use ``ui.getpass()`` instead, which
     checks if the session is interactive first.
     """
-    pw = ""
+    pw = u""
     while True:
         c = msvcrt.getwch()  # pytype: disable=module-attr
-        if c == '\r' or c == '\n':
+        if c == u'\r' or c == u'\n':
             break
-        if c == '\003':
+        if c == u'\003':
             raise KeyboardInterrupt
-        if c == '\b':
+        if c == u'\b':
             pw = pw[:-1]
         else:
             pw = pw + c
-    msvcrt.putwch('\r')  # pytype: disable=module-attr
-    msvcrt.putwch('\n')  # pytype: disable=module-attr
-    return encoding.strtolocal(pw)
+    msvcrt.putwch(u'\r')  # pytype: disable=module-attr
+    msvcrt.putwch(u'\n')  # pytype: disable=module-attr
+    return encoding.unitolocal(pw)
 
 
 class winstdout(object):
--- a/rust/hg-core/src/errors.rs	Tue Jul 20 17:20:19 2021 +0200
+++ b/rust/hg-core/src/errors.rs	Sun Aug 22 16:32:06 2021 -0400
@@ -47,6 +47,8 @@
 /// Details about where an I/O error happened
 #[derive(Debug)]
 pub enum IoErrorContext {
+    /// `std::fs::metadata`
+    ReadingMetadata(std::path::PathBuf),
     ReadingFile(std::path::PathBuf),
     WritingFile(std::path::PathBuf),
     RemovingFile(std::path::PathBuf),
@@ -108,6 +110,9 @@
 impl fmt::Display for IoErrorContext {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
+            IoErrorContext::ReadingMetadata(path) => {
+                write!(f, "when reading metadata of {}", path.display())
+            }
             IoErrorContext::ReadingFile(path) => {
                 write!(f, "when reading {}", path.display())
             }
--- a/rust/hg-core/src/repo.rs	Tue Jul 20 17:20:19 2021 +0200
+++ b/rust/hg-core/src/repo.rs	Sun Aug 22 16:32:06 2021 -0400
@@ -6,6 +6,7 @@
 use crate::utils::SliceExt;
 use memmap::{Mmap, MmapOptions};
 use std::collections::HashSet;
+use std::io::ErrorKind;
 use std::path::{Path, PathBuf};
 
 /// A repository on disk
@@ -51,7 +52,7 @@
         // ancestors() is inclusive: it first yields `current_directory`
         // as-is.
         for ancestor in current_directory.ancestors() {
-            if ancestor.join(".hg").is_dir() {
+            if is_dir(ancestor.join(".hg"))? {
                 return Ok(ancestor.to_path_buf());
             }
         }
@@ -73,9 +74,9 @@
         explicit_path: Option<PathBuf>,
     ) -> Result<Self, RepoError> {
         if let Some(root) = explicit_path {
-            if root.join(".hg").is_dir() {
+            if is_dir(root.join(".hg"))? {
                 Self::new_at_path(root.to_owned(), config)
-            } else if root.is_file() {
+            } else if is_file(&root)? {
                 Err(HgError::unsupported("bundle repository").into())
             } else {
                 Err(RepoError::NotFound {
@@ -130,7 +131,7 @@
             if relative {
                 shared_path = dot_hg.join(shared_path)
             }
-            if !shared_path.is_dir() {
+            if !is_dir(&shared_path)? {
                 return Err(HgError::corrupted(format!(
                     ".hg/sharedpath points to nonexistent directory {}",
                     shared_path.display()
@@ -286,3 +287,29 @@
             .with_context(|| IoErrorContext::RenamingFile { from, to })
     }
 }
+
+fn fs_metadata(
+    path: impl AsRef<Path>,
+) -> Result<Option<std::fs::Metadata>, HgError> {
+    let path = path.as_ref();
+    match std::fs::metadata(path) {
+        Ok(meta) => Ok(Some(meta)),
+        Err(error) => match error.kind() {
+            // TODO: when we require a Rust version where `NotADirectory` is
+            // stable, invert this logic and return None for it and `NotFound`
+            // and propagate any other error.
+            ErrorKind::PermissionDenied => Err(error).with_context(|| {
+                IoErrorContext::ReadingMetadata(path.to_owned())
+            }),
+            _ => Ok(None),
+        },
+    }
+}
+
+fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> {
+    Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir()))
+}
+
+fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> {
+    Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file()))
+}
--- a/rust/hg-cpython/src/revlog.rs	Tue Jul 20 17:20:19 2021 +0200
+++ b/rust/hg-cpython/src/revlog.rs	Sun Aug 22 16:32:06 2021 -0400
@@ -59,12 +59,22 @@
 
     /// Return Revision if found, raises a bare `error.RevlogError`
     /// in case of ambiguity, same as C version does
-    def get_rev(&self, node: PyBytes) -> PyResult<Option<Revision>> {
+    def get_rev(&self, pynode: PyBytes) -> PyResult<Option<Revision>> {
         let opt = self.get_nodetree(py)?.borrow();
         let nt = opt.as_ref().unwrap();
         let idx = &*self.cindex(py).borrow();
-        let node = node_from_py_bytes(py, &node)?;
-        nt.find_bin(idx, node.into()).map_err(|e| nodemap_error(py, e))
+        let node = node_from_py_bytes(py, &pynode)?;
+        match nt.find_bin(idx, node.into())
+        {
+            Ok(None) =>
+                // fallback to C implementation, remove once
+                // https://bz.mercurial-scm.org/show_bug.cgi?id=6554
+                // is fixed (a simple backout should do)
+                self.call_cindex(py, "get_rev", &PyTuple::new(py, &[pynode.into_object()]), None)?
+                .extract(py),
+            Ok(Some(rev)) => Ok(Some(rev)),
+            Err(e) => Err(nodemap_error(py, e)),
+        }
     }
 
     /// same as `get_rev()` but raises a bare `error.RevlogError` if node
@@ -94,27 +104,34 @@
         }
     }
 
-    def partialmatch(&self, node: PyObject) -> PyResult<Option<PyBytes>> {
+    def partialmatch(&self, pynode: PyObject) -> PyResult<Option<PyBytes>> {
         let opt = self.get_nodetree(py)?.borrow();
         let nt = opt.as_ref().unwrap();
         let idx = &*self.cindex(py).borrow();
 
         let node_as_string = if cfg!(feature = "python3-sys") {
-            node.cast_as::<PyString>(py)?.to_string(py)?.to_string()
+            pynode.cast_as::<PyString>(py)?.to_string(py)?.to_string()
         }
         else {
-            let node = node.extract::<PyBytes>(py)?;
+            let node = pynode.extract::<PyBytes>(py)?;
             String::from_utf8_lossy(node.data(py)).to_string()
         };
 
         let prefix = NodePrefix::from_hex(&node_as_string).map_err(|_| PyErr::new::<ValueError, _>(py, "Invalid node or prefix"))?;
 
-        nt.find_bin(idx, prefix)
-            // TODO make an inner API returning the node directly
-            .map(|opt| opt.map(
-                |rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes())))
-            .map_err(|e| nodemap_error(py, e))
-
+        match nt.find_bin(idx, prefix) {
+            Ok(None) =>
+                // fallback to C implementation, remove once
+                // https://bz.mercurial-scm.org/show_bug.cgi?id=6554
+                // is fixed (a simple backout should do)
+                self.call_cindex(
+                    py, "partialmatch",
+                    &PyTuple::new(py, &[pynode]), None
+                )?.extract(py),
+            Ok(Some(rev)) =>
+                Ok(Some(PyBytes::new(py, idx.node(rev).unwrap().as_bytes()))),
+            Err(e) => Err(nodemap_error(py, e)),
+        }
     }
 
     /// append an index entry
--- a/rust/hgcli/pyoxidizer.bzl	Tue Jul 20 17:20:19 2021 +0200
+++ b/rust/hgcli/pyoxidizer.bzl	Sun Aug 22 16:32:06 2021 -0400
@@ -35,7 +35,20 @@
 IS_WINDOWS = "windows" in BUILD_TARGET_TRIPLE
 
 # Code to run in Python interpreter.
-RUN_CODE = "import hgdemandimport; hgdemandimport.enable(); from mercurial import dispatch; dispatch.run()"
+RUN_CODE = """
+import os
+import sys
+extra_path = os.environ.get('PYTHONPATH')
+if extra_path is not None:
+    # extensions and hooks expect a working python environment
+    # We do not prepend the values because the Mercurial library wants to be in
+    # the front of the sys.path to avoid picking up other installations.
+    sys.path.extend(extra_path.split(os.pathsep))
+import hgdemandimport;
+hgdemandimport.enable();
+from mercurial import dispatch;
+dispatch.run();
+"""
 
 set_build_path(ROOT + "/build/pyoxidizer")
 
--- a/rust/rhg/README.md	Tue Jul 20 17:20:19 2021 +0200
+++ b/rust/rhg/README.md	Sun Aug 22 16:32:06 2021 -0400
@@ -1,4 +1,77 @@
-# rhg
+# `rhg`
+
+The `rhg` executable implements a subset of the functionnality of `hg`
+using only Rust, to avoid the startup cost of a Python interpreter.
+This subset is initially small but grows over time as `rhg` is improved.
+When fallback to the Python implementation is configured (see below),
+`rhg` aims to be a drop-in replacement for `hg` that should behave the same,
+except that some commands run faster.
+
+
+## Building
+
+To compile `rhg`, either run `cargo build --release` from this `rust/rhg/`
+directory, or run `make build-rhg` from the repository root.
+The executable can then be found at `rust/target/release/rhg`.
+
+
+## Mercurial configuration
+
+`rhg` reads Mercurial configuration from the usual sources:
+the user’s `~/.hgrc`, a repository’s `.hg/hgrc`, command line `--config`, etc.
+It has some specific configuration in the `[rhg]` section:
+
+* `on-unsupported` governs the behavior of `rhg` when it encounters something
+  that it does not support but “full” `hg` possibly does.
+  This can be in configuration, on the command line, or in a repository.
+
+  - `abort`, the default value, makes `rhg` print a message to stderr
+    to explain what is not supported, then terminate with a 252 exit code.
+  - `abort-silent` makes it terminate with the same exit code,
+    but without printing anything.
+  - `fallback` makes it silently call a (presumably Python-based) `hg`
+    subprocess with the same command-line parameters.
+    The `rhg.fallback-executable` configuration must be set.
+
+* `fallback-executable`: path to the executable to run in a sub-process
+  when falling back to a Python implementation of Mercurial.
 
-This project provides a fastpath Rust implementation of the Mercurial (`hg`)
-version control tool.
+* `allowed-extensions`: a list of extension names that `rhg` can ignore.
+
+  Mercurial extensions can modify the behavior of existing `hg` sub-commands,
+  including those that `rhg` otherwise supports.
+  Because it cannot load Python extensions, finding them
+  enabled in configuration is considered “unsupported” (see above).
+  A few exceptions are made for extensions that `rhg` does know about,
+  with the Rust implementation duplicating their behavior.
+
+  This configuration makes additional exceptions: `rhg` will proceed even if
+  those extensions are enabled.
+
+
+## Installation and configuration example
+
+For example, to install `rhg` as `hg` for the current user with fallback to
+the system-wide install of Mercurial, and allow it to run even though the
+`rebase` and `absorb` extensions are enabled, on a Unix-like platform:
+
+* Build `rhg` (see above)
+* Make sure the `~/.local/bin` exists and is in `$PATH`
+* From the repository root, make a symbolic link with
+  `ln -s rust/target/release/rhg ~/.local/bin/hg`
+* Configure `~/.hgrc` with:
+
+```
+[rhg]
+on-unsupported = fallback
+fallback-executable = /usr/bin/hg
+allowed-extensions = rebase, absorb
+```
+
+* Check that the output of running
+  `hg notarealsubcommand`
+  starts with `hg: unknown command`, which indicates fallback.
+
+* Check that the output of running
+  `hg notarealsubcommand --config rhg.on-unsupported=abort`
+  starts with `unsupported feature:`.
Binary file tests/bundles/issue6528.hg-v1 has changed
Binary file tests/bundles/issue6528.hg-v2 has changed
Binary file tests/bundles/issue6528.tar has changed
--- a/tests/dummyssh	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/dummyssh	Sun Aug 22 16:32:06 2021 -0400
@@ -31,5 +31,5 @@
     hgcmd = shlex.join(cmds)
     # shlex generate windows incompatible string...
     hgcmd = hgcmd.replace("'", '"')
-r = subprocess.call(hgcmd, shell=True)
+r = subprocess.call(hgcmd, shell=True, close_fds=True)
 sys.exit(bool(r))
--- a/tests/hghave.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/hghave.py	Sun Aug 22 16:32:06 2021 -0400
@@ -199,6 +199,11 @@
     return 'RHG_INSTALLED_AS_HG' in os.environ
 
 
+@check("pyoxidizer", "running with pyoxidizer build as 'hg'")
+def has_rhg():
+    return 'PYOXIDIZED_INSTALLED_AS_HG' in os.environ
+
+
 @check("cvs", "cvs client/server")
 def has_cvs():
     re = br'Concurrent Versions System.*?server'
--- a/tests/run-tests.py	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/run-tests.py	Sun Aug 22 16:32:06 2021 -0400
@@ -594,6 +594,11 @@
         action="store_true",
         help="install and use rhg Rust implementation in place of hg",
     )
+    hgconf.add_argument(
+        "--pyoxidized",
+        action="store_true",
+        help="build the hg binary using pyoxidizer",
+    )
     hgconf.add_argument("--compiler", help="compiler to build with")
     hgconf.add_argument(
         '--extra-config-opt',
@@ -731,6 +736,8 @@
             parser.error(
                 '--local cannot be used with --with-hg or --with-rhg or --with-chg'
             )
+        if options.pyoxidized:
+            parser.error('--pyoxidized does not work with --local (yet)')
         testdir = os.path.dirname(_sys2bytes(canonpath(sys.argv[0])))
         reporootdir = os.path.dirname(testdir)
         pathandattrs = [(b'hg', 'with_hg')]
@@ -764,6 +771,8 @@
         parser.error('chg does not work on %s' % os.name)
     if (options.rhg or options.with_rhg) and WINDOWS:
         parser.error('rhg does not work on %s' % os.name)
+    if options.pyoxidized and not WINDOWS:
+        parser.error('--pyoxidized is currently Windows only')
     if options.with_chg:
         options.chg = False  # no installation to temporary location
         options.with_chg = canonpath(_sys2bytes(options.with_chg))
@@ -1546,6 +1555,8 @@
             hgrc.write(b'mergemarkers = detailed\n')
             hgrc.write(b'promptecho = True\n')
             hgrc.write(b'timeout.warn=15\n')
+            hgrc.write(b'[chgserver]\n')
+            hgrc.write(b'idletimeout=60\n')
             hgrc.write(b'[defaults]\n')
             hgrc.write(b'[devel]\n')
             hgrc.write(b'all-warnings = true\n')
@@ -1587,6 +1598,7 @@
             proc = subprocess.Popen(
                 _bytes2sys(cmd),
                 shell=True,
+                close_fds=closefds,
                 cwd=_bytes2sys(self._testtmp),
                 env=env,
             )
@@ -3220,6 +3232,20 @@
             rhgbindir = os.path.dirname(os.path.realpath(self.options.with_rhg))
             self._hgcommand = os.path.basename(self.options.with_rhg)
 
+        if self.options.pyoxidized:
+            testdir = os.path.dirname(_sys2bytes(canonpath(sys.argv[0])))
+            reporootdir = os.path.dirname(testdir)
+            # XXX we should ideally install stuff instead of using the local build
+            bin_path = (
+                b'build/pyoxidizer/x86_64-pc-windows-msvc/release/app/hg.exe'
+            )
+            full_path = os.path.join(reporootdir, bin_path)
+            self._hgcommand = full_path
+            # Affects hghave.py
+            osenvironb[b'PYOXIDIZED_INSTALLED_AS_HG'] = b'1'
+        else:
+            osenvironb.pop(b'PYOXIDIZED_INSTALLED_AS_HG', None)
+
         osenvironb[b"BINDIR"] = self._bindir
         osenvironb[b"PYTHON"] = PYTHON
 
@@ -3460,6 +3486,8 @@
                 if self.options.rhg:
                     assert self._installdir
                     self._installrhg()
+                elif self.options.pyoxidized:
+                    self._build_pyoxidized()
                 self._use_correct_mercurial()
 
                 log(
@@ -3872,6 +3900,37 @@
                 sys.stdout.write(out)
             sys.exit(1)
 
+    def _build_pyoxidized(self):
+        """build a pyoxidized version of mercurial into the test environment
+
+        Ideally this function would be `install_pyoxidier` and would both build
+        and install pyoxidier. However we are starting small to get pyoxidizer
+        build binary to testing quickly.
+        """
+        vlog('# build a pyoxidized version of Mercurial')
+        assert os.path.dirname(self._bindir) == self._installdir
+        assert self._hgroot, 'must be called after _installhg()'
+        cmd = b'"%(make)s" pyoxidizer-windows-tests' % {
+            b'make': b'make',
+        }
+        cwd = self._hgroot
+        vlog("# Running", cmd)
+        proc = subprocess.Popen(
+            _bytes2sys(cmd),
+            shell=True,
+            cwd=_bytes2sys(cwd),
+            stdin=subprocess.PIPE,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.STDOUT,
+        )
+        out, _err = proc.communicate()
+        if proc.returncode != 0:
+            if PYTHON3:
+                sys.stdout.buffer.write(out)
+            else:
+                sys.stdout.write(out)
+            sys.exit(1)
+
     def _outputcoverage(self):
         """Produce code coverage output."""
         import coverage
--- a/tests/test-annotate.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-annotate.t	Sun Aug 22 16:32:06 2021 -0400
@@ -631,7 +631,7 @@
   $ rm baz
 
   $ hg annotate -ncr "wdir()" baz
-  abort: $TESTTMP\repo\baz: $ENOENT$ (windows !)
+  abort: $TESTTMP\repo/baz: $ENOENT$ (windows !)
   abort: $ENOENT$: '$TESTTMP/repo/baz' (no-windows !)
   [255]
 
@@ -640,7 +640,7 @@
   $ hg rm baz
 
   $ hg annotate -ncr "wdir()" baz
-  abort: $TESTTMP\repo\baz: $ENOENT$ (windows !)
+  abort: $TESTTMP\repo/baz: $ENOENT$ (windows !)
   abort: $ENOENT$: '$TESTTMP/repo/baz' (no-windows !)
   [255]
 
--- a/tests/test-bad-extension.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-bad-extension.t	Sun Aug 22 16:32:06 2021 -0400
@@ -20,7 +20,8 @@
   show help for a given topic or a help overview
   error in exit handlers:
   Traceback (most recent call last):
-    File "*/mercurial/dispatch.py", line *, in _runexithandlers (glob)
+    File "*/mercurial/dispatch.py", line *, in _runexithandlers (glob) (no-pyoxidizer !)
+    File "mercurial.dispatch", line *, in _runexithandlers (glob) (pyoxidizer !)
       func(*args, **kwargs)
     File "$TESTTMP/bailatexit.py", line *, in bail (glob)
       raise RuntimeError('ui.atexit handler exception')
--- a/tests/test-basic.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-basic.t	Sun Aug 22 16:32:06 2021 -0400
@@ -2,6 +2,7 @@
 
 #if no-extraextensions
   $ hg config
+  chgserver.idletimeout=60
   devel.all-warnings=true
   devel.default-date=0 0
   extensions.fsmonitor= (fsmonitor !)
--- a/tests/test-clone-uncompressed.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-clone-uncompressed.t	Sun Aug 22 16:32:06 2021 -0400
@@ -89,6 +89,13 @@
   $ echo foo > store/undo.foo.d
   $ echo foo > store/undo.foo.n
   $ echo foo > store/undo.babar
+
+Name with special characters
+
+  $ echo foo > store/CélesteVille_is_a_Capital_City
+
+All all that
+
   $ hg add .
   adding 00changelog-ab349180a0405010.nd
   adding 00changelog.d
@@ -132,6 +139,7 @@
   adding savanah/undo.i
   adding savanah/undo.n
   adding savanah/undo.py
+  adding store/C\xc3\xa9lesteVille_is_a_Capital_City (esc)
   adding store/foo.d
   adding store/foo.i
   adding store/foo.n
@@ -156,6 +164,19 @@
   $ cat hg.pid > $DAEMON_PIDS
   $ cd ..
 
+Check local clone
+==================
+
+The logic is close enough of uncompressed.
+This is present here to reuse the testing around file with "special" names.
+
+  $ hg clone server local-clone
+  updating to branch default
+  1087 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Check uncompressed
+==================
+
 Cannot stream clone when server.uncompressed is set
 
   $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out'
@@ -211,8 +232,8 @@
   adding changesets
   adding manifests
   adding file changes
-  added 3 changesets with 1086 changes to 1086 files
-  new changesets 96ee1d7354c4:7406a3463c3d
+  added 3 changesets with 1087 changes to 1087 files
+  new changesets 96ee1d7354c4:42e820400e84
 
   $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=getbundle' content-type --bodyfile body --hgproto 0.2 --requestheader "x-hgarg-1=bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=0000000000000000000000000000000000000000&heads=c17445101a72edac06facd130d14808dfbd5c7c2&stream=1"
   200 Script output follows
@@ -278,8 +299,8 @@
   adding changesets
   adding manifests
   adding file changes
-  added 3 changesets with 1086 changes to 1086 files
-  new changesets 96ee1d7354c4:7406a3463c3d
+  added 3 changesets with 1087 changes to 1087 files
+  new changesets 96ee1d7354c4:42e820400e84
 
   $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=getbundle' content-type --bodyfile body --hgproto 0.2 --requestheader "x-hgarg-1=bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=0000000000000000000000000000000000000000&heads=c17445101a72edac06facd130d14808dfbd5c7c2&stream=1"
   200 Script output follows
@@ -309,10 +330,10 @@
 #if stream-legacy
   $ hg clone --stream -U http://localhost:$HGPORT clone1
   streaming all changes
-  1088 files to transfer, 101 KB of data (no-zstd !)
+  1089 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (*/sec) (glob) (no-zstd !)
-  1088 files to transfer, 98.4 KB of data (zstd !)
-  transferred 98.4 KB in * seconds (*/sec) (glob) (zstd !)
+  1089 files to transfer, 98.5 KB of data (zstd !)
+  transferred 98.5 KB in * seconds (*/sec) (glob) (zstd !)
   searching for changes
   no changes found
   $ cat server/errors.txt
@@ -320,10 +341,10 @@
 #if stream-bundle2
   $ hg clone --stream -U http://localhost:$HGPORT clone1
   streaming all changes
-  1091 files to transfer, 101 KB of data (no-zstd !)
+  1092 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (*/sec) (glob) (no-zstd !)
-  1091 files to transfer, 98.5 KB of data (zstd !)
-  transferred 98.5 KB in * seconds (* */sec) (glob) (zstd !)
+  1092 files to transfer, 98.6 KB of data (zstd !)
+  transferred 98.6 KB in * seconds (* */sec) (glob) (zstd !)
 
   $ ls -1 clone1/.hg/cache
   branch2-base
@@ -348,12 +369,12 @@
 
 #if no-zstd no-rust
   $ f --size --hex --bytes 256 body
-  body: size=118551
+  body: size=118737
   0000: 04 6e 6f 6e 65 48 47 32 30 00 00 00 00 00 00 00 |.noneHG20.......|
   0010: 80 07 53 54 52 45 41 4d 32 00 00 00 00 03 00 09 |..STREAM2.......|
   0020: 06 09 04 0c 44 62 79 74 65 63 6f 75 6e 74 31 30 |....Dbytecount10|
-  0030: 33 36 39 35 66 69 6c 65 63 6f 75 6e 74 31 30 39 |3695filecount109|
-  0040: 31 72 65 71 75 69 72 65 6d 65 6e 74 73 64 6f 74 |1requirementsdot|
+  0030: 33 38 33 34 66 69 6c 65 63 6f 75 6e 74 31 30 39 |3834filecount109|
+  0040: 32 72 65 71 75 69 72 65 6d 65 6e 74 73 64 6f 74 |2requirementsdot|
   0050: 65 6e 63 6f 64 65 25 32 43 66 6e 63 61 63 68 65 |encode%2Cfncache|
   0060: 25 32 43 67 65 6e 65 72 61 6c 64 65 6c 74 61 25 |%2Cgeneraldelta%|
   0070: 32 43 72 65 76 6c 6f 67 76 31 25 32 43 73 70 61 |2Crevlogv1%2Cspa|
@@ -368,12 +389,12 @@
 #endif
 #if zstd no-rust
   $ f --size --hex --bytes 256 body
-  body: size=115738
+  body: size=115921
   0000: 04 6e 6f 6e 65 48 47 32 30 00 00 00 00 00 00 00 |.noneHG20.......|
   0010: 9a 07 53 54 52 45 41 4d 32 00 00 00 00 03 00 09 |..STREAM2.......|
   0020: 06 09 04 0c 5e 62 79 74 65 63 6f 75 6e 74 31 30 |....^bytecount10|
-  0030: 30 38 35 36 66 69 6c 65 63 6f 75 6e 74 31 30 39 |0856filecount109|
-  0040: 31 72 65 71 75 69 72 65 6d 65 6e 74 73 64 6f 74 |1requirementsdot|
+  0030: 30 39 39 32 66 69 6c 65 63 6f 75 6e 74 31 30 39 |0992filecount109|
+  0040: 32 72 65 71 75 69 72 65 6d 65 6e 74 73 64 6f 74 |2requirementsdot|
   0050: 65 6e 63 6f 64 65 25 32 43 66 6e 63 61 63 68 65 |encode%2Cfncache|
   0060: 25 32 43 67 65 6e 65 72 61 6c 64 65 6c 74 61 25 |%2Cgeneraldelta%|
   0070: 32 43 72 65 76 6c 6f 67 2d 63 6f 6d 70 72 65 73 |2Crevlog-compres|
@@ -388,12 +409,12 @@
 #endif
 #if zstd rust no-dirstate-v2
   $ f --size --hex --bytes 256 body
-  body: size=115759
+  body: size=115942
   0000: 04 6e 6f 6e 65 48 47 32 30 00 00 00 00 00 00 00 |.noneHG20.......|
   0010: af 07 53 54 52 45 41 4d 32 00 00 00 00 03 00 09 |..STREAM2.......|
   0020: 06 09 04 0c 73 62 79 74 65 63 6f 75 6e 74 31 30 |....sbytecount10|
-  0030: 30 38 35 36 66 69 6c 65 63 6f 75 6e 74 31 30 39 |0856filecount109|
-  0040: 31 72 65 71 75 69 72 65 6d 65 6e 74 73 64 6f 74 |1requirementsdot|
+  0030: 30 39 39 32 66 69 6c 65 63 6f 75 6e 74 31 30 39 |0992filecount109|
+  0040: 32 72 65 71 75 69 72 65 6d 65 6e 74 73 64 6f 74 |2requirementsdot|
   0050: 65 6e 63 6f 64 65 25 32 43 66 6e 63 61 63 68 65 |encode%2Cfncache|
   0060: 25 32 43 67 65 6e 65 72 61 6c 64 65 6c 74 61 25 |%2Cgeneraldelta%|
   0070: 32 43 70 65 72 73 69 73 74 65 6e 74 2d 6e 6f 64 |2Cpersistent-nod|
@@ -408,7 +429,7 @@
 #endif
 #if zstd dirstate-v2
   $ f --size --hex --bytes 256 body
-  body: size=109449
+  body: size=109549
   0000: 04 6e 6f 6e 65 48 47 32 30 00 00 00 00 00 00 00 |.noneHG20.......|
   0010: c0 07 53 54 52 45 41 4d 32 00 00 00 00 03 00 09 |..STREAM2.......|
   0020: 05 09 04 0c 85 62 79 74 65 63 6f 75 6e 74 39 35 |.....bytecount95|
@@ -432,20 +453,20 @@
 #if stream-legacy
   $ hg clone --uncompressed -U http://localhost:$HGPORT clone1-uncompressed
   streaming all changes
-  1088 files to transfer, 101 KB of data (no-zstd !)
+  1089 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (*/sec) (glob) (no-zstd !)
-  1088 files to transfer, 98.4 KB of data (zstd !)
-  transferred 98.4 KB in * seconds (*/sec) (glob) (zstd !)
+  1089 files to transfer, 98.5 KB of data (zstd !)
+  transferred 98.5 KB in * seconds (*/sec) (glob) (zstd !)
   searching for changes
   no changes found
 #endif
 #if stream-bundle2
   $ hg clone --uncompressed -U http://localhost:$HGPORT clone1-uncompressed
   streaming all changes
-  1091 files to transfer, 101 KB of data (no-zstd !)
+  1092 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (* */sec) (glob) (no-zstd !)
-  1091 files to transfer, 98.5 KB of data (zstd !)
-  transferred 98.5 KB in * seconds (* */sec) (glob) (zstd !)
+  1092 files to transfer, 98.6 KB of data (zstd !)
+  transferred 98.6 KB in * seconds (* */sec) (glob) (zstd !)
 #endif
 
 Clone with background file closing enabled
@@ -457,12 +478,12 @@
   sending branchmap command
   streaming all changes
   sending stream_out command
-  1088 files to transfer, 101 KB of data (no-zstd !)
-  1088 files to transfer, 98.4 KB of data (zstd !)
+  1089 files to transfer, 101 KB of data (no-zstd !)
+  1089 files to transfer, 98.5 KB of data (zstd !)
   starting 4 threads for background file closing
   updating the branch cache
   transferred 101 KB in * seconds (*/sec) (glob) (no-zstd !)
-  transferred 98.4 KB in * seconds (*/sec) (glob) (zstd !)
+  transferred 98.5 KB in * seconds (*/sec) (glob) (zstd !)
   query 1; heads
   sending batch command
   searching for changes
@@ -489,15 +510,15 @@
   bundle2-input-bundle: with-transaction
   bundle2-input-part: "stream2" (params: 3 mandatory) supported
   applying stream bundle
-  1091 files to transfer, 101 KB of data (no-zstd !)
-  1091 files to transfer, 98.5 KB of data (zstd !)
+  1092 files to transfer, 101 KB of data (no-zstd !)
+  1092 files to transfer, 98.6 KB of data (zstd !)
   starting 4 threads for background file closing
   starting 4 threads for background file closing
   updating the branch cache
   transferred 101 KB in * seconds (* */sec) (glob) (no-zstd !)
-  bundle2-input-part: total payload size 118382 (no-zstd !)
-  transferred 98.5 KB in * seconds (* */sec) (glob) (zstd !)
-  bundle2-input-part: total payload size 115543 (zstd !)
+  bundle2-input-part: total payload size 118568 (no-zstd !)
+  transferred 98.6 KB in * seconds (* */sec) (glob) (zstd !)
+  bundle2-input-part: total payload size 115726 (zstd !)
   bundle2-input-part: "listkeys" (params: 1 mandatory) supported
   bundle2-input-bundle: 2 parts total
   checking for updated bookmarks
@@ -529,20 +550,20 @@
 #if stream-legacy
   $ hg clone --stream -U http://localhost:$HGPORT secret-allowed
   streaming all changes
-  1088 files to transfer, 101 KB of data (no-zstd !)
+  1089 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (*/sec) (glob) (no-zstd !)
-  1088 files to transfer, 98.4 KB of data (zstd !)
-  transferred 98.4 KB in * seconds (*/sec) (glob) (zstd !)
+  1089 files to transfer, 98.5 KB of data (zstd !)
+  transferred 98.5 KB in * seconds (*/sec) (glob) (zstd !)
   searching for changes
   no changes found
 #endif
 #if stream-bundle2
   $ hg clone --stream -U http://localhost:$HGPORT secret-allowed
   streaming all changes
-  1091 files to transfer, 101 KB of data (no-zstd !)
+  1092 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (* */sec) (glob) (no-zstd !)
-  1091 files to transfer, 98.5 KB of data (zstd !)
-  transferred 98.5 KB in * seconds (* */sec) (glob) (zstd !)
+  1092 files to transfer, 98.6 KB of data (zstd !)
+  transferred 98.6 KB in * seconds (* */sec) (glob) (zstd !)
 #endif
 
   $ killdaemons.py
@@ -681,33 +702,33 @@
 #if stream-legacy
   $ hg clone --stream http://localhost:$HGPORT with-bookmarks
   streaming all changes
-  1088 files to transfer, 101 KB of data (no-zstd !)
+  1089 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (*) (glob) (no-zstd !)
-  1088 files to transfer, 98.4 KB of data (zstd !)
-  transferred 98.4 KB in * seconds (*/sec) (glob) (zstd !)
+  1089 files to transfer, 98.5 KB of data (zstd !)
+  transferred 98.5 KB in * seconds (*/sec) (glob) (zstd !)
   searching for changes
   no changes found
   updating to branch default
-  1086 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1087 files updated, 0 files merged, 0 files removed, 0 files unresolved
 #endif
 #if stream-bundle2
   $ hg clone --stream http://localhost:$HGPORT with-bookmarks
   streaming all changes
-  1094 files to transfer, 101 KB of data (no-zstd !)
-  transferred 101 KB in * seconds (* */sec) (glob) (no-zstd !)
-  1094 files to transfer, 98.7 KB of data (zstd !)
-  transferred 98.7 KB in * seconds (* */sec) (glob) (zstd !)
+  1095 files to transfer, 102 KB of data (no-zstd !)
+  transferred 102 KB in * seconds (* */sec) (glob) (no-zstd !)
+  1095 files to transfer, 98.8 KB of data (zstd !)
+  transferred 98.8 KB in * seconds (* */sec) (glob) (zstd !)
   updating to branch default
-  1086 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1087 files updated, 0 files merged, 0 files removed, 0 files unresolved
 #endif
   $ hg verify -R with-bookmarks
   checking changesets
   checking manifests
   crosschecking files in changesets and manifests
   checking files
-  checked 3 changesets with 1086 changes to 1086 files
+  checked 3 changesets with 1087 changes to 1087 files
   $ hg -R with-bookmarks bookmarks
-     some-bookmark             2:7406a3463c3d
+     some-bookmark             2:42e820400e84
 
 Stream repository with phases
 -----------------------------
@@ -722,31 +743,31 @@
 #if stream-legacy
   $ hg clone --stream http://localhost:$HGPORT phase-publish
   streaming all changes
-  1088 files to transfer, 101 KB of data (no-zstd !)
+  1089 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (*) (glob) (no-zstd !)
-  1088 files to transfer, 98.4 KB of data (zstd !)
-  transferred 98.4 KB in * seconds (*/sec) (glob) (zstd !)
+  1089 files to transfer, 98.5 KB of data (zstd !)
+  transferred 98.5 KB in * seconds (*/sec) (glob) (zstd !)
   searching for changes
   no changes found
   updating to branch default
-  1086 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1087 files updated, 0 files merged, 0 files removed, 0 files unresolved
 #endif
 #if stream-bundle2
   $ hg clone --stream http://localhost:$HGPORT phase-publish
   streaming all changes
-  1094 files to transfer, 101 KB of data (no-zstd !)
-  transferred 101 KB in * seconds (* */sec) (glob) (no-zstd !)
-  1094 files to transfer, 98.7 KB of data (zstd !)
-  transferred 98.7 KB in * seconds (* */sec) (glob) (zstd !)
+  1095 files to transfer, 102 KB of data (no-zstd !)
+  transferred 102 KB in * seconds (* */sec) (glob) (no-zstd !)
+  1095 files to transfer, 98.8 KB of data (zstd !)
+  transferred 98.8 KB in * seconds (* */sec) (glob) (zstd !)
   updating to branch default
-  1086 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1087 files updated, 0 files merged, 0 files removed, 0 files unresolved
 #endif
   $ hg verify -R phase-publish
   checking changesets
   checking manifests
   crosschecking files in changesets and manifests
   checking files
-  checked 3 changesets with 1086 changes to 1086 files
+  checked 3 changesets with 1087 changes to 1087 files
   $ hg -R phase-publish phase -r 'all()'
   0: public
   1: public
@@ -769,14 +790,14 @@
 
   $ hg clone --stream http://localhost:$HGPORT phase-no-publish
   streaming all changes
-  1088 files to transfer, 101 KB of data (no-zstd !)
+  1089 files to transfer, 101 KB of data (no-zstd !)
   transferred 101 KB in * seconds (* */sec) (glob) (no-zstd !)
-  1088 files to transfer, 98.4 KB of data (zstd !)
-  transferred 98.4 KB in * seconds (*/sec) (glob) (zstd !)
+  1089 files to transfer, 98.5 KB of data (zstd !)
+  transferred 98.5 KB in * seconds (*/sec) (glob) (zstd !)
   searching for changes
   no changes found
   updating to branch default
-  1086 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1087 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg -R phase-no-publish phase -r 'all()'
   0: public
   1: public
@@ -785,12 +806,12 @@
 #if stream-bundle2
   $ hg clone --stream http://localhost:$HGPORT phase-no-publish
   streaming all changes
-  1095 files to transfer, 101 KB of data (no-zstd !)
-  transferred 101 KB in * seconds (* */sec) (glob) (no-zstd !)
-  1095 files to transfer, 98.7 KB of data (zstd !)
-  transferred 98.7 KB in * seconds (* */sec) (glob) (zstd !)
+  1096 files to transfer, 102 KB of data (no-zstd !)
+  transferred 102 KB in * seconds (* */sec) (glob) (no-zstd !)
+  1096 files to transfer, 98.8 KB of data (zstd !)
+  transferred 98.8 KB in * seconds (* */sec) (glob) (zstd !)
   updating to branch default
-  1086 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1087 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg -R phase-no-publish phase -r 'all()'
   0: draft
   1: draft
@@ -801,7 +822,7 @@
   checking manifests
   crosschecking files in changesets and manifests
   checking files
-  checked 3 changesets with 1086 changes to 1086 files
+  checked 3 changesets with 1087 changes to 1087 files
 
   $ killdaemons.py
 
@@ -840,22 +861,22 @@
 
   $ hg clone -U --stream http://localhost:$HGPORT with-obsolescence
   streaming all changes
-  1096 files to transfer, 102 KB of data (no-zstd !)
+  1097 files to transfer, 102 KB of data (no-zstd !)
   transferred 102 KB in * seconds (* */sec) (glob) (no-zstd !)
-  1096 files to transfer, 99.1 KB of data (zstd !)
-  transferred 99.1 KB in * seconds (* */sec) (glob) (zstd !)
+  1097 files to transfer, 99.2 KB of data (zstd !)
+  transferred 99.2 KB in * seconds (* */sec) (glob) (zstd !)
   $ hg -R with-obsolescence log -T '{rev}: {phase}\n'
   2: draft
   1: draft
   0: draft
   $ hg debugobsolete -R with-obsolescence
-  aa82d3f59e13f41649d8ba3324e1ac8849ba78e7 0 {7406a3463c3de22c4288b4306d199705369a285a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  e53e122156df12330d3a0b72351e3a84bfd14195 0 {42e820400e843bc479ad36068ff772a69c8affe9} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
   $ hg verify -R with-obsolescence
   checking changesets
   checking manifests
   crosschecking files in changesets and manifests
   checking files
-  checked 4 changesets with 1087 changes to 1086 files
+  checked 4 changesets with 1088 changes to 1087 files
 
   $ hg clone -U --stream --config experimental.evolution=0 http://localhost:$HGPORT with-obsolescence-no-evolution
   streaming all changes
--- a/tests/test-commandserver.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-commandserver.t	Sun Aug 22 16:32:06 2021 -0400
@@ -214,6 +214,7 @@
   ...     runcommand(server, [b'-R', b'foo', b'showconfig', b'ui', b'defaults'])
   *** runcommand showconfig
   bundle.mainreporoot=$TESTTMP/repo
+  chgserver.idletimeout=60
   devel.all-warnings=true
   devel.default-date=0 0
   extensions.fsmonitor= (fsmonitor !)
--- a/tests/test-completion.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-completion.t	Sun Aug 22 16:32:06 2021 -0400
@@ -74,6 +74,7 @@
 
 Show debug commands if there are no other candidates
   $ hg debugcomplete debug
+  debug-repair-issue6528
   debugancestor
   debugantivirusrunning
   debugapplystreamclonebundle
@@ -266,6 +267,7 @@
   config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
   continue: dry-run
   copy: forget, after, at-rev, force, include, exclude, dry-run
+  debug-repair-issue6528: to-report, from-report, paranoid, dry-run
   debugancestor: 
   debugantivirusrunning: 
   debugapplystreamclonebundle: 
--- a/tests/test-devel-warnings.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-devel-warnings.t	Sun Aug 22 16:32:06 2021 -0400
@@ -98,7 +98,7 @@
   > EOF
   $ hg buggylocking
   devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
-#if no-chg
+#if no-chg no-pyoxidizer
   $ hg buggylocking --traceback
   devel-warn: "wlock" acquired after "lock" at:
    */hg:* in <module> (glob) (?)
@@ -115,7 +115,8 @@
    */mercurial/dispatch.py:* in <lambda> (glob)
    */mercurial/util.py:* in check (glob)
    $TESTTMP/buggylocking.py:* in buggylocking (glob)
-#else
+#endif
+#if chg no-pyoxidizer
   $ hg buggylocking --traceback
   devel-warn: "wlock" acquired after "lock" at:
    */hg:* in <module> (glob) (?)
@@ -156,6 +157,24 @@
    */mercurial/util.py:* in check (glob)
    $TESTTMP/buggylocking.py:* in buggylocking (glob)
 #endif
+#if pyoxidizer
+  $ hg buggylocking --traceback
+  devel-warn: "wlock" acquired after "lock" at:
+   <string>:* (glob)
+   mercurial.dispatch:* in run (glob)
+   mercurial.dispatch:* in dispatch (glob)
+   mercurial.dispatch:* in _rundispatch (glob)
+   mercurial.dispatch:* in _runcatch (glob)
+   mercurial.dispatch:* in _callcatch (glob)
+   mercurial.scmutil:* in callcatch (glob)
+   mercurial.dispatch:* in _runcatchfunc (glob)
+   mercurial.dispatch:* in _dispatch (glob)
+   mercurial.dispatch:* in runcommand (glob)
+   mercurial.dispatch:* in _runcommand (glob)
+   mercurial.dispatch:* in <lambda> (glob)
+   mercurial.util:* in check (glob)
+   $TESTTMP/buggylocking.py:* in buggylocking (glob)
+#endif
   $ hg properlocking
   $ hg nowaitlocking
 
@@ -180,7 +199,7 @@
   devel-warn: foorbar is deprecated, go shopping
   (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
 
-#if no-chg
+#if no-chg no-pyoxidizer
   $ hg oldanddeprecated --traceback
   devel-warn: foorbar is deprecated, go shopping
   (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
@@ -198,7 +217,8 @@
    */mercurial/dispatch.py:* in <lambda> (glob)
    */mercurial/util.py:* in check (glob)
    $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
-#else
+#endif
+#if chg no-pyoxidizer
   $ hg oldanddeprecated --traceback
   devel-warn: foorbar is deprecated, go shopping
   (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
@@ -240,8 +260,27 @@
    */mercurial/util.py:* in check (glob)
    $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
 #endif
+#if pyoxidizer
+  $ hg oldanddeprecated --traceback
+  devel-warn: foorbar is deprecated, go shopping
+  (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
+   <string>:* (glob)
+   mercurial.dispatch:* in run (glob)
+   mercurial.dispatch:* in dispatch (glob)
+   mercurial.dispatch:* in _rundispatch (glob)
+   mercurial.dispatch:* in _runcatch (glob)
+   mercurial.dispatch:* in _callcatch (glob)
+   mercurial.scmutil:* in callcatch (glob)
+   mercurial.dispatch:* in _runcatchfunc (glob)
+   mercurial.dispatch:* in _dispatch (glob)
+   mercurial.dispatch:* in runcommand (glob)
+   mercurial.dispatch:* in _runcommand (glob)
+   mercurial.dispatch:* in <lambda> (glob)
+   mercurial.util:* in check (glob)
+   $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
+#endif
 
-#if no-chg
+#if no-chg no-pyoxidizer
   $ hg blackbox -l 7
   1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
   1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
@@ -266,7 +305,8 @@
    $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
   1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
   1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
-#else
+#endif
+#if chg no-pyoxidizer
   $ hg blackbox -l 7
   1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
   1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
@@ -315,6 +355,32 @@
   1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
   1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
 #endif
+#if pyoxidizer
+  $ hg blackbox -l 7
+  1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
+  1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
+  (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
+  1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
+  1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
+  (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
+   <string>:* in <module> (glob)
+   mercurial.dispatch:* in run (glob)
+   mercurial.dispatch:* in dispatch (glob)
+   mercurial.dispatch:* in _rundispatch (glob)
+   mercurial.dispatch:* in _runcatch (glob)
+   mercurial.dispatch:* in _callcatch (glob)
+   mercurial.scmutil* in callcatch (glob)
+   mercurial.dispatch:* in _runcatchfunc (glob)
+   mercurial.dispatch:* in _dispatch (glob)
+   mercurial.dispatch:* in runcommand (glob)
+   mercurial.dispatch:* in _runcommand (glob)
+   mercurial.dispatch:* in <lambda> (glob)
+   mercurial.util:* in check (glob)
+   $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
+  1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
+#endif
 
 Test programming error failure:
 
@@ -389,8 +455,10 @@
   > EOF
 
   $ hg --config "extensions.buggyconfig=${TESTTMP}/buggyconfig.py" buggyconfig
-  devel-warn: extension 'buggyconfig' overwrite config item 'ui.interactive' at: */mercurial/extensions.py:* (_loadextra) (glob)
-  devel-warn: extension 'buggyconfig' overwrite config item 'ui.quiet' at: */mercurial/extensions.py:* (_loadextra) (glob)
+  devel-warn: extension 'buggyconfig' overwrite config item 'ui.interactive' at: */mercurial/extensions.py:* (_loadextra) (glob) (no-pyoxidizer !)
+  devel-warn: extension 'buggyconfig' overwrite config item 'ui.quiet' at: */mercurial/extensions.py:* (_loadextra) (glob) (no-pyoxidizer !)
+  devel-warn: extension 'buggyconfig' overwrite config item 'ui.interactive' at: mercurial.extensions:* (_loadextra) (glob) (pyoxidizer !)
+  devel-warn: extension 'buggyconfig' overwrite config item 'ui.quiet' at: mercurial.extensions:* (_loadextra) (glob) (pyoxidizer !)
   devel-warn: specifying a mismatched default value for a registered config item: 'ui.quiet' 'True' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
   devel-warn: specifying a mismatched default value for a registered config item: 'ui.interactive' 'False' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
   devel-warn: specifying a mismatched default value for a registered config item: 'test.some' 'bar' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
--- a/tests/test-extension.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-extension.t	Sun Aug 22 16:32:06 2021 -0400
@@ -668,7 +668,8 @@
 Even though the extension fails during uisetup, hg is still basically usable:
   $ hg --config extensions.baduisetup=$TESTTMP/baduisetup.py version
   Traceback (most recent call last):
-    File "*/mercurial/extensions.py", line *, in _runuisetup (glob)
+    File "*/mercurial/extensions.py", line *, in _runuisetup (glob) (no-pyoxidizer !)
+    File "mercurial.extensions", line *, in _runuisetup (glob) (pyoxidizer !)
       uisetup(ui)
     File "$TESTTMP/baduisetup.py", line 2, in uisetup
       1 / 0
@@ -1377,6 +1378,18 @@
   (use 'hg help extensions' for information on enabling extensions)
 
 
+Help can find unimported extensions
+-----------------------------------
+
+XXX-PYOXIDIZER since the frozen binary does not have source directory tree,
+this make the checking for actual file under `hgext` a bit complicated. In
+addition these tests do some strange dance to ensure some other module are the
+first in `sys.path` (since the current install path is always in front
+otherwise) that are fragile and that does not match reality in the field. So
+for now we disable this test untill a deeper rework of that logic is done.
+
+#if no-pyoxidizer
+
 Broken disabled extension and command:
 
   $ mkdir hgext
@@ -1412,6 +1425,10 @@
   (try 'hg help --keyword foo')
   [255]
 
+#endif
+
+---
+
   $ cat > throw.py <<EOF
   > from mercurial import commands, registrar, util
   > cmdtable = {}
--- a/tests/test-fix.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-fix.t	Sun Aug 22 16:32:06 2021 -0400
@@ -3,6 +3,7 @@
 
   $ UPPERCASEPY="$TESTTMP/uppercase.py"
   $ cat > $UPPERCASEPY <<EOF
+  > import re
   > import sys
   > from mercurial.utils.procutil import setbinary
   > setbinary(sys.stdin)
@@ -10,16 +11,18 @@
   > stdin = getattr(sys.stdin, 'buffer', sys.stdin)
   > stdout = getattr(sys.stdout, 'buffer', sys.stdout)
   > lines = set()
+  > def format(text):
+  >   return re.sub(b' +', b' ', text.upper())
   > for arg in sys.argv[1:]:
   >   if arg == 'all':
-  >     stdout.write(stdin.read().upper())
+  >     stdout.write(format(stdin.read()))
   >     sys.exit(0)
   >   else:
   >     first, last = arg.split('-')
   >     lines.update(range(int(first), int(last) + 1))
   > for i, line in enumerate(stdin.readlines()):
   >   if i + 1 in lines:
-  >     stdout.write(line.upper())
+  >     stdout.write(format(line))
   >   else:
   >     stdout.write(line)
   > EOF
@@ -354,6 +357,23 @@
 
   $ cd ..
 
+Test that the working copy is reported clean if formatting of the parent makes
+it clean.
+  $ hg init wc-already-formatted
+  $ cd wc-already-formatted
+
+  $ printf "hello   world\n" > hello.whole
+  $ hg commit -Am initial
+  adding hello.whole
+  $ hg fix -w *
+  $ hg st
+  M hello.whole
+  $ hg fix -s . *
+  $ hg st
+  $ hg diff
+
+  $ cd ..
+
 Test the effect of fixing the working directory for each possible status, with
 and without providing explicit file arguments.
 
--- a/tests/test-flagprocessor.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-flagprocessor.t	Sun Aug 22 16:32:06 2021 -0400
@@ -201,14 +201,17 @@
   > EOF
   $ hg debugrebuilddirstate
   Traceback (most recent call last):
-    File "*/mercurial/extensions.py", line *, in _runextsetup (glob)
+    File "*/mercurial/extensions.py", line *, in _runextsetup (glob) (no-pyoxidizer !)
+    File "mercurial.extensions", line *, in _runextsetup (glob) (pyoxidizer !)
       extsetup(ui)
     File "*/tests/flagprocessorext.py", line *, in extsetup (glob)
       flagutil.addflagprocessor( (py38 !)
       validatehash, (no-py38 !)
-    File "*/mercurial/revlogutils/flagutil.py", line *, in addflagprocessor (glob)
+    File "*/mercurial/revlogutils/flagutil.py", line *, in addflagprocessor (glob) (no-pyoxidizer !)
+    File "mercurial.revlogutils.flagutil", line *, in addflagprocessor (glob) (pyoxidizer !)
       insertflagprocessor(flag, processor, flagprocessors)
-    File "*/mercurial/revlogutils/flagutil.py", line *, in insertflagprocessor (glob)
+    File "*/mercurial/revlogutils/flagutil.py", line *, in insertflagprocessor (glob) (no-pyoxidizer !)
+    File "mercurial.revlogutils.flagutil", line *, in insertflagprocessor (glob) (pyoxidizer !)
       raise error.Abort(msg)
   mercurial.error.Abort: cannot register multiple processors on flag '0x8'. (py3 !)
   Abort: cannot register multiple processors on flag '0x8'. (no-py3 !)
--- a/tests/test-help.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-help.t	Sun Aug 22 16:32:06 2021 -0400
@@ -975,6 +975,9 @@
   $ hg help debug
   debug commands (internal and unsupported):
   
+   debug-repair-issue6528
+                 find affected revisions and repair them. See issue6528 for more
+                 details.
    debugancestor
                  find the ancestor revision of two revisions in a given index
    debugantivirusrunning
--- a/tests/test-hgrc.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-hgrc.t	Sun Aug 22 16:32:06 2021 -0400
@@ -303,5 +303,16 @@
   $ hg paths --config extensions.zeroconf=
   config error at $TESTTMP/.hg/hgrc:3: [broken
   [255]
+
+XXX-PYOXIDIZER Pyoxidizer build have trouble with zeroconf for unclear reason,
+we accept the bad output for now as this is the last thing in the way of
+testing the pyoxidizer build.
+
+#if no-pyoxidizer
   $ HGRCSKIPREPO=1 hg paths --config extensions.zeroconf=
   foo = $TESTTMP/bar
+#else
+  $ HGRCSKIPREPO=1 hg paths --config extensions.zeroconf=
+  abort: An invalid argument was supplied (known-bad-output !)
+  [255]
+#endif
--- a/tests/test-install.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-install.t	Sun Aug 22 16:32:06 2021 -0400
@@ -5,7 +5,8 @@
   checking Python implementation (*) (glob)
   checking Python version (2.*) (glob) (no-py3 !)
   checking Python version (3.*) (glob) (py3 !)
-  checking Python lib (.*[Ll]ib.*)... (re)
+  checking Python lib (.*[Ll]ib.*)... (re) (no-pyoxidizer !)
+  checking Python lib (.*pyoxidizer.*)... (re) (pyoxidizer !)
   checking Python security support (*) (glob)
     TLS 1.2 not supported by Python install; network connections lack modern security (?)
     SNI not supported by Python install; may have connectivity issues with some servers (?)
@@ -18,8 +19,10 @@
   checking available compression engines (*zlib*) (glob)
   checking available compression engines for wire protocol (*zlib*) (glob)
   checking "re2" regexp engine \((available|missing)\) (re)
-  checking templates (*mercurial?templates)... (glob)
-  checking default template (*mercurial?templates?map-cmdline.default) (glob)
+  checking templates (*mercurial?templates)... (glob) (no-pyoxidizer !)
+  checking templates (*app?templates)... (glob) (pyoxidizer !)
+  checking default template (*mercurial?templates?map-cmdline.default) (glob) (no-pyoxidizer !)
+  checking default template (*app?templates?map-cmdline.default) (glob) (pyoxidizer !)
   checking commit editor... (*) (glob)
   checking username (test)
   no problems detected
@@ -31,7 +34,8 @@
     "compengines": ["bz2", "bz2truncated", "none", "zlib"*], (glob)
     "compenginesavail": ["bz2", "bz2truncated", "none", "zlib"*], (glob)
     "compenginesserver": [*"zlib"*], (glob)
-    "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob)
+    "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob) (no-pyoxidizer !)
+    "defaulttemplate": "*app?templates?map-cmdline.default", (glob) (pyoxidizer !)
     "defaulttemplateerror": null,
     "defaulttemplatenotfound": "default",
     "editor": "*", (glob)
@@ -50,7 +54,8 @@
     "pythonsecurity": [*], (glob)
     "pythonver": "*.*.*", (glob)
     "re2": (true|false), (re)
-    "templatedirs": "*mercurial?templates", (glob)
+    "templatedirs": "*mercurial?templates", (glob) (no-pyoxidizer !)
+    "templatedirs": "*app?templates", (glob) (pyoxidizer !)
     "username": "test",
     "usernameerror": null,
     "vinotfound": false
@@ -64,7 +69,8 @@
   checking Python implementation (*) (glob)
   checking Python version (2.*) (glob) (no-py3 !)
   checking Python version (3.*) (glob) (py3 !)
-  checking Python lib (.*[Ll]ib.*)... (re)
+  checking Python lib (.*[Ll]ib.*)... (re) (no-pyoxidizer !)
+  checking Python lib (.*pyoxidizer.*)... (re) (pyoxidizer !)
   checking Python security support (*) (glob)
     TLS 1.2 not supported by Python install; network connections lack modern security (?)
     SNI not supported by Python install; may have connectivity issues with some servers (?)
@@ -77,8 +83,10 @@
   checking available compression engines (*zlib*) (glob)
   checking available compression engines for wire protocol (*zlib*) (glob)
   checking "re2" regexp engine \((available|missing)\) (re)
-  checking templates (*mercurial?templates)... (glob)
-  checking default template (*mercurial?templates?map-cmdline.default) (glob)
+  checking templates (*mercurial?templates)... (glob) (no-pyoxidizer !)
+  checking templates (*app?templates)... (glob) (pyoxidizer !)
+  checking default template (*mercurial?templates?map-cmdline.default) (glob) (no-pyoxidizer !)
+  checking default template (*app?templates?map-cmdline.default) (glob) (pyoxidizer !)
   checking commit editor... (*) (glob)
   checking username...
    no username supplied
@@ -111,7 +119,8 @@
   checking Python implementation (*) (glob)
   checking Python version (2.*) (glob) (no-py3 !)
   checking Python version (3.*) (glob) (py3 !)
-  checking Python lib (.*[Ll]ib.*)... (re)
+  checking Python lib (.*[Ll]ib.*)... (re) (no-pyoxidizer !)
+  checking Python lib (.*pyoxidizer.*)... (re) (pyoxidizer !)
   checking Python security support (*) (glob)
     TLS 1.2 not supported by Python install; network connections lack modern security (?)
     SNI not supported by Python install; may have connectivity issues with some servers (?)
@@ -124,8 +133,10 @@
   checking available compression engines (*zlib*) (glob)
   checking available compression engines for wire protocol (*zlib*) (glob)
   checking "re2" regexp engine \((available|missing)\) (re)
-  checking templates (*mercurial?templates)... (glob)
-  checking default template (*mercurial?templates?map-cmdline.default) (glob)
+  checking templates (*mercurial?templates)... (glob) (no-pyoxidizer !)
+  checking templates (*app?templates)... (glob) (pyoxidizer !)
+  checking default template (*mercurial?templates?map-cmdline.default) (glob) (no-pyoxidizer !)
+  checking default template (*app?templates?map-cmdline.default) (glob) (pyoxidizer !)
   checking commit editor... ($TESTTMP/tools/testeditor.exe)
   checking username (test)
   no problems detected
@@ -138,7 +149,8 @@
   checking Python implementation (*) (glob)
   checking Python version (2.*) (glob) (no-py3 !)
   checking Python version (3.*) (glob) (py3 !)
-  checking Python lib (.*[Ll]ib.*)... (re)
+  checking Python lib (.*[Ll]ib.*)... (re) (no-pyoxidizer !)
+  checking Python lib (.*pyoxidizer.*)... (re) (pyoxidizer !)
   checking Python security support (*) (glob)
     TLS 1.2 not supported by Python install; network connections lack modern security (?)
     SNI not supported by Python install; may have connectivity issues with some servers (?)
@@ -151,8 +163,10 @@
   checking available compression engines (*zlib*) (glob)
   checking available compression engines for wire protocol (*zlib*) (glob)
   checking "re2" regexp engine \((available|missing)\) (re)
-  checking templates (*mercurial?templates)... (glob)
-  checking default template (*mercurial?templates?map-cmdline.default) (glob)
+  checking templates (*mercurial?templates)... (glob) (no-pyoxidizer !)
+  checking templates (*app?templates)... (glob) (pyoxidizer !)
+  checking default template (*mercurial?templates?map-cmdline.default) (glob) (no-pyoxidizer !)
+  checking default template (*app?templates?map-cmdline.default) (glob) (pyoxidizer !)
   checking commit editor... (c:\foo\bar\baz.exe) (windows !)
    Can't find editor 'c:\foo\bar\baz.exe' in PATH (windows !)
   checking commit editor... (c:foobarbaz.exe) (no-windows !)
@@ -184,7 +198,7 @@
   $ cd $TESTTMP
   $ unset PYTHONPATH
 
-#if py3 ensurepip network-io
+#if py3 ensurepip network-io no-pyoxidizer
   $ "$PYTHON" -m venv installenv >> pip.log
 
 Hack: Debian does something a bit different in ensurepip.bootstrap. This makes
@@ -224,7 +238,7 @@
   no problems detected
 #endif
 
-#if virtualenv no-py3 network-io
+#if virtualenv no-py3 network-io no-pyoxidizer
 
 Note: --no-site-packages is the default for all versions enabled by hghave
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue6528.t	Sun Aug 22 16:32:06 2021 -0400
@@ -0,0 +1,627 @@
+===============================================================
+Test non-regression on the corruption associated with issue6528
+===============================================================
+
+Setup
+=====
+
+  $ hg init base-repo
+  $ cd base-repo
+
+  $ cat <<EOF > a.txt
+  > 1
+  > 2
+  > 3
+  > 4
+  > 5
+  > 6
+  > EOF
+
+  $ hg add a.txt
+  $ hg commit -m 'c_base_c - create a.txt'
+
+Modify a.txt
+
+  $ sed -e 's/1/foo/' a.txt > a.tmp; mv a.tmp a.txt
+  $ hg commit -m 'c_modify_c - modify a.txt'
+
+Modify and rename a.txt to b.txt
+
+  $ hg up -r "desc('c_base_c')"
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ sed -e 's/6/bar/' a.txt > a.tmp; mv a.tmp a.txt
+  $ hg mv a.txt b.txt
+  $ hg commit -m 'c_rename_c - rename and modify a.txt to b.txt'
+  created new head
+
+Merge each branch
+
+  $ hg merge -r "desc('c_modify_c')"
+  merging b.txt and a.txt to b.txt
+  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg commit -m 'c_merge_c: commit merge'
+
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+
+Check commit Graph
+
+  $ hg log -G
+  @    changeset:   3:a1cc2bdca0aa
+  |\   tag:         tip
+  | |  parent:      2:615c6ccefd15
+  | |  parent:      1:373d507f4667
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     c_merge_c: commit merge
+  | |
+  | o  changeset:   2:615c6ccefd15
+  | |  parent:      0:f5a5a568022f
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     c_rename_c - rename and modify a.txt to b.txt
+  | |
+  o |  changeset:   1:373d507f4667
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     c_modify_c - modify a.txt
+  |
+  o  changeset:   0:f5a5a568022f
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     c_base_c - create a.txt
+  
+
+  $ hg cat -r . b.txt
+  foo
+  2
+  3
+  4
+  5
+  bar
+  $ cat b.txt
+  foo
+  2
+  3
+  4
+  5
+  bar
+  $ cd ..
+
+
+Check the lack of corruption
+============================
+
+  $ hg clone --pull base-repo cloned
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 4 changes to 2 files
+  new changesets f5a5a568022f:a1cc2bdca0aa
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd cloned
+  $ hg up -r "desc('c_merge_c')"
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+
+Status is buggy, even with debugrebuilddirstate
+
+  $ hg cat -r . b.txt
+  foo
+  2
+  3
+  4
+  5
+  bar
+  $ cat b.txt
+  foo
+  2
+  3
+  4
+  5
+  bar
+  $ hg status
+  $ hg debugrebuilddirstate
+  $ hg status
+
+the history was altered
+
+in theory p1/p2 order does not matter but in practice p1 == nullid is used as a
+marker that some metadata are present and should be fetched.
+
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+
+Check commit Graph
+
+  $ hg log -G
+  @    changeset:   3:a1cc2bdca0aa
+  |\   tag:         tip
+  | |  parent:      2:615c6ccefd15
+  | |  parent:      1:373d507f4667
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     c_merge_c: commit merge
+  | |
+  | o  changeset:   2:615c6ccefd15
+  | |  parent:      0:f5a5a568022f
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     c_rename_c - rename and modify a.txt to b.txt
+  | |
+  o |  changeset:   1:373d507f4667
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     c_modify_c - modify a.txt
+  |
+  o  changeset:   0:f5a5a568022f
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     c_base_c - create a.txt
+  
+
+Test the command that fixes the issue
+=====================================
+
+Restore a broken repository with multiple broken revisions and a filename that
+would get encoded to test the `report` options.
+It's a tarball because unbundle might magically fix the issue later.
+
+  $ cd ..
+  $ mkdir repo-to-fix
+  $ cd repo-to-fix
+#if windows
+tar interprets `:` in paths (like `C:`) as being remote, force local on Windows
+only since some versions of tar don't have this flag.
+
+  $ tar --force-local -xf $TESTDIR/bundles/issue6528.tar
+#else
+  $ tar xf $TESTDIR/bundles/issue6528.tar
+#endif
+
+Check that the issue is present
+  $ hg st
+  M D.txt
+  M b.txt
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 05b806ebe5ea 000000000000
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 216a5fe8b8ed 000000000000
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 2a8d3833f2fb 000000000000
+
+Dry-run the fix
+  $ hg debug-repair-issue6528 --dry-run
+  found affected revision 1 for filelog 'data/D.txt.i'
+  found affected revision 1 for filelog 'data/b.txt.i'
+  found affected revision 3 for filelog 'data/b.txt.i'
+  $ hg st
+  M D.txt
+  M b.txt
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 05b806ebe5ea 000000000000
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 216a5fe8b8ed 000000000000
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 2a8d3833f2fb 000000000000
+
+Test the --paranoid option
+  $ hg debug-repair-issue6528 --dry-run --paranoid
+  found affected revision 1 for filelog 'data/D.txt.i'
+  found affected revision 1 for filelog 'data/b.txt.i'
+  found affected revision 3 for filelog 'data/b.txt.i'
+  $ hg st
+  M D.txt
+  M b.txt
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 05b806ebe5ea 000000000000
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 216a5fe8b8ed 000000000000
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 2a8d3833f2fb 000000000000
+
+Run the fix
+  $ hg debug-repair-issue6528
+  found affected revision 1 for filelog 'data/D.txt.i'
+  repaired revision 1 of 'filelog data/D.txt.i'
+  found affected revision 1 for filelog 'data/b.txt.i'
+  found affected revision 3 for filelog 'data/b.txt.i'
+  repaired revision 1 of 'filelog data/b.txt.i'
+  repaired revision 3 of 'filelog data/b.txt.i'
+
+Check that the fix worked and that running it twice does nothing
+  $ hg st
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+  $ hg debug-repair-issue6528
+  no affected revisions were found
+  $ hg st
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+
+Try the using the report options
+--------------------------------
+
+  $ cd ..
+  $ mkdir repo-to-fix-report
+  $ cd repo-to-fix
+#if windows
+tar interprets `:` in paths (like `C:`) as being remote, force local on Windows
+only since some versions of tar don't have this flag.
+
+  $ tar --force-local -xf $TESTDIR/bundles/issue6528.tar
+#else
+  $ tar xf $TESTDIR/bundles/issue6528.tar
+#endif
+
+  $ hg debug-repair-issue6528 --to-report $TESTTMP/report.txt
+  found affected revision 1 for filelog 'data/D.txt.i'
+  found affected revision 1 for filelog 'data/b.txt.i'
+  found affected revision 3 for filelog 'data/b.txt.i'
+  $ cat $TESTTMP/report.txt
+  2a80419dfc31d7dfb308ac40f3f138282de7d73b D.txt
+  a58b36ad6b6545195952793099613c2116f3563b,ea4f2f2463cca5b29ddf3461012b8ce5c6dac175 b.txt
+
+  $ hg debug-repair-issue6528 --from-report $TESTTMP/report.txt --dry-run
+  loading report file '$TESTTMP/report.txt'
+  found affected revision 1 for filelog 'D.txt'
+  found affected revision 1 for filelog 'b.txt'
+  found affected revision 3 for filelog 'b.txt'
+  $ hg st
+  M D.txt
+  M b.txt
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 05b806ebe5ea 000000000000
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 216a5fe8b8ed 000000000000
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 2a8d3833f2fb 000000000000
+
+  $ hg debug-repair-issue6528 --from-report $TESTTMP/report.txt
+  loading report file '$TESTTMP/report.txt'
+  found affected revision 1 for filelog 'D.txt'
+  repaired revision 1 of 'filelog data/D.txt.i'
+  found affected revision 1 for filelog 'b.txt'
+  found affected revision 3 for filelog 'b.txt'
+  repaired revision 1 of 'filelog data/b.txt.i'
+  repaired revision 3 of 'filelog data/b.txt.i'
+  $ hg st
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+
+Check that the revision is not "fixed" again
+
+  $ hg debug-repair-issue6528 --from-report $TESTTMP/report.txt
+  loading report file '$TESTTMP/report.txt'
+  revision 2a80419dfc31d7dfb308ac40f3f138282de7d73b of file 'D.txt' is not affected
+  no affected revisions were found for 'D.txt'
+  revision a58b36ad6b6545195952793099613c2116f3563b of file 'b.txt' is not affected
+  revision ea4f2f2463cca5b29ddf3461012b8ce5c6dac175 of file 'b.txt' is not affected
+  no affected revisions were found for 'b.txt'
+  $ hg st
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+
+Try it with a non-inline revlog
+-------------------------------
+
+  $ cd ..
+  $ mkdir $TESTTMP/ext
+  $ cat << EOF > $TESTTMP/ext/small_inline.py
+  > from mercurial import revlog
+  > revlog._maxinline = 8
+  > EOF
+
+  $ cat << EOF >> $HGRCPATH
+  > [extensions]
+  > small_inline=$TESTTMP/ext/small_inline.py
+  > EOF
+
+  $ mkdir repo-to-fix-not-inline
+  $ cd repo-to-fix-not-inline
+#if windows
+tar interprets `:` in paths (like `C:`) as being remote, force local on Windows
+only since some versions of tar don't have this flag.
+
+  $ tar --force-local -xf $TESTDIR/bundles/issue6528.tar
+#else
+  $ tar xf $TESTDIR/bundles/issue6528.tar
+#endif
+  $ echo b >> b.txt
+  $ hg commit -qm "inline -> separate"
+  $ find .hg -name *b.txt.d
+  .hg/store/data/b.txt.d
+
+Status is correct, but the problem is still there, in the earlier revision
+  $ hg st
+  $ hg up 3
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg st
+  M b.txt
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 05b806ebe5ea 000000000000
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 216a5fe8b8ed 000000000000
+       4       8 db234885e2fe ea4f2f2463cc 000000000000
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 2a8d3833f2fb 000000000000
+       2       8 65aecc89bb5d 2a80419dfc31 000000000000
+
+Run the fix on the non-inline revlog
+  $ hg debug-repair-issue6528
+  found affected revision 1 for filelog 'data/D.txt.i'
+  repaired revision 1 of 'filelog data/D.txt.i'
+  found affected revision 1 for filelog 'data/b.txt.i'
+  found affected revision 3 for filelog 'data/b.txt.i'
+  repaired revision 1 of 'filelog data/b.txt.i'
+  repaired revision 3 of 'filelog data/b.txt.i'
+
+Check that it worked
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+       4       8 db234885e2fe ea4f2f2463cc 000000000000
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+       2       8 65aecc89bb5d 2a80419dfc31 000000000000
+  $ hg debug-repair-issue6528
+  no affected revisions were found
+  $ hg st
+
+  $ cd ..
+
+Applying a bad bundle should fix it on the fly
+----------------------------------------------
+
+from a v1 bundle
+~~~~~~~~~~~~~~~~
+
+  $ hg debugbundle  --spec "$TESTDIR"/bundles/issue6528.hg-v1
+  bzip2-v1
+
+  $ hg init unbundle-v1
+  $ cd unbundle-v1
+
+  $ hg unbundle "$TESTDIR"/bundles/issue6528.hg-v1
+  adding changesets
+  adding manifests
+  adding file changes
+  added 8 changesets with 12 changes to 4 files
+  new changesets f5a5a568022f:3beabb508514 (8 drafts)
+  (run 'hg update' to get a working copy)
+
+Check that revision were fixed on the fly
+
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+
+That we don't see the symptoms of the bug
+
+  $ hg up -- -1
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg status
+
+And that the repair command does not find anything to fix
+
+  $ hg debug-repair-issue6528
+  no affected revisions were found
+
+  $ cd ..
+
+from a v2 bundle
+~~~~~~~~~~~~~~~~
+
+  $ hg debugbundle --spec "$TESTDIR"/bundles/issue6528.hg-v2
+  bzip2-v2
+
+  $ hg init unbundle-v2
+  $ cd unbundle-v2
+
+  $ hg unbundle "$TESTDIR"/bundles/issue6528.hg-v2
+  adding changesets
+  adding manifests
+  adding file changes
+  added 8 changesets with 12 changes to 4 files
+  new changesets f5a5a568022f:3beabb508514 (8 drafts)
+  (run 'hg update' to get a working copy)
+
+Check that revision were fixed on the fly
+
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+
+That we don't see the symptoms of the bug
+
+  $ hg up -- -1
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg status
+
+And that the repair command does not find anything to fix
+
+  $ hg debug-repair-issue6528
+  no affected revisions were found
+
+  $ cd ..
+
+A config option can disable the fixing of the bad bundle on the fly
+-------------------------------------------------------------------
+
+
+
+from a v1 bundle
+~~~~~~~~~~~~~~~~
+
+  $ hg debugbundle  --spec "$TESTDIR"/bundles/issue6528.hg-v1
+  bzip2-v1
+
+  $ hg init unbundle-v1-no-fix
+  $ cd unbundle-v1-no-fix
+
+  $ hg unbundle "$TESTDIR"/bundles/issue6528.hg-v1 --config storage.revlog.issue6528.fix-incoming=no
+  adding changesets
+  adding manifests
+  adding file changes
+  added 8 changesets with 12 changes to 4 files
+  new changesets f5a5a568022f:3beabb508514 (8 drafts)
+  (run 'hg update' to get a working copy)
+
+Check that revision were not fixed on the fly
+
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 05b806ebe5ea 000000000000
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 216a5fe8b8ed 000000000000
+
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 2a8d3833f2fb 000000000000
+
+That we do see the symptoms of the bug
+
+  $ hg up -- -1
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg status
+  M D.txt (?)
+  M b.txt (?)
+
+And that the repair command find issue to fix.
+
+  $ hg debug-repair-issue6528 --dry-run
+  found affected revision 1 for filelog 'data/D.txt.i'
+  found affected revision 1 for filelog 'data/b.txt.i'
+  found affected revision 3 for filelog 'data/b.txt.i'
+
+  $ cd ..
+
+from a v2 bundle
+~~~~~~~~~~~~~~~~
+
+  $ hg debugbundle --spec "$TESTDIR"/bundles/issue6528.hg-v2
+  bzip2-v2
+
+  $ hg init unbundle-v2-no-fix
+  $ cd unbundle-v2-no-fix
+
+  $ hg unbundle "$TESTDIR"/bundles/issue6528.hg-v2 --config storage.revlog.issue6528.fix-incoming=no
+  adding changesets
+  adding manifests
+  adding file changes
+  added 8 changesets with 12 changes to 4 files
+  new changesets f5a5a568022f:3beabb508514 (8 drafts)
+  (run 'hg update' to get a working copy)
+
+Check that revision were not fixed on the fly
+
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 05b806ebe5ea 000000000000
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 216a5fe8b8ed 000000000000
+
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 2a8d3833f2fb 000000000000
+
+That we do see the symptoms of the bug
+
+  $ hg up -- -1
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg status
+  M D.txt (?)
+  M b.txt (?)
+
+And that the repair command find issue to fix.
+
+  $ hg debug-repair-issue6528 --dry-run
+  found affected revision 1 for filelog 'data/D.txt.i'
+  found affected revision 1 for filelog 'data/b.txt.i'
+  found affected revision 3 for filelog 'data/b.txt.i'
+
+  $ cd ..
--- a/tests/test-narrow-shallow-merges.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-narrow-shallow-merges.t	Sun Aug 22 16:32:06 2021 -0400
@@ -179,7 +179,7 @@
   
 
   $ hg log -T '{if(ellipsis,"...")}{node|short} {p1node|short} {p2node|short} {desc}\n' | sort
-  ...2a20009de83e 3ac1f5779de3 000000000000 outside 10
+  ...2a20009de83e 000000000000 3ac1f5779de3 outside 10
   ...3ac1f5779de3 bb96a08b062a 465567bdfb2d merge a/b/c/d 9
   ...8d874d57adea 7ef88b4dd4fa 000000000000 outside 12
   ...b844052e7b3b 000000000000 000000000000 outside 2c
--- a/tests/test-nointerrupt.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-nointerrupt.t	Sun Aug 22 16:32:06 2021 -0400
@@ -5,85 +5,90 @@
 buggy. This need to be resolved sooner than later.
 
 Dummy extension simulating unsafe long running command
-  $ cat > sleepext.py <<EOF
-  > import itertools
+  $ SYNC_FILE="$TESTTMP/sync-file"
+  $ export SYNC_FILE
+  $ DONE_FILE="$TESTTMP/done-file"
+  $ export DONE_FILE
+  $ 
+  $ cat > wait_ext.py <<EOF
+  > import os
   > import time
   > 
   > from mercurial.i18n import _
   > from mercurial import registrar
+  > from mercurial import testing
   > 
   > cmdtable = {}
   > command = registrar.command(cmdtable)
   > 
-  > @command(b'sleep', [], _(b'TIME'), norepo=True)
-  > def sleep(ui, sleeptime=b"1", **opts):
+  > @command(b'wait-signal', [], _(b'SYNC_FILE DONE_FILE'), norepo=True)
+  > def sleep(ui, sync_file=b"$SYNC_FILE", done_file=b"$DONE_FILE", **opts):
+  >     start = time.time()
   >     with ui.uninterruptible():
-  >         for _i in itertools.repeat(None, int(sleeptime)):
-  >             time.sleep(1)
+  >         testing.write_file(sync_file, b'%d' % os.getpid())
+  >         testing.wait_file(done_file)
+  >         # make sure we get rescheduled and the signal get a chance to be handled
+  >         time.sleep(0.1)
   >         ui.warn(b"end of unsafe operation\n")
-  >     ui.warn(b"%s second(s) passed\n" % sleeptime)
+  >     ui.warn(b"%d second(s) passed\n" % int(time.time() - start))
   > EOF
 
+  $ cat > send-signal.sh << EOF
+  > #!/bin/sh
+  > SIG=\$1
+  > if [ -z "\$SIG" ]; then
+  >    echo "send-signal.sh requires one argument" >&2
+  >    exit 1
+  > fi
+  > "$RUNTESTDIR/testlib/wait-on-file" 10 "$SYNC_FILE" || exit 2
+  > kill -s \$SIG \`cat "$SYNC_FILE"\`
+  > sleep 1
+  > touch "$DONE_FILE"
+  > EOF
+
+#if no-windows
+  $ chmod +x send-signal.sh
+#endif
+
 Kludge to emulate timeout(1) which is not generally available.
-  $ cat > timeout.py <<EOF
-  > from __future__ import print_function
-  > import argparse
-  > import signal
-  > import subprocess
-  > import sys
-  > import time
-  > 
-  > ap = argparse.ArgumentParser()
-  > ap.add_argument('-s', nargs=1, default='SIGTERM')
-  > ap.add_argument('duration', nargs=1, type=int)
-  > ap.add_argument('argv', nargs='*')
-  > opts = ap.parse_args()
-  > try:
-  >     sig = int(opts.s[0])
-  > except ValueError:
-  >     sname = opts.s[0]
-  >     if not sname.startswith('SIG'):
-  >         sname = 'SIG' + sname
-  >     sig = getattr(signal, sname)
-  > proc = subprocess.Popen(opts.argv)
-  > time.sleep(opts.duration[0])
-  > proc.poll()
-  > if proc.returncode is None:
-  >     proc.send_signal(sig)
-  >     proc.wait()
-  >     sys.exit(124)
-  > EOF
 
 Set up repository
   $ hg init repo
   $ cd repo
   $ cat >> $HGRCPATH << EOF
   > [extensions]
-  > sleepext = ../sleepext.py
+  > wait_ext = $TESTTMP/wait_ext.py
   > EOF
 
+
 Test ctrl-c
-  $ "$PYTHON" $TESTTMP/timeout.py -s INT 1 hg sleep 2
+  $ rm -f $SYNC_FILE $DONE_FILE
+  $ sh -c "../send-signal.sh INT" &
+  $ hg wait-signal
   interrupted!
-  [124]
+  [255]
 
   $ cat >> $HGRCPATH << EOF
   > [experimental]
   > nointerrupt = yes
   > EOF
 
-  $ "$PYTHON" $TESTTMP/timeout.py -s INT 1 hg sleep 2
+  $ rm -f $SYNC_FILE $DONE_FILE
+  $ sh -c "../send-signal.sh INT" &
+  $ hg wait-signal
   interrupted!
-  [124]
+  [255]
 
   $ cat >> $HGRCPATH << EOF
   > [experimental]
   > nointerrupt-interactiveonly = False
   > EOF
 
-  $ "$PYTHON" $TESTTMP/timeout.py -s INT 1 hg sleep 2
+  $ rm -f $SYNC_FILE $DONE_FILE
+  $ sh -c "../send-signal.sh INT" &
+  $ hg wait-signal
   shutting down cleanly
   press ^C again to terminate immediately (dangerous)
   end of unsafe operation
   interrupted!
-  [124]
+  [255]
--- a/tests/test-pager.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-pager.t	Sun Aug 22 16:32:06 2021 -0400
@@ -219,27 +219,27 @@
 #endif
 
 A complicated pager command gets worse behavior. Bonus points if you can
-improve this. Windows apparently does this better?
+improve this. Windows apparently does this better, but only sometimes?
 #if windows
   $ hg log --limit 3 \
   >   --config pager.pager='this-command-better-never-exist --seriously' \
   >  2>/dev/null || true
-  \x1b[0;33mchangeset:   10:46106edeeb38\x1b[0m (esc)
-  tag:         tip
-  user:        test
-  date:        Thu Jan 01 00:00:00 1970 +0000
-  summary:     modify a 10
-  
-  \x1b[0;33mchangeset:   9:6dd8ea7dd621\x1b[0m (esc)
-  user:        test
-  date:        Thu Jan 01 00:00:00 1970 +0000
-  summary:     modify a 9
-  
-  \x1b[0;33mchangeset:   8:cff05a6312fe\x1b[0m (esc)
-  user:        test
-  date:        Thu Jan 01 00:00:00 1970 +0000
-  summary:     modify a 8
-  
+  \x1b[0;33mchangeset:   10:46106edeeb38\x1b[0m (esc) (?)
+  tag:         tip (?)
+  user:        test (?)
+  date:        Thu Jan 01 00:00:00 1970 +0000 (?)
+  summary:     modify a 10 (?)
+   (?)
+  \x1b[0;33mchangeset:   9:6dd8ea7dd621\x1b[0m (esc) (?)
+  user:        test (?)
+  date:        Thu Jan 01 00:00:00 1970 +0000 (?)
+  summary:     modify a 9 (?)
+   (?)
+  \x1b[0;33mchangeset:   8:cff05a6312fe\x1b[0m (esc) (?)
+  user:        test (?)
+  date:        Thu Jan 01 00:00:00 1970 +0000 (?)
+  summary:     modify a 8 (?)
+   (?)
 #else
   $ hg log --limit 3 \
   >   --config pager.pager='this-command-better-never-exist --seriously' \
--- a/tests/test-paths.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-paths.t	Sun Aug 22 16:32:06 2021 -0400
@@ -140,11 +140,22 @@
 
 zeroconf wraps ui.configitems(), which shouldn't crash at least:
 
+XXX-PYOXIDIZER Pyoxidizer build have trouble with zeroconf for unclear reason,
+we accept the bad output for now as this is the last thing in the way of
+testing the pyoxidizer build.
+
+#if no-pyoxidizer
   $ hg paths --config extensions.zeroconf=
   dupe = $TESTTMP/b#tip
   dupe:pushurl = https://example.com/dupe
   expand = $TESTTMP/a/$SOMETHING/bar
   insecure = http://foo:***@example.com/
+#else
+  $ hg paths --config extensions.zeroconf=
+  abort: An invalid argument was supplied (known-bad-output !)
+  [255]
+#endif
+
 
   $ cd ..
 
--- a/tests/test-persistent-nodemap.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-persistent-nodemap.t	Sun Aug 22 16:32:06 2021 -0400
@@ -428,6 +428,46 @@
   data-length: 121088
   data-unused: 0
   data-unused: 0.000%
+
+Sub-case: fallback for corrupted data file
+------------------------------------------
+
+Sabotaging the data file so that nodemap resolutions fail, triggering fallback to
+(non-persistent) C implementation.
+
+
+  $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
+  > sed 's/uid: //'`
+  $ FILE=.hg/store/00changelog-"${UUID}".nd
+  $ python -c "fobj = open('$FILE', 'r+b'); fobj.write(b'\xff' * 121088); fobj.close()"
+
+The nodemap data file is still considered in sync with the docket. This
+would fail without the fallback to the (non-persistent) C implementation:
+
+  $ hg log -r b355ef8adce0949b8bdf6afc72ca853740d65944 -T '{rev}\n' --traceback
+  5002
+
+The nodemap data file hasn't been fixed, more tests can be inserted:
+
+  $ hg debugnodemap --dump-disk | f --bytes=256 --hexdump --size
+  size=121088
+  0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  00a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+  00f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+
   $ mv ../tmp-data-file $FILE
   $ mv ../tmp-docket .hg/store/00changelog.n
 
--- a/tests/test-phases.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-phases.t	Sun Aug 22 16:32:06 2021 -0400
@@ -898,11 +898,11 @@
   A X
   $ hg --config "phases.new-commit=internal" commit -m "my test internal commit" 2>&1 | grep ProgrammingError
   ** ProgrammingError: this repository does not support the internal phase
-      raise error.ProgrammingError(msg)
+      raise error.ProgrammingError(msg) (no-pyoxidizer !)
   *ProgrammingError: this repository does not support the internal phase (glob)
   $ hg --config "phases.new-commit=archived" commit -m "my test archived commit" 2>&1 | grep ProgrammingError
   ** ProgrammingError: this repository does not support the archived phase
-      raise error.ProgrammingError(msg)
+      raise error.ProgrammingError(msg) (no-pyoxidizer !)
   *ProgrammingError: this repository does not support the archived phase (glob)
 
   $ cd ..
--- a/tests/test-rebase-inmemory.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-rebase-inmemory.t	Sun Aug 22 16:32:06 2021 -0400
@@ -963,6 +963,46 @@
   o  0: d20a80d4def3 'base'
   
 
+Test that update_hash_refs works.
+  $ hg co 0
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo update_hash_refs > update_hash_refs
+  $ hg add update_hash_refs
+  $ hg ci -m 'this will change hash'
+  created new head
+  $ echo changed >> update_hash_refs
+  $ hg ci -m "this starts as the child of `hg log -r . -T'{node|short}'` but not 506e2454484b. Also, ffffffffffffffff"
+  $ hg tglog
+  @  5: a8b42cbbde83 'this starts as the child of 98789aa60148 but not 506e2454484b. Also, ffffffffffffffff'
+  |
+  o  4: 98789aa60148 'this will change hash'
+  |
+  | o    3: 506e2454484b 'merge'
+  | |\
+  +---o  2: 531f80391e4a 'c'
+  | |
+  | o  1: 6f252845ea45 'a'
+  |/
+  o  0: d20a80d4def3 'base'
+  
+  $ hg rebase -r '.^::' -d 3
+  rebasing 4:98789aa60148 "this will change hash"
+  rebasing 5:a8b42cbbde83 tip "this starts as the child of 98789aa60148 but not 506e2454484b. Also, ffffffffffffffff"
+  saved backup bundle to $TESTTMP/keep_merge/.hg/strip-backup/98789aa60148-da3f4c2c-rebase.hg
+  $ hg tglog
+  @  5: 0fd2912e6cc1 'this starts as the child of c16c25696fe7 but not 506e2454484b. Also, ffffffffffffffff'
+  |
+  o  4: c16c25696fe7 'this will change hash'
+  |
+  o    3: 506e2454484b 'merge'
+  |\
+  | o  2: 531f80391e4a 'c'
+  | |
+  o |  1: 6f252845ea45 'a'
+  |/
+  o  0: d20a80d4def3 'base'
+  
+
   $ cd ..
 
 Test (virtual) working directory without changes, created by merge conflict
--- a/tests/test-serve.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-serve.t	Sun Aug 22 16:32:06 2021 -0400
@@ -44,13 +44,20 @@
   listening at http://localhost/ (bound to *$LOCALIP*:HGPORT2) (glob) (?)
   % errors
 
-With -v and -p daytime (should fail because low port)
+With -v and -p daytime
 
-#if no-root no-windows
+# On some system this will fails because port < 1024 are not bindable by normal
+# users.
+#
+# On some others the kernel is configured to allow any user to bind them and
+# this will work fine
+
+#if no-windows
   $ KILLQUIETLY=Y
   $ hgserve -p daytime
-  abort: cannot start server at 'localhost:13': Permission denied
-  abort: child process failed to start
+  abort: cannot start server at 'localhost:13': Permission denied (?)
+  abort: child process failed to start (?)
+  listening at http://localhost/ (bound to $LOCALIP:13) (?)
   % errors
   $ KILLQUIETLY=N
 #endif
--- a/tests/test-subrepo-git.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-subrepo-git.t	Sun Aug 22 16:32:06 2021 -0400
@@ -1,5 +1,20 @@
 #require git
 
+# XXX-CHG When running with python2 + chg this test tend to get stuck and end up
+# as a time-out error. My effort to reproduce this outside of the CI failed. The
+# test itself seems to pass fine, but never "complete". Debugging it is slow and
+# tedious. This as a bad impact on the development process as most CI run end up
+# wasting abotu 1h until that one fails.
+#
+# Pierre-Yves David, Augie Fackler and Raphaël Gomès all agreed to disable this
+# case in that specific case until we figure this out (or we drop python2 o:-) )
+
+#if no-py3 chg
+  $ echo 'skipped: this test get stuck on the CI with python2 + chg. investigation needed'
+  $ exit 80
+#endif
+
+
 make git commits repeatable
 
   $ cat >> $HGRCPATH <<EOF
--- a/tests/test-transaction-safety.t	Tue Jul 20 17:20:19 2021 +0200
+++ b/tests/test-transaction-safety.t	Sun Aug 22 16:32:06 2021 -0400
@@ -41,7 +41,23 @@
 setup
 -----
 
-synchronisation+output script:
+synchronisation+output script using the following schedule:
+
+[A1] "external"       is started
+[A2] "external"       waits on EXT_UNLOCK
+[A2] "external"       + creates EXT_WAITING → unlocks [C1]
+[B1] "hg commit/pull" is started
+[B2] "hg commit/pull" is ready to be committed
+[B3] "hg commit/pull" spawn "internal" using a pretxnclose hook (need [C4])
+[C1] "internal"       waits on EXT_WAITING (need [A2])
+[C2] "internal"       creates EXT_UNLOCK → unlocks [A2]
+[C3] "internal"       show the tipmost revision (inside of the transaction)
+[C4] "internal"       waits on EXT_DONE (need [A4])
+[A3] "external"       show the tipmost revision (outside of the transaction)
+[A4] "external"       creates EXT_DONE → unlocks [C4]
+[C5] "internal"       end of execution -> unlock [B3]
+[B4] "hg commit/pull" transaction is committed on disk
+
 
   $ mkdir sync
   $ mkdir output
@@ -60,8 +76,10 @@
   > EOF
   $ cat << EOF > script/internal.sh
   > #!/bin/sh
+  > "$RUNTESTDIR/testlib/wait-on-file" 5 "$HG_TEST_FILE_EXT_WAITING"
+  > touch "$HG_TEST_FILE_EXT_UNLOCK"
   > hg log --rev 'tip' -T 'internal: {rev} {desc}\n' > "$TESTTMP/output/internal.out"
-  > "$RUNTESTDIR/testlib/wait-on-file" 5 "$HG_TEST_FILE_EXT_DONE" "$HG_TEST_FILE_EXT_UNLOCK"
+  > "$RUNTESTDIR/testlib/wait-on-file" 5 "$HG_TEST_FILE_EXT_DONE"
   > EOF