hgext/narrow/narrowrevlog.py
changeset 37372 1b2fa531fd7a
parent 37270 6ff8bd691fb8
child 37373 c50078fc32f3
equal deleted inserted replaced
37371:d3286dd2ca2f 37372:1b2fa531fd7a
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
    10 from mercurial import (
    10 from mercurial import (
    11    error,
       
    12    manifest,
    11    manifest,
    13    revlog,
    12    revlog,
    14    util,
    13    util,
    15 )
    14 )
    16 
    15 
    29 def setup():
    28 def setup():
    30     # We just wanted to add the flag processor, which is done at module
    29     # We just wanted to add the flag processor, which is done at module
    31     # load time.
    30     # load time.
    32     pass
    31     pass
    33 
    32 
    34 class excludeddir(manifest.treemanifest):
       
    35     """Stand-in for a directory that is excluded from the repository.
       
    36 
       
    37     With narrowing active on a repository that uses treemanifests,
       
    38     some of the directory revlogs will be excluded from the resulting
       
    39     clone. This is a huge storage win for clients, but means we need
       
    40     some sort of pseudo-manifest to surface to internals so we can
       
    41     detect a merge conflict outside the narrowspec. That's what this
       
    42     class is: it stands in for a directory whose node is known, but
       
    43     whose contents are unknown.
       
    44     """
       
    45     def __init__(self, dir, node):
       
    46         super(excludeddir, self).__init__(dir)
       
    47         self._node = node
       
    48         # Add an empty file, which will be included by iterators and such,
       
    49         # appearing as the directory itself (i.e. something like "dir/")
       
    50         self._files[''] = node
       
    51         self._flags[''] = 't'
       
    52 
       
    53     # Manifests outside the narrowspec should never be modified, so avoid
       
    54     # copying. This makes a noticeable difference when there are very many
       
    55     # directories outside the narrowspec. Also, it makes sense for the copy to
       
    56     # be of the same type as the original, which would not happen with the
       
    57     # super type's copy().
       
    58     def copy(self):
       
    59         return self
       
    60 
       
    61 class excludeddirmanifestctx(manifest.treemanifestctx):
       
    62     """context wrapper for excludeddir - see that docstring for rationale"""
       
    63     def __init__(self, dir, node):
       
    64         self._dir = dir
       
    65         self._node = node
       
    66 
       
    67     def read(self):
       
    68         return excludeddir(self._dir, self._node)
       
    69 
       
    70     def write(self, *args):
       
    71         raise error.ProgrammingError(
       
    72             'attempt to write manifest from excluded dir %s' % self._dir)
       
    73 
       
    74 class excludedmanifestrevlog(manifest.manifestrevlog):
       
    75     """Stand-in for excluded treemanifest revlogs.
       
    76 
       
    77     When narrowing is active on a treemanifest repository, we'll have
       
    78     references to directories we can't see due to the revlog being
       
    79     skipped. This class exists to conform to the manifestrevlog
       
    80     interface for those directories and proactively prevent writes to
       
    81     outside the narrowspec.
       
    82     """
       
    83 
       
    84     def __init__(self, dir):
       
    85         self._dir = dir
       
    86 
       
    87     def __len__(self):
       
    88         raise error.ProgrammingError(
       
    89             'attempt to get length of excluded dir %s' % self._dir)
       
    90 
       
    91     def rev(self, node):
       
    92         raise error.ProgrammingError(
       
    93             'attempt to get rev from excluded dir %s' % self._dir)
       
    94 
       
    95     def linkrev(self, node):
       
    96         raise error.ProgrammingError(
       
    97             'attempt to get linkrev from excluded dir %s' % self._dir)
       
    98 
       
    99     def node(self, rev):
       
   100         raise error.ProgrammingError(
       
   101             'attempt to get node from excluded dir %s' % self._dir)
       
   102 
       
   103     def add(self, *args, **kwargs):
       
   104         # We should never write entries in dirlogs outside the narrow clone.
       
   105         # However, the method still gets called from writesubtree() in
       
   106         # _addtree(), so we need to handle it. We should possibly make that
       
   107         # avoid calling add() with a clean manifest (_dirty is always False
       
   108         # in excludeddir instances).
       
   109         pass
       
   110 
       
   111 def makenarrowmanifestrevlog(mfrevlog, repo):
    33 def makenarrowmanifestrevlog(mfrevlog, repo):
   112     if util.safehasattr(mfrevlog, '_narrowed'):
    34     if util.safehasattr(mfrevlog, '_narrowed'):
   113         return
    35         return
   114 
    36 
   115     class narrowmanifestrevlog(mfrevlog.__class__):
    37     class narrowmanifestrevlog(mfrevlog.__class__):
   116         # This function is called via debug{revlog,index,data}, but also during
    38         # This function is called via debug{revlog,index,data}, but also during
   117         # at least some push operations. This will be used to wrap/exclude the
    39         # at least some push operations. This will be used to wrap/exclude the
   118         # child directories when using treemanifests.
    40         # child directories when using treemanifests.
   119         def dirlog(self, d):
    41         def dirlog(self, d):
   120             if not repo.narrowmatch().visitdir(d[:-1] or '.'):
    42             if not repo.narrowmatch().visitdir(d[:-1] or '.'):
   121                 return excludedmanifestrevlog(d)
    43                 return manifest.excludedmanifestrevlog(d)
   122             result = super(narrowmanifestrevlog, self).dirlog(d)
    44             result = super(narrowmanifestrevlog, self).dirlog(d)
   123             makenarrowmanifestrevlog(result, repo)
    45             makenarrowmanifestrevlog(result, repo)
   124             return result
    46             return result
   125 
    47 
   126     mfrevlog.__class__ = narrowmanifestrevlog
    48     mfrevlog.__class__ = narrowmanifestrevlog
   128 
    50 
   129 def makenarrowmanifestlog(mfl, repo):
    51 def makenarrowmanifestlog(mfl, repo):
   130     class narrowmanifestlog(mfl.__class__):
    52     class narrowmanifestlog(mfl.__class__):
   131         def get(self, dir, node, verify=True):
    53         def get(self, dir, node, verify=True):
   132             if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
    54             if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
   133                 return excludeddirmanifestctx(dir, node)
    55                 return manifest.excludeddirmanifestctx(dir, node)
   134             return super(narrowmanifestlog, self).get(dir, node, verify=verify)
    56             return super(narrowmanifestlog, self).get(dir, node, verify=verify)
   135     mfl.__class__ = narrowmanifestlog
    57     mfl.__class__ = narrowmanifestlog
   136 
    58 
   137 def makenarrowfilelog(fl, narrowmatch):
    59 def makenarrowfilelog(fl, narrowmatch):
   138     class narrowfilelog(fl.__class__):
    60     class narrowfilelog(fl.__class__):