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