/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.358.2 by Jelmer Vernooij
Refresh copyright headers, add my email.
1
# Copyright (C) 2009-2018 Jelmer Vernooij <jelmer@jelmer.uk>
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
0.358.1 by Jelmer Vernooij
Fix FSF address.
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
16
17
18
"""Git Trees."""
19
0.200.1594 by Jelmer Vernooij
Use absolute_import everywhere.
20
from __future__ import absolute_import
21
0.360.2 by Jelmer Vernooij
Fix test.
22
import errno
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
23
from io import BytesIO
24
import os
25
26
from dulwich.index import (
27
    index_entry_from_stat,
28
    )
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
29
from dulwich.object_store import (
30
    tree_lookup_path,
31
    OverlayObjectStore,
32
    )
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
33
from dulwich.objects import (
34
    Blob,
35
    Tree,
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
36
    ZERO_SHA,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
37
    )
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
38
import stat
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
39
import posixpath
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
40
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
41
from ... import (
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
42
    delta,
43
    errors,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
44
    lock,
45
    mutabletree,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
46
    osutils,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
47
    revisiontree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
48
    trace,
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
49
    tree as _mod_tree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
50
    workingtree,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
51
    )
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
52
from ...revision import NULL_REVISION
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
53
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
54
from .mapping import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
55
    mode_is_executable,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
56
    mode_kind,
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
57
    GitFileIdMap,
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
58
    default_mapping,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
59
    )
60
61
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
62
class GitTreeDirectory(_mod_tree.TreeDirectory):
63
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
64
    __slots__ = ['file_id', 'name', 'parent_id', 'children']
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
65
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
66
    def __init__(self, file_id, name, parent_id):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
67
        self.file_id = file_id
68
        self.name = name
69
        self.parent_id = parent_id
70
        # TODO(jelmer)
71
        self.children = {}
72
73
    @property
74
    def kind(self):
75
        return 'directory'
76
77
    @property
78
    def executable(self):
79
        return False
80
81
    def copy(self):
82
        return self.__class__(
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
83
            self.file_id, self.name, self.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
84
85
    def __repr__(self):
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
86
        return "%s(file_id=%r, name=%r, parent_id=%r)" % (
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
87
            self.__class__.__name__, self.file_id, self.name,
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
88
            self.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
89
90
    def __eq__(self, other):
91
        return (self.kind == other.kind and
92
                self.file_id == other.file_id and
93
                self.name == other.name and
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
94
                self.parent_id == other.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
95
96
97
class GitTreeFile(_mod_tree.TreeFile):
98
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
99
    __slots__ = ['file_id', 'name', 'parent_id', 'text_size', 'text_sha1',
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
100
                 'executable']
101
0.390.2 by Jelmer Vernooij
merge trunk
102
    def __init__(self, file_id, name, parent_id, text_size=None,
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
103
                 text_sha1=None, executable=None):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
104
        self.file_id = file_id
105
        self.name = name
106
        self.parent_id = parent_id
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
107
        self.text_size = text_size
108
        self.text_sha1 = text_sha1
109
        self.executable = executable
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
110
111
    @property
112
    def kind(self):
113
        return 'file'
114
115
    def __eq__(self, other):
116
        return (self.kind == other.kind and
117
                self.file_id == other.file_id and
118
                self.name == other.name and
119
                self.parent_id == other.parent_id and
120
                self.text_sha1 == other.text_sha1 and
121
                self.text_size == other.text_size and
122
                self.executable == other.executable)
123
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
124
    def __repr__(self):
0.390.2 by Jelmer Vernooij
merge trunk
125
        return "%s(file_id=%r, name=%r, parent_id=%r, text_size=%r, text_sha1=%r, executable=%r)" % (
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
126
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.390.2 by Jelmer Vernooij
merge trunk
127
            self.text_size, self.text_sha1, self.executable)
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
128
0.365.2 by Jelmer Vernooij
Add eq/copy.
129
    def copy(self):
130
        ret = self.__class__(
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
131
                self.file_id, self.name, self.parent_id)
0.365.2 by Jelmer Vernooij
Add eq/copy.
132
        ret.text_sha1 = self.text_sha1
133
        ret.text_size = self.text_size
134
        ret.executable = self.executable
135
        return ret
136
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
137
138
class GitTreeSymlink(_mod_tree.TreeLink):
139
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
140
    __slots__ = ['file_id', 'name', 'parent_id', 'symlink_target']
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
141
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
142
    def __init__(self, file_id, name, parent_id,
0.365.2 by Jelmer Vernooij
Add eq/copy.
143
                 symlink_target=None):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
144
        self.file_id = file_id
145
        self.name = name
146
        self.parent_id = parent_id
0.365.2 by Jelmer Vernooij
Add eq/copy.
147
        self.symlink_target = symlink_target
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
148
149
    @property
150
    def kind(self):
151
        return 'symlink'
152
153
    @property
154
    def executable(self):
155
        return False
156
157
    @property
158
    def text_size(self):
159
        return None
160
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
161
    def __repr__(self):
0.390.2 by Jelmer Vernooij
merge trunk
162
        return "%s(file_id=%r, name=%r, parent_id=%r, symlink_target=%r)" % (
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
163
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.390.2 by Jelmer Vernooij
merge trunk
164
            self.symlink_target)
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
165
0.365.2 by Jelmer Vernooij
Add eq/copy.
166
    def __eq__(self, other):
167
        return (self.kind == other.kind and
168
                self.file_id == other.file_id and
169
                self.name == other.name and
170
                self.parent_id == other.parent_id and
171
                self.symlink_target == other.symlink_target)
172
173
    def copy(self):
174
        return self.__class__(
175
                self.file_id, self.name, self.parent_id,
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
176
                self.symlink_target)
0.365.2 by Jelmer Vernooij
Add eq/copy.
177
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
178
179
entry_factory = {
180
    'directory': GitTreeDirectory,
181
    'file': GitTreeFile,
182
    'symlink': GitTreeSymlink,
183
    }
184
185
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
186
def ensure_normalized_path(path):
187
    """Check whether path is normalized.
188
189
    :raises InvalidNormalization: When path is not normalized, and cannot be
190
        accessed on this platform by the normalized path.
191
    :return: The NFC normalised version of path.
192
    """
193
    norm_path, can_access = osutils.normalized_filename(path)
194
    if norm_path != path:
195
        if can_access:
196
            return norm_path
197
        else:
198
            raise errors.InvalidNormalization(path)
199
    return path
200
201
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
202
class GitRevisionTree(revisiontree.RevisionTree):
0.200.959 by Jelmer Vernooij
Improve docstrings.
203
    """Revision tree implementation based on Git objects."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
204
205
    def __init__(self, repository, revision_id):
206
        self._revision_id = revision_id
207
        self._repository = repository
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
208
        self.store = repository._git.object_store
0.361.1 by Jelmer Vernooij
Don't use assert.
209
        if type(revision_id) is not str:
210
            raise TypeError(revision_id)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
211
        self.commit_id, self.mapping = repository.lookup_bzr_revision_id(revision_id)
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
212
        if revision_id == NULL_REVISION:
213
            self.tree = None
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
214
            self.mapping = default_mapping
215
            self._fileid_map = GitFileIdMap(
0.287.4 by Jelmer Vernooij
Fix GitRevisionTree behaviour for null:
216
                {},
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
217
                default_mapping)
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
218
        else:
219
            try:
220
                commit = self.store[self.commit_id]
221
            except KeyError, r:
222
                raise errors.NoSuchRevision(repository, revision_id)
223
            self.tree = commit.tree
224
            self._fileid_map = self.mapping.get_fileid_map(self.store.__getitem__, self.tree)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
225
0.349.1 by Jelmer Vernooij
Support supports_rename_tracking method.
226
    def supports_rename_tracking(self):
227
        return False
228
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
229
    def get_file_revision(self, path, file_id=None):
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
230
        change_scanner = self._repository._file_change_scanner
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
231
        if self.commit_id == ZERO_SHA:
232
            return NULL_REVISION
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
233
        (path, commit_id) = change_scanner.find_last_change_revision(
234
            path.encode('utf-8'), self.commit_id)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
235
        return self._repository.lookup_foreign_revision_id(commit_id, self.mapping)
236
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
237
    def get_file_mtime(self, path, file_id=None):
238
        revid = self.get_file_revision(path, file_id)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
239
        try:
240
            rev = self._repository.get_revision(revid)
241
        except errors.NoSuchRevision:
242
            raise errors.FileTimestampUnavailable(path)
243
        return rev.timestamp
244
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
245
    def id2path(self, file_id):
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
246
        try:
0.329.1 by Jelmer Vernooij
Check that path actually exists in Tree.id2path.
247
            path = self._fileid_map.lookup_path(file_id)
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
248
        except ValueError:
0.200.1714 by Jelmer Vernooij
Fix NoSuchId raising.
249
            raise errors.NoSuchId(self, file_id)
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
250
        path = path.decode('utf-8')
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
251
        if self.is_versioned(path):
0.329.1 by Jelmer Vernooij
Check that path actually exists in Tree.id2path.
252
            return path
253
        raise errors.NoSuchId(self, file_id)
254
255
    def is_versioned(self, path):
256
        return self.has_filename(path)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
257
258
    def path2id(self, path):
0.200.1328 by Jelmer Vernooij
More test fixes.
259
        if self.mapping.is_special_file(path):
260
            return None
261
        return self._fileid_map.lookup_file_id(path.encode('utf-8'))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
262
0.200.1569 by Jelmer Vernooij
Implement GitRevisionTree.all_file_ids().
263
    def all_file_ids(self):
264
        return set(self._fileid_map.all_file_ids())
265
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
266
    def all_versioned_paths(self):
267
        ret = set()
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
268
        todo = set([(store, '', self.tree)])
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
269
        while todo:
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
270
            (store, path, tree_id) = todo.pop()
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
271
            if tree_id is None:
272
                continue
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
273
            tree = store[tree_id]
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
274
            for name, mode, hexsha in tree.items():
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
275
                subpath = posixpath.join(path, name)
276
                if stat.S_ISDIR(mode):
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
277
                    todo.add((store, subpath, hexsha))
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
278
                else:
279
                    ret.add(subpath)
280
        return ret
281
0.200.1204 by Jelmer Vernooij
Implement GitRevisionTree.get_root_id().
282
    def get_root_id(self):
0.378.1 by Jelmer Vernooij
Return None from Tree.get_root_id() when encountering an empty tree.
283
        if self.tree is None:
284
            return None
0.200.1204 by Jelmer Vernooij
Implement GitRevisionTree.get_root_id().
285
        return self.path2id("")
286
0.200.1208 by Jelmer Vernooij
Add GitWorkingTree.has_id and GitWorkingTree.has_or_had_id.
287
    def has_or_had_id(self, file_id):
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
288
        try:
289
            path = self.id2path(file_id)
290
        except errors.NoSuchId:
291
            return False
292
        return True
0.200.1208 by Jelmer Vernooij
Add GitWorkingTree.has_id and GitWorkingTree.has_or_had_id.
293
294
    def has_id(self, file_id):
295
        try:
296
            path = self.id2path(file_id)
297
        except errors.NoSuchId:
298
            return False
299
        return self.has_filename(path)
300
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
301
    def _lookup_path(self, path):
302
        if self.tree is None:
303
            raise errors.NoSuchFile(path)
304
        try:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
305
            (mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree,
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
306
                path.encode('utf-8'))
307
        except KeyError:
308
            raise errors.NoSuchFile(self, path)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
309
        else:
310
            return (self.store, mode, hexsha)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
311
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
312
    def is_executable(self, path, file_id=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
313
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1615 by Jelmer Vernooij
Implement GitRevisionTree.is_executable.:
314
        if mode is None:
315
            # the tree root is a directory
316
            return False
317
        return mode_is_executable(mode)
318
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
319
    def kind(self, path, file_id=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
320
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1253 by Jelmer Vernooij
Fix Tree.kind(TREE_ROOT).
321
        if mode is None:
322
            # the tree root is a directory
323
            return "directory"
0.200.1241 by Jelmer Vernooij
Implement GitRevisionTree.kind.
324
        return mode_kind(mode)
325
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
326
    def has_filename(self, path):
327
        try:
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
328
            self._lookup_path(path)
329
        except errors.NoSuchFile:
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
330
            return False
331
        else:
332
            return True
333
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
334
    def list_files(self, include_root=False, from_dir=None, recursive=True):
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
335
        if self.tree is None:
336
            return
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
337
        if from_dir is None:
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
338
            from_dir = u""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
339
        (store, mode, hexsha) = self._lookup_path(from_dir)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
340
        if mode is None: # Root
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
341
            root_ie = self._get_dir_ie(b"", None)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
342
        else:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
343
            parent_path = posixpath.dirname(from_dir.encode("utf-8"))
0.200.1328 by Jelmer Vernooij
More test fixes.
344
            parent_id = self._fileid_map.lookup_file_id(parent_path)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
345
            if mode_kind(mode) == 'directory':
346
                root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
347
            else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
348
                root_ie = self._get_file_ie(store, from_dir.encode("utf-8"),
0.264.10 by Jelmer Vernooij
Yield inventory entries.
349
                    posixpath.basename(from_dir), mode, hexsha)
350
        if from_dir != "" or include_root:
351
            yield (from_dir, "V", root_ie.kind, root_ie.file_id, root_ie)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
352
        todo = set()
0.264.10 by Jelmer Vernooij
Yield inventory entries.
353
        if root_ie.kind == 'directory':
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
354
            todo.add((store, from_dir.encode("utf-8"), hexsha, root_ie.file_id))
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
355
        while todo:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
356
            (store, path, hexsha, parent_id) = todo.pop()
357
            tree = store[hexsha]
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
358
            for name, mode, hexsha in tree.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
359
                if self.mapping.is_special_file(name):
360
                    continue
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
361
                child_path = posixpath.join(path, name)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
362
                if stat.S_ISDIR(mode):
363
                    ie = self._get_dir_ie(child_path, parent_id)
364
                    if recursive:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
365
                        todo.add((store, child_path, hexsha, ie.file_id))
0.264.10 by Jelmer Vernooij
Yield inventory entries.
366
                else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
367
                    ie = self._get_file_ie(store, child_path, name, mode, hexsha, parent_id)
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
368
                yield child_path.decode('utf-8'), "V", ie.kind, ie.file_id, ie
0.264.10 by Jelmer Vernooij
Yield inventory entries.
369
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
370
    def _get_file_ie(self, store, path, name, mode, hexsha, parent_id):
0.361.1 by Jelmer Vernooij
Don't use assert.
371
        if type(path) is not bytes:
372
            raise TypeError(path)
373
        if type(name) is not bytes:
374
            raise TypeError(name)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
375
        kind = mode_kind(mode)
0.200.1328 by Jelmer Vernooij
More test fixes.
376
        file_id = self._fileid_map.lookup_file_id(path)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
377
        ie = entry_factory[kind](file_id, name.decode("utf-8"), parent_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
378
        if kind == 'symlink':
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
379
            ie.symlink_target = store[hexsha].data.decode('utf-8')
0.200.1401 by Jelmer Vernooij
Cope with submodules in working trees.
380
        elif kind == 'tree-reference':
381
            ie.reference_revision = self.mapping.revision_id_foreign_to_bzr(hexsha)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
382
        else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
383
            data = store[hexsha].data
0.264.10 by Jelmer Vernooij
Yield inventory entries.
384
            ie.text_sha1 = osutils.sha_string(data)
385
            ie.text_size = len(data)
386
            ie.executable = mode_is_executable(mode)
387
        return ie
388
389
    def _get_dir_ie(self, path, parent_id):
0.200.1328 by Jelmer Vernooij
More test fixes.
390
        file_id = self._fileid_map.lookup_file_id(path)
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
391
        return GitTreeDirectory(file_id,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
392
            posixpath.basename(path).decode("utf-8"), parent_id)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
393
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
394
    def iter_child_entries(self, path, file_id=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
395
        (store, mode, tree_sha) = self._lookup_path(path)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
396
397
        if not stat.S_ISDIR(mode):
398
            return
399
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
400
        encoded_path = path.encode('utf-8')
401
        file_id = self.path2id(path)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
402
        tree = store[tree_sha]
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
403
        for name, mode, hexsha in tree.iteritems():
404
            if self.mapping.is_special_file(name):
405
                continue
406
            child_path = posixpath.join(encoded_path, name)
407
            if stat.S_ISDIR(mode):
408
                yield self._get_dir_ie(child_path, file_id)
409
            else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
410
                yield self._get_file_ie(store, child_path, name, mode, hexsha,
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
411
                                        file_id)
412
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
413
    def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
0.287.4 by Jelmer Vernooij
Fix GitRevisionTree behaviour for null:
414
        if self.tree is None:
415
            return
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
416
        if yield_parents:
417
            # TODO(jelmer): Support yield parents
418
            raise NotImplementedError
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
419
        if specific_files is not None:
420
            if specific_files in ([""], []):
421
                specific_files = None
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
422
            else:
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
423
                specific_files = set([p.encode('utf-8') for p in specific_files])
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
424
        todo = set([(self.store, "", self.tree, None)])
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
425
        while todo:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
426
            store, path, tree_sha, parent_id = todo.pop()
0.264.10 by Jelmer Vernooij
Yield inventory entries.
427
            ie = self._get_dir_ie(path, parent_id)
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
428
            if specific_files is None or path in specific_files:
0.200.1715 by Jelmer Vernooij
Fix some more tests.
429
                yield path.decode("utf-8"), ie
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
430
            tree = store[tree_sha]
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
431
            for name, mode, hexsha in tree.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
432
                if self.mapping.is_special_file(name):
433
                    continue
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
434
                child_path = posixpath.join(path, name)
435
                if stat.S_ISDIR(mode):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
436
                    if (specific_files is None or
437
                        any(filter(lambda p: p.startswith(child_path), specific_files))):
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
438
                        todo.add((store, child_path, hexsha, ie.file_id))
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
439
                elif specific_files is None or child_path in specific_files:
0.200.1715 by Jelmer Vernooij
Fix some more tests.
440
                    yield (child_path.decode("utf-8"),
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
441
                            self._get_file_ie(store, child_path, name, mode, hexsha,
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
442
                           ie.file_id))
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
443
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
444
    def get_revision_id(self):
0.200.959 by Jelmer Vernooij
Improve docstrings.
445
        """See RevisionTree.get_revision_id."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
446
        return self._revision_id
447
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
448
    def get_file_sha1(self, path, file_id=None, stat_value=None):
0.287.6 by Jelmer Vernooij
Fix some more tests.
449
        if self.tree is None:
450
            raise errors.NoSuchFile(path)
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
451
        return osutils.sha_string(self.get_file_text(path, file_id))
0.200.1255 by Jelmer Vernooij
Implement GitRevisionTree.get_file_sha1.
452
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
453
    def get_file_verifier(self, path, file_id=None, stat_value=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
454
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
455
        return ("GIT", hexsha)
456
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
457
    def get_file_text(self, path, file_id=None):
0.200.959 by Jelmer Vernooij
Improve docstrings.
458
        """See RevisionTree.get_file_text."""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
459
        (store, mode, hexsha) = self._lookup_path(path)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
460
        if stat.S_ISREG(mode):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
461
            return store[hexsha].data
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
462
        else:
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
463
            return b""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
464
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
465
    def get_symlink_target(self, path, file_id=None):
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
466
        """See RevisionTree.get_symlink_target."""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
467
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
468
        if stat.S_ISLNK(mode):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
469
            return store[hexsha].data.decode('utf-8')
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
470
        else:
471
            return None
472
0.264.10 by Jelmer Vernooij
Yield inventory entries.
473
    def _comparison_data(self, entry, path):
474
        if entry is None:
475
            return None, False, None
476
        return entry.kind, entry.executable, None
477
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
478
    def path_content_summary(self, path):
479
        """See Tree.path_content_summary."""
480
        try:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
481
            (store, mode, hexsha) = self._lookup_path(path)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
482
        except errors.NoSuchFile:
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
483
            return ('missing', None, None, None)
484
        kind = mode_kind(mode)
485
        if kind == 'file':
486
            executable = mode_is_executable(mode)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
487
            contents = store[hexsha].data
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
488
            return (kind, len(contents), executable, osutils.sha_string(contents))
489
        elif kind == 'symlink':
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
490
            return (kind, None, None, store[hexsha].data)
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
491
        else:
492
            return (kind, None, None, None)
493
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
494
    def find_related_paths_across_trees(self, paths, trees=[],
495
            require_versioned=True):
496
        if paths is None:
497
            return None
498
        if require_versioned:
499
            trees = [self] + (trees if trees is not None else [])
500
            unversioned = set()
501
            for p in paths:
502
                for t in trees:
503
                    if t.is_versioned(p):
504
                        break
505
                else:
506
                    unversioned.add(p)
507
            if unversioned:
508
                raise errors.PathsNotVersionedError(unversioned)
509
        return filter(self.is_versioned, paths)
510
0.393.1 by Jelmer Vernooij
Avoid expensive bzr APIs in commit.
511
    def _iter_tree_contents(self, include_trees=False):
512
        if self.tree is None:
513
            return iter([])
514
        return self.store.iter_tree_contents(
515
                self.tree, include_trees=include_trees)
516
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
517
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
518
def tree_delta_from_git_changes(changes, mapping,
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
519
        (old_fileid_map, new_fileid_map), specific_files=None,
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
520
        require_versioned=False, include_root=False,
521
        target_extras=None):
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
522
    """Create a TreeDelta from two git trees.
0.200.959 by Jelmer Vernooij
Improve docstrings.
523
524
    source and target are iterators over tuples with:
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
525
        (filename, sha, mode)
526
    """
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
527
    if target_extras is None:
528
        target_extras = set()
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
529
    ret = delta.TreeDelta()
530
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
0.287.5 by Jelmer Vernooij
Fix root handling.
531
        if newpath == u'' and not include_root:
532
            continue
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
533
        if not (specific_files is None or
0.287.5 by Jelmer Vernooij
Fix root handling.
534
                (oldpath is not None and osutils.is_inside_or_parent_of_any(specific_files, oldpath)) or
535
                (newpath is not None and osutils.is_inside_or_parent_of_any(specific_files, newpath))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
536
            continue
0.200.1752 by Jelmer Vernooij
Don't traverse nested trees in WorkingTree.smart_add.
537
        if mapping.is_special_file(oldpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
538
            oldpath = None
0.200.1752 by Jelmer Vernooij
Don't traverse nested trees in WorkingTree.smart_add.
539
        if mapping.is_special_file(newpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
540
            newpath = None
541
        if oldpath is None and newpath is None:
542
            continue
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
543
        if oldpath is None:
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
544
            if newpath in target_extras:
545
                ret.unversioned.append(
546
                    (osutils.normalized_filename(newpath)[0], None, mode_kind(newmode)))
547
            else:
548
                file_id = new_fileid_map.lookup_file_id(newpath)
549
                ret.added.append((newpath.decode('utf-8'), file_id, mode_kind(newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
550
        elif newpath is None:
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
551
            file_id = old_fileid_map.lookup_file_id(oldpath)
552
            ret.removed.append((oldpath.decode('utf-8'), file_id, mode_kind(oldmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
553
        elif oldpath != newpath:
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
554
            file_id = old_fileid_map.lookup_file_id(oldpath)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
555
            ret.renamed.append(
556
                (oldpath.decode('utf-8'), newpath.decode('utf-8'), file_id,
557
                mode_kind(newmode), (oldsha != newsha),
558
                (oldmode != newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
559
        elif mode_kind(oldmode) != mode_kind(newmode):
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
560
            file_id = new_fileid_map.lookup_file_id(newpath)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
561
            ret.kind_changed.append(
562
                (newpath.decode('utf-8'), file_id, mode_kind(oldmode),
563
                mode_kind(newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
564
        elif oldsha != newsha or oldmode != newmode:
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
565
            if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
566
                continue
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
567
            file_id = new_fileid_map.lookup_file_id(newpath)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
568
            ret.modified.append(
569
                (newpath.decode('utf-8'), file_id, mode_kind(newmode),
570
                (oldsha != newsha), (oldmode != newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
571
        else:
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
572
            file_id = new_fileid_map.lookup_file_id(newpath)
573
            ret.unchanged.append((newpath.decode('utf-8'), file_id, mode_kind(newmode)))
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
574
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
575
    return ret
576
577
0.391.2 by Jelmer Vernooij
Pass along target_missing.
578
def changes_from_git_changes(changes, mapping, specific_files=None, include_unchanged=False,
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
579
                             target_extras=None):
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
580
    """Create a iter_changes-like generator from a git stream.
0.200.959 by Jelmer Vernooij
Improve docstrings.
581
582
    source and target are iterators over tuples with:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
583
        (filename, sha, mode)
584
    """
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
585
    if target_extras is None:
586
        target_extras = set()
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
587
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
588
        if not (specific_files is None or
0.287.5 by Jelmer Vernooij
Fix root handling.
589
                (oldpath is not None and osutils.is_inside_or_parent_of_any(specific_files, oldpath)) or
590
                (newpath is not None and osutils.is_inside_or_parent_of_any(specific_files, newpath))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
591
            continue
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
592
        path = (oldpath, newpath)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
593
        if oldpath is not None and mapping.is_special_file(oldpath):
594
            continue
595
        if newpath is not None and mapping.is_special_file(newpath):
0.200.1328 by Jelmer Vernooij
More test fixes.
596
            continue
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
597
        if oldpath is None:
598
            fileid = mapping.generate_file_id(newpath)
599
            oldexe = None
600
            oldkind = None
601
            oldname = None
602
            oldparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
603
            oldversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
604
        else:
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
605
            oldversioned = True
0.200.1345 by Jelmer Vernooij
paths should be unicode when yielded by iter_changes.
606
            oldpath = oldpath.decode("utf-8")
0.391.8 by Jelmer Vernooij
Allow missing items in old tree.
607
            if oldmode:
608
                oldexe = mode_is_executable(oldmode)
609
                oldkind = mode_kind(oldmode)
610
            else:
611
                oldexe = False
612
                oldkind = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
613
            if oldpath == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
614
                oldparent = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
615
                oldname = ''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
616
            else:
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
617
                (oldparentpath, oldname) = osutils.split(oldpath)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
618
                oldparent = mapping.generate_file_id(oldparentpath)
619
            fileid = mapping.generate_file_id(oldpath)
620
        if newpath is None:
621
            newexe = None
622
            newkind = None
623
            newname = None
624
            newparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
625
            newversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
626
        else:
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
627
            newversioned = (newpath not in target_extras)
628
            if newmode:
0.200.1576 by Jelmer Vernooij
Merge a bunch of fixes from store-roundtrip-info.
629
                newexe = mode_is_executable(newmode)
630
                newkind = mode_kind(newmode)
631
            else:
632
                newexe = False
633
                newkind = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
634
            newpath = newpath.decode("utf-8")
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
635
            if newpath == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
636
                newparent = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
637
                newname = u''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
638
            else:
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
639
                newparentpath, newname = osutils.split(newpath)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
640
                newparent = mapping.generate_file_id(newparentpath)
0.357.3 by Jelmer Vernooij
More remove fixes.
641
        if (not include_unchanged and
642
            oldkind == 'directory' and newkind == 'directory' and
643
            oldpath == newpath):
644
            continue
0.200.959 by Jelmer Vernooij
Improve docstrings.
645
        yield (fileid, (oldpath, newpath), (oldsha != newsha),
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
646
             (oldversioned, newversioned),
0.200.959 by Jelmer Vernooij
Improve docstrings.
647
             (oldparent, newparent), (oldname, newname),
648
             (oldkind, newkind), (oldexe, newexe))
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
649
650
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
651
class InterGitTrees(_mod_tree.InterTree):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
652
    """InterTree that works between two git trees."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
653
0.200.659 by Jelmer Vernooij
Prevent tests using InterGitRevisionTrees.
654
    _matching_from_tree_format = None
655
    _matching_to_tree_format = None
656
    _test_mutable_trees_to_test_trees = None
657
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
658
    @classmethod
659
    def is_compatible(cls, source, target):
0.200.959 by Jelmer Vernooij
Improve docstrings.
660
        return (isinstance(source, GitRevisionTree) and
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
661
                isinstance(target, GitRevisionTree))
662
663
    def compare(self, want_unchanged=False, specific_files=None,
664
                extra_trees=None, require_versioned=False, include_root=False,
665
                want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
666
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
667
            changes, target_extras = self._iter_git_changes(
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
668
                    want_unchanged=want_unchanged,
669
                    require_versioned=require_versioned,
670
                    specific_files=specific_files,
671
                    extra_trees=extra_trees,
672
                    want_unversioned=want_unversioned)
673
            source_fileid_map = self.source._fileid_map
674
            target_fileid_map = self.target._fileid_map
675
            return tree_delta_from_git_changes(changes, self.target.mapping,
676
                (source_fileid_map, target_fileid_map),
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
677
                specific_files=specific_files, include_root=include_root,
678
                target_extras=target_extras)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
679
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
680
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
681
                     pb=None, extra_trees=[], require_versioned=True,
682
                     want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
683
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
684
            changes, target_extras = self._iter_git_changes(
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
685
                    want_unchanged=include_unchanged,
686
                    require_versioned=require_versioned,
687
                    specific_files=specific_files,
688
                    extra_trees=extra_trees,
689
                    want_unversioned=want_unversioned)
690
            return changes_from_git_changes(
691
                    changes, self.target.mapping,
692
                    specific_files=specific_files,
693
                    include_unchanged=include_unchanged,
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
694
                    target_extras=target_extras)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
695
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
696
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
697
            require_versioned=False, extra_trees=None,
698
            want_unversioned=False):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
699
        raise NotImplementedError(self._iter_git_changes)
700
701
702
class InterGitRevisionTrees(InterGitTrees):
703
    """InterTree that works between two git revision trees."""
704
705
    _matching_from_tree_format = None
706
    _matching_to_tree_format = None
707
    _test_mutable_trees_to_test_trees = None
708
709
    @classmethod
710
    def is_compatible(cls, source, target):
711
        return (isinstance(source, GitRevisionTree) and
712
                isinstance(target, GitRevisionTree))
713
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
714
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
715
            require_versioned=True, extra_trees=None,
716
            want_unversioned=False):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
717
        trees = [self.source]
718
        if extra_trees is not None:
719
            trees.extend(extra_trees)
720
        if specific_files is not None:
721
            specific_files = self.target.find_related_paths_across_trees(
722
                    specific_files, trees,
723
                    require_versioned=require_versioned)
0.357.1 by Jelmer Vernooij
Fix some remove tests.
724
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
725
        if self.source._repository._git.object_store != self.target._repository._git.object_store:
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
726
            store = OverlayObjectStore([self.source._repository._git.object_store,
727
                                        self.target._repository._git.object_store])
728
        else:
729
            store = self.source._repository._git.object_store
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
730
        return self.source._repository._git.object_store.tree_changes(
731
            self.source.tree, self.target.tree, want_unchanged=want_unchanged,
0.391.2 by Jelmer Vernooij
Pass along target_missing.
732
            include_trees=True, change_type_same=True), set()
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
733
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
734
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
735
_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
736
737
738
class MutableGitIndexTree(mutabletree.MutableTree):
739
740
    def __init__(self):
741
        self._lock_mode = None
742
        self._lock_count = 0
743
        self._versioned_dirs = None
744
745
    def is_versioned(self, path):
746
        with self.lock_read():
747
            path = path.rstrip('/').encode('utf-8')
748
            return (path in self.index or self._has_dir(path))
749
750
    def _has_dir(self, path):
751
        if path == "":
752
            return True
753
        if self._versioned_dirs is None:
754
            self._load_dirs()
755
        return path in self._versioned_dirs
756
757
    def _load_dirs(self):
0.361.3 by Jelmer Vernooij
Merge trunk,
758
        if self._lock_mode is None:
759
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
760
        self._versioned_dirs = set()
761
        for p in self.index:
762
            self._ensure_versioned_dir(posixpath.dirname(p))
763
764
    def _ensure_versioned_dir(self, dirname):
765
        if dirname in self._versioned_dirs:
766
            return
767
        if dirname != "":
768
            self._ensure_versioned_dir(posixpath.dirname(dirname))
769
        self._versioned_dirs.add(dirname)
770
771
    def path2id(self, path):
772
        with self.lock_read():
773
            path = path.rstrip('/')
774
            if self.is_versioned(path.rstrip('/')):
775
                return self._fileid_map.lookup_file_id(path.encode("utf-8"))
776
            return None
777
778
    def has_id(self, file_id):
779
        try:
780
            self.id2path(file_id)
781
        except errors.NoSuchId:
782
            return False
783
        else:
784
            return True
785
786
    def id2path(self, file_id):
787
        if file_id is None:
788
            return ''
0.361.3 by Jelmer Vernooij
Merge trunk,
789
        if type(file_id) is not bytes:
790
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
791
        with self.lock_read():
792
            try:
793
                path = self._fileid_map.lookup_path(file_id)
794
            except ValueError:
795
                raise errors.NoSuchId(self, file_id)
796
            path = path.decode('utf-8')
797
            if self.is_versioned(path):
798
                return path
799
            raise errors.NoSuchId(self, file_id)
800
801
    def _set_root_id(self, file_id):
802
        self._fileid_map.set_file_id("", file_id)
803
804
    def get_root_id(self):
805
        return self.path2id("")
806
807
    def _add(self, files, ids, kinds):
808
        for (path, file_id, kind) in zip(files, ids, kinds):
809
            if file_id is not None:
810
                raise workingtree.SettingFileIdUnsupported()
0.366.1 by Jelmer Vernooij
Fix normalized filename checking in add.
811
            path, can_access = osutils.normalized_filename(path)
812
            if not can_access:
813
                raise errors.InvalidNormalization(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
814
            self._index_add_entry(path, kind)
815
816
    def _index_add_entry(self, path, kind, flags=0):
0.361.4 by Jelmer Vernooij
Fix assert.
817
        if not isinstance(path, basestring):
0.361.3 by Jelmer Vernooij
Merge trunk,
818
            raise TypeError(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
819
        if kind == "directory":
820
            # Git indexes don't contain directories
821
            return
822
        if kind == "file":
823
            blob = Blob()
824
            try:
825
                file, stat_val = self.get_file_with_stat(path)
826
            except (errors.NoSuchFile, IOError):
827
                # TODO: Rather than come up with something here, use the old index
828
                file = BytesIO()
829
                stat_val = os.stat_result(
830
                    (stat.S_IFREG | 0644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
831
            blob.set_raw_string(file.read())
832
        elif kind == "symlink":
833
            blob = Blob()
834
            try:
835
                stat_val = self._lstat(path)
836
            except (errors.NoSuchFile, OSError):
837
                # TODO: Rather than come up with something here, use the
838
                # old index
839
                stat_val = os.stat_result(
840
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
841
            blob.set_raw_string(
842
                self.get_symlink_target(path).encode("utf-8"))
843
        else:
844
            raise AssertionError("unknown kind '%s'" % kind)
845
        # Add object to the repository if it didn't exist yet
846
        if not blob.id in self.store:
847
            self.store.add_object(blob)
848
        # Add an entry to the index or update the existing entry
849
        ensure_normalized_path(path)
850
        encoded_path = path.encode("utf-8")
851
        if b'\r' in encoded_path or b'\n' in encoded_path:
852
            # TODO(jelmer): Why do we need to do this?
853
            trace.mutter('ignoring path with invalid newline in it: %r', path)
854
            return
855
        self.index[encoded_path] = index_entry_from_stat(
856
            stat_val, blob.id, flags)
857
        if self._versioned_dirs is not None:
858
            self._ensure_versioned_dir(encoded_path)
859
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
860
    def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
861
        if yield_parents:
862
            raise NotImplementedError(self.iter_entries_by_dir)
863
        with self.lock_read():
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
864
            if specific_files is not None:
865
                specific_files = set(specific_files)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
866
            else:
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
867
                specific_files = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
868
            root_ie = self._get_dir_ie(u"", None)
869
            ret = {}
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
870
            if specific_files is None or u"" in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
871
                ret[(None, u"")] = root_ie
872
            dir_ids = {u"": root_ie.file_id}
873
            for path, value in self.index.iteritems():
874
                if self.mapping.is_special_file(path):
875
                    continue
876
                path = path.decode("utf-8")
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
877
                if specific_files is not None and not path in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
878
                    continue
879
                (parent, name) = posixpath.split(path)
880
                try:
881
                    file_ie = self._get_file_ie(name, path, value, None)
882
                except errors.NoSuchFile:
883
                    continue
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
884
                if yield_parents or specific_files is None:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
885
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
886
                            dir_ids):
887
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
888
                file_ie.parent_id = self.path2id(parent)
889
                ret[(posixpath.dirname(path), path)] = file_ie
890
            return ((path, ie) for ((_, path), ie) in sorted(ret.items()))
891
892
893
    def _get_dir_ie(self, path, parent_id):
894
        file_id = self.path2id(path)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
895
        return GitTreeDirectory(file_id,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
896
            posixpath.basename(path).strip("/"), parent_id)
897
898
    def _get_file_ie(self, name, path, value, parent_id):
0.361.3 by Jelmer Vernooij
Merge trunk,
899
        if type(name) is not unicode:
900
            raise TypeError(name)
901
        if type(path) is not unicode:
902
            raise TypeError(path)
903
        if not isinstance(value, tuple) or len(value) != 10:
904
            raise TypeError(value)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
905
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
906
        file_id = self.path2id(path)
907
        if type(file_id) != str:
908
            raise AssertionError
909
        kind = mode_kind(mode)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
910
        ie = entry_factory[kind](file_id, name, parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
911
        if kind == 'symlink':
912
            ie.symlink_target = self.get_symlink_target(path, file_id)
913
        else:
914
            try:
915
                data = self.get_file_text(path, file_id)
916
            except errors.NoSuchFile:
917
                data = None
918
            except IOError as e:
919
                if e.errno != errno.ENOENT:
920
                    raise
921
                data = None
922
            if data is None:
923
                data = self.branch.repository._git.object_store[sha].data
924
            ie.text_sha1 = osutils.sha_string(data)
925
            ie.text_size = len(data)
926
            ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
927
        return ie
928
929
    def _add_missing_parent_ids(self, path, dir_ids):
930
        if path in dir_ids:
931
            return []
932
        parent = posixpath.dirname(path).strip("/")
933
        ret = self._add_missing_parent_ids(parent, dir_ids)
934
        parent_id = dir_ids[parent]
935
        ie = self._get_dir_ie(path, parent_id)
936
        dir_ids[path] = ie.file_id
937
        ret.append((path, ie))
938
        return ret
939
940
    def _comparison_data(self, entry, path):
941
        if entry is None:
942
            return None, False, None
943
        return entry.kind, entry.executable, None
944
945
    def _unversion_path(self, path):
0.361.3 by Jelmer Vernooij
Merge trunk,
946
        if self._lock_mode is None:
947
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
948
        encoded_path = path.encode("utf-8")
949
        count = 0
950
        try:
951
            del self.index[encoded_path]
952
        except KeyError:
953
            # A directory, perhaps?
954
            for p in list(self.index):
955
                if p.startswith(encoded_path+b"/"):
956
                    count += 1
957
                    del self.index[p]
958
        else:
959
            count = 1
960
        self._versioned_dirs = None
961
        return count
962
963
    def unversion(self, paths, file_ids=None):
964
        with self.lock_tree_write():
965
            for path in paths:
966
                if self._unversion_path(path) == 0:
967
                    raise errors.NoSuchFile(path)
968
            self._versioned_dirs = None
969
            self.flush()
970
971
    def flush(self):
972
        pass
973
974
    def update_basis_by_delta(self, revid, delta):
975
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
976
        for (old_path, new_path, file_id, ie) in delta:
977
            if old_path is not None and old_path.encode('utf-8') in self.index:
978
                del self.index[old_path.encode('utf-8')]
979
                self._versioned_dirs = None
980
            if new_path is not None and ie.kind != 'directory':
981
                self._index_add_entry(new_path, ie.kind)
982
        self.flush()
983
        self._set_merges_from_parent_ids([])
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
984
985
    def move(self, from_paths, to_dir=None, after=None):
986
        rename_tuples = []
987
        with self.lock_tree_write():
988
            to_abs = self.abspath(to_dir)
989
            if not os.path.isdir(to_abs):
990
                raise errors.BzrMoveFailedError('', to_dir,
991
                    errors.NotADirectory(to_abs))
992
993
            for from_rel in from_paths:
994
                from_tail = os.path.split(from_rel)[-1]
995
                to_rel = os.path.join(to_dir, from_tail)
996
                self.rename_one(from_rel, to_rel, after=after)
997
                rename_tuples.append((from_rel, to_rel))
998
            self.flush()
999
            return rename_tuples
1000
1001
    def rename_one(self, from_rel, to_rel, after=None):
1002
        from_path = from_rel.encode("utf-8")
1003
        to_rel, can_access = osutils.normalized_filename(to_rel)
1004
        if not can_access:
1005
            raise errors.InvalidNormalization(to_rel)
1006
        to_path = to_rel.encode("utf-8")
1007
        with self.lock_tree_write():
1008
            if not after:
1009
                # Perhaps it's already moved?
1010
                after = (
1011
                    not self.has_filename(from_rel) and
1012
                    self.has_filename(to_rel) and
1013
                    not self.is_versioned(to_rel))
1014
            if after:
1015
                if not self.has_filename(to_rel):
1016
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1017
                        errors.NoSuchFile(to_rel))
1018
                if self.basis_tree().is_versioned(to_rel):
1019
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1020
                        errors.AlreadyVersionedError(to_rel))
1021
1022
                kind = self.kind(to_rel)
1023
            else:
1024
                try:
1025
                    to_kind = self.kind(to_rel)
1026
                except errors.NoSuchFile:
1027
                    exc_type = errors.BzrRenameFailedError
1028
                    to_kind = None
1029
                else:
1030
                    exc_type = errors.BzrMoveFailedError
1031
                if self.is_versioned(to_rel):
1032
                    raise exc_type(from_rel, to_rel,
1033
                        errors.AlreadyVersionedError(to_rel))
1034
                if not self.has_filename(from_rel):
1035
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1036
                        errors.NoSuchFile(from_rel))
0.388.1 by Jelmer Vernooij
Don't print error moving to an unversioned directory.
1037
                kind = self.kind(from_rel)
1038
                if not self.is_versioned(from_rel) and kind != 'directory':
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1039
                    raise exc_type(from_rel, to_rel,
1040
                        errors.NotVersionedError(from_rel))
1041
                if self.has_filename(to_rel):
1042
                    raise errors.RenameFailedFilesExist(
1043
                        from_rel, to_rel, errors.FileExists(to_rel))
1044
1045
                kind = self.kind(from_rel)
1046
1047
            if not after and not from_path in self.index and kind != 'directory':
1048
                # It's not a file
1049
                raise errors.BzrMoveFailedError(from_rel, to_rel,
1050
                    errors.NotVersionedError(path=from_rel))
1051
1052
            if not after:
1053
                try:
1054
                    self._rename_one(from_rel, to_rel)
1055
                except OSError as e:
1056
                    if e.errno == errno.ENOENT:
1057
                        raise errors.BzrMoveFailedError(from_rel, to_rel,
1058
                            errors.NoSuchFile(to_rel))
1059
                    raise
1060
            if kind != 'directory':
1061
                try:
1062
                    del self.index[from_path]
1063
                except KeyError:
1064
                    pass
1065
                self._index_add_entry(to_rel, kind)
1066
            else:
1067
                todo = [p for p in self.index if p.startswith(from_path+'/')]
1068
                for p in todo:
1069
                    self.index[posixpath.join(to_path, posixpath.relpath(p, from_path))] = self.index[p]
1070
                    del self.index[p]
1071
1072
            self._versioned_dirs = None
1073
            self.flush()
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1074
1075
    def find_related_paths_across_trees(self, paths, trees=[],
1076
            require_versioned=True):
1077
        if paths is None:
1078
            return None
1079
1080
        if require_versioned:
1081
            trees = [self] + (trees if trees is not None else [])
1082
            unversioned = set()
1083
            for p in paths:
1084
                for t in trees:
1085
                    if t.is_versioned(p):
1086
                        break
1087
                else:
1088
                    unversioned.add(p)
1089
            if unversioned:
1090
                raise errors.PathsNotVersionedError(unversioned)
1091
1092
        return filter(self.is_versioned, paths)