/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.358.2 by Jelmer Vernooij
Refresh copyright headers, add my email.
1
# Copyright (C) 2009-2018 Jelmer Vernooij <jelmer@jelmer.uk>
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
0.358.1 by Jelmer Vernooij
Fix FSF address.
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
16
17
18
"""Git Trees."""
19
0.200.1594 by Jelmer Vernooij
Use absolute_import everywhere.
20
from __future__ import absolute_import
21
7096.3.2 by Jelmer Vernooij
Fix some git tests.
22
from collections import deque
0.360.2 by Jelmer Vernooij
Fix test.
23
import errno
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
24
from io import BytesIO
25
import os
26
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
27
from dulwich.config import (
28
    parse_submodules,
29
    ConfigFile as GitConfigFile,
30
    )
31
from dulwich.diff_tree import tree_changes
32
from dulwich.errors import NotTreeError
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
33
from dulwich.index import (
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
34
    blob_from_path_and_stat,
35
    cleanup_mode,
36
    commit_tree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
37
    index_entry_from_stat,
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
38
    Index,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
39
    )
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
40
from dulwich.object_store import (
41
    tree_lookup_path,
42
    OverlayObjectStore,
43
    )
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
44
from dulwich.objects import (
45
    Blob,
46
    Tree,
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
47
    ZERO_SHA,
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
48
    S_IFGITLINK,
0.429.7 by Jelmer Vernooij
Consistent file ids.
49
    S_ISGITLINK,
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
50
    )
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
51
import stat
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
52
import posixpath
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
53
6986.2.1 by Jelmer Vernooij
Move breezy.plugins.git to breezy.git.
54
from .. import (
0.429.26 by Jelmer Vernooij
Fix remaining test.
55
    controldir as _mod_controldir,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
56
    delta,
57
    errors,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
58
    mutabletree,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
59
    osutils,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
60
    revisiontree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
61
    trace,
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
62
    tree as _mod_tree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
63
    workingtree,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
64
    )
6986.2.1 by Jelmer Vernooij
Move breezy.plugins.git to breezy.git.
65
from ..revision import (
6973.2.1 by Jelmer Vernooij
Implement GitRevisionTree.annotate_iter.
66
    CURRENT_REVISION,
67
    NULL_REVISION,
68
    )
6986.2.2 by Jelmer Vernooij
Merge trunk.
69
from ..sixish import (
6973.9.1 by Jelmer Vernooij
More test fixes.
70
    text_type,
71
    viewitems,
72
    )
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
73
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
74
from .mapping import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
75
    mode_is_executable,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
76
    mode_kind,
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
77
    default_mapping,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
78
    )
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
79
from .transportgit import (
80
    TransportObjectStore,
81
    TransportRepo,
82
    )
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
83
84
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
85
class GitTreeDirectory(_mod_tree.TreeDirectory):
86
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
87
    __slots__ = ['file_id', 'name', 'parent_id', 'children']
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
88
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
89
    def __init__(self, file_id, name, parent_id):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
90
        self.file_id = file_id
91
        self.name = name
92
        self.parent_id = parent_id
93
        # TODO(jelmer)
94
        self.children = {}
95
96
    @property
97
    def kind(self):
98
        return 'directory'
99
100
    @property
101
    def executable(self):
102
        return False
103
104
    def copy(self):
105
        return self.__class__(
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
106
            self.file_id, self.name, self.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
107
108
    def __repr__(self):
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
109
        return "%s(file_id=%r, name=%r, parent_id=%r)" % (
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
110
            self.__class__.__name__, self.file_id, self.name,
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
111
            self.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
112
113
    def __eq__(self, other):
114
        return (self.kind == other.kind and
115
                self.file_id == other.file_id and
116
                self.name == other.name and
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
117
                self.parent_id == other.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
118
119
120
class GitTreeFile(_mod_tree.TreeFile):
121
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
122
    __slots__ = ['file_id', 'name', 'parent_id', 'text_size', 'text_sha1',
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
123
                 'executable']
124
0.390.2 by Jelmer Vernooij
merge trunk
125
    def __init__(self, file_id, name, parent_id, text_size=None,
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
126
                 text_sha1=None, executable=None):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
127
        self.file_id = file_id
128
        self.name = name
129
        self.parent_id = parent_id
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
130
        self.text_size = text_size
131
        self.text_sha1 = text_sha1
132
        self.executable = executable
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
133
134
    @property
135
    def kind(self):
136
        return 'file'
137
138
    def __eq__(self, other):
139
        return (self.kind == other.kind and
140
                self.file_id == other.file_id and
141
                self.name == other.name and
142
                self.parent_id == other.parent_id and
143
                self.text_sha1 == other.text_sha1 and
144
                self.text_size == other.text_size and
145
                self.executable == other.executable)
146
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
147
    def __repr__(self):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
148
        return ("%s(file_id=%r, name=%r, parent_id=%r, text_size=%r, "
149
                "text_sha1=%r, executable=%r)") % (
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
150
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.390.2 by Jelmer Vernooij
merge trunk
151
            self.text_size, self.text_sha1, self.executable)
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
152
0.365.2 by Jelmer Vernooij
Add eq/copy.
153
    def copy(self):
154
        ret = self.__class__(
7143.15.2 by Jelmer Vernooij
Run autopep8.
155
            self.file_id, self.name, self.parent_id)
0.365.2 by Jelmer Vernooij
Add eq/copy.
156
        ret.text_sha1 = self.text_sha1
157
        ret.text_size = self.text_size
158
        ret.executable = self.executable
159
        return ret
160
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
161
162
class GitTreeSymlink(_mod_tree.TreeLink):
163
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
164
    __slots__ = ['file_id', 'name', 'parent_id', 'symlink_target']
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
165
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
166
    def __init__(self, file_id, name, parent_id,
0.365.2 by Jelmer Vernooij
Add eq/copy.
167
                 symlink_target=None):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
168
        self.file_id = file_id
169
        self.name = name
170
        self.parent_id = parent_id
0.365.2 by Jelmer Vernooij
Add eq/copy.
171
        self.symlink_target = symlink_target
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
172
173
    @property
174
    def kind(self):
175
        return 'symlink'
176
177
    @property
178
    def executable(self):
179
        return False
180
181
    @property
182
    def text_size(self):
183
        return None
184
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
185
    def __repr__(self):
0.390.2 by Jelmer Vernooij
merge trunk
186
        return "%s(file_id=%r, name=%r, parent_id=%r, symlink_target=%r)" % (
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
187
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.390.2 by Jelmer Vernooij
merge trunk
188
            self.symlink_target)
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
189
0.365.2 by Jelmer Vernooij
Add eq/copy.
190
    def __eq__(self, other):
191
        return (self.kind == other.kind and
192
                self.file_id == other.file_id and
193
                self.name == other.name and
194
                self.parent_id == other.parent_id and
195
                self.symlink_target == other.symlink_target)
196
197
    def copy(self):
198
        return self.__class__(
7143.15.2 by Jelmer Vernooij
Run autopep8.
199
            self.file_id, self.name, self.parent_id,
200
            self.symlink_target)
0.365.2 by Jelmer Vernooij
Add eq/copy.
201
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
202
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
203
class GitTreeSubmodule(_mod_tree.TreeReference):
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
204
0.429.12 by Jelmer Vernooij
Remove revision.
205
    __slots__ = ['file_id', 'name', 'parent_id', 'reference_revision']
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
206
0.429.12 by Jelmer Vernooij
Remove revision.
207
    def __init__(self, file_id, name, parent_id, reference_revision=None):
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
208
        self.file_id = file_id
209
        self.name = name
210
        self.parent_id = parent_id
211
        self.reference_revision = reference_revision
212
213
    @property
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(
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
301
                relpath.decode('utf-8'))
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(
304
                posixpath.join('modules', 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):
7358.4.2 by Jelmer Vernooij
Fix tests on Python 3.
313
        encoded_path = path.encode('utf-8')
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(
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
326
            path.encode('utf-8'), 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
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
341
    def id2path(self, file_id):
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)
7096.3.2 by Jelmer Vernooij
Fix some git tests.
373
                ret.add(subpath.decode('utf-8'))
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
382
        encoded_path = path.encode('utf-8')
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':
449
                root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
450
            else:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
451
                root_ie = self._get_file_ie(
452
                    store, from_dir.encode("utf-8"),
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':
7143.15.2 by Jelmer Vernooij
Run autopep8.
458
            todo.append((store, from_dir.encode("utf-8"),
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)
7143.19.7 by Jelmer Vernooij
merge trunk
481
                yield (child_relpath.decode('utf-8'), "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)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
489
        path = path.decode('utf-8')
490
        name = name.decode("utf-8")
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':
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
494
            ie.symlink_target = store[hexsha].data.decode('utf-8')
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):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
506
        path = path.decode('utf-8')
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
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
516
        encoded_path = path.encode('utf-8')
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:
7143.15.2 by Jelmer Vernooij
Run autopep8.
537
                specific_files = set([p.encode('utf-8')
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)
7096.3.2 by Jelmer Vernooij
Fix some git tests.
550
                child_path_decoded = child_path.decode('utf-8')
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):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
609
            return store[hexsha].data.decode('utf-8')
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):
7358.4.2 by Jelmer Vernooij
Fix tests on Python 3.
617
            nested_repo = self._get_submodule_repository(path.encode('utf-8'))
0.429.26 by Jelmer Vernooij
Fix remaining test.
618
            return nested_repo.lookup_foreign_revision_id(hexsha)
0.429.17 by Jelmer Vernooij
Fix some more tests.
619
        else:
620
            return None
621
0.264.10 by Jelmer Vernooij
Yield inventory entries.
622
    def _comparison_data(self, entry, path):
623
        if entry is None:
624
            return None, False, None
625
        return entry.kind, entry.executable, None
626
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
627
    def path_content_summary(self, path):
628
        """See Tree.path_content_summary."""
629
        try:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
630
            (store, mode, hexsha) = self._lookup_path(path)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
631
        except errors.NoSuchFile:
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
632
            return ('missing', None, None, None)
633
        kind = mode_kind(mode)
634
        if kind == 'file':
635
            executable = mode_is_executable(mode)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
636
            contents = store[hexsha].data
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
637
            return (kind, len(contents), executable,
638
                    osutils.sha_string(contents))
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
639
        elif kind == 'symlink':
7096.3.2 by Jelmer Vernooij
Fix some git tests.
640
            return (kind, None, None, store[hexsha].data.decode('utf-8'))
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
641
        elif kind == 'tree-reference':
7358.4.2 by Jelmer Vernooij
Fix tests on Python 3.
642
            nested_repo = self._get_submodule_repository(path.encode('utf-8'))
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
643
            return (kind, None, None,
0.429.26 by Jelmer Vernooij
Fix remaining test.
644
                    nested_repo.lookup_foreign_revision_id(hexsha))
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
645
        else:
646
            return (kind, None, None, None)
647
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
648
    def find_related_paths_across_trees(self, paths, trees=[],
7143.15.2 by Jelmer Vernooij
Run autopep8.
649
                                        require_versioned=True):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
650
        if paths is None:
651
            return None
652
        if require_versioned:
653
            trees = [self] + (trees if trees is not None else [])
654
            unversioned = set()
655
            for p in paths:
656
                for t in trees:
657
                    if t.is_versioned(p):
658
                        break
659
                else:
660
                    unversioned.add(p)
661
            if unversioned:
662
                raise errors.PathsNotVersionedError(unversioned)
663
        return filter(self.is_versioned, paths)
664
0.393.1 by Jelmer Vernooij
Avoid expensive bzr APIs in commit.
665
    def _iter_tree_contents(self, include_trees=False):
666
        if self.tree is None:
667
            return iter([])
668
        return self.store.iter_tree_contents(
7143.15.2 by Jelmer Vernooij
Run autopep8.
669
            self.tree, include_trees=include_trees)
0.393.1 by Jelmer Vernooij
Avoid expensive bzr APIs in commit.
670
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
671
    def annotate_iter(self, path, default_revision=CURRENT_REVISION):
6973.2.1 by Jelmer Vernooij
Implement GitRevisionTree.annotate_iter.
672
        """Return an iterator of revision_id, line tuples.
673
674
        For working trees (and mutable trees in general), the special
675
        revision_id 'current:' will be used for lines that are new in this
676
        tree, e.g. uncommitted changes.
677
        :param default_revision: For lines that don't match a basis, mark them
678
            with this revision id. Not all implementations will make use of
679
            this value.
680
        """
681
        with self.lock_read():
682
            # Now we have the parents of this content
683
            from breezy.annotate import Annotator
684
            from .annotate import AnnotateProvider
685
            annotator = Annotator(AnnotateProvider(
686
                self._repository._file_change_scanner))
687
            this_key = (path, self.get_file_revision(path))
688
            annotations = [(key[-1], line)
689
                           for key, line in annotator.annotate_flat(this_key)]
690
            return annotations
691
7096.3.2 by Jelmer Vernooij
Fix some git tests.
692
    def _get_rules_searcher(self, default_searcher):
693
        return default_searcher
694
7096.3.6 by Jelmer Vernooij
Fix tests, on python 2 at least.
695
    def walkdirs(self, prefix=u""):
7096.3.2 by Jelmer Vernooij
Fix some git tests.
696
        (store, mode, hexsha) = self._lookup_path(prefix)
7143.15.2 by Jelmer Vernooij
Run autopep8.
697
        todo = deque(
698
            [(store, prefix.encode('utf-8'), hexsha, self.path2id(prefix))])
7096.3.2 by Jelmer Vernooij
Fix some git tests.
699
        while todo:
7096.3.4 by Jelmer Vernooij
Fix returned paths.
700
            store, path, tree_sha, parent_id = todo.popleft()
7096.3.2 by Jelmer Vernooij
Fix some git tests.
701
            path_decoded = path.decode('utf-8')
702
            tree = store[tree_sha]
703
            children = []
704
            for name, mode, hexsha in tree.iteritems():
705
                if self.mapping.is_special_file(name):
706
                    continue
707
                child_path = posixpath.join(path, name)
708
                file_id = self.path2id(child_path.decode('utf-8'))
709
                if stat.S_ISDIR(mode):
7096.3.4 by Jelmer Vernooij
Fix returned paths.
710
                    todo.append((store, child_path, hexsha, file_id))
7096.3.6 by Jelmer Vernooij
Fix tests, on python 2 at least.
711
                children.append(
712
                    (child_path.decode('utf-8'), name.decode('utf-8'),
713
                        mode_kind(mode), None,
714
                        file_id, mode_kind(mode)))
7096.3.4 by Jelmer Vernooij
Fix returned paths.
715
            yield (path_decoded, parent_id), children
7096.3.2 by Jelmer Vernooij
Fix some git tests.
716
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
717
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
718
def tree_delta_from_git_changes(changes, mappings,
719
                                specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
720
                                require_versioned=False, include_root=False,
721
                                target_extras=None):
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
722
    """Create a TreeDelta from two git trees.
0.200.959 by Jelmer Vernooij
Improve docstrings.
723
724
    source and target are iterators over tuples with:
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
725
        (filename, sha, mode)
726
    """
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
727
    (old_mapping, new_mapping) = mappings
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
728
    if target_extras is None:
729
        target_extras = set()
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
730
    ret = delta.TreeDelta()
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
731
    added = []
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
732
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
7018.3.2 by Jelmer Vernooij
Fix some git tests.
733
        if newpath == b'' and not include_root:
0.287.5 by Jelmer Vernooij
Fix root handling.
734
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
735
        if oldpath is not None:
736
            oldpath_decoded = oldpath.decode('utf-8')
737
        else:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
738
            oldpath_decoded = None
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
739
        if newpath is not None:
740
            newpath_decoded = newpath.decode('utf-8')
7027.5.2 by Jelmer Vernooij
Fix some more git tests.
741
        else:
742
            newpath_decoded = None
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
743
        if not (specific_files is None or
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
744
                (oldpath is not None and
745
                    osutils.is_inside_or_parent_of_any(
746
                        specific_files, oldpath_decoded)) or
747
                (newpath is not None and
748
                    osutils.is_inside_or_parent_of_any(
749
                        specific_files, newpath_decoded))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
750
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
751
752
        if oldpath_decoded is None:
7358.11.6 by Jelmer Vernooij
merge trunk.
753
            fileid = new_mapping.generate_file_id(newpath_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
754
            oldexe = None
755
            oldkind = None
756
            oldname = None
757
            oldparent = None
758
            oldversioned = False
759
        else:
760
            oldversioned = True
761
            if oldmode:
762
                oldexe = mode_is_executable(oldmode)
763
                oldkind = mode_kind(oldmode)
764
            else:
765
                oldexe = False
766
                oldkind = None
767
            if oldpath_decoded == u'':
768
                oldparent = None
769
                oldname = u''
770
            else:
771
                (oldparentpath, oldname) = osutils.split(oldpath_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
772
                oldparent = old_mapping.generate_file_id(oldparentpath)
773
            fileid = old_mapping.generate_file_id(oldpath_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
774
        if newpath_decoded is None:
775
            newexe = None
776
            newkind = None
777
            newname = None
778
            newparent = None
779
            newversioned = False
780
        else:
781
            newversioned = (newpath_decoded not in target_extras)
782
            if newmode:
783
                newexe = mode_is_executable(newmode)
784
                newkind = mode_kind(newmode)
785
            else:
786
                newexe = False
787
                newkind = None
788
            if newpath_decoded == u'':
789
                newparent = None
790
                newname = u''
791
            else:
792
                newparentpath, newname = osutils.split(newpath_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
793
                newparent = new_mapping.generate_file_id(newparentpath)
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
794
        if old_mapping.is_special_file(oldpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
795
            oldpath = None
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
796
        if new_mapping.is_special_file(newpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
797
            newpath = None
798
        if oldpath is None and newpath is None:
799
            continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
800
        change = _mod_tree.TreeChange(
801
            fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
802
            (oldversioned, newversioned),
803
            (oldparent, newparent), (oldname, newname),
804
            (oldkind, newkind), (oldexe, newexe))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
805
        if oldpath is None:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
806
            added.append((newpath, newkind))
6977.1.2 by Jelmer Vernooij
Deal with missing files properly in 'bzr st'.
807
        elif newpath is None or newmode == 0:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
808
            ret.removed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
809
        elif oldpath != newpath:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
810
            ret.renamed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
811
        elif mode_kind(oldmode) != mode_kind(newmode):
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
812
            ret.kind_changed.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
813
        elif oldsha != newsha or oldmode != newmode:
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
814
            if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
815
                continue
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
816
            ret.modified.append(change)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
817
        else:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
818
            ret.unchanged.append(change)
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
819
7211.10.7 by Jelmer Vernooij
Fix on python 3.
820
    implicit_dirs = {b''}
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
821
    for path, kind in added:
7211.10.7 by Jelmer Vernooij
Fix on python 3.
822
        if kind == 'directory' or path in target_extras:
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
823
            continue
824
        implicit_dirs.update(osutils.parent_directories(path))
825
826
    for path, kind in added:
7211.10.5 by Jelmer Vernooij
Fix handling of directories.
827
        if kind == 'directory' and path not in implicit_dirs:
828
            continue
7211.10.7 by Jelmer Vernooij
Fix on python 3.
829
        path_decoded = osutils.normalized_filename(path)[0]
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
830
        parent_path, basename = osutils.split(path_decoded)
7358.11.6 by Jelmer Vernooij
merge trunk.
831
        parent_id = new_mapping.generate_file_id(parent_path)
7211.10.5 by Jelmer Vernooij
Fix handling of directories.
832
        if path in target_extras:
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
833
            ret.unversioned.append(_mod_tree.TreeChange(
834
                None, (None, path_decoded),
835
                True, (False, False), (None, parent_id),
836
                (None, basename), (None, kind), (None, False)))
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
837
        else:
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
838
            file_id = new_mapping.generate_file_id(path_decoded)
7358.11.3 by Jelmer Vernooij
TreeDelta holds TreeChange objects rather than tuples of various sizes.
839
            ret.added.append(
840
                _mod_tree.TreeChange(
841
                    file_id, (None, path_decoded), True,
842
                    (False, True),
843
                    (None, parent_id),
844
                    (None, basename), (None, kind), (None, False)))
7211.10.2 by Jelmer Vernooij
Don't list directories without versioned files as 'added'.
845
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
846
    return ret
847
848
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
849
def changes_from_git_changes(changes, mapping, specific_files=None,
850
                             include_unchanged=False, target_extras=None):
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
851
    """Create a iter_changes-like generator from a git stream.
0.200.959 by Jelmer Vernooij
Improve docstrings.
852
853
    source and target are iterators over tuples with:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
854
        (filename, sha, mode)
855
    """
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
856
    if target_extras is None:
857
        target_extras = set()
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
858
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
859
        if oldpath is not None:
860
            oldpath_decoded = oldpath.decode('utf-8')
861
        else:
862
            oldpath_decoded = None
863
        if newpath is not None:
864
            newpath_decoded = newpath.decode('utf-8')
865
        else:
866
            newpath_decoded = None
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
867
        if not (specific_files is None or
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
868
                (oldpath_decoded is not None and
869
                    osutils.is_inside_or_parent_of_any(
870
                        specific_files, oldpath_decoded)) or
871
                (newpath_decoded is not None and
872
                    osutils.is_inside_or_parent_of_any(
873
                        specific_files, newpath_decoded))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
874
            continue
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
875
        if oldpath is not None and mapping.is_special_file(oldpath):
876
            continue
877
        if newpath is not None and mapping.is_special_file(newpath):
0.200.1328 by Jelmer Vernooij
More test fixes.
878
            continue
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
879
        if oldpath_decoded is None:
880
            fileid = mapping.generate_file_id(newpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
881
            oldexe = None
882
            oldkind = None
883
            oldname = None
884
            oldparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
885
            oldversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
886
        else:
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
887
            oldversioned = True
0.391.8 by Jelmer Vernooij
Allow missing items in old tree.
888
            if oldmode:
889
                oldexe = mode_is_executable(oldmode)
890
                oldkind = mode_kind(oldmode)
891
            else:
892
                oldexe = False
893
                oldkind = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
894
            if oldpath_decoded == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
895
                oldparent = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
896
                oldname = u''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
897
            else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
898
                (oldparentpath, oldname) = osutils.split(oldpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
899
                oldparent = mapping.generate_file_id(oldparentpath)
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
900
            fileid = mapping.generate_file_id(oldpath_decoded)
901
        if newpath_decoded is None:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
902
            newexe = None
903
            newkind = None
904
            newname = None
905
            newparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
906
            newversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
907
        else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
908
            newversioned = (newpath_decoded not in target_extras)
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
909
            if newmode:
0.200.1576 by Jelmer Vernooij
Merge a bunch of fixes from store-roundtrip-info.
910
                newexe = mode_is_executable(newmode)
911
                newkind = mode_kind(newmode)
912
            else:
913
                newexe = False
914
                newkind = None
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
915
            if newpath_decoded == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
916
                newparent = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
917
                newname = u''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
918
            else:
7045.4.1 by Jelmer Vernooij
Some brz-git fixes.
919
                newparentpath, newname = osutils.split(newpath_decoded)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
920
                newparent = mapping.generate_file_id(newparentpath)
0.357.3 by Jelmer Vernooij
More remove fixes.
921
        if (not include_unchanged and
922
            oldkind == 'directory' and newkind == 'directory' and
7143.15.2 by Jelmer Vernooij
Run autopep8.
923
                oldpath_decoded == newpath_decoded):
0.357.3 by Jelmer Vernooij
More remove fixes.
924
            continue
7322.1.2 by Jelmer Vernooij
Return TreeChange objects.
925
        yield _mod_tree.TreeChange(
926
            fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
927
            (oldversioned, newversioned),
928
            (oldparent, newparent), (oldname, newname),
929
            (oldkind, newkind), (oldexe, newexe))
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
930
931
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
932
class InterGitTrees(_mod_tree.InterTree):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
933
    """InterTree that works between two git trees."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
934
0.200.659 by Jelmer Vernooij
Prevent tests using InterGitRevisionTrees.
935
    _matching_from_tree_format = None
936
    _matching_to_tree_format = None
937
    _test_mutable_trees_to_test_trees = None
938
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
939
    @classmethod
940
    def is_compatible(cls, source, target):
0.200.959 by Jelmer Vernooij
Improve docstrings.
941
        return (isinstance(source, GitRevisionTree) and
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
942
                isinstance(target, GitRevisionTree))
943
944
    def compare(self, want_unchanged=False, specific_files=None,
945
                extra_trees=None, require_versioned=False, include_root=False,
946
                want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
947
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
948
            changes, target_extras = self._iter_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
949
                want_unchanged=want_unchanged,
950
                require_versioned=require_versioned,
951
                specific_files=specific_files,
952
                extra_trees=extra_trees,
953
                want_unversioned=want_unversioned)
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
954
            return tree_delta_from_git_changes(
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
955
                changes, (self.source.mapping, self.target.mapping),
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
956
                specific_files=specific_files,
957
                include_root=include_root, target_extras=target_extras)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
958
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
959
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
960
                     pb=None, extra_trees=[], require_versioned=True,
961
                     want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
962
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
963
            changes, target_extras = self._iter_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
964
                want_unchanged=include_unchanged,
965
                require_versioned=require_versioned,
966
                specific_files=specific_files,
967
                extra_trees=extra_trees,
968
                want_unversioned=want_unversioned)
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
969
            return changes_from_git_changes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
970
                changes, self.target.mapping,
971
                specific_files=specific_files,
972
                include_unchanged=include_unchanged,
973
                target_extras=target_extras)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
974
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
975
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
976
                          require_versioned=False, extra_trees=None,
977
                          want_unversioned=False):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
978
        raise NotImplementedError(self._iter_git_changes)
979
980
981
class InterGitRevisionTrees(InterGitTrees):
982
    """InterTree that works between two git revision trees."""
983
984
    _matching_from_tree_format = None
985
    _matching_to_tree_format = None
986
    _test_mutable_trees_to_test_trees = None
987
988
    @classmethod
989
    def is_compatible(cls, source, target):
990
        return (isinstance(source, GitRevisionTree) and
991
                isinstance(target, GitRevisionTree))
992
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
993
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
994
                          require_versioned=True, extra_trees=None,
995
                          want_unversioned=False):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
996
        trees = [self.source]
997
        if extra_trees is not None:
998
            trees.extend(extra_trees)
999
        if specific_files is not None:
1000
            specific_files = self.target.find_related_paths_across_trees(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1001
                specific_files, trees,
1002
                require_versioned=require_versioned)
0.357.1 by Jelmer Vernooij
Fix some remove tests.
1003
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1004
        if (self.source._repository._git.object_store !=
1005
                self.target._repository._git.object_store):
1006
            store = OverlayObjectStore(
1007
                [self.source._repository._git.object_store,
1008
                    self.target._repository._git.object_store])
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
1009
        else:
1010
            store = self.source._repository._git.object_store
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1011
        return store.tree_changes(
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1012
            self.source.tree, self.target.tree, want_unchanged=want_unchanged,
0.391.2 by Jelmer Vernooij
Pass along target_missing.
1013
            include_trees=True, change_type_same=True), set()
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1014
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
1015
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1016
_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1017
1018
1019
class MutableGitIndexTree(mutabletree.MutableTree):
1020
1021
    def __init__(self):
1022
        self._lock_mode = None
1023
        self._lock_count = 0
1024
        self._versioned_dirs = None
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1025
        self._index_dirty = False
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1026
        self._submodules = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1027
1028
    def is_versioned(self, path):
1029
        with self.lock_read():
1030
            path = path.rstrip('/').encode('utf-8')
0.429.1 by Jelmer Vernooij
Abstract away index access.
1031
            (index, subpath) = self._lookup_index(path)
1032
            return (subpath in index or self._has_dir(path))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1033
1034
    def _has_dir(self, path):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1035
        if not isinstance(path, bytes):
1036
            raise TypeError(path)
1037
        if path == b"":
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1038
            return True
1039
        if self._versioned_dirs is None:
1040
            self._load_dirs()
1041
        return path in self._versioned_dirs
1042
1043
    def _load_dirs(self):
0.361.3 by Jelmer Vernooij
Merge trunk,
1044
        if self._lock_mode is None:
1045
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1046
        self._versioned_dirs = set()
0.429.11 by Jelmer Vernooij
Merge trunk.
1047
        for p, i in self._recurse_index_entries():
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1048
            self._ensure_versioned_dir(posixpath.dirname(p))
1049
1050
    def _ensure_versioned_dir(self, dirname):
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1051
        if not isinstance(dirname, bytes):
1052
            raise TypeError(dirname)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1053
        if dirname in self._versioned_dirs:
1054
            return
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1055
        if dirname != b"":
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1056
            self._ensure_versioned_dir(posixpath.dirname(dirname))
1057
        self._versioned_dirs.add(dirname)
1058
1059
    def path2id(self, path):
1060
        with self.lock_read():
1061
            path = path.rstrip('/')
1062
            if self.is_versioned(path.rstrip('/')):
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
1063
                return self.mapping.generate_file_id(
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1064
                    osutils.safe_unicode(path))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1065
            return None
1066
1067
    def id2path(self, file_id):
1068
        if file_id is None:
1069
            return ''
0.361.3 by Jelmer Vernooij
Merge trunk,
1070
        if type(file_id) is not bytes:
1071
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1072
        with self.lock_read():
1073
            try:
7358.13.1 by Jelmer Vernooij
Drop file id roundtripping support in Git.
1074
                path = self.mapping.parse_file_id(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1075
            except ValueError:
1076
                raise errors.NoSuchId(self, file_id)
1077
            if self.is_versioned(path):
1078
                return path
1079
            raise errors.NoSuchId(self, file_id)
1080
1081
    def _set_root_id(self, file_id):
7206.6.1 by Jelmer Vernooij
Drop file_id from record_iter_changes return value.
1082
        raise errors.UnsupportedOperation(self._set_root_id, self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1083
1084
    def _add(self, files, ids, kinds):
1085
        for (path, file_id, kind) in zip(files, ids, kinds):
1086
            if file_id is not None:
1087
                raise workingtree.SettingFileIdUnsupported()
0.366.1 by Jelmer Vernooij
Fix normalized filename checking in add.
1088
            path, can_access = osutils.normalized_filename(path)
1089
            if not can_access:
1090
                raise errors.InvalidNormalization(path)
6964.2.4 by Jelmer Vernooij
Fix running on python2.
1091
            self._index_add_entry(path, kind)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1092
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
1093
    def _read_submodule_head(self, path):
1094
        raise NotImplementedError(self._read_submodule_head)
1095
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1096
    def _submodule_info(self):
1097
        if self._submodules is None:
1098
            try:
1099
                with self.get_file('.gitmodules') as f:
1100
                    config = GitConfigFile.from_file(f)
1101
                    self._submodules = {
1102
                        path: (url, section)
1103
                        for path, url, section in parse_submodules(config)}
1104
            except errors.NoSuchFile:
1105
                self._submodules = {}
1106
        return self._submodules
1107
0.429.1 by Jelmer Vernooij
Abstract away index access.
1108
    def _lookup_index(self, encoded_path):
1109
        if not isinstance(encoded_path, bytes):
1110
            raise TypeError(encoded_path)
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1111
        # Common case:
1112
        if encoded_path in self.index:
1113
            return self.index, encoded_path
1114
        # TODO(jelmer): Perhaps have a cache with paths under which some
1115
        # submodules exist?
1116
        index = self.index
1117
        remaining_path = encoded_path
1118
        while True:
1119
            parts = remaining_path.split(b'/')
1120
            for i in range(1, len(parts)):
1121
                basepath = b'/'.join(parts[:i])
1122
                try:
1123
                    (ctime, mtime, dev, ino, mode, uid, gid, size, sha,
1124
                     flags) = index[basepath]
1125
                except KeyError:
1126
                    continue
1127
                else:
1128
                    if S_ISGITLINK(mode):
1129
                        index = self._get_submodule_index(basepath)
1130
                        remaining_path = b'/'.join(parts[i:])
1131
                        break
1132
                    else:
1133
                        return index, remaining_path
1134
            else:
1135
                return index, remaining_path
1136
        return index, remaining_path
0.429.1 by Jelmer Vernooij
Abstract away index access.
1137
0.429.25 by Jelmer Vernooij
Merge trunk.
1138
    def _index_del_entry(self, index, path):
1139
        del index[path]
1140
        # TODO(jelmer): Keep track of dirty per index
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1141
        self._index_dirty = True
1142
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1143
    def _index_add_entry(self, path, kind, flags=0, reference_revision=None):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1144
        if kind == "directory":
1145
            # Git indexes don't contain directories
1146
            return
1147
        if kind == "file":
1148
            blob = Blob()
1149
            try:
1150
                file, stat_val = self.get_file_with_stat(path)
1151
            except (errors.NoSuchFile, IOError):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1152
                # TODO: Rather than come up with something here, use the old
1153
                # index
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1154
                file = BytesIO()
1155
                stat_val = os.stat_result(
6964.2.1 by Jelmer Vernooij
Initial work to support brz-git on python3.
1156
                    (stat.S_IFREG | 0o644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
7027.4.7 by Jelmer Vernooij
Fix some tests.
1157
            with file:
1158
                blob.set_raw_string(file.read())
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1159
            # Add object to the repository if it didn't exist yet
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1160
            if blob.id not in self.store:
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1161
                self.store.add_object(blob)
1162
            hexsha = blob.id
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1163
        elif kind == "symlink":
1164
            blob = Blob()
1165
            try:
1166
                stat_val = self._lstat(path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1167
            except EnvironmentError:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1168
                # TODO: Rather than come up with something here, use the
1169
                # old index
1170
                stat_val = os.stat_result(
1171
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
1172
            blob.set_raw_string(
1173
                self.get_symlink_target(path).encode("utf-8"))
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1174
            # Add object to the repository if it didn't exist yet
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1175
            if blob.id not in self.store:
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1176
                self.store.add_object(blob)
1177
            hexsha = blob.id
1178
        elif kind == "tree-reference":
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1179
            if reference_revision is not None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1180
                hexsha = self.branch.lookup_bzr_revision_id(
1181
                    reference_revision)[0]
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
1182
            else:
1183
                hexsha = self._read_submodule_head(path)
1184
                if hexsha is None:
1185
                    raise errors.NoCommits(path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1186
            try:
1187
                stat_val = self._lstat(path)
1188
            except EnvironmentError:
1189
                stat_val = os.stat_result(
1190
                    (S_IFGITLINK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
1191
            stat_val = os.stat_result((S_IFGITLINK, ) + stat_val[1:])
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1192
        else:
1193
            raise AssertionError("unknown kind '%s'" % kind)
1194
        # Add an entry to the index or update the existing entry
1195
        ensure_normalized_path(path)
1196
        encoded_path = path.encode("utf-8")
1197
        if b'\r' in encoded_path or b'\n' in encoded_path:
1198
            # TODO(jelmer): Why do we need to do this?
1199
            trace.mutter('ignoring path with invalid newline in it: %r', path)
1200
            return
0.429.1 by Jelmer Vernooij
Abstract away index access.
1201
        (index, index_path) = self._lookup_index(encoded_path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
1202
        index[index_path] = index_entry_from_stat(stat_val, hexsha, flags)
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1203
        self._index_dirty = True
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1204
        if self._versioned_dirs is not None:
0.429.1 by Jelmer Vernooij
Abstract away index access.
1205
            self._ensure_versioned_dir(index_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1206
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1207
    def _recurse_index_entries(self, index=None, basepath=b"",
7404.2.3 by Jelmer Vernooij
s/follow_tree_references/recurse_nested/g
1208
                               recurse_nested=False):
0.429.7 by Jelmer Vernooij
Consistent file ids.
1209
        # Iterate over all index entries
1210
        with self.lock_read():
1211
            if index is None:
1212
                index = self.index
6973.12.3 by Jelmer Vernooij
Fixes.
1213
            for path, value in index.items():
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1214
                (ctime, mtime, dev, ino, mode, uid, gid, size, sha,
1215
                 flags) = value
7404.2.3 by Jelmer Vernooij
s/follow_tree_references/recurse_nested/g
1216
                if S_ISGITLINK(mode) and recurse_nested:
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1217
                    subindex = self._get_submodule_index(path)
1218
                    for entry in self._recurse_index_entries(
1219
                            index=subindex, basepath=path,
7404.2.3 by Jelmer Vernooij
s/follow_tree_references/recurse_nested/g
1220
                            recurse_nested=recurse_nested):
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1221
                        yield entry
1222
                else:
1223
                    yield (posixpath.join(basepath, path), value)
0.429.7 by Jelmer Vernooij
Consistent file ids.
1224
7404.3.1 by Jelmer Vernooij
Add follow_tree_references argument to Tree.iter_entries_by_dir.
1225
    def iter_entries_by_dir(self, specific_files=None,
7404.3.2 by Jelmer Vernooij
Merge rename of flag to recurse_nested.
1226
                            recurse_nested=False):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1227
        with self.lock_read():
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1228
            if specific_files is not None:
1229
                specific_files = set(specific_files)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1230
            else:
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1231
                specific_files = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1232
            root_ie = self._get_dir_ie(u"", None)
1233
            ret = {}
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1234
            if specific_files is None or u"" in specific_files:
7029.4.2 by Jelmer Vernooij
Fix more merge tests.
1235
                ret[(u"", u"")] = root_ie
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1236
            dir_ids = {u"": root_ie.file_id}
7404.3.1 by Jelmer Vernooij
Add follow_tree_references argument to Tree.iter_entries_by_dir.
1237
            for path, value in self._recurse_index_entries(
7404.3.2 by Jelmer Vernooij
Merge rename of flag to recurse_nested.
1238
                    recurse_nested=recurse_nested):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1239
                if self.mapping.is_special_file(path):
1240
                    continue
1241
                path = path.decode("utf-8")
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1242
                if specific_files is not None and path not in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1243
                    continue
1244
                (parent, name) = posixpath.split(path)
1245
                try:
1246
                    file_ie = self._get_file_ie(name, path, value, None)
1247
                except errors.NoSuchFile:
1248
                    continue
7397.2.3 by Jelmer Vernooij
Fix passing directories in specific_files in GitWorkingTree.
1249
                if specific_files is None:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1250
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(
1251
                            parent, dir_ids):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1252
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
0.429.12 by Jelmer Vernooij
Remove revision.
1253
                file_ie.parent_id = self.path2id(parent)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1254
                ret[(posixpath.dirname(path), path)] = file_ie
7397.2.3 by Jelmer Vernooij
Fix passing directories in specific_files in GitWorkingTree.
1255
            # Special casing for directories
1256
            if specific_files:
1257
                for path in specific_files:
1258
                    key = (posixpath.dirname(path), path)
1259
                    if key not in ret and self.is_versioned(path):
1260
                        ret[key] = self._get_dir_ie(path, self.path2id(key[0]))
7029.4.2 by Jelmer Vernooij
Fix more merge tests.
1261
            return ((path, ie) for ((_, path), ie) in sorted(viewitems(ret)))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1262
0.429.7 by Jelmer Vernooij
Consistent file ids.
1263
    def iter_references(self):
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1264
        if self.supports_tree_reference():
1265
            # TODO(jelmer): Implement a more efficient version of this
1266
            for path, entry in self.iter_entries_by_dir():
1267
                if entry.kind == 'tree-reference':
1268
                    yield path
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1269
1270
    def _get_dir_ie(self, path, parent_id):
1271
        file_id = self.path2id(path)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1272
        return GitTreeDirectory(file_id,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1273
                                posixpath.basename(path).strip("/"), parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1274
1275
    def _get_file_ie(self, name, path, value, parent_id):
6973.6.2 by Jelmer Vernooij
Fix more tests.
1276
        if not isinstance(name, text_type):
0.361.3 by Jelmer Vernooij
Merge trunk,
1277
            raise TypeError(name)
6973.6.2 by Jelmer Vernooij
Fix more tests.
1278
        if not isinstance(path, text_type):
0.361.3 by Jelmer Vernooij
Merge trunk,
1279
            raise TypeError(path)
1280
        if not isinstance(value, tuple) or len(value) != 10:
1281
            raise TypeError(value)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1282
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
1283
        file_id = self.path2id(path)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
1284
        if not isinstance(file_id, bytes):
1285
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1286
        kind = mode_kind(mode)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1287
        ie = entry_factory[kind](file_id, name, parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1288
        if kind == 'symlink':
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1289
            ie.symlink_target = self.get_symlink_target(path)
0.429.7 by Jelmer Vernooij
Consistent file ids.
1290
        elif kind == 'tree-reference':
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1291
            ie.reference_revision = self.get_reference_revision(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1292
        else:
1293
            try:
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1294
                data = self.get_file_text(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1295
            except errors.NoSuchFile:
1296
                data = None
1297
            except IOError as e:
1298
                if e.errno != errno.ENOENT:
1299
                    raise
1300
                data = None
1301
            if data is None:
1302
                data = self.branch.repository._git.object_store[sha].data
1303
            ie.text_sha1 = osutils.sha_string(data)
1304
            ie.text_size = len(data)
1305
            ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1306
        return ie
1307
1308
    def _add_missing_parent_ids(self, path, dir_ids):
1309
        if path in dir_ids:
1310
            return []
1311
        parent = posixpath.dirname(path).strip("/")
1312
        ret = self._add_missing_parent_ids(parent, dir_ids)
1313
        parent_id = dir_ids[parent]
1314
        ie = self._get_dir_ie(path, parent_id)
1315
        dir_ids[path] = ie.file_id
1316
        ret.append((path, ie))
1317
        return ret
1318
1319
    def _comparison_data(self, entry, path):
1320
        if entry is None:
1321
            return None, False, None
1322
        return entry.kind, entry.executable, None
1323
1324
    def _unversion_path(self, path):
0.361.3 by Jelmer Vernooij
Merge trunk,
1325
        if self._lock_mode is None:
1326
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1327
        encoded_path = path.encode("utf-8")
1328
        count = 0
0.429.1 by Jelmer Vernooij
Abstract away index access.
1329
        (index, subpath) = self._lookup_index(encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1330
        try:
0.429.25 by Jelmer Vernooij
Merge trunk.
1331
            self._index_del_entry(index, encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1332
        except KeyError:
1333
            # A directory, perhaps?
0.429.1 by Jelmer Vernooij
Abstract away index access.
1334
            # TODO(jelmer): Deletes that involve submodules?
1335
            for p in list(index):
7143.15.2 by Jelmer Vernooij
Run autopep8.
1336
                if p.startswith(subpath + b"/"):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1337
                    count += 1
0.429.25 by Jelmer Vernooij
Merge trunk.
1338
                    self._index_del_entry(index, p)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1339
        else:
1340
            count = 1
1341
        self._versioned_dirs = None
1342
        return count
1343
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1344
    def unversion(self, paths):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1345
        with self.lock_tree_write():
1346
            for path in paths:
1347
                if self._unversion_path(path) == 0:
1348
                    raise errors.NoSuchFile(path)
1349
            self._versioned_dirs = None
1350
            self.flush()
1351
1352
    def flush(self):
1353
        pass
1354
1355
    def update_basis_by_delta(self, revid, delta):
1356
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
1357
        for (old_path, new_path, file_id, ie) in delta:
0.429.1 by Jelmer Vernooij
Abstract away index access.
1358
            if old_path is not None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1359
                (index, old_subpath) = self._lookup_index(
1360
                    old_path.encode('utf-8'))
0.429.1 by Jelmer Vernooij
Abstract away index access.
1361
                if old_subpath in index:
0.429.25 by Jelmer Vernooij
Merge trunk.
1362
                    self._index_del_entry(index, old_subpath)
0.429.1 by Jelmer Vernooij
Abstract away index access.
1363
                    self._versioned_dirs = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1364
            if new_path is not None and ie.kind != 'directory':
6964.2.4 by Jelmer Vernooij
Fix running on python2.
1365
                self._index_add_entry(new_path, ie.kind)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1366
        self.flush()
1367
        self._set_merges_from_parent_ids([])
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1368
1369
    def move(self, from_paths, to_dir=None, after=None):
1370
        rename_tuples = []
1371
        with self.lock_tree_write():
1372
            to_abs = self.abspath(to_dir)
1373
            if not os.path.isdir(to_abs):
1374
                raise errors.BzrMoveFailedError('', to_dir,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1375
                                                errors.NotADirectory(to_abs))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1376
1377
            for from_rel in from_paths:
1378
                from_tail = os.path.split(from_rel)[-1]
1379
                to_rel = os.path.join(to_dir, from_tail)
1380
                self.rename_one(from_rel, to_rel, after=after)
1381
                rename_tuples.append((from_rel, to_rel))
1382
            self.flush()
1383
            return rename_tuples
1384
1385
    def rename_one(self, from_rel, to_rel, after=None):
1386
        from_path = from_rel.encode("utf-8")
1387
        to_rel, can_access = osutils.normalized_filename(to_rel)
1388
        if not can_access:
1389
            raise errors.InvalidNormalization(to_rel)
1390
        to_path = to_rel.encode("utf-8")
1391
        with self.lock_tree_write():
1392
            if not after:
1393
                # Perhaps it's already moved?
1394
                after = (
1395
                    not self.has_filename(from_rel) and
1396
                    self.has_filename(to_rel) and
1397
                    not self.is_versioned(to_rel))
1398
            if after:
1399
                if not self.has_filename(to_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1400
                    raise errors.BzrMoveFailedError(
1401
                        from_rel, to_rel, errors.NoSuchFile(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1402
                if self.basis_tree().is_versioned(to_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1403
                    raise errors.BzrMoveFailedError(
1404
                        from_rel, to_rel, errors.AlreadyVersionedError(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1405
1406
                kind = self.kind(to_rel)
1407
            else:
1408
                try:
1409
                    to_kind = self.kind(to_rel)
1410
                except errors.NoSuchFile:
1411
                    exc_type = errors.BzrRenameFailedError
1412
                    to_kind = None
1413
                else:
1414
                    exc_type = errors.BzrMoveFailedError
1415
                if self.is_versioned(to_rel):
1416
                    raise exc_type(from_rel, to_rel,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1417
                                   errors.AlreadyVersionedError(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1418
                if not self.has_filename(from_rel):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1419
                    raise errors.BzrMoveFailedError(
1420
                        from_rel, to_rel, errors.NoSuchFile(from_rel))
0.388.1 by Jelmer Vernooij
Don't print error moving to an unversioned directory.
1421
                kind = self.kind(from_rel)
1422
                if not self.is_versioned(from_rel) and kind != 'directory':
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1423
                    raise exc_type(from_rel, to_rel,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1424
                                   errors.NotVersionedError(from_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1425
                if self.has_filename(to_rel):
1426
                    raise errors.RenameFailedFilesExist(
1427
                        from_rel, to_rel, errors.FileExists(to_rel))
1428
1429
                kind = self.kind(from_rel)
1430
0.429.1 by Jelmer Vernooij
Abstract away index access.
1431
            if not after and kind != 'directory':
1432
                (index, from_subpath) = self._lookup_index(from_path)
1433
                if from_subpath not in index:
1434
                    # It's not a file
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1435
                    raise errors.BzrMoveFailedError(
1436
                        from_rel, to_rel,
1437
                        errors.NotVersionedError(path=from_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1438
1439
            if not after:
1440
                try:
1441
                    self._rename_one(from_rel, to_rel)
1442
                except OSError as e:
1443
                    if e.errno == errno.ENOENT:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1444
                        raise errors.BzrMoveFailedError(
1445
                            from_rel, to_rel, errors.NoSuchFile(to_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1446
                    raise
1447
            if kind != 'directory':
0.429.13 by Jelmer Vernooij
Fix regressions.
1448
                (index, from_index_path) = self._lookup_index(from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1449
                try:
0.429.25 by Jelmer Vernooij
Merge trunk.
1450
                    self._index_del_entry(index, from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1451
                except KeyError:
1452
                    pass
1453
                self._index_add_entry(to_rel, kind)
1454
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1455
                todo = [(p, i) for (p, i) in self._recurse_index_entries()
1456
                        if p.startswith(from_path + b'/')]
0.429.13 by Jelmer Vernooij
Fix regressions.
1457
                for child_path, child_value in todo:
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1458
                    (child_to_index, child_to_index_path) = self._lookup_index(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1459
                        posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
0.429.13 by Jelmer Vernooij
Fix regressions.
1460
                    child_to_index[child_to_index_path] = child_value
0.429.25 by Jelmer Vernooij
Merge trunk.
1461
                    # TODO(jelmer): Mark individual index as dirty
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1462
                    self._index_dirty = True
7143.15.2 by Jelmer Vernooij
Run autopep8.
1463
                    (child_from_index, child_from_index_path) = self._lookup_index(
1464
                        child_path)
1465
                    self._index_del_entry(
1466
                        child_from_index, child_from_index_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1467
1468
            self._versioned_dirs = None
1469
            self.flush()
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1470
1471
    def find_related_paths_across_trees(self, paths, trees=[],
7143.15.2 by Jelmer Vernooij
Run autopep8.
1472
                                        require_versioned=True):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1473
        if paths is None:
1474
            return None
1475
1476
        if require_versioned:
1477
            trees = [self] + (trees if trees is not None else [])
1478
            unversioned = set()
1479
            for p in paths:
1480
                for t in trees:
1481
                    if t.is_versioned(p):
1482
                        break
1483
                else:
1484
                    unversioned.add(p)
1485
            if unversioned:
1486
                raise errors.PathsNotVersionedError(unversioned)
1487
1488
        return filter(self.is_versioned, paths)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
1489
1490
    def path_content_summary(self, path):
1491
        """See Tree.path_content_summary."""
1492
        try:
1493
            stat_result = self._lstat(path)
1494
        except OSError as e:
1495
            if getattr(e, 'errno', None) == errno.ENOENT:
1496
                # no file.
1497
                return ('missing', None, None, None)
1498
            # propagate other errors
1499
            raise
1500
        kind = mode_kind(stat_result.st_mode)
1501
        if kind == 'file':
1502
            return self._file_content_summary(path, stat_result)
1503
        elif kind == 'directory':
1504
            # perhaps it looks like a plain directory, but it's really a
1505
            # reference.
1506
            if self._directory_is_tree_reference(path):
1507
                kind = 'tree-reference'
1508
            return kind, None, None, None
1509
        elif kind == 'symlink':
1510
            target = osutils.readlink(self.abspath(path))
1511
            return ('symlink', None, None, target)
1512
        else:
1513
            return (kind, None, None, None)
1514
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1515
    def stored_kind(self, relpath):
1516
        (index, index_path) = self._lookup_index(relpath.encode('utf-8'))
1517
        if index is None:
1518
            return kind
1519
        try:
1520
            mode = index[index_path].mode
1521
        except KeyError:
1522
            return kind
1523
        else:
1524
            if S_ISGITLINK(mode):
1525
                return 'tree-reference'
1526
            return 'directory'
1527
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1528
    def kind(self, relpath):
0.429.15 by Jelmer Vernooij
Autodetect tree-reference based on index.
1529
        kind = osutils.file_kind(self.abspath(relpath))
1530
        if kind == 'directory':
7404.2.1 by Jelmer Vernooij
Add a follow_tree_references argument to Tree.list_files.
1531
            if self._directory_is_tree_reference(relpath):
1532
                return 'tree-reference'
1533
            return 'directory'
0.429.15 by Jelmer Vernooij
Autodetect tree-reference based on index.
1534
        else:
1535
            return kind
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1536
1537
    def _live_entry(self, relpath):
1538
        raise NotImplementedError(self._live_entry)
1539
7350.3.1 by Jelmer Vernooij
Add Tree.get_transform.
1540
    def get_transform(self, pb=None):
1541
        from ..transform import TreeTransform
7350.3.7 by Jelmer Vernooij
Fix pb propagation.
1542
        return TreeTransform(self, pb=pb)
7350.3.1 by Jelmer Vernooij
Add Tree.get_transform.
1543
1544
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1545
1546
class InterIndexGitTree(InterGitTrees):
1547
    """InterTree that works between a Git revision tree and an index."""
1548
1549
    def __init__(self, source, target):
1550
        super(InterIndexGitTree, self).__init__(source, target)
1551
        self._index = target.index
1552
1553
    @classmethod
1554
    def is_compatible(cls, source, target):
1555
        return (isinstance(source, GitRevisionTree) and
1556
                isinstance(target, MutableGitIndexTree))
1557
1558
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1559
                          require_versioned=False, extra_trees=None,
1560
                          want_unversioned=False):
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1561
        trees = [self.source]
1562
        if extra_trees is not None:
1563
            trees.extend(extra_trees)
1564
        if specific_files is not None:
1565
            specific_files = self.target.find_related_paths_across_trees(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1566
                specific_files, trees,
1567
                require_versioned=require_versioned)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1568
        # TODO(jelmer): Restrict to specific_files, for performance reasons.
1569
        with self.lock_read():
1570
            return changes_between_git_tree_and_working_copy(
1571
                self.source.store, self.source.tree,
1572
                self.target, want_unchanged=want_unchanged,
1573
                want_unversioned=want_unversioned)
1574
1575
1576
_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
1577
1578
1579
def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
1580
                                              want_unchanged=False,
1581
                                              want_unversioned=False):
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1582
    """Determine the changes between a git tree and a working tree with index.
1583
1584
    """
1585
    extras = set()
1586
    blobs = {}
1587
    # Report dirified directories to commit_tree first, so that they can be
1588
    # replaced with non-empty directories if they have contents.
1589
    dirified = []
7122.7.5 by Jelmer Vernooij
Only trust filesystem for executable bit where supported.
1590
    trust_executable = target._supports_executable()
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1591
    for path, index_entry in target._recurse_index_entries():
1592
        try:
7045.3.2 by Jelmer Vernooij
Fix tests.
1593
            live_entry = target._live_entry(path)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1594
        except EnvironmentError as e:
1595
            if e.errno == errno.ENOENT:
1596
                # Entry was removed; keep it listed, but mark it as gone.
1597
                blobs[path] = (ZERO_SHA, 0)
1598
            elif e.errno == errno.EISDIR:
7296.1.2 by Jelmer Vernooij
Cope with API change in Dulwich.
1599
                # Backwards compatibility with Dulwich < 0.19.12;
1600
                # newer versions of Dulwich return either an entry for the
1601
                # submodule or None for directories.
7131.13.1 by Jelmer Vernooij
Don't show a delta for unchanged submodules.
1602
                if S_ISGITLINK(index_entry.mode):
1603
                    blobs[path] = (index_entry.sha, index_entry.mode)
1604
                else:
1605
                    # Entry was turned into a directory
1606
                    dirified.append((path, Tree().id, stat.S_IFDIR))
1607
                    store.add_object(Tree())
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1608
            else:
1609
                raise
1610
        else:
7296.1.2 by Jelmer Vernooij
Cope with API change in Dulwich.
1611
            if live_entry is None:
1612
                # Entry was turned into a directory
1613
                dirified.append((path, Tree().id, stat.S_IFDIR))
1614
                store.add_object(Tree())
1615
            else:
7122.6.8 by Jelmer Vernooij
Merge trunk.
1616
                mode = live_entry.mode
1617
                if not trust_executable:
1618
                    if mode_is_executable(index_entry.mode):
1619
                        mode |= 0o111
1620
                    else:
1621
                        mode &= ~0o111
7296.1.2 by Jelmer Vernooij
Cope with API change in Dulwich.
1622
                blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1623
    if want_unversioned:
1624
        for e in target.extras():
1625
            st = target._lstat(e)
1626
            try:
1627
                np, accessible = osutils.normalized_filename(e)
1628
            except UnicodeDecodeError:
1629
                raise errors.BadFilenameEncoding(
1630
                    e, osutils._fs_enc)
1631
            if stat.S_ISDIR(st.st_mode):
1632
                blob = Tree()
1633
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
1634
                blob = blob_from_path_and_stat(
1635
                    target.abspath(e).encode(osutils._fs_enc), st)
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1636
            store.add_object(blob)
1637
            np = np.encode('utf-8')
1638
            blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1639
            extras.add(np)
7143.15.2 by Jelmer Vernooij
Run autopep8.
1640
    to_tree_sha = commit_tree(
1641
        store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
6973.1.1 by Jelmer Vernooij
Make InterIndexGitTree suitable for use with MemoryGitTree.
1642
    return store.tree_changes(
1643
        from_tree_sha, to_tree_sha, include_trees=True,
1644
        want_unchanged=want_unchanged, change_type_same=True), extras