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