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