mercurial/localrepo.py
branchstable
changeset 49366 288de6f5d724
parent 49355 0540c1628fd4
child 49451 0c70d888a484
child 49467 0705afae6253
--- a/mercurial/localrepo.py	Thu Jun 16 15:15:03 2022 +0200
+++ b/mercurial/localrepo.py	Thu Jun 16 15:28:54 2022 +0200
@@ -6,9 +6,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from __future__ import absolute_import
-
-import errno
+
 import functools
 import os
 import random
@@ -16,6 +14,7 @@
 import time
 import weakref
 
+from concurrent import futures
 from .i18n import _
 from .node import (
     bin,
@@ -251,7 +250,7 @@
 
 
 @interfaceutil.implementer(repository.ipeercommandexecutor)
-class localcommandexecutor(object):
+class localcommandexecutor:
     def __init__(self, peer):
         self._peer = peer
         self._sent = False
@@ -278,7 +277,7 @@
         # method on the peer and return a resolved future.
         fn = getattr(self._peer, pycompat.sysstr(command))
 
-        f = pycompat.futures.Future()
+        f = futures.Future()
 
         try:
             result = fn(**pycompat.strkwargs(args))
@@ -517,19 +516,18 @@
     """reads the require file present at root of this vfs
     and return a set of requirements
 
-    If allowmissing is True, we suppress ENOENT if raised"""
+    If allowmissing is True, we suppress FileNotFoundError if raised"""
     # requires file contains a newline-delimited list of
     # features/capabilities the opener (us) must have in order to use
     # the repository. This file was introduced in Mercurial 0.9.2,
     # which means very old repositories may not have one. We assume
     # a missing file translates to no requirements.
     try:
-        requirements = set(vfs.read(b'requires').splitlines())
-    except IOError as e:
-        if not (allowmissing and e.errno == errno.ENOENT):
+        return set(vfs.read(b'requires').splitlines())
+    except FileNotFoundError:
+        if not allowmissing:
             raise
-        requirements = set()
-    return requirements
+        return set()
 
 
 def makelocalrepository(baseui, path, intents=None):
@@ -583,9 +581,8 @@
     if not hgvfs.isdir():
         try:
             hgvfs.stat()
-        except OSError as e:
-            if e.errno != errno.ENOENT:
-                raise
+        except FileNotFoundError:
+            pass
         except ValueError as e:
             # Can be raised on Python 3.8 when path is invalid.
             raise error.Abort(
@@ -631,6 +628,9 @@
             mismatch_config = ui.config(
                 b'share', b'safe-mismatch.source-not-safe'
             )
+            mismatch_verbose_upgrade = ui.configbool(
+                b'share', b'safe-mismatch.source-not-safe:verbose-upgrade'
+            )
             if mismatch_config in (
                 b'downgrade-allow',
                 b'allow',
@@ -646,6 +646,7 @@
                     requirements,
                     mismatch_config,
                     mismatch_warn,
+                    mismatch_verbose_upgrade,
                 )
             elif mismatch_config == b'abort':
                 raise error.Abort(
@@ -671,6 +672,9 @@
             mismatch_warn = ui.configbool(
                 b'share', b'safe-mismatch.source-safe.warn'
             )
+            mismatch_verbose_upgrade = ui.configbool(
+                b'share', b'safe-mismatch.source-safe:verbose-upgrade'
+            )
             if mismatch_config in (
                 b'upgrade-allow',
                 b'allow',
@@ -686,6 +690,7 @@
                     requirements,
                     mismatch_config,
                     mismatch_warn,
+                    mismatch_verbose_upgrade,
                 )
             elif mismatch_config == b'abort':
                 raise error.Abort(
@@ -1070,6 +1075,7 @@
         b'storage', b'revlog.optimize-delta-parent-choice'
     )
     options[b'deltabothparents'] = deltabothparents
+    options[b'debug-delta'] = ui.configbool(b'debug', b'revlog.debug-delta')
 
     issue6528 = ui.configbool(b'storage', b'revlog.issue6528.fix-incoming')
     options[b'issue6528.fix-incoming'] = issue6528
@@ -1215,7 +1221,7 @@
 
 
 @interfaceutil.implementer(repository.ilocalrepositoryfilestorage)
-class revlogfilestorage(object):
+class revlogfilestorage:
     """File storage when using revlogs."""
 
     def file(self, path):
@@ -1226,7 +1232,7 @@
 
 
 @interfaceutil.implementer(repository.ilocalrepositoryfilestorage)
-class revlognarrowfilestorage(object):
+class revlognarrowfilestorage:
     """File storage when using revlogs and narrow files."""
 
     def file(self, path):
@@ -1259,7 +1265,7 @@
 
 
 @interfaceutil.implementer(repository.ilocalrepositorymain)
-class localrepository(object):
+class localrepository:
     """Main class for representing local repositories.
 
     All local repositories are instances of this class.
@@ -1741,7 +1747,9 @@
 
     def _makedirstate(self):
         """Extension point for wrapping the dirstate per-repo."""
-        sparsematchfn = lambda: sparse.matcher(self)
+        sparsematchfn = None
+        if sparse.use_sparse(self):
+            sparsematchfn = lambda: sparse.matcher(self)
         v2_req = requirementsmod.DIRSTATE_V2_REQUIREMENT
         th = requirementsmod.DIRSTATE_TRACKED_HINT_V1
         use_dirstate_v2 = v2_req in self.requirements
@@ -1884,7 +1892,7 @@
             # wdirrev isn't contiguous so the slice shouldn't include it
             return [
                 self[i]
-                for i in pycompat.xrange(*changeid.indices(len(self)))
+                for i in range(*changeid.indices(len(self)))
                 if i not in self.changelog.filteredrevs
             ]
 
@@ -2044,7 +2052,7 @@
 
         # This simplifies its cache management by having one decorated
         # function (this one) and the rest simply fetch things from it.
-        class tagscache(object):
+        class tagscache:
             def __init__(self):
                 # These two define the set of tags for this repository. tags
                 # maps tag name to node; tagtypes maps tag name to 'global' or
@@ -2068,7 +2076,7 @@
         else:
             tags = self._tagscache.tags
         rev = self.changelog.rev
-        for k, v in pycompat.iteritems(tags):
+        for k, v in tags.items():
             try:
                 # ignore tags to unknown nodes
                 rev(v)
@@ -2103,13 +2111,12 @@
         # writing to the cache), but the rest of Mercurial wants them in
         # local encoding.
         tags = {}
-        for (name, (node, hist)) in pycompat.iteritems(alltags):
+        for (name, (node, hist)) in alltags.items():
             if node != self.nullid:
                 tags[encoding.tolocal(name)] = node
         tags[b'tip'] = self.changelog.tip()
         tagtypes = {
-            encoding.tolocal(name): value
-            for (name, value) in pycompat.iteritems(tagtypes)
+            encoding.tolocal(name): value for (name, value) in tagtypes.items()
         }
         return (tags, tagtypes)
 
@@ -2128,7 +2135,7 @@
         '''return a list of tags ordered by revision'''
         if not self._tagscache.tagslist:
             l = []
-            for t, n in pycompat.iteritems(self.tags()):
+            for t, n in self.tags().items():
                 l.append((self.changelog.rev(n), t, n))
             self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
 
@@ -2138,9 +2145,9 @@
         '''return the tags associated with a node'''
         if not self._tagscache.nodetagscache:
             nodetagscache = {}
-            for t, n in pycompat.iteritems(self._tagscache.tags):
+            for t, n in self._tagscache.tags.items():
                 nodetagscache.setdefault(n, []).append(t)
-            for tags in pycompat.itervalues(nodetagscache):
+            for tags in nodetagscache.values():
                 tags.sort()
             self._tagscache.nodetagscache = nodetagscache
         return self._tagscache.nodetagscache.get(node, [])
@@ -2256,7 +2263,7 @@
                 mf = matchmod.match(self.root, b'', [pat])
                 fn = None
                 params = cmd
-                for name, filterfn in pycompat.iteritems(self._datafilters):
+                for name, filterfn in self._datafilters.items():
                     if cmd.startswith(name):
                         fn = filterfn
                         params = cmd[len(name) :].lstrip()
@@ -3503,9 +3510,8 @@
             vfs.tryunlink(dest)
             try:
                 vfs.rename(src, dest)
-            except OSError as exc:  # journal file does not yet exist
-                if exc.errno != errno.ENOENT:
-                    raise
+            except FileNotFoundError:  # journal file does not yet exist
+                pass
 
     return a
 
@@ -3517,11 +3523,20 @@
 
 
 def instance(ui, path, create, intents=None, createopts=None):
+
+    # prevent cyclic import localrepo -> upgrade -> localrepo
+    from . import upgrade
+
     localpath = urlutil.urllocalpath(path)
     if create:
         createrepository(ui, localpath, createopts=createopts)
 
-    return makelocalrepository(ui, localpath, intents=intents)
+    def repo_maker():
+        return makelocalrepository(ui, localpath, intents=intents)
+
+    repo = repo_maker()
+    repo = upgrade.may_auto_upgrade(repo, repo_maker)
+    return repo
 
 
 def islocal(path):
@@ -3914,7 +3929,7 @@
     #
     # But we have to allow the close() method because some constructors
     # of repos call close() on repo references.
-    class poisonedrepository(object):
+    class poisonedrepository:
         def __getattribute__(self, item):
             if item == 'close':
                 return object.__getattribute__(self, item)