/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,
729
                                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()
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
738
    ret = delta.TreeDelta()
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
739
    added = []
7467.4.1 by Jelmer Vernooij
Support Git rename tracking.
740
    for (change_type, old, new) in changes:
741
        (oldpath, oldmode, oldsha) = old
742
        (newpath, newmode, newsha) = new
7018.3.2 by Jelmer Vernooij
Fix some git tests.
743
        if newpath == b'' and not include_root:
0.287.5 by Jelmer Vernooij
Fix root handling.
744
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
745
        if oldpath is not None:
746
            oldpath_decoded = oldpath.decode('utf-8')
747
        else:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
748
            oldpath_decoded = None
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
749
        if newpath is not None:
750
            newpath_decoded = newpath.decode('utf-8')
7027.5.2 by Jelmer Vernooij
Fix some more git tests.
751
        else:
752
            newpath_decoded = None
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
753
        if not (specific_files is None or
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
754
                (oldpath is not None and
755
                    osutils.is_inside_or_parent_of_any(
756
                        specific_files, oldpath_decoded)) or
757
                (newpath is not None and
758
                    osutils.is_inside_or_parent_of_any(
759
                        specific_files, newpath_decoded))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
760
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
761
762
        if oldpath_decoded is None:
7358.11.6 by Jelmer Vernooij
merge trunk.
763
            fileid = new_mapping.generate_file_id(newpath_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
764
            oldexe = None
765
            oldkind = None
766
            oldname = None
767
            oldparent = None
768
            oldversioned = False
769
        else:
770
            oldversioned = True
771
            if oldmode:
772
                oldexe = mode_is_executable(oldmode)
773
                oldkind = mode_kind(oldmode)
774
            else:
775
                oldexe = False
776
                oldkind = None
777
            if oldpath_decoded == u'':
778
                oldparent = None
779
                oldname = u''
780
            else:
781
                (oldparentpath, oldname) = osutils.split(oldpath_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
782
                oldparent = old_mapping.generate_file_id(oldparentpath)
783
            fileid = old_mapping.generate_file_id(oldpath_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
784
        if newpath_decoded is None:
785
            newexe = None
786
            newkind = None
787
            newname = None
788
            newparent = None
789
            newversioned = False
790
        else:
791
            newversioned = (newpath_decoded not in target_extras)
792
            if newmode:
793
                newexe = mode_is_executable(newmode)
794
                newkind = mode_kind(newmode)
795
            else:
796
                newexe = False
797
                newkind = None
798
            if newpath_decoded == u'':
799
                newparent = None
800
                newname = u''
801
            else:
802
                newparentpath, newname = osutils.split(newpath_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
803
                newparent = new_mapping.generate_file_id(newparentpath)
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
804
        if old_mapping.is_special_file(oldpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
805
            oldpath = None
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
806
        if new_mapping.is_special_file(newpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
807
            newpath = None
808
        if oldpath is None and newpath is None:
809
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
810
        change = _mod_tree.TreeChange(
811
            fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
812
            (oldversioned, newversioned),
813
            (oldparent, newparent), (oldname, newname),
7467.4.1 by Jelmer Vernooij
Support Git rename tracking.
814
            (oldkind, newkind), (oldexe, newexe),
7467.4.2 by Jelmer Vernooij
Add some tests.
815
            copied=(change_type == 'copy'))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
816
        if oldpath is None:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
817
            added.append((newpath, newkind))
6977.1.2 by Jelmer Vernooij
Deal with missing files properly in 'bzr st'.
818
        elif newpath is None or newmode == 0:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
819
            ret.removed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
820
        elif oldpath != newpath:
7467.4.1 by Jelmer Vernooij
Support Git rename tracking.
821
            if change_type == 'copy':
822
                ret.copied.append(change)
823
            else:
824
                ret.renamed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
825
        elif mode_kind(oldmode) != mode_kind(newmode):
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
826
            ret.kind_changed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
827
        elif oldsha != newsha or oldmode != newmode:
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
828
            if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
829
                continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
830
            ret.modified.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
831
        else:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
832
            ret.unchanged.append(change)
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
833
7211.10.7 by Jelmer Vernooij
Fix on python 3.
834
    implicit_dirs = {b''}
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
835
    for path, kind in added:
7211.10.7 by Jelmer Vernooij
Fix on python 3.
836
        if kind == 'directory' or path in target_extras:
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
837
            continue
838
        implicit_dirs.update(osutils.parent_directories(path))
839
840
    for path, kind in added:
7211.10.5 by Jelmer Vernooij
Fix handling of directories.
841
        if kind == 'directory' and path not in implicit_dirs:
842
            continue
7211.10.7 by Jelmer Vernooij
Fix on python 3.
843
        path_decoded = osutils.normalized_filename(path)[0]
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
844
        parent_path, basename = osutils.split(path_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
845
        parent_id = new_mapping.generate_file_id(parent_path)
7211.10.5 by Jelmer Vernooij
Fix handling of directories.
846
        if path in target_extras:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
847
            ret.unversioned.append(_mod_tree.TreeChange(
848
                None, (None, path_decoded),
849
                True, (False, False), (None, parent_id),
850
                (None, basename), (None, kind), (None, False)))
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
851
        else:
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
852
            file_id = new_mapping.generate_file_id(path_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
853
            ret.added.append(
854
                _mod_tree.TreeChange(
855
                    file_id, (None, path_decoded), True,
856
                    (False, True),
857
                    (None, parent_id),
858
                    (None, basename), (None, kind), (None, False)))
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
859
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
860
    return ret
861
862
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
863
def changes_from_git_changes(changes, mapping, specific_files=None,
864
                             include_unchanged=False, target_extras=None):
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
865
    """Create a iter_changes-like generator from a git stream.
0.200.959 by Jelmer Vernooij
Improve docstrings.
866
867
    source and target are iterators over tuples with:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
868
        (filename, sha, mode)
869
    """
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
870
    if target_extras is None:
871
        target_extras = set()
7467.4.2 by Jelmer Vernooij
Add some tests.
872
    for (change_type, old, new) in changes:
873
        (oldpath, oldmode, oldsha) = old
874
        (newpath, newmode, newsha) = new
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
875
        if oldpath is not None:
876
            oldpath_decoded = oldpath.decode('utf-8')
877
        else:
878
            oldpath_decoded = None
879
        if newpath is not None:
880
            newpath_decoded = newpath.decode('utf-8')
881
        else:
882
            newpath_decoded = None
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
883
        if not (specific_files is None or
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
884
                (oldpath_decoded is not None and
885
                    osutils.is_inside_or_parent_of_any(
886
                        specific_files, oldpath_decoded)) or
887
                (newpath_decoded is not None and
888
                    osutils.is_inside_or_parent_of_any(
889
                        specific_files, newpath_decoded))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
890
            continue
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
891
        if oldpath is not None and mapping.is_special_file(oldpath):
892
            continue
893
        if newpath is not None and mapping.is_special_file(newpath):
0.200.1328 by Jelmer Vernooij
More test fixes.
894
            continue
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
895
        if oldpath_decoded is None:
896
            fileid = mapping.generate_file_id(newpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
897
            oldexe = None
898
            oldkind = None
899
            oldname = None
900
            oldparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
901
            oldversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
902
        else:
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
903
            oldversioned = True
0.391.8 by Jelmer Vernooij
Allow missing items in old tree.
904
            if oldmode:
905
                oldexe = mode_is_executable(oldmode)
906
                oldkind = mode_kind(oldmode)
907
            else:
908
                oldexe = False
909
                oldkind = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
910
            if oldpath_decoded == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
911
                oldparent = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
912
                oldname = u''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
913
            else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
914
                (oldparentpath, oldname) = osutils.split(oldpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
915
                oldparent = mapping.generate_file_id(oldparentpath)
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
916
            fileid = mapping.generate_file_id(oldpath_decoded)
917
        if newpath_decoded is None:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
918
            newexe = None
919
            newkind = None
920
            newname = None
921
            newparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
922
            newversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
923
        else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
924
            newversioned = (newpath_decoded not in target_extras)
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
925
            if newmode:
0.200.1576 by Jelmer Vernooij
Merge a bunch of fixes from store-roundtrip-info.
926
                newexe = mode_is_executable(newmode)
927
                newkind = mode_kind(newmode)
928
            else:
929
                newexe = False
930
                newkind = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
931
            if newpath_decoded == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
932
                newparent = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
933
                newname = u''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
934
            else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
935
                newparentpath, newname = osutils.split(newpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
936
                newparent = mapping.generate_file_id(newparentpath)
0.357.3 by Jelmer Vernooij
More remove fixes.
937
        if (not include_unchanged and
938
            oldkind == 'directory' and newkind == 'directory' and
7143.15.2 by Jelmer Vernooij
Run autopep8.
939
                oldpath_decoded == newpath_decoded):
0.357.3 by Jelmer Vernooij
More remove fixes.
940
            continue
7322.1.2 by Jelmer Vernooij
Return TreeChange objects.
941
        yield _mod_tree.TreeChange(
942
            fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
943
            (oldversioned, newversioned),
944
            (oldparent, newparent), (oldname, newname),
7467.4.2 by Jelmer Vernooij
Add some tests.
945
            (oldkind, newkind), (oldexe, newexe),
946
            copied=(change_type == 'copy'))
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
947
948
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
949
class InterGitTrees(_mod_tree.InterTree):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
950
    """InterTree that works between two git trees."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
951
0.200.659 by Jelmer Vernooij
Prevent tests using InterGitRevisionTrees.
952
    _matching_from_tree_format = None
953
    _matching_to_tree_format = None
954
    _test_mutable_trees_to_test_trees = None
955
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
956
    @classmethod
957
    def is_compatible(cls, source, target):
0.200.959 by Jelmer Vernooij
Improve docstrings.
958
        return (isinstance(source, GitRevisionTree) and
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
959
                isinstance(target, GitRevisionTree))
960
961
    def compare(self, want_unchanged=False, specific_files=None,
962
                extra_trees=None, require_versioned=False, include_root=False,
963
                want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
964
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
965
            changes, target_extras = self._iter_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
966
                want_unchanged=want_unchanged,
967
                require_versioned=require_versioned,
968
                specific_files=specific_files,
969
                extra_trees=extra_trees,
970
                want_unversioned=want_unversioned)
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
971
            return tree_delta_from_git_changes(
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
972
                changes, (self.source.mapping, self.target.mapping),
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
973
                specific_files=specific_files,
974
                include_root=include_root, target_extras=target_extras)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
975
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
976
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
977
                     pb=None, extra_trees=[], require_versioned=True,
978
                     want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
979
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
980
            changes, target_extras = self._iter_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
981
                want_unchanged=include_unchanged,
982
                require_versioned=require_versioned,
983
                specific_files=specific_files,
984
                extra_trees=extra_trees,
985
                want_unversioned=want_unversioned)
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
986
            return changes_from_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
987
                changes, self.target.mapping,
988
                specific_files=specific_files,
989
                include_unchanged=include_unchanged,
990
                target_extras=target_extras)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
991
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
992
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
993
                          require_versioned=False, extra_trees=None,
994
                          want_unversioned=False):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
995
        raise NotImplementedError(self._iter_git_changes)
996
7357.1.6 by Jelmer Vernooij
Add find_source_path.
997
    def find_target_path(self, path, recurse='none'):
998
        ret = self.find_target_paths([path], recurse=recurse)
999
        return ret[path]
1000
1001
    def find_source_path(self, path, recurse='none'):
1002
        ret = self.find_source_paths([path], recurse=recurse)
1003
        return ret[path]
1004
1005
    def find_target_paths(self, paths, recurse='none'):
1006
        paths = set(paths)
1007
        ret = {}
1008
        changes = self._iter_git_changes(specific_files=paths)[0]
7467.4.4 by Jelmer Vernooij
Merge trunk.
1009
        for (change_type, old, new) in changes:
1010
            oldpath = old[0]
1011
            newpath = new[0]
7357.1.6 by Jelmer Vernooij
Add find_source_path.
1012
            if oldpath in paths:
1013
                ret[oldpath] = newpath
7357.1.7 by Jelmer Vernooij
Add tests.
1014
        for path in paths:
1015
            if path not in ret:
1016
                if self.source.has_filename(path):
1017
                    if self.target.has_filename(path):
1018
                        ret[path] = path
1019
                    else:
1020
                        ret[path] = None
1021
                else:
1022
                    raise errors.NoSuchFile(path)
7357.1.6 by Jelmer Vernooij
Add find_source_path.
1023
        return ret
1024
1025
    def find_source_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 newpath in paths:
1033
                ret[newpath] = oldpath
7357.1.7 by Jelmer Vernooij
Add tests.
1034
        for path in paths:
1035
            if path not in ret:
1036
                if self.target.has_filename(path):
1037
                    if self.source.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
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1045
1046
class InterGitRevisionTrees(InterGitTrees):
1047
    """InterTree that works between two git revision trees."""
1048
1049
    _matching_from_tree_format = None
1050
    _matching_to_tree_format = None
1051
    _test_mutable_trees_to_test_trees = None
1052
1053
    @classmethod
1054
    def is_compatible(cls, source, target):
1055
        return (isinstance(source, GitRevisionTree) and
1056
                isinstance(target, GitRevisionTree))
1057
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1058
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1059
                          require_versioned=True, extra_trees=None,
1060
                          want_unversioned=False):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1061
        trees = [self.source]
1062
        if extra_trees is not None:
1063
            trees.extend(extra_trees)
1064
        if specific_files is not None:
1065
            specific_files = self.target.find_related_paths_across_trees(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1066
                specific_files, trees,
1067
                require_versioned=require_versioned)
0.357.1 by Jelmer Vernooij
Fix some remove tests.
1068
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1069
        if (self.source._repository._git.object_store !=
1070
                self.target._repository._git.object_store):
1071
            store = OverlayObjectStore(
1072
                [self.source._repository._git.object_store,
1073
                    self.target._repository._git.object_store])
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
1074
        else:
1075
            store = self.source._repository._git.object_store
7467.4.11 by Jelmer Vernooij
Fix another test.
1076
        rename_detector = RenameDetector(store)
7467.4.1 by Jelmer Vernooij
Support Git rename tracking.
1077
        return tree_changes(
1078
            store, self.source.tree, self.target.tree, want_unchanged=want_unchanged,
1079
            include_trees=True, change_type_same=True, rename_detector=rename_detector), set()
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1080
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
1081
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1082
_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1083
1084
1085
class MutableGitIndexTree(mutabletree.MutableTree):
1086
1087
    def __init__(self):
1088
        self._lock_mode = None
1089
        self._lock_count = 0
1090
        self._versioned_dirs = None
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1091
        self._index_dirty = False
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1092
        self._submodules = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1093
1094
    def is_versioned(self, path):
1095
        with self.lock_read():
1096
            path = path.rstrip('/').encode('utf-8')
0.429.1 by Jelmer Vernooij
Abstract away index access.
1097
            (index, subpath) = self._lookup_index(path)
1098
            return (subpath in index or self._has_dir(path))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1099
1100
    def _has_dir(self, path):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1101
        if not isinstance(path, bytes):
1102
            raise TypeError(path)
1103
        if path == b"":
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1104
            return True
1105
        if self._versioned_dirs is None:
1106
            self._load_dirs()
1107
        return path in self._versioned_dirs
1108
1109
    def _load_dirs(self):
0.361.3 by Jelmer Vernooij
Merge trunk,
1110
        if self._lock_mode is None:
1111
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1112
        self._versioned_dirs = set()
0.429.11 by Jelmer Vernooij
Merge trunk.
1113
        for p, i in self._recurse_index_entries():
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1114
            self._ensure_versioned_dir(posixpath.dirname(p))
1115
1116
    def _ensure_versioned_dir(self, dirname):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1117
        if not isinstance(dirname, bytes):
1118
            raise TypeError(dirname)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1119
        if dirname in self._versioned_dirs:
1120
            return
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1121
        if dirname != b"":
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1122
            self._ensure_versioned_dir(posixpath.dirname(dirname))
1123
        self._versioned_dirs.add(dirname)
1124
1125
    def path2id(self, path):
1126
        with self.lock_read():
1127
            path = path.rstrip('/')
1128
            if self.is_versioned(path.rstrip('/')):
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
1129
                return self.mapping.generate_file_id(
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1130
                    osutils.safe_unicode(path))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1131
            return None
1132
7450.1.1 by Jelmer Vernooij
Support recurse argument to id2path.
1133
    def id2path(self, file_id, recurse='down'):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1134
        if file_id is None:
1135
            return ''
0.361.3 by Jelmer Vernooij
Merge trunk,
1136
        if type(file_id) is not bytes:
1137
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1138
        with self.lock_read():
1139
            try:
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
1140
                path = self.mapping.parse_file_id(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1141
            except ValueError:
1142
                raise errors.NoSuchId(self, file_id)
1143
            if self.is_versioned(path):
1144
                return path
1145
            raise errors.NoSuchId(self, file_id)
1146
1147
    def _set_root_id(self, file_id):
7206.6.1 by Jelmer Vernooij
Drop file_id from record_iter_changes return value.
1148
        raise errors.UnsupportedOperation(self._set_root_id, self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1149
1150
    def _add(self, files, ids, kinds):
1151
        for (path, file_id, kind) in zip(files, ids, kinds):
1152
            if file_id is not None:
1153
                raise workingtree.SettingFileIdUnsupported()
0.366.1 by Jelmer Vernooij
Fix normalized filename checking in add.
1154
            path, can_access = osutils.normalized_filename(path)
1155
            if not can_access:
1156
                raise errors.InvalidNormalization(path)
6964.2.4 by Jelmer Vernooij
Fix running on python2.
1157
            self._index_add_entry(path, kind)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1158
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
1159
    def _read_submodule_head(self, path):
1160
        raise NotImplementedError(self._read_submodule_head)
1161
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1162
    def _submodule_info(self):
1163
        if self._submodules is None:
1164
            try:
1165
                with self.get_file('.gitmodules') as f:
1166
                    config = GitConfigFile.from_file(f)
1167
                    self._submodules = {
1168
                        path: (url, section)
1169
                        for path, url, section in parse_submodules(config)}
1170
            except errors.NoSuchFile:
1171
                self._submodules = {}
1172
        return self._submodules
1173
0.429.1 by Jelmer Vernooij
Abstract away index access.
1174
    def _lookup_index(self, encoded_path):
1175
        if not isinstance(encoded_path, bytes):
1176
            raise TypeError(encoded_path)
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1177
        # Common case:
1178
        if encoded_path in self.index:
1179
            return self.index, encoded_path
1180
        # TODO(jelmer): Perhaps have a cache with paths under which some
1181
        # submodules exist?
1182
        index = self.index
1183
        remaining_path = encoded_path
1184
        while True:
1185
            parts = remaining_path.split(b'/')
1186
            for i in range(1, len(parts)):
1187
                basepath = b'/'.join(parts[:i])
1188
                try:
1189
                    (ctime, mtime, dev, ino, mode, uid, gid, size, sha,
1190
                     flags) = index[basepath]
1191
                except KeyError:
1192
                    continue
1193
                else:
1194
                    if S_ISGITLINK(mode):
1195
                        index = self._get_submodule_index(basepath)
1196
                        remaining_path = b'/'.join(parts[i:])
1197
                        break
1198
                    else:
1199
                        return index, remaining_path
1200
            else:
1201
                return index, remaining_path
1202
        return index, remaining_path
0.429.1 by Jelmer Vernooij
Abstract away index access.
1203
0.429.25 by Jelmer Vernooij
Merge trunk.
1204
    def _index_del_entry(self, index, path):
1205
        del index[path]
1206
        # TODO(jelmer): Keep track of dirty per index
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1207
        self._index_dirty = True
1208
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1209
    def _index_add_entry(self, path, kind, flags=0, reference_revision=None):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1210
        if kind == "directory":
1211
            # Git indexes don't contain directories
1212
            return
1213
        if kind == "file":
1214
            blob = Blob()
1215
            try:
1216
                file, stat_val = self.get_file_with_stat(path)
1217
            except (errors.NoSuchFile, IOError):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1218
                # TODO: Rather than come up with something here, use the old
1219
                # index
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1220
                file = BytesIO()
1221
                stat_val = os.stat_result(
6964.2.1 by Jelmer Vernooij
Initial work to support brz-git on python3.
1222
                    (stat.S_IFREG | 0o644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
7027.4.7 by Jelmer Vernooij
Fix some tests.
1223
            with file:
1224
                blob.set_raw_string(file.read())
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1225
            # Add object to the repository if it didn't exist yet
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1226
            if blob.id not in self.store:
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1227
                self.store.add_object(blob)
1228
            hexsha = blob.id
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1229
        elif kind == "symlink":
1230
            blob = Blob()
1231
            try:
1232
                stat_val = self._lstat(path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1233
            except EnvironmentError:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1234
                # TODO: Rather than come up with something here, use the
1235
                # old index
1236
                stat_val = os.stat_result(
1237
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
1238
            blob.set_raw_string(
1239
                self.get_symlink_target(path).encode("utf-8"))
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1240
            # Add object to the repository if it didn't exist yet
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1241
            if blob.id not in self.store:
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1242
                self.store.add_object(blob)
1243
            hexsha = blob.id
1244
        elif kind == "tree-reference":
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1245
            if reference_revision is not None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1246
                hexsha = self.branch.lookup_bzr_revision_id(
1247
                    reference_revision)[0]
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1248
            else:
1249
                hexsha = self._read_submodule_head(path)
1250
                if hexsha is None:
1251
                    raise errors.NoCommits(path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1252
            try:
1253
                stat_val = self._lstat(path)
1254
            except EnvironmentError:
1255
                stat_val = os.stat_result(
1256
                    (S_IFGITLINK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
1257
            stat_val = os.stat_result((S_IFGITLINK, ) + stat_val[1:])
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1258
        else:
1259
            raise AssertionError("unknown kind '%s'" % kind)
1260
        # Add an entry to the index or update the existing entry
1261
        ensure_normalized_path(path)
1262
        encoded_path = path.encode("utf-8")
1263
        if b'\r' in encoded_path or b'\n' in encoded_path:
1264
            # TODO(jelmer): Why do we need to do this?
1265
            trace.mutter('ignoring path with invalid newline in it: %r', path)
1266
            return
0.429.1 by Jelmer Vernooij
Abstract away index access.
1267
        (index, index_path) = self._lookup_index(encoded_path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1268
        index[index_path] = index_entry_from_stat(stat_val, hexsha, flags)
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1269
        self._index_dirty = True
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1270
        if self._versioned_dirs is not None:
0.429.1 by Jelmer Vernooij
Abstract away index access.
1271
            self._ensure_versioned_dir(index_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1272
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1273
    def _recurse_index_entries(self, index=None, basepath=b"",
7404.2.3 by Jelmer Vernooij
s/follow_tree_references/recurse_nested/g
1274
                               recurse_nested=False):
0.429.7 by Jelmer Vernooij
Consistent file ids.
1275
        # Iterate over all index entries
1276
        with self.lock_read():
1277
            if index is None:
1278
                index = self.index
6973.12.3 by Jelmer Vernooij
Fixes.
1279
            for path, value in index.items():
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1280
                (ctime, mtime, dev, ino, mode, uid, gid, size, sha,
1281
                 flags) = value
7404.2.3 by Jelmer Vernooij
s/follow_tree_references/recurse_nested/g
1282
                if S_ISGITLINK(mode) and recurse_nested:
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1283
                    subindex = self._get_submodule_index(path)
1284
                    for entry in self._recurse_index_entries(
1285
                            index=subindex, basepath=path,
7404.2.3 by Jelmer Vernooij
s/follow_tree_references/recurse_nested/g
1286
                            recurse_nested=recurse_nested):
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1287
                        yield entry
1288
                else:
1289
                    yield (posixpath.join(basepath, path), value)
0.429.7 by Jelmer Vernooij
Consistent file ids.
1290
7404.3.1 by Jelmer Vernooij
Add follow_tree_references argument to Tree.iter_entries_by_dir.
1291
    def iter_entries_by_dir(self, specific_files=None,
7404.3.2 by Jelmer Vernooij
Merge rename of flag to recurse_nested.
1292
                            recurse_nested=False):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1293
        with self.lock_read():
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1294
            if specific_files is not None:
1295
                specific_files = set(specific_files)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1296
            else:
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1297
                specific_files = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1298
            root_ie = self._get_dir_ie(u"", None)
1299
            ret = {}
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1300
            if specific_files is None or u"" in specific_files:
7029.4.2 by Jelmer Vernooij
Fix more merge tests.
1301
                ret[(u"", u"")] = root_ie
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1302
            dir_ids = {u"": root_ie.file_id}
7404.3.1 by Jelmer Vernooij
Add follow_tree_references argument to Tree.iter_entries_by_dir.
1303
            for path, value in self._recurse_index_entries(
7404.3.2 by Jelmer Vernooij
Merge rename of flag to recurse_nested.
1304
                    recurse_nested=recurse_nested):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1305
                if self.mapping.is_special_file(path):
1306
                    continue
1307
                path = path.decode("utf-8")
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1308
                if specific_files is not None and path not in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1309
                    continue
1310
                (parent, name) = posixpath.split(path)
1311
                try:
1312
                    file_ie = self._get_file_ie(name, path, value, None)
1313
                except errors.NoSuchFile:
1314
                    continue
7397.2.3 by Jelmer Vernooij
Fix passing directories in specific_files in GitWorkingTree.
1315
                if specific_files is None:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1316
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(
1317
                            parent, dir_ids):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1318
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
0.429.12 by Jelmer Vernooij
Remove revision.
1319
                file_ie.parent_id = self.path2id(parent)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1320
                ret[(posixpath.dirname(path), path)] = file_ie
7397.2.3 by Jelmer Vernooij
Fix passing directories in specific_files in GitWorkingTree.
1321
            # Special casing for directories
1322
            if specific_files:
1323
                for path in specific_files:
1324
                    key = (posixpath.dirname(path), path)
1325
                    if key not in ret and self.is_versioned(path):
1326
                        ret[key] = self._get_dir_ie(path, self.path2id(key[0]))
7029.4.2 by Jelmer Vernooij
Fix more merge tests.
1327
            return ((path, ie) for ((_, path), ie) in sorted(viewitems(ret)))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1328
0.429.7 by Jelmer Vernooij
Consistent file ids.
1329
    def iter_references(self):
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1330
        if self.supports_tree_reference():
1331
            # TODO(jelmer): Implement a more efficient version of this
1332
            for path, entry in self.iter_entries_by_dir():
1333
                if entry.kind == 'tree-reference':
1334
                    yield path
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1335
1336
    def _get_dir_ie(self, path, parent_id):
1337
        file_id = self.path2id(path)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1338
        return GitTreeDirectory(file_id,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1339
                                posixpath.basename(path).strip("/"), parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1340
1341
    def _get_file_ie(self, name, path, value, parent_id):
6973.6.2 by Jelmer Vernooij
Fix more tests.
1342
        if not isinstance(name, text_type):
0.361.3 by Jelmer Vernooij
Merge trunk,
1343
            raise TypeError(name)
6973.6.2 by Jelmer Vernooij
Fix more tests.
1344
        if not isinstance(path, text_type):
0.361.3 by Jelmer Vernooij
Merge trunk,
1345
            raise TypeError(path)
1346
        if not isinstance(value, tuple) or len(value) != 10:
1347
            raise TypeError(value)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1348
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
1349
        file_id = self.path2id(path)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1350
        if not isinstance(file_id, bytes):
1351
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1352
        kind = mode_kind(mode)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1353
        ie = entry_factory[kind](file_id, name, parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1354
        if kind == 'symlink':
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1355
            ie.symlink_target = self.get_symlink_target(path)
0.429.7 by Jelmer Vernooij
Consistent file ids.
1356
        elif kind == 'tree-reference':
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1357
            ie.reference_revision = self.get_reference_revision(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1358
        else:
1359
            try:
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1360
                data = self.get_file_text(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1361
            except errors.NoSuchFile:
1362
                data = None
1363
            except IOError as e:
1364
                if e.errno != errno.ENOENT:
1365
                    raise
1366
                data = None
1367
            if data is None:
1368
                data = self.branch.repository._git.object_store[sha].data
1369
            ie.text_sha1 = osutils.sha_string(data)
1370
            ie.text_size = len(data)
1371
            ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1372
        return ie
1373
1374
    def _add_missing_parent_ids(self, path, dir_ids):
1375
        if path in dir_ids:
1376
            return []
1377
        parent = posixpath.dirname(path).strip("/")
1378
        ret = self._add_missing_parent_ids(parent, dir_ids)
1379
        parent_id = dir_ids[parent]
1380
        ie = self._get_dir_ie(path, parent_id)
1381
        dir_ids[path] = ie.file_id
1382
        ret.append((path, ie))
1383
        return ret
1384
1385
    def _comparison_data(self, entry, path):
1386
        if entry is None:
1387
            return None, False, None
1388
        return entry.kind, entry.executable, None
1389
1390
    def _unversion_path(self, path):
0.361.3 by Jelmer Vernooij
Merge trunk,
1391
        if self._lock_mode is None:
1392
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1393
        encoded_path = path.encode("utf-8")
1394
        count = 0
0.429.1 by Jelmer Vernooij
Abstract away index access.
1395
        (index, subpath) = self._lookup_index(encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1396
        try:
0.429.25 by Jelmer Vernooij
Merge trunk.
1397
            self._index_del_entry(index, encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1398
        except KeyError:
1399
            # A directory, perhaps?
0.429.1 by Jelmer Vernooij
Abstract away index access.
1400
            # TODO(jelmer): Deletes that involve submodules?
1401
            for p in list(index):
7143.15.2 by Jelmer Vernooij
Run autopep8.
1402
                if p.startswith(subpath + b"/"):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1403
                    count += 1
0.429.25 by Jelmer Vernooij
Merge trunk.
1404
                    self._index_del_entry(index, p)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1405
        else:
1406
            count = 1
1407
        self._versioned_dirs = None
1408
        return count
1409
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1410
    def unversion(self, paths):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1411
        with self.lock_tree_write():
1412
            for path in paths:
1413
                if self._unversion_path(path) == 0:
1414
                    raise errors.NoSuchFile(path)
1415
            self._versioned_dirs = None
1416
            self.flush()
1417
1418
    def flush(self):
1419
        pass
1420
1421
    def update_basis_by_delta(self, revid, delta):
1422
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
1423
        for (old_path, new_path, file_id, ie) in delta:
0.429.1 by Jelmer Vernooij
Abstract away index access.
1424
            if old_path is not None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1425
                (index, old_subpath) = self._lookup_index(
1426
                    old_path.encode('utf-8'))
0.429.1 by Jelmer Vernooij
Abstract away index access.
1427
                if old_subpath in index:
0.429.25 by Jelmer Vernooij
Merge trunk.
1428
                    self._index_del_entry(index, old_subpath)
0.429.1 by Jelmer Vernooij
Abstract away index access.
1429
                    self._versioned_dirs = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1430
            if new_path is not None and ie.kind != 'directory':
6964.2.4 by Jelmer Vernooij
Fix running on python2.
1431
                self._index_add_entry(new_path, ie.kind)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1432
        self.flush()
1433
        self._set_merges_from_parent_ids([])
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1434
1435
    def move(self, from_paths, to_dir=None, after=None):
1436
        rename_tuples = []
1437
        with self.lock_tree_write():
1438
            to_abs = self.abspath(to_dir)
1439
            if not os.path.isdir(to_abs):
1440
                raise errors.BzrMoveFailedError('', to_dir,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1441
                                                errors.NotADirectory(to_abs))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1442
1443
            for from_rel in from_paths:
1444
                from_tail = os.path.split(from_rel)[-1]
1445
                to_rel = os.path.join(to_dir, from_tail)
1446
                self.rename_one(from_rel, to_rel, after=after)
1447
                rename_tuples.append((from_rel, to_rel))
1448
            self.flush()
1449
            return rename_tuples
1450
1451
    def rename_one(self, from_rel, to_rel, after=None):
1452
        from_path = from_rel.encode("utf-8")
1453
        to_rel, can_access = osutils.normalized_filename(to_rel)
1454
        if not can_access:
1455
            raise errors.InvalidNormalization(to_rel)
1456
        to_path = to_rel.encode("utf-8")
1457
        with self.lock_tree_write():
1458
            if not after:
1459
                # Perhaps it's already moved?
1460
                after = (
1461
                    not self.has_filename(from_rel) and
1462
                    self.has_filename(to_rel) and
1463
                    not self.is_versioned(to_rel))
1464
            if after:
1465
                if not self.has_filename(to_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1466
                    raise errors.BzrMoveFailedError(
1467
                        from_rel, to_rel, errors.NoSuchFile(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1468
                if self.basis_tree().is_versioned(to_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1469
                    raise errors.BzrMoveFailedError(
1470
                        from_rel, to_rel, errors.AlreadyVersionedError(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1471
1472
                kind = self.kind(to_rel)
1473
            else:
1474
                try:
1475
                    to_kind = self.kind(to_rel)
1476
                except errors.NoSuchFile:
1477
                    exc_type = errors.BzrRenameFailedError
1478
                    to_kind = None
1479
                else:
1480
                    exc_type = errors.BzrMoveFailedError
1481
                if self.is_versioned(to_rel):
1482
                    raise exc_type(from_rel, to_rel,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1483
                                   errors.AlreadyVersionedError(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1484
                if not self.has_filename(from_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1485
                    raise errors.BzrMoveFailedError(
1486
                        from_rel, to_rel, errors.NoSuchFile(from_rel))
0.388.1 by Jelmer Vernooij
Don't print error moving to an unversioned directory.
1487
                kind = self.kind(from_rel)
1488
                if not self.is_versioned(from_rel) and kind != 'directory':
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1489
                    raise exc_type(from_rel, to_rel,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1490
                                   errors.NotVersionedError(from_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1491
                if self.has_filename(to_rel):
1492
                    raise errors.RenameFailedFilesExist(
1493
                        from_rel, to_rel, errors.FileExists(to_rel))
1494
1495
                kind = self.kind(from_rel)
1496
0.429.1 by Jelmer Vernooij
Abstract away index access.
1497
            if not after and kind != 'directory':
1498
                (index, from_subpath) = self._lookup_index(from_path)
1499
                if from_subpath not in index:
1500
                    # It's not a file
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1501
                    raise errors.BzrMoveFailedError(
1502
                        from_rel, to_rel,
1503
                        errors.NotVersionedError(path=from_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1504
1505
            if not after:
1506
                try:
1507
                    self._rename_one(from_rel, to_rel)
1508
                except OSError as e:
1509
                    if e.errno == errno.ENOENT:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1510
                        raise errors.BzrMoveFailedError(
1511
                            from_rel, to_rel, errors.NoSuchFile(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1512
                    raise
1513
            if kind != 'directory':
0.429.13 by Jelmer Vernooij
Fix regressions.
1514
                (index, from_index_path) = self._lookup_index(from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1515
                try:
0.429.25 by Jelmer Vernooij
Merge trunk.
1516
                    self._index_del_entry(index, from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1517
                except KeyError:
1518
                    pass
1519
                self._index_add_entry(to_rel, kind)
1520
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1521
                todo = [(p, i) for (p, i) in self._recurse_index_entries()
1522
                        if p.startswith(from_path + b'/')]
0.429.13 by Jelmer Vernooij
Fix regressions.
1523
                for child_path, child_value in todo:
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1524
                    (child_to_index, child_to_index_path) = self._lookup_index(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1525
                        posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
0.429.13 by Jelmer Vernooij
Fix regressions.
1526
                    child_to_index[child_to_index_path] = child_value
0.429.25 by Jelmer Vernooij
Merge trunk.
1527
                    # TODO(jelmer): Mark individual index as dirty
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1528
                    self._index_dirty = True
7143.15.2 by Jelmer Vernooij
Run autopep8.
1529
                    (child_from_index, child_from_index_path) = self._lookup_index(
1530
                        child_path)
1531
                    self._index_del_entry(
1532
                        child_from_index, child_from_index_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1533
1534
            self._versioned_dirs = None
1535
            self.flush()
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1536
1537
    def find_related_paths_across_trees(self, paths, trees=[],
7143.15.2 by Jelmer Vernooij
Run autopep8.
1538
                                        require_versioned=True):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1539
        if paths is None:
1540
            return None
1541
1542
        if require_versioned:
1543
            trees = [self] + (trees if trees is not None else [])
1544
            unversioned = set()
1545
            for p in paths:
1546
                for t in trees:
1547
                    if t.is_versioned(p):
1548
                        break
1549
                else:
1550
                    unversioned.add(p)
1551
            if unversioned:
1552
                raise errors.PathsNotVersionedError(unversioned)
1553
1554
        return filter(self.is_versioned, paths)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
1555
1556
    def path_content_summary(self, path):
1557
        """See Tree.path_content_summary."""
1558
        try:
1559
            stat_result = self._lstat(path)
1560
        except OSError as e:
1561
            if getattr(e, 'errno', None) == errno.ENOENT:
1562
                # no file.
1563
                return ('missing', None, None, None)
1564
            # propagate other errors
1565
            raise
1566
        kind = mode_kind(stat_result.st_mode)
1567
        if kind == 'file':
1568
            return self._file_content_summary(path, stat_result)
1569
        elif kind == 'directory':
1570
            # perhaps it looks like a plain directory, but it's really a
1571
            # reference.
1572
            if self._directory_is_tree_reference(path):
1573
                kind = 'tree-reference'
1574
            return kind, None, None, None
1575
        elif kind == 'symlink':
1576
            target = osutils.readlink(self.abspath(path))
1577
            return ('symlink', None, None, target)
1578
        else:
1579
            return (kind, None, None, None)
1580
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1581
    def stored_kind(self, relpath):
1582
        (index, index_path) = self._lookup_index(relpath.encode('utf-8'))
1583
        if index is None:
1584
            return kind
1585
        try:
1586
            mode = index[index_path].mode
1587
        except KeyError:
1588
            return kind
1589
        else:
1590
            if S_ISGITLINK(mode):
1591
                return 'tree-reference'
1592
            return 'directory'
1593
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1594
    def kind(self, relpath):
0.429.15 by Jelmer Vernooij
Autodetect tree-reference based on index.
1595
        kind = osutils.file_kind(self.abspath(relpath))
1596
        if kind == 'directory':
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1597
            if self._directory_is_tree_reference(relpath):
1598
                return 'tree-reference'
1599
            return 'directory'
0.429.15 by Jelmer Vernooij
Autodetect tree-reference based on index.
1600
        else:
1601
            return kind
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1602
1603
    def _live_entry(self, relpath):
1604
        raise NotImplementedError(self._live_entry)
1605
7350.3.1 by Jelmer Vernooij
Add Tree.get_transform.
1606
    def get_transform(self, pb=None):
1607
        from ..transform import TreeTransform
7350.3.7 by Jelmer Vernooij
Fix pb propagation.
1608
        return TreeTransform(self, pb=pb)
7350.3.1 by Jelmer Vernooij
Add Tree.get_transform.
1609
1610
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1611
1612
class InterIndexGitTree(InterGitTrees):
1613
    """InterTree that works between a Git revision tree and an index."""
1614
1615
    def __init__(self, source, target):
1616
        super(InterIndexGitTree, self).__init__(source, target)
1617
        self._index = target.index
7467.4.11 by Jelmer Vernooij
Fix another test.
1618
        if self.source.store == self.target.store:
1619
            self.store = self.source.store
7467.4.1 by Jelmer Vernooij
Support Git rename tracking.
1620
        else:
7467.4.11 by Jelmer Vernooij
Fix another test.
1621
            self.store = OverlayObjectStore(
1622
                [self.source.store, self.target.store])
1623
        self.rename_detector = RenameDetector(self.store)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1624
1625
    @classmethod
1626
    def is_compatible(cls, source, target):
1627
        return (isinstance(source, GitRevisionTree) and
1628
                isinstance(target, MutableGitIndexTree))
1629
1630
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1631
                          require_versioned=False, extra_trees=None,
1632
                          want_unversioned=False):
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1633
        trees = [self.source]
1634
        if extra_trees is not None:
1635
            trees.extend(extra_trees)
1636
        if specific_files is not None:
1637
            specific_files = self.target.find_related_paths_across_trees(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1638
                specific_files, trees,
1639
                require_versioned=require_versioned)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1640
        # TODO(jelmer): Restrict to specific_files, for performance reasons.
1641
        with self.lock_read():
1642
            return changes_between_git_tree_and_working_copy(
1643
                self.source.store, self.source.tree,
1644
                self.target, want_unchanged=want_unchanged,
7467.4.1 by Jelmer Vernooij
Support Git rename tracking.
1645
                want_unversioned=want_unversioned,
1646
                rename_detector=self.rename_detector)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1647
1648
1649
_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
1650
1651
7467.4.11 by Jelmer Vernooij
Fix another test.
1652
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.
1653
                                              want_unchanged=False,
7467.4.1 by Jelmer Vernooij
Support Git rename tracking.
1654
                                              want_unversioned=False,
1655
                                              rename_detector=None):
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1656
    """Determine the changes between a git tree and a working tree with index.
1657
1658
    """
1659
    extras = set()
1660
    blobs = {}
1661
    # Report dirified directories to commit_tree first, so that they can be
1662
    # replaced with non-empty directories if they have contents.
1663
    dirified = []
7122.7.5 by Jelmer Vernooij
Only trust filesystem for executable bit where supported.
1664
    trust_executable = target._supports_executable()
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1665
    for path, index_entry in target._recurse_index_entries():
1666
        try:
7045.3.2 by Jelmer Vernooij
Fix tests.
1667
            live_entry = target._live_entry(path)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1668
        except EnvironmentError as e:
1669
            if e.errno == errno.ENOENT:
1670
                # Entry was removed; keep it listed, but mark it as gone.
1671
                blobs[path] = (ZERO_SHA, 0)
7452.1.1 by Jelmer Vernooij
Don't show submodules that are not checked out as deltas.
1672
            else:
1673
                raise
1674
        else:
1675
            if live_entry is None:
1676
                # Entry was turned into a directory.
1677
                # 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.
1678
                if S_ISGITLINK(index_entry.mode):
1679
                    blobs[path] = (index_entry.sha, index_entry.mode)
1680
                else:
1681
                    dirified.append((path, Tree().id, stat.S_IFDIR))
7467.4.11 by Jelmer Vernooij
Fix another test.
1682
                    target.store.add_object(Tree())
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1683
            else:
7122.6.8 by Jelmer Vernooij
Merge trunk.
1684
                mode = live_entry.mode
1685
                if not trust_executable:
1686
                    if mode_is_executable(index_entry.mode):
1687
                        mode |= 0o111
1688
                    else:
1689
                        mode &= ~0o111
7467.4.10 by Jelmer Vernooij
Make sure all relevant blobs are present.
1690
                if live_entry.sha != index_entry.sha:
1691
                    rp = path.decode('utf-8')
1692
                    if stat.S_ISREG(live_entry.mode):
1693
                        blob = Blob()
1694
                        with target.get_file(rp) as f:
1695
                            blob.data = f.read()
1696
                    elif stat.S_ISLNK(live_entry.mode):
1697
                        blob = Blob()
1698
                        blob.data = target.get_symlink_target(rp).encode(osutils._fs_enc)
1699
                    else:
1700
                        blob = None
1701
                    if blob is not None:
7467.4.11 by Jelmer Vernooij
Fix another test.
1702
                        target.store.add_object(blob)
7296.1.2 by Jelmer Vernooij
Cope with API change in Dulwich.
1703
                blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1704
    if want_unversioned:
1705
        for e in target.extras():
1706
            st = target._lstat(e)
1707
            try:
1708
                np, accessible = osutils.normalized_filename(e)
1709
            except UnicodeDecodeError:
1710
                raise errors.BadFilenameEncoding(
1711
                    e, osutils._fs_enc)
1712
            if stat.S_ISDIR(st.st_mode):
1713
                blob = Tree()
7490.24.1 by Jelmer Vernooij
Ignore socket paths in Git repositories.
1714
            elif stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
7143.15.2 by Jelmer Vernooij
Run autopep8.
1715
                blob = blob_from_path_and_stat(
1716
                    target.abspath(e).encode(osutils._fs_enc), st)
7490.24.1 by Jelmer Vernooij
Ignore socket paths in Git repositories.
1717
            else:
1718
                continue
7467.4.11 by Jelmer Vernooij
Fix another test.
1719
            target.store.add_object(blob)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1720
            np = np.encode('utf-8')
1721
            blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1722
            extras.add(np)
7143.15.2 by Jelmer Vernooij
Run autopep8.
1723
    to_tree_sha = commit_tree(
7467.4.11 by Jelmer Vernooij
Fix another test.
1724
        target.store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1725
    store = OverlayObjectStore([source_store, target.store])
7467.4.4 by Jelmer Vernooij
Merge trunk.
1726
    return tree_changes(
1727
        store, from_tree_sha, to_tree_sha, include_trees=True,
7467.4.1 by Jelmer Vernooij
Support Git rename tracking.
1728
        rename_detector=rename_detector,
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1729
        want_unchanged=want_unchanged, change_type_same=True), extras