mercurial/repoview.py
author Pierre-Yves David <pierre-yves.david@ens-lyon.org>
Thu, 20 Dec 2012 15:32:42 +0100
changeset 18100 3a6ddacb7198
child 18101 a464deecc9dd
permissions -rw-r--r--
clfilter: add actual repo filtering mechanism We add a `filtered` method on repo. This method return an instance of `repoview` that behaves exactly as the original repository but with a filtered changelog attribute. Filters are identified by a "name". Planned filter are `unserved`, `hidden` and `mutable`. Filtering the repository in place what out of question as it wont not allows multiple thread to share the same repo. It would makes control of the filtering scope harder too. See the `repoview` docstring for details. A mechanism to compute filtered revision is also installed. Some caches will be installed in later commit.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     1
# repoview.py - Filtered view of a localrepo object
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     2
#
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     3
# Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     4
#                Logilab SA        <contact@logilab.fr>
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     5
#
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     6
# This software may be used and distributed according to the terms of the
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     7
# GNU General Public License version 2 or any later version.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     8
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
     9
import copy
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    10
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    11
# function to compute filtered set
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    12
filtertable = {}
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    13
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    14
def filteredrevs(repo, filtername):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    15
    """returns set of filtered revision for this filter name"""
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    16
    return filtertable[filtername](repo.unfiltered())
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    17
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    18
class repoview(object):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    19
    """Provide a read/write view of a repo through a filtered changelog
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    20
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    21
    This object is used to access a filtered version of a repository without
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    22
    altering the original repository object itself. We can not alter the
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    23
    original object for two main reasons:
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    24
    - It prevents the use of a repo with multiple filters at the same time. In
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    25
      particular when multiple threads are involved.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    26
    - It makes scope of the filtering harder to control.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    27
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    28
    This object behaves very closely to the original repository. All attribute
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    29
    operations are done on the original repository:
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    30
    - An access to `repoview.someattr` actually returns `repo.someattr`,
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    31
    - A write to `repoview.someattr` actually sets value of `repo.someattr`,
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    32
    - A deletion of `repoview.someattr` actually drops `someattr`
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    33
      from `repo.__dict__`.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    34
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    35
    The only exception is the `changelog` property. It is overridden to return
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    36
    a (surface) copy of `repo.changelog` with some revisions filtered. The
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    37
    `filtername` attribute of the view control the revisions that need to be
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    38
    filtered.  (the fact the changelog is copied is an implementation detail).
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    39
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    40
    Unlike attributes, this object intercepts all method calls. This means that
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    41
    all methods are run on the `repoview` object with the filtered `changelog`
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    42
    property. For this purpose the simple `repoview` class must be mixed with
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    43
    the actual class of the repository. This ensures that the resulting
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    44
    `repoview` object have the very same methods than the repo object. This
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    45
    leads to the property below.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    46
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    47
        repoview.method() --> repo.__class__.method(repoview)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    48
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    49
    The inheritance has to be done dynamically because `repo` can be of any
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    50
    subclasses of `localrepo`. Eg: `bundlerepo` or `httprepo`.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    51
    """
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    52
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    53
    def __init__(self, repo, filtername):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    54
        object.__setattr__(self, '_unfilteredrepo', repo)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    55
        object.__setattr__(self, 'filtername', filtername)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    56
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    57
    # not a cacheproperty on purpose we shall implement a proper cache later
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    58
    @property
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    59
    def changelog(self):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    60
        """return a filtered version of the changeset
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    61
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    62
        this changelog must not be used for writing"""
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    63
        # some cache may be implemented later
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    64
        cl = copy.copy(self._unfilteredrepo.changelog)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    65
        cl.filteredrevs = filteredrevs(self._unfilteredrepo, self.filtername)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    66
        return cl
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    67
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    68
    def unfiltered(self):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    69
        """Return an unfiltered version of a repo"""
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    70
        return self._unfilteredrepo
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    71
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    72
    def filtered(self, name):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    73
        """Return a filtered version of a repository"""
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    74
        if name == self.filtername:
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    75
            return self
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    76
        return self.unfiltered().filtered(name)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    77
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    78
    # everything access are forwarded to the proxied repo
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    79
    def __getattr__(self, attr):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    80
        return getattr(self._unfilteredrepo, attr)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    81
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    82
    def __setattr__(self, attr, value):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    83
        return setattr(self._unfilteredrepo, attr, value)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    84
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    85
    def __delattr__(self, attr):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    86
        return delattr(self._unfilteredrepo, attr)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    87
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    88
    # The `requirement` attribut is initialiazed during __init__. But
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    89
    # __getattr__ won't be called as it also exists on the class. We need
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    90
    # explicit forwarding to main repo here
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    91
    @property
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    92
    def requirements(self):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    93
        return self._unfilteredrepo.requirements
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
    94