/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
7096.3.2 by Jelmer Vernooij
Fix some git tests.
22
from collections import deque
0.360.2 by Jelmer Vernooij
Fix test.
23
import errno
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
24
from io import BytesIO
25
import os
26
27
from dulwich.index import (
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
28
    blob_from_path_and_stat,
29
    cleanup_mode,
30
    commit_tree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
31
    index_entry_from_stat,
32
    )
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
33
from dulwich.object_store import (
34
    tree_lookup_path,
35
    OverlayObjectStore,
36
    )
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
37
from dulwich.objects import (
38
    Blob,
39
    Tree,
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
40
    ZERO_SHA,
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
41
    S_IFGITLINK,
0.429.7 by Jelmer Vernooij
Consistent file ids.
42
    S_ISGITLINK,
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
43
    )
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
44
import stat
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
45
import posixpath
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
46
6986.2.1 by Jelmer Vernooij
Move breezy.plugins.git to breezy.git.
47
from .. import (
0.429.26 by Jelmer Vernooij
Fix remaining test.
48
    controldir as _mod_controldir,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
49
    delta,
50
    errors,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
51
    mutabletree,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
52
    osutils,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
53
    revisiontree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
54
    trace,
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
55
    tree as _mod_tree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
56
    workingtree,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
57
    )
6986.2.1 by Jelmer Vernooij
Move breezy.plugins.git to breezy.git.
58
from ..revision import (
6973.2.1 by Jelmer Vernooij
Implement GitRevisionTree.annotate_iter.
59
    CURRENT_REVISION,
60
    NULL_REVISION,
61
    )
6986.2.2 by Jelmer Vernooij
Merge trunk.
62
from ..sixish import (
6973.9.1 by Jelmer Vernooij
More test fixes.
63
    text_type,
64
    viewitems,
65
    )
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
66
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
67
from .mapping import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
68
    mode_is_executable,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
69
    mode_kind,
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
70
    default_mapping,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
71
    )
72
73
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
74
class GitTreeDirectory(_mod_tree.TreeDirectory):
75
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.
76
    __slots__ = ['file_id', 'name', 'parent_id', 'children']
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
77
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.
78
    def __init__(self, file_id, name, parent_id):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
79
        self.file_id = file_id
80
        self.name = name
81
        self.parent_id = parent_id
82
        # TODO(jelmer)
83
        self.children = {}
84
85
    @property
86
    def kind(self):
87
        return 'directory'
88
89
    @property
90
    def executable(self):
91
        return False
92
93
    def copy(self):
94
        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.
95
            self.file_id, self.name, self.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
96
97
    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.
98
        return "%s(file_id=%r, name=%r, parent_id=%r)" % (
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
99
            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.
100
            self.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
101
102
    def __eq__(self, other):
103
        return (self.kind == other.kind and
104
                self.file_id == other.file_id and
105
                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.
106
                self.parent_id == other.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
107
108
109
class GitTreeFile(_mod_tree.TreeFile):
110
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.
111
    __slots__ = ['file_id', 'name', 'parent_id', 'text_size', 'text_sha1',
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
112
                 'executable']
113
0.390.2 by Jelmer Vernooij
merge trunk
114
    def __init__(self, file_id, name, parent_id, text_size=None,
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
115
                 text_sha1=None, executable=None):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
116
        self.file_id = file_id
117
        self.name = name
118
        self.parent_id = parent_id
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
119
        self.text_size = text_size
120
        self.text_sha1 = text_sha1
121
        self.executable = executable
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
122
123
    @property
124
    def kind(self):
125
        return 'file'
126
127
    def __eq__(self, other):
128
        return (self.kind == other.kind and
129
                self.file_id == other.file_id and
130
                self.name == other.name and
131
                self.parent_id == other.parent_id and
132
                self.text_sha1 == other.text_sha1 and
133
                self.text_size == other.text_size and
134
                self.executable == other.executable)
135
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
136
    def __repr__(self):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
137
        return ("%s(file_id=%r, name=%r, parent_id=%r, text_size=%r, "
138
                "text_sha1=%r, executable=%r)") % (
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
139
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.390.2 by Jelmer Vernooij
merge trunk
140
            self.text_size, self.text_sha1, self.executable)
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
141
0.365.2 by Jelmer Vernooij
Add eq/copy.
142
    def copy(self):
143
        ret = self.__class__(
7143.15.2 by Jelmer Vernooij
Run autopep8.
144
            self.file_id, self.name, self.parent_id)
0.365.2 by Jelmer Vernooij
Add eq/copy.
145
        ret.text_sha1 = self.text_sha1
146
        ret.text_size = self.text_size
147
        ret.executable = self.executable
148
        return ret
149
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
150
151
class GitTreeSymlink(_mod_tree.TreeLink):
152
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.
153
    __slots__ = ['file_id', 'name', 'parent_id', 'symlink_target']
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
154
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.
155
    def __init__(self, file_id, name, parent_id,
0.365.2 by Jelmer Vernooij
Add eq/copy.
156
                 symlink_target=None):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
157
        self.file_id = file_id
158
        self.name = name
159
        self.parent_id = parent_id
0.365.2 by Jelmer Vernooij
Add eq/copy.
160
        self.symlink_target = symlink_target
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
161
162
    @property
163
    def kind(self):
164
        return 'symlink'
165
166
    @property
167
    def executable(self):
168
        return False
169
170
    @property
171
    def text_size(self):
172
        return None
173
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
174
    def __repr__(self):
0.390.2 by Jelmer Vernooij
merge trunk
175
        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.
176
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.390.2 by Jelmer Vernooij
merge trunk
177
            self.symlink_target)
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
178
0.365.2 by Jelmer Vernooij
Add eq/copy.
179
    def __eq__(self, other):
180
        return (self.kind == other.kind and
181
                self.file_id == other.file_id and
182
                self.name == other.name and
183
                self.parent_id == other.parent_id and
184
                self.symlink_target == other.symlink_target)
185
186
    def copy(self):
187
        return self.__class__(
7143.15.2 by Jelmer Vernooij
Run autopep8.
188
            self.file_id, self.name, self.parent_id,
189
            self.symlink_target)
0.365.2 by Jelmer Vernooij
Add eq/copy.
190
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
191
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
192
class GitTreeSubmodule(_mod_tree.TreeLink):
193
0.429.12 by Jelmer Vernooij
Remove revision.
194
    __slots__ = ['file_id', 'name', 'parent_id', 'reference_revision']
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
195
0.429.12 by Jelmer Vernooij
Remove revision.
196
    def __init__(self, file_id, name, parent_id, reference_revision=None):
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
197
        self.file_id = file_id
198
        self.name = name
199
        self.parent_id = parent_id
200
        self.reference_revision = reference_revision
201
202
    @property
203
    def kind(self):
204
        return 'tree-reference'
205
206
    def __repr__(self):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
207
        return ("%s(file_id=%r, name=%r, parent_id=%r, "
208
                "reference_revision=%r)") % (
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
209
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.429.12 by Jelmer Vernooij
Remove revision.
210
            self.reference_revision)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
211
212
    def __eq__(self, other):
213
        return (self.kind == other.kind and
214
                self.file_id == other.file_id and
215
                self.name == other.name and
216
                self.parent_id == other.parent_id and
217
                self.reference_revision == other.reference_revision)
218
219
    def copy(self):
220
        return self.__class__(
7143.15.2 by Jelmer Vernooij
Run autopep8.
221
            self.file_id, self.name, self.parent_id,
222
            self.reference_revision)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
223
224
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
225
entry_factory = {
226
    'directory': GitTreeDirectory,
227
    'file': GitTreeFile,
228
    'symlink': GitTreeSymlink,
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
229
    'tree-reference': GitTreeSubmodule,
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
230
    }
231
232
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
233
def ensure_normalized_path(path):
234
    """Check whether path is normalized.
235
236
    :raises InvalidNormalization: When path is not normalized, and cannot be
237
        accessed on this platform by the normalized path.
238
    :return: The NFC normalised version of path.
239
    """
240
    norm_path, can_access = osutils.normalized_filename(path)
241
    if norm_path != path:
242
        if can_access:
243
            return norm_path
244
        else:
245
            raise errors.InvalidNormalization(path)
246
    return path
247
248
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
249
class GitRevisionTree(revisiontree.RevisionTree):
0.200.959 by Jelmer Vernooij
Improve docstrings.
250
    """Revision tree implementation based on Git objects."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
251
252
    def __init__(self, repository, revision_id):
253
        self._revision_id = revision_id
254
        self._repository = repository
7358.4.1 by Jelmer Vernooij
Add Tree.get_nested_tree.
255
        self._submodules = None
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
256
        self.store = repository._git.object_store
6964.2.3 by Jelmer Vernooij
Review comments.
257
        if not isinstance(revision_id, bytes):
0.361.1 by Jelmer Vernooij
Don't use assert.
258
            raise TypeError(revision_id)
7143.15.2 by Jelmer Vernooij
Run autopep8.
259
        self.commit_id, self.mapping = repository.lookup_bzr_revision_id(
260
            revision_id)
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
261
        if revision_id == NULL_REVISION:
262
            self.tree = None
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
263
            self.mapping = default_mapping
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
264
        else:
265
            try:
266
                commit = self.store[self.commit_id]
6964.2.1 by Jelmer Vernooij
Initial work to support brz-git on python3.
267
            except KeyError:
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
268
                raise errors.NoSuchRevision(repository, revision_id)
269
            self.tree = commit.tree
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
270
7358.4.1 by Jelmer Vernooij
Add Tree.get_nested_tree.
271
    def _submodule_info(self):
272
        if self._submodules is None:
273
            try:
274
                with self.get_file('.gitmodules') as f:
275
                    config = GitConfigFile.from_file(f)
276
                    self._submodules = {
277
                        path: (url, section)
278
                        for path, url, section in parse_submodules(config)}
279
            except errors.NoSuchFile:
280
                self._submodules = {}
281
        return self._submodules
282
283
    def _get_submodule_repository(self, relpath):
284
        if not isinstance(relpath, bytes):
285
            raise TypeError(relpath)
286
        try:
287
            info = self._submodule_info()[relpath]
288
        except KeyError:
289
            nested_repo_transport = self._repository.user_transport.clone(relpath.decode('utf-8'))
290
        else:
291
            nested_repo_transport = self._repository.control_transport.clone(
292
                posixpath.join('modules', info[0]))
7143.15.2 by Jelmer Vernooij
Run autopep8.
293
        nested_controldir = _mod_controldir.ControlDir.open_from_transport(
294
            nested_repo_transport)
0.429.26 by Jelmer Vernooij
Fix remaining test.
295
        return nested_controldir.find_repository()
296
7358.4.1 by Jelmer Vernooij
Add Tree.get_nested_tree.
297
    def get_nested_tree(self, path):
7358.4.2 by Jelmer Vernooij
Fix tests on Python 3.
298
        encoded_path = path.encode('utf-8')
299
        nested_repo = self._get_submodule_repository(encoded_path)
7358.4.1 by Jelmer Vernooij
Add Tree.get_nested_tree.
300
        ref_rev = self.get_reference_revision(path)
301
        return nested_repo.revision_tree(ref_rev)
302
0.349.1 by Jelmer Vernooij
Support supports_rename_tracking method.
303
    def supports_rename_tracking(self):
304
        return False
305
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
306
    def get_file_revision(self, path):
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
307
        change_scanner = self._repository._file_change_scanner
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
308
        if self.commit_id == ZERO_SHA:
309
            return NULL_REVISION
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
310
        (unused_path, commit_id) = change_scanner.find_last_change_revision(
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
311
            path.encode('utf-8'), self.commit_id)
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
312
        return self._repository.lookup_foreign_revision_id(
313
            commit_id, self.mapping)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
314
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
315
    def get_file_mtime(self, path):
6965.1.1 by Jelmer Vernooij
Add basic support for horizoned history.
316
        try:
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
317
            revid = self.get_file_revision(path)
6965.1.1 by Jelmer Vernooij
Add basic support for horizoned history.
318
        except KeyError:
7096.3.2 by Jelmer Vernooij
Fix some git tests.
319
            raise errors.NoSuchFile(path)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
320
        try:
321
            rev = self._repository.get_revision(revid)
322
        except errors.NoSuchRevision:
6965.1.1 by Jelmer Vernooij
Add basic support for horizoned history.
323
            raise _mod_tree.FileTimestampUnavailable(path)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
324
        return rev.timestamp
325
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
326
    def id2path(self, file_id):
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
327
        try:
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
328
            path = self.mapping.parse_file_id(file_id)
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
329
        except ValueError:
0.200.1714 by Jelmer Vernooij
Fix NoSuchId raising.
330
            raise errors.NoSuchId(self, file_id)
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
331
        if self.is_versioned(path):
0.329.1 by Jelmer Vernooij
Check that path actually exists in Tree.id2path.
332
            return path
333
        raise errors.NoSuchId(self, file_id)
334
335
    def is_versioned(self, path):
336
        return self.has_filename(path)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
337
338
    def path2id(self, path):
0.200.1328 by Jelmer Vernooij
More test fixes.
339
        if self.mapping.is_special_file(path):
340
            return None
7096.3.6 by Jelmer Vernooij
Fix tests, on python 2 at least.
341
        if not self.is_versioned(path):
342
            return None
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
343
        return self.mapping.generate_file_id(osutils.safe_unicode(path))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
344
0.200.1569 by Jelmer Vernooij
Implement GitRevisionTree.all_file_ids().
345
    def all_file_ids(self):
7170.3.1 by Jelmer Vernooij
Make Tree.all_file_ids optional.
346
        raise errors.UnsupportedOperation(self.all_file_ids, self)
0.200.1569 by Jelmer Vernooij
Implement GitRevisionTree.all_file_ids().
347
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
348
    def all_versioned_paths(self):
7096.3.2 by Jelmer Vernooij
Fix some git tests.
349
        ret = {u''}
7045.2.17 by Jelmer Vernooij
Some more.
350
        todo = [(self.store, b'', self.tree)]
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
351
        while todo:
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
352
            (store, path, tree_id) = todo.pop()
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
353
            if tree_id is None:
354
                continue
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
355
            tree = store[tree_id]
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
356
            for name, mode, hexsha in tree.items():
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
357
                subpath = posixpath.join(path, name)
7096.3.2 by Jelmer Vernooij
Fix some git tests.
358
                ret.add(subpath.decode('utf-8'))
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
359
                if stat.S_ISDIR(mode):
7045.2.17 by Jelmer Vernooij
Some more.
360
                    todo.append((store, subpath, hexsha))
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
361
        return ret
362
0.200.1208 by Jelmer Vernooij
Add GitWorkingTree.has_id and GitWorkingTree.has_or_had_id.
363
    def has_id(self, file_id):
364
        try:
365
            path = self.id2path(file_id)
366
        except errors.NoSuchId:
367
            return False
368
        return self.has_filename(path)
369
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
370
    def _lookup_path(self, path):
371
        if self.tree is None:
372
            raise errors.NoSuchFile(path)
373
        try:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
374
            (mode, hexsha) = tree_lookup_path(
375
                self.store.__getitem__, self.tree, path.encode('utf-8'))
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
376
        except KeyError:
377
            raise errors.NoSuchFile(self, path)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
378
        else:
379
            return (self.store, mode, hexsha)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
380
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
381
    def is_executable(self, path):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
382
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1615 by Jelmer Vernooij
Implement GitRevisionTree.is_executable.:
383
        if mode is None:
384
            # the tree root is a directory
385
            return False
386
        return mode_is_executable(mode)
387
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
388
    def kind(self, path):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
389
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1253 by Jelmer Vernooij
Fix Tree.kind(TREE_ROOT).
390
        if mode is None:
391
            # the tree root is a directory
392
            return "directory"
0.200.1241 by Jelmer Vernooij
Implement GitRevisionTree.kind.
393
        return mode_kind(mode)
394
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
395
    def has_filename(self, path):
396
        try:
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
397
            self._lookup_path(path)
398
        except errors.NoSuchFile:
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
399
            return False
400
        else:
401
            return True
402
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
403
    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.
404
        if self.tree is None:
405
            return
7143.17.1 by Jelmer Vernooij
Fix grep in git working trees.
406
        if from_dir is None or from_dir == '.':
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
407
            from_dir = u""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
408
        (store, mode, hexsha) = self._lookup_path(from_dir)
7143.15.2 by Jelmer Vernooij
Run autopep8.
409
        if mode is None:  # Root
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
410
            root_ie = self._get_dir_ie(b"", None)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
411
        else:
7096.3.2 by Jelmer Vernooij
Fix some git tests.
412
            parent_path = posixpath.dirname(from_dir)
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
413
            parent_id = self.mapping.generate_file_id(parent_path)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
414
            if mode_kind(mode) == 'directory':
415
                root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
416
            else:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
417
                root_ie = self._get_file_ie(
418
                    store, from_dir.encode("utf-8"),
419
                    posixpath.basename(from_dir), mode, hexsha)
7096.3.2 by Jelmer Vernooij
Fix some git tests.
420
        if include_root:
7143.19.5 by Jelmer Vernooij
Undo removal of kind.
421
            yield (from_dir, "V", root_ie.kind, root_ie)
7018.3.7 by Jelmer Vernooij
Fix remaining git tests.
422
        todo = []
0.264.10 by Jelmer Vernooij
Yield inventory entries.
423
        if root_ie.kind == 'directory':
7143.15.2 by Jelmer Vernooij
Run autopep8.
424
            todo.append((store, from_dir.encode("utf-8"),
425
                         b"", hexsha, root_ie.file_id))
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
426
        while todo:
7096.3.2 by Jelmer Vernooij
Fix some git tests.
427
            (store, path, relpath, hexsha, parent_id) = todo.pop()
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
428
            tree = store[hexsha]
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
429
            for name, mode, hexsha in tree.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
430
                if self.mapping.is_special_file(name):
431
                    continue
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
432
                child_path = posixpath.join(path, name)
7096.3.2 by Jelmer Vernooij
Fix some git tests.
433
                child_relpath = posixpath.join(relpath, name)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
434
                if stat.S_ISDIR(mode):
435
                    ie = self._get_dir_ie(child_path, parent_id)
436
                    if recursive:
7143.15.2 by Jelmer Vernooij
Run autopep8.
437
                        todo.append(
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
438
                            (store, child_path, child_relpath, hexsha,
439
                             ie.file_id))
0.264.10 by Jelmer Vernooij
Yield inventory entries.
440
                else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
441
                    ie = self._get_file_ie(
442
                        store, child_path, name, mode, hexsha, parent_id)
7143.19.7 by Jelmer Vernooij
merge trunk
443
                yield (child_relpath.decode('utf-8'), "V", ie.kind, ie)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
444
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
445
    def _get_file_ie(self, store, path, name, mode, hexsha, parent_id):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
446
        if not isinstance(path, bytes):
0.361.1 by Jelmer Vernooij
Don't use assert.
447
            raise TypeError(path)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
448
        if not isinstance(name, bytes):
0.361.1 by Jelmer Vernooij
Don't use assert.
449
            raise TypeError(name)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
450
        kind = mode_kind(mode)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
451
        path = path.decode('utf-8')
452
        name = name.decode("utf-8")
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
453
        file_id = self.mapping.generate_file_id(path)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
454
        ie = entry_factory[kind](file_id, name, parent_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
455
        if kind == 'symlink':
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
456
            ie.symlink_target = store[hexsha].data.decode('utf-8')
0.200.1401 by Jelmer Vernooij
Cope with submodules in working trees.
457
        elif kind == 'tree-reference':
7143.15.2 by Jelmer Vernooij
Run autopep8.
458
            ie.reference_revision = self.mapping.revision_id_foreign_to_bzr(
459
                hexsha)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
460
        else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
461
            data = store[hexsha].data
0.264.10 by Jelmer Vernooij
Yield inventory entries.
462
            ie.text_sha1 = osutils.sha_string(data)
463
            ie.text_size = len(data)
464
            ie.executable = mode_is_executable(mode)
465
        return ie
466
467
    def _get_dir_ie(self, path, parent_id):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
468
        path = path.decode('utf-8')
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
469
        file_id = self.mapping.generate_file_id(path)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
470
        return GitTreeDirectory(file_id, posixpath.basename(path), parent_id)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
471
7192.5.1 by Jelmer Vernooij
Remove more file ids.
472
    def iter_child_entries(self, path):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
473
        (store, mode, tree_sha) = self._lookup_path(path)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
474
7096.3.1 by Jelmer Vernooij
Run tests against GitRevisionTree.
475
        if mode is not None and not stat.S_ISDIR(mode):
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
476
            return
477
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
478
        encoded_path = path.encode('utf-8')
479
        file_id = self.path2id(path)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
480
        tree = store[tree_sha]
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
481
        for name, mode, hexsha in tree.iteritems():
482
            if self.mapping.is_special_file(name):
483
                continue
484
            child_path = posixpath.join(encoded_path, name)
485
            if stat.S_ISDIR(mode):
486
                yield self._get_dir_ie(child_path, file_id)
487
            else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
488
                yield self._get_file_ie(store, child_path, name, mode, hexsha,
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
489
                                        file_id)
490
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
491
    def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
0.287.4 by Jelmer Vernooij
Fix GitRevisionTree behaviour for null:
492
        if self.tree is None:
493
            return
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
494
        if yield_parents:
495
            # TODO(jelmer): Support yield parents
496
            raise NotImplementedError
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
497
        if specific_files is not None:
498
            if specific_files in ([""], []):
499
                specific_files = None
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
500
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
501
                specific_files = set([p.encode('utf-8')
502
                                      for p in specific_files])
7358.14.1 by Jelmer Vernooij
Remove Tree.get_root_id() in favour of Tree.path2id('').
503
        todo = deque([(self.store, b"", self.tree, self.path2id(''))])
7096.3.2 by Jelmer Vernooij
Fix some git tests.
504
        if specific_files is None or u"" in specific_files:
7096.3.7 by Jelmer Vernooij
Fix tests on python 3.
505
            yield u"", self._get_dir_ie(b"", None)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
506
        while todo:
7096.3.2 by Jelmer Vernooij
Fix some git tests.
507
            store, path, tree_sha, parent_id = todo.popleft()
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
508
            tree = store[tree_sha]
7096.3.2 by Jelmer Vernooij
Fix some git tests.
509
            extradirs = []
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
510
            for name, mode, hexsha in tree.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
511
                if self.mapping.is_special_file(name):
512
                    continue
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
513
                child_path = posixpath.join(path, name)
7096.3.2 by Jelmer Vernooij
Fix some git tests.
514
                child_path_decoded = child_path.decode('utf-8')
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
515
                if stat.S_ISDIR(mode):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
516
                    if (specific_files is None or
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
517
                            any([p for p in specific_files if p.startswith(
518
                                child_path)])):
7096.3.2 by Jelmer Vernooij
Fix some git tests.
519
                        extradirs.append(
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
520
                            (store, child_path, hexsha,
521
                             self.path2id(child_path_decoded)))
7096.3.2 by Jelmer Vernooij
Fix some git tests.
522
                if specific_files is None or child_path in specific_files:
523
                    if stat.S_ISDIR(mode):
524
                        yield (child_path_decoded,
525
                               self._get_dir_ie(child_path, parent_id))
526
                    else:
527
                        yield (child_path_decoded,
528
                               self._get_file_ie(store, child_path, name, mode,
7143.15.2 by Jelmer Vernooij
Run autopep8.
529
                                                 hexsha, parent_id))
7096.3.2 by Jelmer Vernooij
Fix some git tests.
530
            todo.extendleft(reversed(extradirs))
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
531
7096.3.5 by Jelmer Vernooij
Fix GitRevisionTree.iter_references.
532
    def iter_references(self):
533
        if self.supports_tree_reference():
534
            for path, entry in self.iter_entries_by_dir():
535
                if entry.kind == 'tree-reference':
7350.2.1 by Jelmer Vernooij
Drop file_id return value from Tree.iter_references.
536
                    yield path
7096.3.5 by Jelmer Vernooij
Fix GitRevisionTree.iter_references.
537
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
538
    def get_revision_id(self):
0.200.959 by Jelmer Vernooij
Improve docstrings.
539
        """See RevisionTree.get_revision_id."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
540
        return self._revision_id
541
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
542
    def get_file_sha1(self, path, stat_value=None):
0.287.6 by Jelmer Vernooij
Fix some more tests.
543
        if self.tree is None:
544
            raise errors.NoSuchFile(path)
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
545
        return osutils.sha_string(self.get_file_text(path))
0.200.1255 by Jelmer Vernooij
Implement GitRevisionTree.get_file_sha1.
546
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
547
    def get_file_verifier(self, path, stat_value=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
548
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
549
        return ("GIT", hexsha)
550
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
551
    def get_file_size(self, path):
7096.3.2 by Jelmer Vernooij
Fix some git tests.
552
        (store, mode, hexsha) = self._lookup_path(path)
553
        if stat.S_ISREG(mode):
554
            return len(store[hexsha].data)
555
        return None
556
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
557
    def get_file_text(self, path):
0.200.959 by Jelmer Vernooij
Improve docstrings.
558
        """See RevisionTree.get_file_text."""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
559
        (store, mode, hexsha) = self._lookup_path(path)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
560
        if stat.S_ISREG(mode):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
561
            return store[hexsha].data
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
562
        else:
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
563
            return b""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
564
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
565
    def get_symlink_target(self, path):
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
566
        """See RevisionTree.get_symlink_target."""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
567
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
568
        if stat.S_ISLNK(mode):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
569
            return store[hexsha].data.decode('utf-8')
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
570
        else:
571
            return None
572
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
573
    def get_reference_revision(self, path):
0.429.17 by Jelmer Vernooij
Fix some more tests.
574
        """See RevisionTree.get_symlink_target."""
0.429.25 by Jelmer Vernooij
Merge trunk.
575
        (store, mode, hexsha) = self._lookup_path(path)
0.429.17 by Jelmer Vernooij
Fix some more tests.
576
        if S_ISGITLINK(mode):
7358.4.2 by Jelmer Vernooij
Fix tests on Python 3.
577
            nested_repo = self._get_submodule_repository(path.encode('utf-8'))
0.429.26 by Jelmer Vernooij
Fix remaining test.
578
            return nested_repo.lookup_foreign_revision_id(hexsha)
0.429.17 by Jelmer Vernooij
Fix some more tests.
579
        else:
580
            return None
581
0.264.10 by Jelmer Vernooij
Yield inventory entries.
582
    def _comparison_data(self, entry, path):
583
        if entry is None:
584
            return None, False, None
585
        return entry.kind, entry.executable, None
586
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
587
    def path_content_summary(self, path):
588
        """See Tree.path_content_summary."""
589
        try:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
590
            (store, mode, hexsha) = self._lookup_path(path)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
591
        except errors.NoSuchFile:
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
592
            return ('missing', None, None, None)
593
        kind = mode_kind(mode)
594
        if kind == 'file':
595
            executable = mode_is_executable(mode)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
596
            contents = store[hexsha].data
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
597
            return (kind, len(contents), executable,
598
                    osutils.sha_string(contents))
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
599
        elif kind == 'symlink':
7096.3.2 by Jelmer Vernooij
Fix some git tests.
600
            return (kind, None, None, store[hexsha].data.decode('utf-8'))
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
601
        elif kind == 'tree-reference':
7358.4.2 by Jelmer Vernooij
Fix tests on Python 3.
602
            nested_repo = self._get_submodule_repository(path.encode('utf-8'))
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
603
            return (kind, None, None,
0.429.26 by Jelmer Vernooij
Fix remaining test.
604
                    nested_repo.lookup_foreign_revision_id(hexsha))
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
605
        else:
606
            return (kind, None, None, None)
607
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
608
    def find_related_paths_across_trees(self, paths, trees=[],
7143.15.2 by Jelmer Vernooij
Run autopep8.
609
                                        require_versioned=True):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
610
        if paths is None:
611
            return None
612
        if require_versioned:
613
            trees = [self] + (trees if trees is not None else [])
614
            unversioned = set()
615
            for p in paths:
616
                for t in trees:
617
                    if t.is_versioned(p):
618
                        break
619
                else:
620
                    unversioned.add(p)
621
            if unversioned:
622
                raise errors.PathsNotVersionedError(unversioned)
623
        return filter(self.is_versioned, paths)
624
0.393.1 by Jelmer Vernooij
Avoid expensive bzr APIs in commit.
625
    def _iter_tree_contents(self, include_trees=False):
626
        if self.tree is None:
627
            return iter([])
628
        return self.store.iter_tree_contents(
7143.15.2 by Jelmer Vernooij
Run autopep8.
629
            self.tree, include_trees=include_trees)
0.393.1 by Jelmer Vernooij
Avoid expensive bzr APIs in commit.
630
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
631
    def annotate_iter(self, path, default_revision=CURRENT_REVISION):
6973.2.1 by Jelmer Vernooij
Implement GitRevisionTree.annotate_iter.
632
        """Return an iterator of revision_id, line tuples.
633
634
        For working trees (and mutable trees in general), the special
635
        revision_id 'current:' will be used for lines that are new in this
636
        tree, e.g. uncommitted changes.
637
        :param default_revision: For lines that don't match a basis, mark them
638
            with this revision id. Not all implementations will make use of
639
            this value.
640
        """
641
        with self.lock_read():
642
            # Now we have the parents of this content
643
            from breezy.annotate import Annotator
644
            from .annotate import AnnotateProvider
645
            annotator = Annotator(AnnotateProvider(
646
                self._repository._file_change_scanner))
647
            this_key = (path, self.get_file_revision(path))
648
            annotations = [(key[-1], line)
649
                           for key, line in annotator.annotate_flat(this_key)]
650
            return annotations
651
7096.3.2 by Jelmer Vernooij
Fix some git tests.
652
    def _get_rules_searcher(self, default_searcher):
653
        return default_searcher
654
7096.3.6 by Jelmer Vernooij
Fix tests, on python 2 at least.
655
    def walkdirs(self, prefix=u""):
7096.3.2 by Jelmer Vernooij
Fix some git tests.
656
        (store, mode, hexsha) = self._lookup_path(prefix)
7143.15.2 by Jelmer Vernooij
Run autopep8.
657
        todo = deque(
658
            [(store, prefix.encode('utf-8'), hexsha, self.path2id(prefix))])
7096.3.2 by Jelmer Vernooij
Fix some git tests.
659
        while todo:
7096.3.4 by Jelmer Vernooij
Fix returned paths.
660
            store, path, tree_sha, parent_id = todo.popleft()
7096.3.2 by Jelmer Vernooij
Fix some git tests.
661
            path_decoded = path.decode('utf-8')
662
            tree = store[tree_sha]
663
            children = []
664
            for name, mode, hexsha in tree.iteritems():
665
                if self.mapping.is_special_file(name):
666
                    continue
667
                child_path = posixpath.join(path, name)
668
                file_id = self.path2id(child_path.decode('utf-8'))
669
                if stat.S_ISDIR(mode):
7096.3.4 by Jelmer Vernooij
Fix returned paths.
670
                    todo.append((store, child_path, hexsha, file_id))
7096.3.6 by Jelmer Vernooij
Fix tests, on python 2 at least.
671
                children.append(
672
                    (child_path.decode('utf-8'), name.decode('utf-8'),
673
                        mode_kind(mode), None,
674
                        file_id, mode_kind(mode)))
7096.3.4 by Jelmer Vernooij
Fix returned paths.
675
            yield (path_decoded, parent_id), children
7096.3.2 by Jelmer Vernooij
Fix some git tests.
676
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
677
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
678
def tree_delta_from_git_changes(changes, mappings,
679
                                specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
680
                                require_versioned=False, include_root=False,
681
                                target_extras=None):
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
682
    """Create a TreeDelta from two git trees.
0.200.959 by Jelmer Vernooij
Improve docstrings.
683
684
    source and target are iterators over tuples with:
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
685
        (filename, sha, mode)
686
    """
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
687
    (old_mapping, new_mapping) = mappings
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
688
    if target_extras is None:
689
        target_extras = set()
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
690
    ret = delta.TreeDelta()
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
691
    added = []
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
692
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
7018.3.2 by Jelmer Vernooij
Fix some git tests.
693
        if newpath == b'' and not include_root:
0.287.5 by Jelmer Vernooij
Fix root handling.
694
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
695
        if oldpath is not None:
696
            oldpath_decoded = oldpath.decode('utf-8')
697
        else:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
698
            oldpath_decoded = None
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
699
        if newpath is not None:
700
            newpath_decoded = newpath.decode('utf-8')
7027.5.2 by Jelmer Vernooij
Fix some more git tests.
701
        else:
702
            newpath_decoded = None
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
703
        if not (specific_files is None or
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
704
                (oldpath is not None and
705
                    osutils.is_inside_or_parent_of_any(
706
                        specific_files, oldpath_decoded)) or
707
                (newpath is not None and
708
                    osutils.is_inside_or_parent_of_any(
709
                        specific_files, newpath_decoded))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
710
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
711
712
        if oldpath_decoded is None:
7358.11.6 by Jelmer Vernooij
merge trunk.
713
            fileid = new_mapping.generate_file_id(newpath_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
714
            oldexe = None
715
            oldkind = None
716
            oldname = None
717
            oldparent = None
718
            oldversioned = False
719
        else:
720
            oldversioned = True
721
            if oldmode:
722
                oldexe = mode_is_executable(oldmode)
723
                oldkind = mode_kind(oldmode)
724
            else:
725
                oldexe = False
726
                oldkind = None
727
            if oldpath_decoded == u'':
728
                oldparent = None
729
                oldname = u''
730
            else:
731
                (oldparentpath, oldname) = osutils.split(oldpath_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
732
                oldparent = old_mapping.generate_file_id(oldparentpath)
733
            fileid = old_mapping.generate_file_id(oldpath_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
734
        if newpath_decoded is None:
735
            newexe = None
736
            newkind = None
737
            newname = None
738
            newparent = None
739
            newversioned = False
740
        else:
741
            newversioned = (newpath_decoded not in target_extras)
742
            if newmode:
743
                newexe = mode_is_executable(newmode)
744
                newkind = mode_kind(newmode)
745
            else:
746
                newexe = False
747
                newkind = None
748
            if newpath_decoded == u'':
749
                newparent = None
750
                newname = u''
751
            else:
752
                newparentpath, newname = osutils.split(newpath_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
753
                newparent = new_mapping.generate_file_id(newparentpath)
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
754
        if old_mapping.is_special_file(oldpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
755
            oldpath = None
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
756
        if new_mapping.is_special_file(newpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
757
            newpath = None
758
        if oldpath is None and newpath is None:
759
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
760
        change = _mod_tree.TreeChange(
761
            fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
762
            (oldversioned, newversioned),
763
            (oldparent, newparent), (oldname, newname),
764
            (oldkind, newkind), (oldexe, newexe))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
765
        if oldpath is None:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
766
            added.append((newpath, newkind))
6977.1.2 by Jelmer Vernooij
Deal with missing files properly in 'bzr st'.
767
        elif newpath is None or newmode == 0:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
768
            ret.removed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
769
        elif oldpath != newpath:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
770
            ret.renamed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
771
        elif mode_kind(oldmode) != mode_kind(newmode):
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
772
            ret.kind_changed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
773
        elif oldsha != newsha or oldmode != newmode:
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
774
            if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
775
                continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
776
            ret.modified.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
777
        else:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
778
            ret.unchanged.append(change)
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
779
7211.10.7 by Jelmer Vernooij
Fix on python 3.
780
    implicit_dirs = {b''}
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
781
    for path, kind in added:
7211.10.7 by Jelmer Vernooij
Fix on python 3.
782
        if kind == 'directory' or path in target_extras:
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
783
            continue
784
        implicit_dirs.update(osutils.parent_directories(path))
785
786
    for path, kind in added:
7211.10.5 by Jelmer Vernooij
Fix handling of directories.
787
        if kind == 'directory' and path not in implicit_dirs:
788
            continue
7211.10.7 by Jelmer Vernooij
Fix on python 3.
789
        path_decoded = osutils.normalized_filename(path)[0]
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
790
        parent_path, basename = osutils.split(path_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
791
        parent_id = new_mapping.generate_file_id(parent_path)
7211.10.5 by Jelmer Vernooij
Fix handling of directories.
792
        if path in target_extras:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
793
            ret.unversioned.append(_mod_tree.TreeChange(
794
                None, (None, path_decoded),
795
                True, (False, False), (None, parent_id),
796
                (None, basename), (None, kind), (None, False)))
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
797
        else:
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
798
            file_id = new_mapping.generate_file_id(path_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
799
            ret.added.append(
800
                _mod_tree.TreeChange(
801
                    file_id, (None, path_decoded), True,
802
                    (False, True),
803
                    (None, parent_id),
804
                    (None, basename), (None, kind), (None, False)))
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
805
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
806
    return ret
807
808
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
809
def changes_from_git_changes(changes, mapping, specific_files=None,
810
                             include_unchanged=False, target_extras=None):
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
811
    """Create a iter_changes-like generator from a git stream.
0.200.959 by Jelmer Vernooij
Improve docstrings.
812
813
    source and target are iterators over tuples with:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
814
        (filename, sha, mode)
815
    """
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
816
    if target_extras is None:
817
        target_extras = set()
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
818
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
819
        if oldpath is not None:
820
            oldpath_decoded = oldpath.decode('utf-8')
821
        else:
822
            oldpath_decoded = None
823
        if newpath is not None:
824
            newpath_decoded = newpath.decode('utf-8')
825
        else:
826
            newpath_decoded = None
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
827
        if not (specific_files is None or
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
828
                (oldpath_decoded is not None and
829
                    osutils.is_inside_or_parent_of_any(
830
                        specific_files, oldpath_decoded)) or
831
                (newpath_decoded is not None and
832
                    osutils.is_inside_or_parent_of_any(
833
                        specific_files, newpath_decoded))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
834
            continue
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
835
        if oldpath is not None and mapping.is_special_file(oldpath):
836
            continue
837
        if newpath is not None and mapping.is_special_file(newpath):
0.200.1328 by Jelmer Vernooij
More test fixes.
838
            continue
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
839
        if oldpath_decoded is None:
840
            fileid = mapping.generate_file_id(newpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
841
            oldexe = None
842
            oldkind = None
843
            oldname = None
844
            oldparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
845
            oldversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
846
        else:
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
847
            oldversioned = True
0.391.8 by Jelmer Vernooij
Allow missing items in old tree.
848
            if oldmode:
849
                oldexe = mode_is_executable(oldmode)
850
                oldkind = mode_kind(oldmode)
851
            else:
852
                oldexe = False
853
                oldkind = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
854
            if oldpath_decoded == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
855
                oldparent = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
856
                oldname = u''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
857
            else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
858
                (oldparentpath, oldname) = osutils.split(oldpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
859
                oldparent = mapping.generate_file_id(oldparentpath)
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
860
            fileid = mapping.generate_file_id(oldpath_decoded)
861
        if newpath_decoded is None:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
862
            newexe = None
863
            newkind = None
864
            newname = None
865
            newparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
866
            newversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
867
        else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
868
            newversioned = (newpath_decoded not in target_extras)
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
869
            if newmode:
0.200.1576 by Jelmer Vernooij
Merge a bunch of fixes from store-roundtrip-info.
870
                newexe = mode_is_executable(newmode)
871
                newkind = mode_kind(newmode)
872
            else:
873
                newexe = False
874
                newkind = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
875
            if newpath_decoded == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
876
                newparent = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
877
                newname = u''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
878
            else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
879
                newparentpath, newname = osutils.split(newpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
880
                newparent = mapping.generate_file_id(newparentpath)
0.357.3 by Jelmer Vernooij
More remove fixes.
881
        if (not include_unchanged and
882
            oldkind == 'directory' and newkind == 'directory' and
7143.15.2 by Jelmer Vernooij
Run autopep8.
883
                oldpath_decoded == newpath_decoded):
0.357.3 by Jelmer Vernooij
More remove fixes.
884
            continue
7322.1.2 by Jelmer Vernooij
Return TreeChange objects.
885
        yield _mod_tree.TreeChange(
886
            fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
887
            (oldversioned, newversioned),
888
            (oldparent, newparent), (oldname, newname),
889
            (oldkind, newkind), (oldexe, newexe))
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
890
891
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
892
class InterGitTrees(_mod_tree.InterTree):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
893
    """InterTree that works between two git trees."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
894
0.200.659 by Jelmer Vernooij
Prevent tests using InterGitRevisionTrees.
895
    _matching_from_tree_format = None
896
    _matching_to_tree_format = None
897
    _test_mutable_trees_to_test_trees = None
898
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
899
    @classmethod
900
    def is_compatible(cls, source, target):
0.200.959 by Jelmer Vernooij
Improve docstrings.
901
        return (isinstance(source, GitRevisionTree) and
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
902
                isinstance(target, GitRevisionTree))
903
904
    def compare(self, want_unchanged=False, specific_files=None,
905
                extra_trees=None, require_versioned=False, include_root=False,
906
                want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
907
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
908
            changes, target_extras = self._iter_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
909
                want_unchanged=want_unchanged,
910
                require_versioned=require_versioned,
911
                specific_files=specific_files,
912
                extra_trees=extra_trees,
913
                want_unversioned=want_unversioned)
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
914
            return tree_delta_from_git_changes(
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
915
                changes, (self.source.mapping, self.target.mapping),
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
916
                specific_files=specific_files,
917
                include_root=include_root, target_extras=target_extras)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
918
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
919
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
920
                     pb=None, extra_trees=[], require_versioned=True,
921
                     want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
922
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
923
            changes, target_extras = self._iter_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
924
                want_unchanged=include_unchanged,
925
                require_versioned=require_versioned,
926
                specific_files=specific_files,
927
                extra_trees=extra_trees,
928
                want_unversioned=want_unversioned)
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
929
            return changes_from_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
930
                changes, self.target.mapping,
931
                specific_files=specific_files,
932
                include_unchanged=include_unchanged,
933
                target_extras=target_extras)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
934
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
935
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
936
                          require_versioned=False, extra_trees=None,
937
                          want_unversioned=False):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
938
        raise NotImplementedError(self._iter_git_changes)
939
940
941
class InterGitRevisionTrees(InterGitTrees):
942
    """InterTree that works between two git revision trees."""
943
944
    _matching_from_tree_format = None
945
    _matching_to_tree_format = None
946
    _test_mutable_trees_to_test_trees = None
947
948
    @classmethod
949
    def is_compatible(cls, source, target):
950
        return (isinstance(source, GitRevisionTree) and
951
                isinstance(target, GitRevisionTree))
952
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
953
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
954
                          require_versioned=True, extra_trees=None,
955
                          want_unversioned=False):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
956
        trees = [self.source]
957
        if extra_trees is not None:
958
            trees.extend(extra_trees)
959
        if specific_files is not None:
960
            specific_files = self.target.find_related_paths_across_trees(
7143.15.2 by Jelmer Vernooij
Run autopep8.
961
                specific_files, trees,
962
                require_versioned=require_versioned)
0.357.1 by Jelmer Vernooij
Fix some remove tests.
963
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
964
        if (self.source._repository._git.object_store !=
965
                self.target._repository._git.object_store):
966
            store = OverlayObjectStore(
967
                [self.source._repository._git.object_store,
968
                    self.target._repository._git.object_store])
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
969
        else:
970
            store = self.source._repository._git.object_store
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
971
        return store.tree_changes(
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
972
            self.source.tree, self.target.tree, want_unchanged=want_unchanged,
0.391.2 by Jelmer Vernooij
Pass along target_missing.
973
            include_trees=True, change_type_same=True), set()
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
974
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
975
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
976
_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
977
978
979
class MutableGitIndexTree(mutabletree.MutableTree):
980
981
    def __init__(self):
982
        self._lock_mode = None
983
        self._lock_count = 0
984
        self._versioned_dirs = None
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
985
        self._index_dirty = False
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
986
987
    def is_versioned(self, path):
988
        with self.lock_read():
989
            path = path.rstrip('/').encode('utf-8')
0.429.1 by Jelmer Vernooij
Abstract away index access.
990
            (index, subpath) = self._lookup_index(path)
991
            return (subpath in index or self._has_dir(path))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
992
993
    def _has_dir(self, path):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
994
        if not isinstance(path, bytes):
995
            raise TypeError(path)
996
        if path == b"":
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
997
            return True
998
        if self._versioned_dirs is None:
999
            self._load_dirs()
1000
        return path in self._versioned_dirs
1001
1002
    def _load_dirs(self):
0.361.3 by Jelmer Vernooij
Merge trunk,
1003
        if self._lock_mode is None:
1004
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1005
        self._versioned_dirs = set()
0.429.1 by Jelmer Vernooij
Abstract away index access.
1006
        # TODO(jelmer): Browse over all indexes
0.429.11 by Jelmer Vernooij
Merge trunk.
1007
        for p, i in self._recurse_index_entries():
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1008
            self._ensure_versioned_dir(posixpath.dirname(p))
1009
1010
    def _ensure_versioned_dir(self, dirname):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1011
        if not isinstance(dirname, bytes):
1012
            raise TypeError(dirname)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1013
        if dirname in self._versioned_dirs:
1014
            return
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1015
        if dirname != b"":
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1016
            self._ensure_versioned_dir(posixpath.dirname(dirname))
1017
        self._versioned_dirs.add(dirname)
1018
1019
    def path2id(self, path):
1020
        with self.lock_read():
1021
            path = path.rstrip('/')
1022
            if self.is_versioned(path.rstrip('/')):
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
1023
                return self.mapping.generate_file_id(
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1024
                    osutils.safe_unicode(path))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1025
            return None
1026
1027
    def has_id(self, file_id):
1028
        try:
1029
            self.id2path(file_id)
1030
        except errors.NoSuchId:
1031
            return False
1032
        else:
1033
            return True
1034
1035
    def id2path(self, file_id):
1036
        if file_id is None:
1037
            return ''
0.361.3 by Jelmer Vernooij
Merge trunk,
1038
        if type(file_id) is not bytes:
1039
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1040
        with self.lock_read():
1041
            try:
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
1042
                path = self.mapping.parse_file_id(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1043
            except ValueError:
1044
                raise errors.NoSuchId(self, file_id)
1045
            if self.is_versioned(path):
1046
                return path
1047
            raise errors.NoSuchId(self, file_id)
1048
1049
    def _set_root_id(self, file_id):
7206.6.1 by Jelmer Vernooij
Drop file_id from record_iter_changes return value.
1050
        raise errors.UnsupportedOperation(self._set_root_id, self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1051
1052
    def _add(self, files, ids, kinds):
1053
        for (path, file_id, kind) in zip(files, ids, kinds):
1054
            if file_id is not None:
1055
                raise workingtree.SettingFileIdUnsupported()
0.366.1 by Jelmer Vernooij
Fix normalized filename checking in add.
1056
            path, can_access = osutils.normalized_filename(path)
1057
            if not can_access:
1058
                raise errors.InvalidNormalization(path)
6964.2.4 by Jelmer Vernooij
Fix running on python2.
1059
            self._index_add_entry(path, kind)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1060
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
1061
    def _read_submodule_head(self, path):
1062
        raise NotImplementedError(self._read_submodule_head)
1063
0.429.1 by Jelmer Vernooij
Abstract away index access.
1064
    def _lookup_index(self, encoded_path):
1065
        if not isinstance(encoded_path, bytes):
1066
            raise TypeError(encoded_path)
0.429.11 by Jelmer Vernooij
Merge trunk.
1067
        # TODO(jelmer): Look in other indexes
0.429.1 by Jelmer Vernooij
Abstract away index access.
1068
        return self.index, encoded_path
1069
0.429.25 by Jelmer Vernooij
Merge trunk.
1070
    def _index_del_entry(self, index, path):
1071
        del index[path]
1072
        # TODO(jelmer): Keep track of dirty per index
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1073
        self._index_dirty = True
1074
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1075
    def _index_add_entry(self, path, kind, flags=0, reference_revision=None):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1076
        if kind == "directory":
1077
            # Git indexes don't contain directories
1078
            return
1079
        if kind == "file":
1080
            blob = Blob()
1081
            try:
1082
                file, stat_val = self.get_file_with_stat(path)
1083
            except (errors.NoSuchFile, IOError):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1084
                # TODO: Rather than come up with something here, use the old
1085
                # index
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1086
                file = BytesIO()
1087
                stat_val = os.stat_result(
6964.2.1 by Jelmer Vernooij
Initial work to support brz-git on python3.
1088
                    (stat.S_IFREG | 0o644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
7027.4.7 by Jelmer Vernooij
Fix some tests.
1089
            with file:
1090
                blob.set_raw_string(file.read())
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1091
            # Add object to the repository if it didn't exist yet
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1092
            if blob.id not in self.store:
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1093
                self.store.add_object(blob)
1094
            hexsha = blob.id
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1095
        elif kind == "symlink":
1096
            blob = Blob()
1097
            try:
1098
                stat_val = self._lstat(path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1099
            except EnvironmentError:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1100
                # TODO: Rather than come up with something here, use the
1101
                # old index
1102
                stat_val = os.stat_result(
1103
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
1104
            blob.set_raw_string(
1105
                self.get_symlink_target(path).encode("utf-8"))
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1106
            # Add object to the repository if it didn't exist yet
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1107
            if blob.id not in self.store:
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1108
                self.store.add_object(blob)
1109
            hexsha = blob.id
1110
        elif kind == "tree-reference":
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1111
            if reference_revision is not None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1112
                hexsha = self.branch.lookup_bzr_revision_id(
1113
                    reference_revision)[0]
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1114
            else:
1115
                hexsha = self._read_submodule_head(path)
1116
                if hexsha is None:
1117
                    raise errors.NoCommits(path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1118
            try:
1119
                stat_val = self._lstat(path)
1120
            except EnvironmentError:
1121
                stat_val = os.stat_result(
1122
                    (S_IFGITLINK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
1123
            stat_val = os.stat_result((S_IFGITLINK, ) + stat_val[1:])
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1124
        else:
1125
            raise AssertionError("unknown kind '%s'" % kind)
1126
        # Add an entry to the index or update the existing entry
1127
        ensure_normalized_path(path)
1128
        encoded_path = path.encode("utf-8")
1129
        if b'\r' in encoded_path or b'\n' in encoded_path:
1130
            # TODO(jelmer): Why do we need to do this?
1131
            trace.mutter('ignoring path with invalid newline in it: %r', path)
1132
            return
0.429.1 by Jelmer Vernooij
Abstract away index access.
1133
        (index, index_path) = self._lookup_index(encoded_path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1134
        index[index_path] = index_entry_from_stat(stat_val, hexsha, flags)
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1135
        self._index_dirty = True
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1136
        if self._versioned_dirs is not None:
0.429.1 by Jelmer Vernooij
Abstract away index access.
1137
            self._ensure_versioned_dir(index_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1138
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1139
    def _recurse_index_entries(self, index=None, basepath=b""):
0.429.7 by Jelmer Vernooij
Consistent file ids.
1140
        # Iterate over all index entries
1141
        with self.lock_read():
1142
            if index is None:
1143
                index = self.index
6973.12.3 by Jelmer Vernooij
Fixes.
1144
            for path, value in index.items():
0.429.7 by Jelmer Vernooij
Consistent file ids.
1145
                yield (posixpath.join(basepath, path), value)
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1146
                (ctime, mtime, dev, ino, mode, uid, gid, size, sha,
1147
                 flags) = value
0.429.10 by Jelmer Vernooij
use new read_submodule_head from dulwich.
1148
                if S_ISGITLINK(mode):
7143.15.2 by Jelmer Vernooij
Run autopep8.
1149
                    pass  # TODO(jelmer): dive into submodule
0.429.7 by Jelmer Vernooij
Consistent file ids.
1150
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1151
    def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1152
        if yield_parents:
1153
            raise NotImplementedError(self.iter_entries_by_dir)
1154
        with self.lock_read():
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1155
            if specific_files is not None:
1156
                specific_files = set(specific_files)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1157
            else:
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1158
                specific_files = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1159
            root_ie = self._get_dir_ie(u"", None)
1160
            ret = {}
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1161
            if specific_files is None or u"" in specific_files:
7029.4.2 by Jelmer Vernooij
Fix more merge tests.
1162
                ret[(u"", u"")] = root_ie
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1163
            dir_ids = {u"": root_ie.file_id}
0.429.7 by Jelmer Vernooij
Consistent file ids.
1164
            for path, value in self._recurse_index_entries():
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1165
                if self.mapping.is_special_file(path):
1166
                    continue
1167
                path = path.decode("utf-8")
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1168
                if specific_files is not None and path not in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1169
                    continue
1170
                (parent, name) = posixpath.split(path)
1171
                try:
1172
                    file_ie = self._get_file_ie(name, path, value, None)
1173
                except errors.NoSuchFile:
1174
                    continue
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1175
                if yield_parents or specific_files is None:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1176
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(
1177
                            parent, dir_ids):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1178
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
0.429.12 by Jelmer Vernooij
Remove revision.
1179
                file_ie.parent_id = self.path2id(parent)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1180
                ret[(posixpath.dirname(path), path)] = file_ie
7029.4.2 by Jelmer Vernooij
Fix more merge tests.
1181
            return ((path, ie) for ((_, path), ie) in sorted(viewitems(ret)))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1182
0.429.7 by Jelmer Vernooij
Consistent file ids.
1183
    def iter_references(self):
1184
        # TODO(jelmer): Implement a more efficient version of this
1185
        for path, entry in self.iter_entries_by_dir():
1186
            if entry.kind == 'tree-reference':
7350.2.1 by Jelmer Vernooij
Drop file_id return value from Tree.iter_references.
1187
                yield path
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1188
1189
    def _get_dir_ie(self, path, parent_id):
1190
        file_id = self.path2id(path)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1191
        return GitTreeDirectory(file_id,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1192
                                posixpath.basename(path).strip("/"), parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1193
1194
    def _get_file_ie(self, name, path, value, parent_id):
6973.6.2 by Jelmer Vernooij
Fix more tests.
1195
        if not isinstance(name, text_type):
0.361.3 by Jelmer Vernooij
Merge trunk,
1196
            raise TypeError(name)
6973.6.2 by Jelmer Vernooij
Fix more tests.
1197
        if not isinstance(path, text_type):
0.361.3 by Jelmer Vernooij
Merge trunk,
1198
            raise TypeError(path)
1199
        if not isinstance(value, tuple) or len(value) != 10:
1200
            raise TypeError(value)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1201
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
1202
        file_id = self.path2id(path)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1203
        if not isinstance(file_id, bytes):
1204
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1205
        kind = mode_kind(mode)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1206
        ie = entry_factory[kind](file_id, name, parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1207
        if kind == 'symlink':
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1208
            ie.symlink_target = self.get_symlink_target(path)
0.429.7 by Jelmer Vernooij
Consistent file ids.
1209
        elif kind == 'tree-reference':
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1210
            ie.reference_revision = self.get_reference_revision(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1211
        else:
1212
            try:
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1213
                data = self.get_file_text(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1214
            except errors.NoSuchFile:
1215
                data = None
1216
            except IOError as e:
1217
                if e.errno != errno.ENOENT:
1218
                    raise
1219
                data = None
1220
            if data is None:
1221
                data = self.branch.repository._git.object_store[sha].data
1222
            ie.text_sha1 = osutils.sha_string(data)
1223
            ie.text_size = len(data)
1224
            ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1225
        return ie
1226
1227
    def _add_missing_parent_ids(self, path, dir_ids):
1228
        if path in dir_ids:
1229
            return []
1230
        parent = posixpath.dirname(path).strip("/")
1231
        ret = self._add_missing_parent_ids(parent, dir_ids)
1232
        parent_id = dir_ids[parent]
1233
        ie = self._get_dir_ie(path, parent_id)
1234
        dir_ids[path] = ie.file_id
1235
        ret.append((path, ie))
1236
        return ret
1237
1238
    def _comparison_data(self, entry, path):
1239
        if entry is None:
1240
            return None, False, None
1241
        return entry.kind, entry.executable, None
1242
1243
    def _unversion_path(self, path):
0.361.3 by Jelmer Vernooij
Merge trunk,
1244
        if self._lock_mode is None:
1245
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1246
        encoded_path = path.encode("utf-8")
1247
        count = 0
0.429.1 by Jelmer Vernooij
Abstract away index access.
1248
        (index, subpath) = self._lookup_index(encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1249
        try:
0.429.25 by Jelmer Vernooij
Merge trunk.
1250
            self._index_del_entry(index, encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1251
        except KeyError:
1252
            # A directory, perhaps?
0.429.1 by Jelmer Vernooij
Abstract away index access.
1253
            # TODO(jelmer): Deletes that involve submodules?
1254
            for p in list(index):
7143.15.2 by Jelmer Vernooij
Run autopep8.
1255
                if p.startswith(subpath + b"/"):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1256
                    count += 1
0.429.25 by Jelmer Vernooij
Merge trunk.
1257
                    self._index_del_entry(index, p)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1258
        else:
1259
            count = 1
1260
        self._versioned_dirs = None
1261
        return count
1262
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1263
    def unversion(self, paths):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1264
        with self.lock_tree_write():
1265
            for path in paths:
1266
                if self._unversion_path(path) == 0:
1267
                    raise errors.NoSuchFile(path)
1268
            self._versioned_dirs = None
1269
            self.flush()
1270
1271
    def flush(self):
1272
        pass
1273
1274
    def update_basis_by_delta(self, revid, delta):
1275
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
1276
        for (old_path, new_path, file_id, ie) in delta:
0.429.1 by Jelmer Vernooij
Abstract away index access.
1277
            if old_path is not None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1278
                (index, old_subpath) = self._lookup_index(
1279
                    old_path.encode('utf-8'))
0.429.1 by Jelmer Vernooij
Abstract away index access.
1280
                if old_subpath in index:
0.429.25 by Jelmer Vernooij
Merge trunk.
1281
                    self._index_del_entry(index, old_subpath)
0.429.1 by Jelmer Vernooij
Abstract away index access.
1282
                    self._versioned_dirs = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1283
            if new_path is not None and ie.kind != 'directory':
6964.2.4 by Jelmer Vernooij
Fix running on python2.
1284
                self._index_add_entry(new_path, ie.kind)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1285
        self.flush()
1286
        self._set_merges_from_parent_ids([])
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1287
1288
    def move(self, from_paths, to_dir=None, after=None):
1289
        rename_tuples = []
1290
        with self.lock_tree_write():
1291
            to_abs = self.abspath(to_dir)
1292
            if not os.path.isdir(to_abs):
1293
                raise errors.BzrMoveFailedError('', to_dir,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1294
                                                errors.NotADirectory(to_abs))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1295
1296
            for from_rel in from_paths:
1297
                from_tail = os.path.split(from_rel)[-1]
1298
                to_rel = os.path.join(to_dir, from_tail)
1299
                self.rename_one(from_rel, to_rel, after=after)
1300
                rename_tuples.append((from_rel, to_rel))
1301
            self.flush()
1302
            return rename_tuples
1303
1304
    def rename_one(self, from_rel, to_rel, after=None):
1305
        from_path = from_rel.encode("utf-8")
1306
        to_rel, can_access = osutils.normalized_filename(to_rel)
1307
        if not can_access:
1308
            raise errors.InvalidNormalization(to_rel)
1309
        to_path = to_rel.encode("utf-8")
1310
        with self.lock_tree_write():
1311
            if not after:
1312
                # Perhaps it's already moved?
1313
                after = (
1314
                    not self.has_filename(from_rel) and
1315
                    self.has_filename(to_rel) and
1316
                    not self.is_versioned(to_rel))
1317
            if after:
1318
                if not self.has_filename(to_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1319
                    raise errors.BzrMoveFailedError(
1320
                        from_rel, to_rel, errors.NoSuchFile(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1321
                if self.basis_tree().is_versioned(to_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1322
                    raise errors.BzrMoveFailedError(
1323
                        from_rel, to_rel, errors.AlreadyVersionedError(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1324
1325
                kind = self.kind(to_rel)
1326
            else:
1327
                try:
1328
                    to_kind = self.kind(to_rel)
1329
                except errors.NoSuchFile:
1330
                    exc_type = errors.BzrRenameFailedError
1331
                    to_kind = None
1332
                else:
1333
                    exc_type = errors.BzrMoveFailedError
1334
                if self.is_versioned(to_rel):
1335
                    raise exc_type(from_rel, to_rel,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1336
                                   errors.AlreadyVersionedError(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1337
                if not self.has_filename(from_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1338
                    raise errors.BzrMoveFailedError(
1339
                        from_rel, to_rel, errors.NoSuchFile(from_rel))
0.388.1 by Jelmer Vernooij
Don't print error moving to an unversioned directory.
1340
                kind = self.kind(from_rel)
1341
                if not self.is_versioned(from_rel) and kind != 'directory':
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1342
                    raise exc_type(from_rel, to_rel,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1343
                                   errors.NotVersionedError(from_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1344
                if self.has_filename(to_rel):
1345
                    raise errors.RenameFailedFilesExist(
1346
                        from_rel, to_rel, errors.FileExists(to_rel))
1347
1348
                kind = self.kind(from_rel)
1349
0.429.1 by Jelmer Vernooij
Abstract away index access.
1350
            if not after and kind != 'directory':
1351
                (index, from_subpath) = self._lookup_index(from_path)
1352
                if from_subpath not in index:
1353
                    # It's not a file
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1354
                    raise errors.BzrMoveFailedError(
1355
                        from_rel, to_rel,
1356
                        errors.NotVersionedError(path=from_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1357
1358
            if not after:
1359
                try:
1360
                    self._rename_one(from_rel, to_rel)
1361
                except OSError as e:
1362
                    if e.errno == errno.ENOENT:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1363
                        raise errors.BzrMoveFailedError(
1364
                            from_rel, to_rel, errors.NoSuchFile(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1365
                    raise
1366
            if kind != 'directory':
0.429.13 by Jelmer Vernooij
Fix regressions.
1367
                (index, from_index_path) = self._lookup_index(from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1368
                try:
0.429.25 by Jelmer Vernooij
Merge trunk.
1369
                    self._index_del_entry(index, from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1370
                except KeyError:
1371
                    pass
1372
                self._index_add_entry(to_rel, kind)
1373
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1374
                todo = [(p, i) for (p, i) in self._recurse_index_entries()
1375
                        if p.startswith(from_path + b'/')]
0.429.13 by Jelmer Vernooij
Fix regressions.
1376
                for child_path, child_value in todo:
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1377
                    (child_to_index, child_to_index_path) = self._lookup_index(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1378
                        posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
0.429.13 by Jelmer Vernooij
Fix regressions.
1379
                    child_to_index[child_to_index_path] = child_value
0.429.25 by Jelmer Vernooij
Merge trunk.
1380
                    # TODO(jelmer): Mark individual index as dirty
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1381
                    self._index_dirty = True
7143.15.2 by Jelmer Vernooij
Run autopep8.
1382
                    (child_from_index, child_from_index_path) = self._lookup_index(
1383
                        child_path)
1384
                    self._index_del_entry(
1385
                        child_from_index, child_from_index_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1386
1387
            self._versioned_dirs = None
1388
            self.flush()
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1389
1390
    def find_related_paths_across_trees(self, paths, trees=[],
7143.15.2 by Jelmer Vernooij
Run autopep8.
1391
                                        require_versioned=True):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1392
        if paths is None:
1393
            return None
1394
1395
        if require_versioned:
1396
            trees = [self] + (trees if trees is not None else [])
1397
            unversioned = set()
1398
            for p in paths:
1399
                for t in trees:
1400
                    if t.is_versioned(p):
1401
                        break
1402
                else:
1403
                    unversioned.add(p)
1404
            if unversioned:
1405
                raise errors.PathsNotVersionedError(unversioned)
1406
1407
        return filter(self.is_versioned, paths)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
1408
1409
    def path_content_summary(self, path):
1410
        """See Tree.path_content_summary."""
1411
        try:
1412
            stat_result = self._lstat(path)
1413
        except OSError as e:
1414
            if getattr(e, 'errno', None) == errno.ENOENT:
1415
                # no file.
1416
                return ('missing', None, None, None)
1417
            # propagate other errors
1418
            raise
1419
        kind = mode_kind(stat_result.st_mode)
1420
        if kind == 'file':
1421
            return self._file_content_summary(path, stat_result)
1422
        elif kind == 'directory':
1423
            # perhaps it looks like a plain directory, but it's really a
1424
            # reference.
1425
            if self._directory_is_tree_reference(path):
1426
                kind = 'tree-reference'
1427
            return kind, None, None, None
1428
        elif kind == 'symlink':
1429
            target = osutils.readlink(self.abspath(path))
1430
            return ('symlink', None, None, target)
1431
        else:
1432
            return (kind, None, None, None)
1433
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1434
    def kind(self, relpath):
0.429.15 by Jelmer Vernooij
Autodetect tree-reference based on index.
1435
        kind = osutils.file_kind(self.abspath(relpath))
1436
        if kind == 'directory':
1437
            (index, index_path) = self._lookup_index(relpath.encode('utf-8'))
7065.1.1 by Jelmer Vernooij
Properly handle ignored directories in Git.
1438
            if index is None:
1439
                return kind
0.429.15 by Jelmer Vernooij
Autodetect tree-reference based on index.
1440
            try:
1441
                mode = index[index_path].mode
1442
            except KeyError:
1443
                return kind
1444
            else:
1445
                if S_ISGITLINK(mode):
1446
                    return 'tree-reference'
1447
                return 'directory'
1448
        else:
1449
            return kind
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1450
1451
    def _live_entry(self, relpath):
1452
        raise NotImplementedError(self._live_entry)
1453
7350.3.1 by Jelmer Vernooij
Add Tree.get_transform.
1454
    def get_transform(self, pb=None):
1455
        from ..transform import TreeTransform
7350.3.7 by Jelmer Vernooij
Fix pb propagation.
1456
        return TreeTransform(self, pb=pb)
7350.3.1 by Jelmer Vernooij
Add Tree.get_transform.
1457
1458
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1459
1460
class InterIndexGitTree(InterGitTrees):
1461
    """InterTree that works between a Git revision tree and an index."""
1462
1463
    def __init__(self, source, target):
1464
        super(InterIndexGitTree, self).__init__(source, target)
1465
        self._index = target.index
1466
1467
    @classmethod
1468
    def is_compatible(cls, source, target):
1469
        return (isinstance(source, GitRevisionTree) and
1470
                isinstance(target, MutableGitIndexTree))
1471
1472
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1473
                          require_versioned=False, extra_trees=None,
1474
                          want_unversioned=False):
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1475
        trees = [self.source]
1476
        if extra_trees is not None:
1477
            trees.extend(extra_trees)
1478
        if specific_files is not None:
1479
            specific_files = self.target.find_related_paths_across_trees(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1480
                specific_files, trees,
1481
                require_versioned=require_versioned)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1482
        # TODO(jelmer): Restrict to specific_files, for performance reasons.
1483
        with self.lock_read():
1484
            return changes_between_git_tree_and_working_copy(
1485
                self.source.store, self.source.tree,
1486
                self.target, want_unchanged=want_unchanged,
1487
                want_unversioned=want_unversioned)
1488
1489
1490
_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
1491
1492
1493
def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1494
                                              want_unchanged=False,
1495
                                              want_unversioned=False):
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1496
    """Determine the changes between a git tree and a working tree with index.
1497
1498
    """
1499
    extras = set()
1500
    blobs = {}
1501
    # Report dirified directories to commit_tree first, so that they can be
1502
    # replaced with non-empty directories if they have contents.
1503
    dirified = []
7122.7.5 by Jelmer Vernooij
Only trust filesystem for executable bit where supported.
1504
    trust_executable = target._supports_executable()
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1505
    for path, index_entry in target._recurse_index_entries():
1506
        try:
7045.3.2 by Jelmer Vernooij
Fix tests.
1507
            live_entry = target._live_entry(path)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1508
        except EnvironmentError as e:
1509
            if e.errno == errno.ENOENT:
1510
                # Entry was removed; keep it listed, but mark it as gone.
1511
                blobs[path] = (ZERO_SHA, 0)
1512
            elif e.errno == errno.EISDIR:
7296.1.2 by Jelmer Vernooij
Cope with API change in Dulwich.
1513
                # Backwards compatibility with Dulwich < 0.19.12;
1514
                # newer versions of Dulwich return either an entry for the
1515
                # submodule or None for directories.
7131.13.1 by Jelmer Vernooij
Don't show a delta for unchanged submodules.
1516
                if S_ISGITLINK(index_entry.mode):
1517
                    blobs[path] = (index_entry.sha, index_entry.mode)
1518
                else:
1519
                    # Entry was turned into a directory
1520
                    dirified.append((path, Tree().id, stat.S_IFDIR))
1521
                    store.add_object(Tree())
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1522
            else:
1523
                raise
1524
        else:
7296.1.2 by Jelmer Vernooij
Cope with API change in Dulwich.
1525
            if live_entry is None:
1526
                # Entry was turned into a directory
1527
                dirified.append((path, Tree().id, stat.S_IFDIR))
1528
                store.add_object(Tree())
1529
            else:
7122.6.8 by Jelmer Vernooij
Merge trunk.
1530
                mode = live_entry.mode
1531
                if not trust_executable:
1532
                    if mode_is_executable(index_entry.mode):
1533
                        mode |= 0o111
1534
                    else:
1535
                        mode &= ~0o111
7296.1.2 by Jelmer Vernooij
Cope with API change in Dulwich.
1536
                blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1537
    if want_unversioned:
1538
        for e in target.extras():
1539
            st = target._lstat(e)
1540
            try:
1541
                np, accessible = osutils.normalized_filename(e)
1542
            except UnicodeDecodeError:
1543
                raise errors.BadFilenameEncoding(
1544
                    e, osutils._fs_enc)
1545
            if stat.S_ISDIR(st.st_mode):
1546
                blob = Tree()
1547
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1548
                blob = blob_from_path_and_stat(
1549
                    target.abspath(e).encode(osutils._fs_enc), st)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1550
            store.add_object(blob)
1551
            np = np.encode('utf-8')
1552
            blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1553
            extras.add(np)
7143.15.2 by Jelmer Vernooij
Run autopep8.
1554
    to_tree_sha = commit_tree(
1555
        store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1556
    return store.tree_changes(
1557
        from_tree_sha, to_tree_sha, include_trees=True,
1558
        want_unchanged=want_unchanged, change_type_same=True), extras