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