hgext/git/manifest.py
author Manuel Jacob <me@manueljacob.de>
Sun, 22 May 2022 03:50:34 +0200
changeset 49269 395f28064826
parent 48946 642e31cb55f0
child 51863 f4733654f144
permissions -rw-r--r--
worker: avoid potential partial write of pickled data Previously, the code wrote the pickled data using os.write(). However, os.write() can write less bytes than passed to it. To trigger the problem, the pickled data had to be larger than 2147479552 bytes on my system. Instead, open a file object and pass it to pickle.dump(). This also has the advantage that it doesn’t buffer the whole pickled data in memory. Note that the opened file must be buffered because pickle doesn’t support unbuffered streams because unbuffered streams’ write() method might write less bytes than passed to it (like os.write()) but pickle.dump() relies on that all bytes are written (see https://github.com/python/cpython/issues/93050). The side effect of using a file object and a with statement is that wfd is explicitly closed now while it seems like before it was implicitly closed by process exit.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     1
from mercurial import (
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     2
    match as matchmod,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     3
    pathutil,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     4
    pycompat,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     5
    util,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     6
)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     7
from mercurial.interfaces import (
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     8
    repository,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
     9
    util as interfaceutil,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    10
)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    11
from . import gitutil
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    12
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    13
44484
ec54b3d2af0b git: don't fail import when pygit2 is not install
Martin von Zweigbergk <martinvonz@google.com>
parents: 44479
diff changeset
    14
pygit2 = gitutil.get_pygit2()
ec54b3d2af0b git: don't fail import when pygit2 is not install
Martin von Zweigbergk <martinvonz@google.com>
parents: 44479
diff changeset
    15
ec54b3d2af0b git: don't fail import when pygit2 is not install
Martin von Zweigbergk <martinvonz@google.com>
parents: 44479
diff changeset
    16
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    17
@interfaceutil.implementer(repository.imanifestdict)
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
    18
class gittreemanifest:
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    19
    """Expose git trees (and optionally a builder's overlay) as a manifestdict.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    20
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    21
    Very similar to mercurial.manifest.treemanifest.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    22
    """
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    23
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    24
    def __init__(self, git_repo, root_tree, pending_changes):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    25
        """Initializer.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    26
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    27
        Args:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    28
          git_repo: The git_repo we're walking (required to look up child
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    29
              trees).
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    30
          root_tree: The root Git tree object for this manifest.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    31
          pending_changes: A dict in which pending changes will be
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    32
              tracked. The enclosing memgittreemanifestctx will use this to
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    33
              construct any required Tree objects in Git during it's
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    34
              `write()` method.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    35
        """
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    36
        self._git_repo = git_repo
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    37
        self._tree = root_tree
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    38
        if pending_changes is None:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    39
            pending_changes = {}
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    40
        # dict of path: Optional[Tuple(node, flags)]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    41
        self._pending_changes = pending_changes
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    42
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    43
    def _resolve_entry(self, path):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    44
        """Given a path, load its node and flags, or raise KeyError if missing.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    45
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    46
        This takes into account any pending writes in the builder.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    47
        """
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    48
        upath = pycompat.fsdecode(path)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    49
        ent = None
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    50
        if path in self._pending_changes:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    51
            val = self._pending_changes[path]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    52
            if val is None:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    53
                raise KeyError
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    54
            return val
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    55
        t = self._tree
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    56
        comps = upath.split('/')
44930
47ce28a78f4a git: properly visit child tree objects when resolving a path
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44929
diff changeset
    57
        te = self._tree
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    58
        for comp in comps[:-1]:
44930
47ce28a78f4a git: properly visit child tree objects when resolving a path
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44929
diff changeset
    59
            te = te[comp]
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    60
            t = self._git_repo[te.id]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    61
        ent = t[comps[-1]]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    62
        if ent.filemode == pygit2.GIT_FILEMODE_BLOB:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    63
            flags = b''
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    64
        elif ent.filemode == pygit2.GIT_FILEMODE_BLOB_EXECUTABLE:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    65
            flags = b'x'
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    66
        elif ent.filemode == pygit2.GIT_FILEMODE_LINK:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    67
            flags = b'l'
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    68
        else:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    69
            raise ValueError('unsupported mode %s' % oct(ent.filemode))
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    70
        return ent.id.raw, flags
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    71
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    72
    def __getitem__(self, path):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    73
        return self._resolve_entry(path)[0]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    74
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    75
    def find(self, path):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    76
        return self._resolve_entry(path)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    77
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    78
    def __len__(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    79
        return len(list(self.walk(matchmod.always())))
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    80
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    81
    def __nonzero__(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    82
        try:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    83
            next(iter(self))
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    84
            return True
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    85
        except StopIteration:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    86
            return False
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    87
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    88
    __bool__ = __nonzero__
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    89
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    90
    def __contains__(self, path):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    91
        try:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    92
            self._resolve_entry(path)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    93
            return True
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    94
        except KeyError:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    95
            return False
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    96
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    97
    def iterkeys(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    98
        return self.walk(matchmod.always())
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
    99
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   100
    def keys(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   101
        return list(self.iterkeys())
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   102
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   103
    def __iter__(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   104
        return self.iterkeys()
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   105
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   106
    def __setitem__(self, path, node):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   107
        self._pending_changes[path] = node, self.flags(path)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   108
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   109
    def __delitem__(self, path):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   110
        # TODO: should probably KeyError for already-deleted  files?
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   111
        self._pending_changes[path] = None
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   112
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   113
    def filesnotin(self, other, match=None):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   114
        if match is not None:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   115
            match = matchmod.badmatch(match, lambda path, msg: None)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   116
            sm2 = set(other.walk(match))
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   117
            return {f for f in self.walk(match) if f not in sm2}
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   118
        return {f for f in self if f not in other}
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   119
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   120
    @util.propertycache
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   121
    def _dirs(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   122
        return pathutil.dirs(self)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   123
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   124
    def hasdir(self, dir):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   125
        return dir in self._dirs
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   126
44931
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   127
    def diff(self, other, match=lambda x: True, clean=False):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45516
diff changeset
   128
        """Finds changes between the current manifest and m2.
44931
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   129
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   130
        The result is returned as a dict with filename as key and
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   131
        values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   132
        nodeid in the current/other manifest and fl1/fl2 is the flag
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   133
        in the current/other manifest. Where the file does not exist,
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   134
        the nodeid will be None and the flags will be the empty
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   135
        string.
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45516
diff changeset
   136
        """
44931
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   137
        result = {}
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   138
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   139
        def _iterativediff(t1, t2, subdir):
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   140
            """compares two trees and appends new tree nodes to examine to
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   141
            the stack"""
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   142
            if t1 is None:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   143
                t1 = {}
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   144
            if t2 is None:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   145
                t2 = {}
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   146
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   147
            for e1 in t1:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   148
                realname = subdir + pycompat.fsencode(e1.name)
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   149
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   150
                if e1.type == pygit2.GIT_OBJ_TREE:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   151
                    try:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   152
                        e2 = t2[e1.name]
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   153
                        if e2.type != pygit2.GIT_OBJ_TREE:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   154
                            e2 = None
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   155
                    except KeyError:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   156
                        e2 = None
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   157
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   158
                    stack.append((realname + b'/', e1, e2))
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   159
                else:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   160
                    n1, fl1 = self.find(realname)
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   161
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   162
                    try:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   163
                        e2 = t2[e1.name]
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   164
                        n2, fl2 = other.find(realname)
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   165
                    except KeyError:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   166
                        e2 = None
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   167
                        n2, fl2 = (None, b'')
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   168
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   169
                    if e2 is not None and e2.type == pygit2.GIT_OBJ_TREE:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   170
                        stack.append((realname + b'/', None, e2))
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   171
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   172
                    if not match(realname):
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   173
                        continue
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   174
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   175
                    if n1 != n2 or fl1 != fl2:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   176
                        result[realname] = ((n1, fl1), (n2, fl2))
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   177
                    elif clean:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   178
                        result[realname] = None
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   179
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   180
            for e2 in t2:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   181
                if e2.name in t1:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   182
                    continue
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   183
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   184
                realname = subdir + pycompat.fsencode(e2.name)
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   185
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   186
                if e2.type == pygit2.GIT_OBJ_TREE:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   187
                    stack.append((realname + b'/', None, e2))
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   188
                elif match(realname):
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   189
                    n2, fl2 = other.find(realname)
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   190
                    result[realname] = ((None, b''), (n2, fl2))
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   191
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   192
        stack = []
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   193
        _iterativediff(self._tree, other._tree, b'')
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   194
        while stack:
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   195
            subdir, t1, t2 = stack.pop()
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   196
            # stack is populated in the function call
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   197
            _iterativediff(t1, t2, subdir)
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   198
f294b4e14fd0 git: implement diff manifest method
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44930
diff changeset
   199
        return result
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   200
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   201
    def setflag(self, path, flag):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   202
        node, unused_flag = self._resolve_entry(path)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   203
        self._pending_changes[path] = node, flag
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   204
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   205
    def get(self, path, default=None):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   206
        try:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   207
            return self._resolve_entry(path)[0]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   208
        except KeyError:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   209
            return default
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   210
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   211
    def flags(self, path):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   212
        try:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   213
            return self._resolve_entry(path)[1]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   214
        except KeyError:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   215
            return b''
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   216
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   217
    def copy(self):
45417
c8695439d7e3 git: actually copy treemanifest instances in .copy() (issue6398)
Augie Fackler <raf@durin42.com>
parents: 44931
diff changeset
   218
        return gittreemanifest(
c8695439d7e3 git: actually copy treemanifest instances in .copy() (issue6398)
Augie Fackler <raf@durin42.com>
parents: 44931
diff changeset
   219
            self._git_repo, self._tree, dict(self._pending_changes)
c8695439d7e3 git: actually copy treemanifest instances in .copy() (issue6398)
Augie Fackler <raf@durin42.com>
parents: 44931
diff changeset
   220
        )
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   221
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   222
    def items(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   223
        for f in self:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   224
            # TODO: build a proper iterator version of this
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   225
            yield self[f]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   226
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   227
    def iteritems(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   228
        return self.items()
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   229
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   230
    def iterentries(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   231
        for f in self:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   232
            # TODO: build a proper iterator version of this
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   233
            yield self._resolve_entry(f)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   234
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   235
    def text(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   236
        assert False  # TODO can this method move out of the manifest iface?
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   237
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   238
    def _walkonetree(self, tree, match, subdir):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   239
        for te in tree:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   240
            # TODO: can we prune dir walks with the matcher?
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   241
            realname = subdir + pycompat.fsencode(te.name)
44928
935c9f347bdb git: correctly check for type of object when walking
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44843
diff changeset
   242
            if te.type == pygit2.GIT_OBJ_TREE:
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   243
                for inner in self._walkonetree(
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   244
                    self._git_repo[te.id], match, realname + b'/'
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   245
                ):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   246
                    yield inner
44929
3679c88b7f4e git: don't yield paths for directories when walking
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44928
diff changeset
   247
            elif match(realname):
3679c88b7f4e git: don't yield paths for directories when walking
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44928
diff changeset
   248
                yield pycompat.fsencode(realname)
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   249
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   250
    def walk(self, match):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   251
        # TODO: this is a very lazy way to merge in the pending
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   252
        # changes. There is absolutely room for optimization here by
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   253
        # being clever about walking over the sets...
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   254
        baseline = set(self._walkonetree(self._tree, match, b''))
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   255
        deleted = {p for p, v in self._pending_changes.items() if v is None}
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   256
        pend = {p for p in self._pending_changes if match(p)}
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   257
        return iter(sorted((baseline | pend) - deleted))
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   258
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   259
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   260
@interfaceutil.implementer(repository.imanifestrevisionstored)
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   261
class gittreemanifestctx:
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   262
    def __init__(self, repo, gittree):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   263
        self._repo = repo
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   264
        self._tree = gittree
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   265
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   266
    def read(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   267
        return gittreemanifest(self._repo, self._tree, None)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   268
44479
7518ea76eff4 git: add readfast() method to manifest
Augie Fackler <raf@durin42.com>
parents: 44477
diff changeset
   269
    def readfast(self, shallow=False):
7518ea76eff4 git: add readfast() method to manifest
Augie Fackler <raf@durin42.com>
parents: 44477
diff changeset
   270
        return self.read()
7518ea76eff4 git: add readfast() method to manifest
Augie Fackler <raf@durin42.com>
parents: 44477
diff changeset
   271
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   272
    def copy(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   273
        # NB: it's important that we return a memgittreemanifestctx
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   274
        # because the caller expects a mutable manifest.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   275
        return memgittreemanifestctx(self._repo, self._tree)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   276
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   277
    def find(self, path):
44843
288328c6711b git: fix probable missing return
Romain DEP. <rom1dep@gmail.com>
parents: 44625
diff changeset
   278
        return self.read()[path]
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   279
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   280
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   281
@interfaceutil.implementer(repository.imanifestrevisionwritable)
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   282
class memgittreemanifestctx:
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   283
    def __init__(self, repo, tree):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   284
        self._repo = repo
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   285
        self._tree = tree
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   286
        # dict of path: Optional[Tuple(node, flags)]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   287
        self._pending_changes = {}
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   288
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   289
    def read(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   290
        return gittreemanifest(self._repo, self._tree, self._pending_changes)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   291
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   292
    def copy(self):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   293
        # TODO: if we have a builder in play, what should happen here?
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   294
        # Maybe we can shuffle copy() into the immutable interface.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   295
        return memgittreemanifestctx(self._repo, self._tree)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   296
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   297
    def write(self, transaction, link, p1, p2, added, removed, match=None):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   298
        # We're not (for now, anyway) going to audit filenames, so we
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   299
        # can ignore added and removed.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   300
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   301
        # TODO what does this match argument get used for? hopefully
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   302
        # just narrow?
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   303
        assert not match or isinstance(match, matchmod.alwaysmatcher)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   304
44625
e9e7156a8d6c git: pass a list to pathutil.dirs to indicate that it is a manifest
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44484
diff changeset
   305
        touched_dirs = pathutil.dirs(list(self._pending_changes))
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   306
        trees = {
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   307
            b'': self._tree,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   308
        }
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   309
        # path: treebuilder
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   310
        builders = {
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   311
            b'': self._repo.TreeBuilder(self._tree),
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   312
        }
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   313
        # get a TreeBuilder for every tree in the touched_dirs set
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   314
        for d in sorted(touched_dirs, key=lambda x: (len(x), x)):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   315
            if d == b'':
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   316
                # loaded root tree above
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   317
                continue
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   318
            comps = d.split(b'/')
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   319
            full = b''
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   320
            for part in comps:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   321
                parent = trees[full]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   322
                try:
45516
73a5aa5e1857 git: pass `id` attribute of `pygit2.Tree` object
Connor Sheehan <sheehan@mozilla.com>
parents: 45417
diff changeset
   323
                    parent_tree_id = parent[pycompat.fsdecode(part)].id
73a5aa5e1857 git: pass `id` attribute of `pygit2.Tree` object
Connor Sheehan <sheehan@mozilla.com>
parents: 45417
diff changeset
   324
                    new = self._repo[parent_tree_id]
44477
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   325
                except KeyError:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   326
                    # new directory
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   327
                    new = None
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   328
                full += b'/' + part
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   329
                if new is not None:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   330
                    # existing directory
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   331
                    trees[full] = new
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   332
                    builders[full] = self._repo.TreeBuilder(new)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   333
                else:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   334
                    # new directory, use an empty dict to easily
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   335
                    # generate KeyError as any nested new dirs get
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   336
                    # created.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   337
                    trees[full] = {}
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   338
                    builders[full] = self._repo.TreeBuilder()
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   339
        for f, info in self._pending_changes.items():
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   340
            if b'/' not in f:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   341
                dirname = b''
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   342
                basename = f
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   343
            else:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   344
                dirname, basename = f.rsplit(b'/', 1)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   345
                dirname = b'/' + dirname
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   346
            if info is None:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   347
                builders[dirname].remove(pycompat.fsdecode(basename))
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   348
            else:
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   349
                n, fl = info
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   350
                mode = {
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   351
                    b'': pygit2.GIT_FILEMODE_BLOB,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   352
                    b'x': pygit2.GIT_FILEMODE_BLOB_EXECUTABLE,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   353
                    b'l': pygit2.GIT_FILEMODE_LINK,
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   354
                }[fl]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   355
                builders[dirname].insert(
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   356
                    pycompat.fsdecode(basename), gitutil.togitnode(n), mode
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   357
                )
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   358
        # This visits the buffered TreeBuilders in deepest-first
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   359
        # order, bubbling up the edits.
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   360
        for b in sorted(builders, key=len, reverse=True):
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   361
            if b == b'':
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   362
                break
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   363
            cb = builders[b]
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   364
            dn, bn = b.rsplit(b'/', 1)
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   365
            builders[dn].insert(
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   366
                pycompat.fsdecode(bn), cb.write(), pygit2.GIT_FILEMODE_TREE
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   367
            )
ad718271a9eb git: skeleton of a new extension to _directly_ operate on git repos
Augie Fackler <augie@google.com>
parents:
diff changeset
   368
        return builders[b''].write().raw