/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
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
744
        self._index_dirty = False
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
745
746
    def is_versioned(self, path):
747
        with self.lock_read():
748
            path = path.rstrip('/').encode('utf-8')
749
            return (path in self.index or self._has_dir(path))
750
751
    def _has_dir(self, path):
752
        if path == "":
753
            return True
754
        if self._versioned_dirs is None:
755
            self._load_dirs()
756
        return path in self._versioned_dirs
757
758
    def _load_dirs(self):
0.361.3 by Jelmer Vernooij
Merge trunk,
759
        if self._lock_mode is None:
760
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
761
        self._versioned_dirs = set()
762
        for p in self.index:
763
            self._ensure_versioned_dir(posixpath.dirname(p))
764
765
    def _ensure_versioned_dir(self, dirname):
766
        if dirname in self._versioned_dirs:
767
            return
768
        if dirname != "":
769
            self._ensure_versioned_dir(posixpath.dirname(dirname))
770
        self._versioned_dirs.add(dirname)
771
772
    def path2id(self, path):
773
        with self.lock_read():
774
            path = path.rstrip('/')
775
            if self.is_versioned(path.rstrip('/')):
776
                return self._fileid_map.lookup_file_id(path.encode("utf-8"))
777
            return None
778
779
    def has_id(self, file_id):
780
        try:
781
            self.id2path(file_id)
782
        except errors.NoSuchId:
783
            return False
784
        else:
785
            return True
786
787
    def id2path(self, file_id):
788
        if file_id is None:
789
            return ''
0.361.3 by Jelmer Vernooij
Merge trunk,
790
        if type(file_id) is not bytes:
791
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
792
        with self.lock_read():
793
            try:
794
                path = self._fileid_map.lookup_path(file_id)
795
            except ValueError:
796
                raise errors.NoSuchId(self, file_id)
797
            path = path.decode('utf-8')
798
            if self.is_versioned(path):
799
                return path
800
            raise errors.NoSuchId(self, file_id)
801
802
    def _set_root_id(self, file_id):
803
        self._fileid_map.set_file_id("", file_id)
804
805
    def get_root_id(self):
806
        return self.path2id("")
807
808
    def _add(self, files, ids, kinds):
809
        for (path, file_id, kind) in zip(files, ids, kinds):
810
            if file_id is not None:
811
                raise workingtree.SettingFileIdUnsupported()
0.366.1 by Jelmer Vernooij
Fix normalized filename checking in add.
812
            path, can_access = osutils.normalized_filename(path)
813
            if not can_access:
814
                raise errors.InvalidNormalization(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
815
            self._index_add_entry(path, kind)
816
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
817
    def _index_del_entry(self, path):
818
        del self.index[path]
819
        self._index_dirty = True
820
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
821
    def _index_add_entry(self, path, kind, flags=0):
0.361.4 by Jelmer Vernooij
Fix assert.
822
        if not isinstance(path, basestring):
0.361.3 by Jelmer Vernooij
Merge trunk,
823
            raise TypeError(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
824
        if kind == "directory":
825
            # Git indexes don't contain directories
826
            return
827
        if kind == "file":
828
            blob = Blob()
829
            try:
830
                file, stat_val = self.get_file_with_stat(path)
831
            except (errors.NoSuchFile, IOError):
832
                # TODO: Rather than come up with something here, use the old index
833
                file = BytesIO()
834
                stat_val = os.stat_result(
835
                    (stat.S_IFREG | 0644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
836
            blob.set_raw_string(file.read())
837
        elif kind == "symlink":
838
            blob = Blob()
839
            try:
840
                stat_val = self._lstat(path)
841
            except (errors.NoSuchFile, OSError):
842
                # TODO: Rather than come up with something here, use the
843
                # old index
844
                stat_val = os.stat_result(
845
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
846
            blob.set_raw_string(
847
                self.get_symlink_target(path).encode("utf-8"))
848
        else:
849
            raise AssertionError("unknown kind '%s'" % kind)
850
        # Add object to the repository if it didn't exist yet
851
        if not blob.id in self.store:
852
            self.store.add_object(blob)
853
        # Add an entry to the index or update the existing entry
854
        ensure_normalized_path(path)
855
        encoded_path = path.encode("utf-8")
856
        if b'\r' in encoded_path or b'\n' in encoded_path:
857
            # TODO(jelmer): Why do we need to do this?
858
            trace.mutter('ignoring path with invalid newline in it: %r', path)
859
            return
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
860
        self._index_dirty = True
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
861
        self.index[encoded_path] = index_entry_from_stat(
862
            stat_val, blob.id, flags)
863
        if self._versioned_dirs is not None:
864
            self._ensure_versioned_dir(encoded_path)
865
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
866
    def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
867
        if yield_parents:
868
            raise NotImplementedError(self.iter_entries_by_dir)
869
        with self.lock_read():
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
870
            if specific_files is not None:
871
                specific_files = set(specific_files)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
872
            else:
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
873
                specific_files = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
874
            root_ie = self._get_dir_ie(u"", None)
875
            ret = {}
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
876
            if specific_files is None or u"" in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
877
                ret[(None, u"")] = root_ie
878
            dir_ids = {u"": root_ie.file_id}
879
            for path, value in self.index.iteritems():
880
                if self.mapping.is_special_file(path):
881
                    continue
882
                path = path.decode("utf-8")
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
883
                if specific_files is not None and not path in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
884
                    continue
885
                (parent, name) = posixpath.split(path)
886
                try:
887
                    file_ie = self._get_file_ie(name, path, value, None)
888
                except errors.NoSuchFile:
889
                    continue
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
890
                if yield_parents or specific_files is None:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
891
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
892
                            dir_ids):
893
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
894
                file_ie.parent_id = self.path2id(parent)
895
                ret[(posixpath.dirname(path), path)] = file_ie
896
            return ((path, ie) for ((_, path), ie) in sorted(ret.items()))
897
898
899
    def _get_dir_ie(self, path, parent_id):
900
        file_id = self.path2id(path)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
901
        return GitTreeDirectory(file_id,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
902
            posixpath.basename(path).strip("/"), parent_id)
903
904
    def _get_file_ie(self, name, path, value, parent_id):
0.361.3 by Jelmer Vernooij
Merge trunk,
905
        if type(name) is not unicode:
906
            raise TypeError(name)
907
        if type(path) is not unicode:
908
            raise TypeError(path)
909
        if not isinstance(value, tuple) or len(value) != 10:
910
            raise TypeError(value)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
911
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
912
        file_id = self.path2id(path)
913
        if type(file_id) != str:
914
            raise AssertionError
915
        kind = mode_kind(mode)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
916
        ie = entry_factory[kind](file_id, name, parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
917
        if kind == 'symlink':
918
            ie.symlink_target = self.get_symlink_target(path, file_id)
919
        else:
920
            try:
921
                data = self.get_file_text(path, file_id)
922
            except errors.NoSuchFile:
923
                data = None
924
            except IOError as e:
925
                if e.errno != errno.ENOENT:
926
                    raise
927
                data = None
928
            if data is None:
929
                data = self.branch.repository._git.object_store[sha].data
930
            ie.text_sha1 = osutils.sha_string(data)
931
            ie.text_size = len(data)
932
            ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
933
        return ie
934
935
    def _add_missing_parent_ids(self, path, dir_ids):
936
        if path in dir_ids:
937
            return []
938
        parent = posixpath.dirname(path).strip("/")
939
        ret = self._add_missing_parent_ids(parent, dir_ids)
940
        parent_id = dir_ids[parent]
941
        ie = self._get_dir_ie(path, parent_id)
942
        dir_ids[path] = ie.file_id
943
        ret.append((path, ie))
944
        return ret
945
946
    def _comparison_data(self, entry, path):
947
        if entry is None:
948
            return None, False, None
949
        return entry.kind, entry.executable, None
950
951
    def _unversion_path(self, path):
0.361.3 by Jelmer Vernooij
Merge trunk,
952
        if self._lock_mode is None:
953
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
954
        encoded_path = path.encode("utf-8")
955
        count = 0
956
        try:
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
957
            self._index_del_entry(encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
958
        except KeyError:
959
            # A directory, perhaps?
960
            for p in list(self.index):
961
                if p.startswith(encoded_path+b"/"):
962
                    count += 1
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
963
                    self._index_del_entry(p)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
964
        else:
965
            count = 1
966
        self._versioned_dirs = None
967
        return count
968
969
    def unversion(self, paths, file_ids=None):
970
        with self.lock_tree_write():
971
            for path in paths:
972
                if self._unversion_path(path) == 0:
973
                    raise errors.NoSuchFile(path)
974
            self._versioned_dirs = None
975
            self.flush()
976
977
    def flush(self):
978
        pass
979
980
    def update_basis_by_delta(self, revid, delta):
981
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
982
        for (old_path, new_path, file_id, ie) in delta:
983
            if old_path is not None and old_path.encode('utf-8') in self.index:
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
984
                self._index_del_entry(old_path.encode('utf-8'))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
985
                self._versioned_dirs = None
986
            if new_path is not None and ie.kind != 'directory':
987
                self._index_add_entry(new_path, ie.kind)
988
        self.flush()
989
        self._set_merges_from_parent_ids([])
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
990
991
    def move(self, from_paths, to_dir=None, after=None):
992
        rename_tuples = []
993
        with self.lock_tree_write():
994
            to_abs = self.abspath(to_dir)
995
            if not os.path.isdir(to_abs):
996
                raise errors.BzrMoveFailedError('', to_dir,
997
                    errors.NotADirectory(to_abs))
998
999
            for from_rel in from_paths:
1000
                from_tail = os.path.split(from_rel)[-1]
1001
                to_rel = os.path.join(to_dir, from_tail)
1002
                self.rename_one(from_rel, to_rel, after=after)
1003
                rename_tuples.append((from_rel, to_rel))
1004
            self.flush()
1005
            return rename_tuples
1006
1007
    def rename_one(self, from_rel, to_rel, after=None):
1008
        from_path = from_rel.encode("utf-8")
1009
        to_rel, can_access = osutils.normalized_filename(to_rel)
1010
        if not can_access:
1011
            raise errors.InvalidNormalization(to_rel)
1012
        to_path = to_rel.encode("utf-8")
1013
        with self.lock_tree_write():
1014
            if not after:
1015
                # Perhaps it's already moved?
1016
                after = (
1017
                    not self.has_filename(from_rel) and
1018
                    self.has_filename(to_rel) and
1019
                    not self.is_versioned(to_rel))
1020
            if after:
1021
                if not self.has_filename(to_rel):
1022
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1023
                        errors.NoSuchFile(to_rel))
1024
                if self.basis_tree().is_versioned(to_rel):
1025
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1026
                        errors.AlreadyVersionedError(to_rel))
1027
1028
                kind = self.kind(to_rel)
1029
            else:
1030
                try:
1031
                    to_kind = self.kind(to_rel)
1032
                except errors.NoSuchFile:
1033
                    exc_type = errors.BzrRenameFailedError
1034
                    to_kind = None
1035
                else:
1036
                    exc_type = errors.BzrMoveFailedError
1037
                if self.is_versioned(to_rel):
1038
                    raise exc_type(from_rel, to_rel,
1039
                        errors.AlreadyVersionedError(to_rel))
1040
                if not self.has_filename(from_rel):
1041
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1042
                        errors.NoSuchFile(from_rel))
0.388.1 by Jelmer Vernooij
Don't print error moving to an unversioned directory.
1043
                kind = self.kind(from_rel)
1044
                if not self.is_versioned(from_rel) and kind != 'directory':
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1045
                    raise exc_type(from_rel, to_rel,
1046
                        errors.NotVersionedError(from_rel))
1047
                if self.has_filename(to_rel):
1048
                    raise errors.RenameFailedFilesExist(
1049
                        from_rel, to_rel, errors.FileExists(to_rel))
1050
1051
                kind = self.kind(from_rel)
1052
1053
            if not after and not from_path in self.index and kind != 'directory':
1054
                # It's not a file
1055
                raise errors.BzrMoveFailedError(from_rel, to_rel,
1056
                    errors.NotVersionedError(path=from_rel))
1057
1058
            if not after:
1059
                try:
1060
                    self._rename_one(from_rel, to_rel)
1061
                except OSError as e:
1062
                    if e.errno == errno.ENOENT:
1063
                        raise errors.BzrMoveFailedError(from_rel, to_rel,
1064
                            errors.NoSuchFile(to_rel))
1065
                    raise
1066
            if kind != 'directory':
1067
                try:
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1068
                    self._index_del_entry(from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1069
                except KeyError:
1070
                    pass
1071
                self._index_add_entry(to_rel, kind)
1072
            else:
1073
                todo = [p for p in self.index if p.startswith(from_path+'/')]
1074
                for p in todo:
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1075
                    self._index_dirty = True
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1076
                    self.index[posixpath.join(to_path, posixpath.relpath(p, from_path))] = self.index[p]
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1077
                    self._index_del_entry(p)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1078
1079
            self._versioned_dirs = None
1080
            self.flush()
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1081
1082
    def find_related_paths_across_trees(self, paths, trees=[],
1083
            require_versioned=True):
1084
        if paths is None:
1085
            return None
1086
1087
        if require_versioned:
1088
            trees = [self] + (trees if trees is not None else [])
1089
            unversioned = set()
1090
            for p in paths:
1091
                for t in trees:
1092
                    if t.is_versioned(p):
1093
                        break
1094
                else:
1095
                    unversioned.add(p)
1096
            if unversioned:
1097
                raise errors.PathsNotVersionedError(unversioned)
1098
1099
        return filter(self.is_versioned, paths)