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