/brz/remove-bazaar

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