/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.358.2 by Jelmer Vernooij
Refresh copyright headers, add my email.
1
# Copyright (C) 2009-2018 Jelmer Vernooij <jelmer@jelmer.uk>
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
0.358.1 by Jelmer Vernooij
Fix FSF address.
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
16
17
18
"""Git Trees."""
19
0.200.1594 by Jelmer Vernooij
Use absolute_import everywhere.
20
from __future__ import absolute_import
21
0.360.2 by Jelmer Vernooij
Fix test.
22
import errno
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
23
from io import BytesIO
24
import os
25
26
from dulwich.index import (
27
    index_entry_from_stat,
28
    )
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
29
from dulwich.object_store import (
30
    tree_lookup_path,
31
    OverlayObjectStore,
32
    )
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
33
from dulwich.objects import (
34
    Blob,
35
    Tree,
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
36
    ZERO_SHA,
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
37
    S_IFGITLINK,
0.429.7 by Jelmer Vernooij
Consistent file ids.
38
    S_ISGITLINK,
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
39
    )
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
40
import stat
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
41
import posixpath
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
42
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
43
from ... import (
0.429.26 by Jelmer Vernooij
Fix remaining test.
44
    controldir as _mod_controldir,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
45
    delta,
46
    errors,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
47
    lock,
48
    mutabletree,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
49
    osutils,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
50
    revisiontree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
51
    trace,
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
52
    tree as _mod_tree,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
53
    workingtree,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
54
    )
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
55
from ...revision import NULL_REVISION
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
56
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
57
from .mapping import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
58
    mode_is_executable,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
59
    mode_kind,
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
60
    GitFileIdMap,
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
61
    default_mapping,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
62
    )
63
64
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
65
class GitTreeDirectory(_mod_tree.TreeDirectory):
66
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.
67
    __slots__ = ['file_id', 'name', 'parent_id', 'children']
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
68
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.
69
    def __init__(self, file_id, name, parent_id):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
70
        self.file_id = file_id
71
        self.name = name
72
        self.parent_id = parent_id
73
        # TODO(jelmer)
74
        self.children = {}
75
76
    @property
77
    def kind(self):
78
        return 'directory'
79
80
    @property
81
    def executable(self):
82
        return False
83
84
    def copy(self):
85
        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.
86
            self.file_id, self.name, self.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
87
88
    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.
89
        return "%s(file_id=%r, name=%r, parent_id=%r)" % (
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
90
            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.
91
            self.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
92
93
    def __eq__(self, other):
94
        return (self.kind == other.kind and
95
                self.file_id == other.file_id and
96
                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.
97
                self.parent_id == other.parent_id)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
98
99
100
class GitTreeFile(_mod_tree.TreeFile):
101
0.390.1 by Jelmer Vernooij
Don't set .revision for returned TreeEntry objects; it's slow, and callers can call Tree.get_file_revision if they really care.
102
    __slots__ = ['file_id', 'name', 'parent_id', 'text_size', 'text_sha1',
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
103
                 'executable']
104
0.390.2 by Jelmer Vernooij
merge trunk
105
    def __init__(self, file_id, name, parent_id, text_size=None,
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
106
                 text_sha1=None, executable=None):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
107
        self.file_id = file_id
108
        self.name = name
109
        self.parent_id = parent_id
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
110
        self.text_size = text_size
111
        self.text_sha1 = text_sha1
112
        self.executable = executable
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
113
114
    @property
115
    def kind(self):
116
        return 'file'
117
118
    def __eq__(self, other):
119
        return (self.kind == other.kind and
120
                self.file_id == other.file_id and
121
                self.name == other.name and
122
                self.parent_id == other.parent_id and
123
                self.text_sha1 == other.text_sha1 and
124
                self.text_size == other.text_size and
125
                self.executable == other.executable)
126
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
127
    def __repr__(self):
0.390.2 by Jelmer Vernooij
merge trunk
128
        return "%s(file_id=%r, name=%r, parent_id=%r, text_size=%r, text_sha1=%r, executable=%r)" % (
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
129
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.390.2 by Jelmer Vernooij
merge trunk
130
            self.text_size, self.text_sha1, self.executable)
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
131
0.365.2 by Jelmer Vernooij
Add eq/copy.
132
    def copy(self):
133
        ret = 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.
134
                self.file_id, self.name, self.parent_id)
0.365.2 by Jelmer Vernooij
Add eq/copy.
135
        ret.text_sha1 = self.text_sha1
136
        ret.text_size = self.text_size
137
        ret.executable = self.executable
138
        return ret
139
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
140
141
class GitTreeSymlink(_mod_tree.TreeLink):
142
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.
143
    __slots__ = ['file_id', 'name', 'parent_id', 'symlink_target']
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
144
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.
145
    def __init__(self, file_id, name, parent_id,
0.365.2 by Jelmer Vernooij
Add eq/copy.
146
                 symlink_target=None):
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
147
        self.file_id = file_id
148
        self.name = name
149
        self.parent_id = parent_id
0.365.2 by Jelmer Vernooij
Add eq/copy.
150
        self.symlink_target = symlink_target
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
151
152
    @property
153
    def kind(self):
154
        return 'symlink'
155
156
    @property
157
    def executable(self):
158
        return False
159
160
    @property
161
    def text_size(self):
162
        return None
163
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
164
    def __repr__(self):
0.390.2 by Jelmer Vernooij
merge trunk
165
        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.
166
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.390.2 by Jelmer Vernooij
merge trunk
167
            self.symlink_target)
0.389.2 by Jelmer Vernooij
Add repr implementation to GitTreeFile & GitTreeLink.
168
0.365.2 by Jelmer Vernooij
Add eq/copy.
169
    def __eq__(self, other):
170
        return (self.kind == other.kind and
171
                self.file_id == other.file_id and
172
                self.name == other.name and
173
                self.parent_id == other.parent_id and
174
                self.symlink_target == other.symlink_target)
175
176
    def copy(self):
177
        return self.__class__(
178
                self.file_id, self.name, self.parent_id,
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.
179
                self.symlink_target)
0.365.2 by Jelmer Vernooij
Add eq/copy.
180
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
181
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
182
class GitTreeSubmodule(_mod_tree.TreeLink):
183
0.429.12 by Jelmer Vernooij
Remove revision.
184
    __slots__ = ['file_id', 'name', 'parent_id', 'reference_revision']
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
185
0.429.12 by Jelmer Vernooij
Remove revision.
186
    def __init__(self, file_id, name, parent_id, reference_revision=None):
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
187
        self.file_id = file_id
188
        self.name = name
189
        self.parent_id = parent_id
190
        self.reference_revision = reference_revision
191
192
    @property
193
    def kind(self):
194
        return 'tree-reference'
195
196
    def __repr__(self):
0.429.12 by Jelmer Vernooij
Remove revision.
197
        return "%s(file_id=%r, name=%r, parent_id=%r, reference_revision=%r)" % (
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
198
            type(self).__name__, self.file_id, self.name, self.parent_id,
0.429.12 by Jelmer Vernooij
Remove revision.
199
            self.reference_revision)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
200
201
    def __eq__(self, other):
202
        return (self.kind == other.kind and
203
                self.file_id == other.file_id and
204
                self.name == other.name and
205
                self.parent_id == other.parent_id and
206
                self.reference_revision == other.reference_revision)
207
208
    def copy(self):
209
        return self.__class__(
210
                self.file_id, self.name, self.parent_id,
0.429.12 by Jelmer Vernooij
Remove revision.
211
                self.reference_revision)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
212
213
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
214
entry_factory = {
215
    'directory': GitTreeDirectory,
216
    'file': GitTreeFile,
217
    'symlink': GitTreeSymlink,
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
218
    'tree-reference': GitTreeSubmodule,
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
219
    }
220
221
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
222
def ensure_normalized_path(path):
223
    """Check whether path is normalized.
224
225
    :raises InvalidNormalization: When path is not normalized, and cannot be
226
        accessed on this platform by the normalized path.
227
    :return: The NFC normalised version of path.
228
    """
229
    norm_path, can_access = osutils.normalized_filename(path)
230
    if norm_path != path:
231
        if can_access:
232
            return norm_path
233
        else:
234
            raise errors.InvalidNormalization(path)
235
    return path
236
237
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
238
class GitRevisionTree(revisiontree.RevisionTree):
0.200.959 by Jelmer Vernooij
Improve docstrings.
239
    """Revision tree implementation based on Git objects."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
240
241
    def __init__(self, repository, revision_id):
242
        self._revision_id = revision_id
243
        self._repository = repository
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
244
        self.store = repository._git.object_store
0.361.1 by Jelmer Vernooij
Don't use assert.
245
        if type(revision_id) is not str:
246
            raise TypeError(revision_id)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
247
        self.commit_id, self.mapping = repository.lookup_bzr_revision_id(revision_id)
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
248
        if revision_id == NULL_REVISION:
249
            self.tree = None
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
250
            self.mapping = default_mapping
251
            self._fileid_map = GitFileIdMap(
0.287.4 by Jelmer Vernooij
Fix GitRevisionTree behaviour for null:
252
                {},
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
253
                default_mapping)
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
254
        else:
255
            try:
256
                commit = self.store[self.commit_id]
257
            except KeyError, r:
258
                raise errors.NoSuchRevision(repository, revision_id)
259
            self.tree = commit.tree
260
            self._fileid_map = self.mapping.get_fileid_map(self.store.__getitem__, self.tree)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
261
0.429.26 by Jelmer Vernooij
Fix remaining test.
262
    def _get_nested_repository(self, path):
263
        nested_repo_transport = self._repository.user_transport.clone(path)
264
        nested_controldir = _mod_controldir.ControlDir.open_from_transport(nested_repo_transport)
265
        return nested_controldir.find_repository()
266
0.349.1 by Jelmer Vernooij
Support supports_rename_tracking method.
267
    def supports_rename_tracking(self):
268
        return False
269
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
270
    def get_file_revision(self, path, file_id=None):
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
271
        change_scanner = self._repository._file_change_scanner
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
272
        if self.commit_id == ZERO_SHA:
273
            return NULL_REVISION
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
274
        (path, commit_id) = change_scanner.find_last_change_revision(
275
            path.encode('utf-8'), self.commit_id)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
276
        return self._repository.lookup_foreign_revision_id(commit_id, self.mapping)
277
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
278
    def get_file_mtime(self, path, file_id=None):
279
        revid = self.get_file_revision(path, file_id)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
280
        try:
281
            rev = self._repository.get_revision(revid)
282
        except errors.NoSuchRevision:
283
            raise errors.FileTimestampUnavailable(path)
284
        return rev.timestamp
285
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
286
    def id2path(self, file_id):
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
287
        try:
0.329.1 by Jelmer Vernooij
Check that path actually exists in Tree.id2path.
288
            path = self._fileid_map.lookup_path(file_id)
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
289
        except ValueError:
0.200.1714 by Jelmer Vernooij
Fix NoSuchId raising.
290
            raise errors.NoSuchId(self, file_id)
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
291
        path = path.decode('utf-8')
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
292
        if self.is_versioned(path):
0.329.1 by Jelmer Vernooij
Check that path actually exists in Tree.id2path.
293
            return path
294
        raise errors.NoSuchId(self, file_id)
295
296
    def is_versioned(self, path):
297
        return self.has_filename(path)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
298
299
    def path2id(self, path):
0.200.1328 by Jelmer Vernooij
More test fixes.
300
        if self.mapping.is_special_file(path):
301
            return None
302
        return self._fileid_map.lookup_file_id(path.encode('utf-8'))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
303
0.200.1569 by Jelmer Vernooij
Implement GitRevisionTree.all_file_ids().
304
    def all_file_ids(self):
305
        return set(self._fileid_map.all_file_ids())
306
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
307
    def all_versioned_paths(self):
308
        ret = set()
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
309
        todo = set([(store, '', self.tree)])
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
310
        while todo:
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
311
            (store, path, tree_id) = todo.pop()
0.287.2 by Jelmer Vernooij
Support empty trees in GitRevisionTree.
312
            if tree_id is None:
313
                continue
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
314
            tree = store[tree_id]
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
315
            for name, mode, hexsha in tree.items():
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
316
                subpath = posixpath.join(path, name)
317
                if stat.S_ISDIR(mode):
0.400.1 by Jelmer Vernooij
Track store in Tree.all_versioned_paths.
318
                    todo.add((store, subpath, hexsha))
0.200.1724 by Jelmer Vernooij
Add GitRevisionTree.all_versioned_paths implementation.
319
                else:
320
                    ret.add(subpath)
321
        return ret
322
0.200.1204 by Jelmer Vernooij
Implement GitRevisionTree.get_root_id().
323
    def get_root_id(self):
0.378.1 by Jelmer Vernooij
Return None from Tree.get_root_id() when encountering an empty tree.
324
        if self.tree is None:
325
            return None
0.200.1204 by Jelmer Vernooij
Implement GitRevisionTree.get_root_id().
326
        return self.path2id("")
327
0.200.1208 by Jelmer Vernooij
Add GitWorkingTree.has_id and GitWorkingTree.has_or_had_id.
328
    def has_or_had_id(self, file_id):
0.372.1 by Jelmer Vernooij
Fix some missing id handling.
329
        try:
330
            path = self.id2path(file_id)
331
        except errors.NoSuchId:
332
            return False
333
        return True
0.200.1208 by Jelmer Vernooij
Add GitWorkingTree.has_id and GitWorkingTree.has_or_had_id.
334
335
    def has_id(self, file_id):
336
        try:
337
            path = self.id2path(file_id)
338
        except errors.NoSuchId:
339
            return False
340
        return self.has_filename(path)
341
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
342
    def _lookup_path(self, path):
343
        if self.tree is None:
344
            raise errors.NoSuchFile(path)
345
        try:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
346
            (mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree,
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
347
                path.encode('utf-8'))
348
        except KeyError:
349
            raise errors.NoSuchFile(self, path)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
350
        else:
351
            return (self.store, mode, hexsha)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
352
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
353
    def is_executable(self, path, file_id=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
354
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1615 by Jelmer Vernooij
Implement GitRevisionTree.is_executable.:
355
        if mode is None:
356
            # the tree root is a directory
357
            return False
358
        return mode_is_executable(mode)
359
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
360
    def kind(self, path, file_id=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
361
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1253 by Jelmer Vernooij
Fix Tree.kind(TREE_ROOT).
362
        if mode is None:
363
            # the tree root is a directory
364
            return "directory"
0.200.1241 by Jelmer Vernooij
Implement GitRevisionTree.kind.
365
        return mode_kind(mode)
366
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
367
    def has_filename(self, path):
368
        try:
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
369
            self._lookup_path(path)
370
        except errors.NoSuchFile:
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
371
            return False
372
        else:
373
            return True
374
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
375
    def list_files(self, include_root=False, from_dir=None, recursive=True):
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
376
        if self.tree is None:
377
            return
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
378
        if from_dir is None:
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
379
            from_dir = u""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
380
        (store, mode, hexsha) = self._lookup_path(from_dir)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
381
        if mode is None: # Root
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
382
            root_ie = self._get_dir_ie(b"", None)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
383
        else:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
384
            parent_path = posixpath.dirname(from_dir.encode("utf-8"))
0.200.1328 by Jelmer Vernooij
More test fixes.
385
            parent_id = self._fileid_map.lookup_file_id(parent_path)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
386
            if mode_kind(mode) == 'directory':
387
                root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
388
            else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
389
                root_ie = self._get_file_ie(store, from_dir.encode("utf-8"),
0.264.10 by Jelmer Vernooij
Yield inventory entries.
390
                    posixpath.basename(from_dir), mode, hexsha)
391
        if from_dir != "" or include_root:
392
            yield (from_dir, "V", root_ie.kind, root_ie.file_id, root_ie)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
393
        todo = set()
0.264.10 by Jelmer Vernooij
Yield inventory entries.
394
        if root_ie.kind == 'directory':
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
395
            todo.add((store, from_dir.encode("utf-8"), hexsha, root_ie.file_id))
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
396
        while todo:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
397
            (store, path, hexsha, parent_id) = todo.pop()
398
            tree = store[hexsha]
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
399
            for name, mode, hexsha in tree.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
400
                if self.mapping.is_special_file(name):
401
                    continue
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
402
                child_path = posixpath.join(path, name)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
403
                if stat.S_ISDIR(mode):
404
                    ie = self._get_dir_ie(child_path, parent_id)
405
                    if recursive:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
406
                        todo.add((store, child_path, hexsha, ie.file_id))
0.264.10 by Jelmer Vernooij
Yield inventory entries.
407
                else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
408
                    ie = self._get_file_ie(store, child_path, name, mode, hexsha, parent_id)
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
409
                yield child_path.decode('utf-8'), "V", ie.kind, ie.file_id, ie
0.264.10 by Jelmer Vernooij
Yield inventory entries.
410
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
411
    def _get_file_ie(self, store, path, name, mode, hexsha, parent_id):
0.361.1 by Jelmer Vernooij
Don't use assert.
412
        if type(path) is not bytes:
413
            raise TypeError(path)
414
        if type(name) is not bytes:
415
            raise TypeError(name)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
416
        kind = mode_kind(mode)
0.200.1328 by Jelmer Vernooij
More test fixes.
417
        file_id = self._fileid_map.lookup_file_id(path)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
418
        ie = entry_factory[kind](file_id, name.decode("utf-8"), parent_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
419
        if kind == 'symlink':
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
420
            ie.symlink_target = store[hexsha].data.decode('utf-8')
0.200.1401 by Jelmer Vernooij
Cope with submodules in working trees.
421
        elif kind == 'tree-reference':
422
            ie.reference_revision = self.mapping.revision_id_foreign_to_bzr(hexsha)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
423
        else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
424
            data = store[hexsha].data
0.264.10 by Jelmer Vernooij
Yield inventory entries.
425
            ie.text_sha1 = osutils.sha_string(data)
426
            ie.text_size = len(data)
427
            ie.executable = mode_is_executable(mode)
428
        return ie
429
430
    def _get_dir_ie(self, path, parent_id):
0.200.1328 by Jelmer Vernooij
More test fixes.
431
        file_id = self._fileid_map.lookup_file_id(path)
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.
432
        return GitTreeDirectory(file_id,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
433
            posixpath.basename(path).decode("utf-8"), parent_id)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
434
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
435
    def iter_child_entries(self, path, file_id=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
436
        (store, mode, tree_sha) = self._lookup_path(path)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
437
438
        if not stat.S_ISDIR(mode):
439
            return
440
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
441
        encoded_path = path.encode('utf-8')
442
        file_id = self.path2id(path)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
443
        tree = store[tree_sha]
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
444
        for name, mode, hexsha in tree.iteritems():
445
            if self.mapping.is_special_file(name):
446
                continue
447
            child_path = posixpath.join(encoded_path, name)
448
            if stat.S_ISDIR(mode):
449
                yield self._get_dir_ie(child_path, file_id)
450
            else:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
451
                yield self._get_file_ie(store, child_path, name, mode, hexsha,
0.374.1 by Jelmer Vernooij
Implement GitRevisionTree.iter_child_entries.
452
                                        file_id)
453
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
454
    def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
0.287.4 by Jelmer Vernooij
Fix GitRevisionTree behaviour for null:
455
        if self.tree is None:
456
            return
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
457
        if yield_parents:
458
            # TODO(jelmer): Support yield parents
459
            raise NotImplementedError
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
460
        if specific_files is not None:
461
            if specific_files in ([""], []):
462
                specific_files = None
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
463
            else:
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
464
                specific_files = set([p.encode('utf-8') for p in specific_files])
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
465
        todo = set([(self.store, "", self.tree, None)])
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
466
        while todo:
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
467
            store, path, tree_sha, parent_id = todo.pop()
0.264.10 by Jelmer Vernooij
Yield inventory entries.
468
            ie = self._get_dir_ie(path, parent_id)
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
469
            if specific_files is None or path in specific_files:
0.200.1715 by Jelmer Vernooij
Fix some more tests.
470
                yield path.decode("utf-8"), ie
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
471
            tree = store[tree_sha]
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
472
            for name, mode, hexsha in tree.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
473
                if self.mapping.is_special_file(name):
474
                    continue
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
475
                child_path = posixpath.join(path, name)
476
                if stat.S_ISDIR(mode):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
477
                    if (specific_files is None or
478
                        any(filter(lambda p: p.startswith(child_path), specific_files))):
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
479
                        todo.add((store, child_path, hexsha, ie.file_id))
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
480
                elif specific_files is None or child_path in specific_files:
0.200.1715 by Jelmer Vernooij
Fix some more tests.
481
                    yield (child_path.decode("utf-8"),
0.400.3 by Jelmer Vernooij
Pass store in a few more places.
482
                            self._get_file_ie(store, child_path, name, mode, hexsha,
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
483
                           ie.file_id))
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
484
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
485
    def get_revision_id(self):
0.200.959 by Jelmer Vernooij
Improve docstrings.
486
        """See RevisionTree.get_revision_id."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
487
        return self._revision_id
488
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
489
    def get_file_sha1(self, path, file_id=None, stat_value=None):
0.287.6 by Jelmer Vernooij
Fix some more tests.
490
        if self.tree is None:
491
            raise errors.NoSuchFile(path)
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
492
        return osutils.sha_string(self.get_file_text(path, file_id))
0.200.1255 by Jelmer Vernooij
Implement GitRevisionTree.get_file_sha1.
493
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
494
    def get_file_verifier(self, path, file_id=None, stat_value=None):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
495
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
496
        return ("GIT", hexsha)
497
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
498
    def get_file_text(self, path, file_id=None):
0.200.959 by Jelmer Vernooij
Improve docstrings.
499
        """See RevisionTree.get_file_text."""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
500
        (store, mode, hexsha) = self._lookup_path(path)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
501
        if stat.S_ISREG(mode):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
502
            return store[hexsha].data
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
503
        else:
0.335.1 by Jelmer Vernooij
Be a bit stricter about encodings.
504
            return b""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
505
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
506
    def get_symlink_target(self, path, file_id=None):
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
507
        """See RevisionTree.get_symlink_target."""
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
508
        (store, mode, hexsha) = self._lookup_path(path)
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
509
        if stat.S_ISLNK(mode):
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
510
            return store[hexsha].data.decode('utf-8')
0.200.1466 by Jelmer Vernooij
Implement GitRevisionTree.get_symlink_target.
511
        else:
512
            return None
513
0.429.17 by Jelmer Vernooij
Fix some more tests.
514
    def get_reference_revision(self, path, file_id=None):
515
        """See RevisionTree.get_symlink_target."""
0.429.25 by Jelmer Vernooij
Merge trunk.
516
        (store, mode, hexsha) = self._lookup_path(path)
0.429.17 by Jelmer Vernooij
Fix some more tests.
517
        if S_ISGITLINK(mode):
0.429.26 by Jelmer Vernooij
Fix remaining test.
518
            nested_repo = self._get_nested_repository(path)
519
            return nested_repo.lookup_foreign_revision_id(hexsha)
0.429.17 by Jelmer Vernooij
Fix some more tests.
520
        else:
521
            return None
522
0.264.10 by Jelmer Vernooij
Yield inventory entries.
523
    def _comparison_data(self, entry, path):
524
        if entry is None:
525
            return None, False, None
526
        return entry.kind, entry.executable, None
527
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
528
    def path_content_summary(self, path):
529
        """See Tree.path_content_summary."""
530
        try:
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
531
            (store, mode, hexsha) = self._lookup_path(path)
0.381.1 by Jelmer Vernooij
Standardize looking up entries in Git trees.
532
        except errors.NoSuchFile:
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
533
            return ('missing', None, None, None)
534
        kind = mode_kind(mode)
535
        if kind == 'file':
536
            executable = mode_is_executable(mode)
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
537
            contents = store[hexsha].data
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
538
            return (kind, len(contents), executable, osutils.sha_string(contents))
539
        elif kind == 'symlink':
0.400.2 by Jelmer Vernooij
Return store from self._lookup_path.
540
            return (kind, None, None, store[hexsha].data)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
541
        elif kind == 'tree-reference':
0.429.26 by Jelmer Vernooij
Fix remaining test.
542
            nested_repo = self._get_nested_repository(path)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
543
            return (kind, None, None,
0.429.26 by Jelmer Vernooij
Fix remaining test.
544
                    nested_repo.lookup_foreign_revision_id(hexsha))
0.200.1568 by Jelmer Vernooij
Implement GitRevisionTree.path_content_summary.
545
        else:
546
            return (kind, None, None, None)
547
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
548
    def find_related_paths_across_trees(self, paths, trees=[],
549
            require_versioned=True):
550
        if paths is None:
551
            return None
552
        if require_versioned:
553
            trees = [self] + (trees if trees is not None else [])
554
            unversioned = set()
555
            for p in paths:
556
                for t in trees:
557
                    if t.is_versioned(p):
558
                        break
559
                else:
560
                    unversioned.add(p)
561
            if unversioned:
562
                raise errors.PathsNotVersionedError(unversioned)
563
        return filter(self.is_versioned, paths)
564
0.393.1 by Jelmer Vernooij
Avoid expensive bzr APIs in commit.
565
    def _iter_tree_contents(self, include_trees=False):
566
        if self.tree is None:
567
            return iter([])
568
        return self.store.iter_tree_contents(
569
                self.tree, include_trees=include_trees)
570
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
571
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
572
def tree_delta_from_git_changes(changes, mapping,
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
573
        (old_fileid_map, new_fileid_map), specific_files=None,
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
574
        require_versioned=False, include_root=False,
575
        target_extras=None):
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
576
    """Create a TreeDelta from two git trees.
0.200.959 by Jelmer Vernooij
Improve docstrings.
577
578
    source and target are iterators over tuples with:
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
579
        (filename, sha, mode)
580
    """
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
581
    if target_extras is None:
582
        target_extras = set()
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
583
    ret = delta.TreeDelta()
584
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
0.287.5 by Jelmer Vernooij
Fix root handling.
585
        if newpath == u'' and not include_root:
586
            continue
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
587
        if not (specific_files is None or
0.287.5 by Jelmer Vernooij
Fix root handling.
588
                (oldpath is not None and osutils.is_inside_or_parent_of_any(specific_files, oldpath)) or
589
                (newpath is not None and osutils.is_inside_or_parent_of_any(specific_files, newpath))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
590
            continue
0.200.1752 by Jelmer Vernooij
Don't traverse nested trees in WorkingTree.smart_add.
591
        if mapping.is_special_file(oldpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
592
            oldpath = None
0.200.1752 by Jelmer Vernooij
Don't traverse nested trees in WorkingTree.smart_add.
593
        if mapping.is_special_file(newpath):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
594
            newpath = None
595
        if oldpath is None and newpath is None:
596
            continue
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
597
        if oldpath is None:
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
598
            if newpath in target_extras:
599
                ret.unversioned.append(
600
                    (osutils.normalized_filename(newpath)[0], None, mode_kind(newmode)))
601
            else:
602
                file_id = new_fileid_map.lookup_file_id(newpath)
603
                ret.added.append((newpath.decode('utf-8'), file_id, mode_kind(newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
604
        elif newpath is None:
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
605
            file_id = old_fileid_map.lookup_file_id(oldpath)
606
            ret.removed.append((oldpath.decode('utf-8'), file_id, mode_kind(oldmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
607
        elif oldpath != newpath:
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
608
            file_id = old_fileid_map.lookup_file_id(oldpath)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
609
            ret.renamed.append(
610
                (oldpath.decode('utf-8'), newpath.decode('utf-8'), file_id,
611
                mode_kind(newmode), (oldsha != newsha),
612
                (oldmode != newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
613
        elif mode_kind(oldmode) != mode_kind(newmode):
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
614
            file_id = new_fileid_map.lookup_file_id(newpath)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
615
            ret.kind_changed.append(
616
                (newpath.decode('utf-8'), file_id, mode_kind(oldmode),
617
                mode_kind(newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
618
        elif oldsha != newsha or oldmode != newmode:
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
619
            if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
620
                continue
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
621
            file_id = new_fileid_map.lookup_file_id(newpath)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
622
            ret.modified.append(
623
                (newpath.decode('utf-8'), file_id, mode_kind(newmode),
624
                (oldsha != newsha), (oldmode != newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
625
        else:
0.200.1613 by Jelmer Vernooij
Handle encoding better in working tree iter changes.
626
            file_id = new_fileid_map.lookup_file_id(newpath)
627
            ret.unchanged.append((newpath.decode('utf-8'), file_id, mode_kind(newmode)))
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
628
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
629
    return ret
630
631
0.391.2 by Jelmer Vernooij
Pass along target_missing.
632
def changes_from_git_changes(changes, mapping, specific_files=None, include_unchanged=False,
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
633
                             target_extras=None):
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
634
    """Create a iter_changes-like generator from a git stream.
0.200.959 by Jelmer Vernooij
Improve docstrings.
635
636
    source and target are iterators over tuples with:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
637
        (filename, sha, mode)
638
    """
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
639
    if target_extras is None:
640
        target_extras = set()
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
641
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
642
        if not (specific_files is None or
0.287.5 by Jelmer Vernooij
Fix root handling.
643
                (oldpath is not None and osutils.is_inside_or_parent_of_any(specific_files, oldpath)) or
644
                (newpath is not None and osutils.is_inside_or_parent_of_any(specific_files, newpath))):
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
645
            continue
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
646
        path = (oldpath, newpath)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
647
        if oldpath is not None and mapping.is_special_file(oldpath):
648
            continue
649
        if newpath is not None and mapping.is_special_file(newpath):
0.200.1328 by Jelmer Vernooij
More test fixes.
650
            continue
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
651
        if oldpath is None:
652
            fileid = mapping.generate_file_id(newpath)
653
            oldexe = None
654
            oldkind = None
655
            oldname = None
656
            oldparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
657
            oldversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
658
        else:
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
659
            oldversioned = True
0.200.1345 by Jelmer Vernooij
paths should be unicode when yielded by iter_changes.
660
            oldpath = oldpath.decode("utf-8")
0.391.8 by Jelmer Vernooij
Allow missing items in old tree.
661
            if oldmode:
662
                oldexe = mode_is_executable(oldmode)
663
                oldkind = mode_kind(oldmode)
664
            else:
665
                oldexe = False
666
                oldkind = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
667
            if oldpath == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
668
                oldparent = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
669
                oldname = ''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
670
            else:
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
671
                (oldparentpath, oldname) = osutils.split(oldpath)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
672
                oldparent = mapping.generate_file_id(oldparentpath)
673
            fileid = mapping.generate_file_id(oldpath)
674
        if newpath is None:
675
            newexe = None
676
            newkind = None
677
            newname = None
678
            newparent = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
679
            newversioned = False
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
680
        else:
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
681
            newversioned = (newpath not in target_extras)
682
            if newmode:
0.200.1576 by Jelmer Vernooij
Merge a bunch of fixes from store-roundtrip-info.
683
                newexe = mode_is_executable(newmode)
684
                newkind = mode_kind(newmode)
685
            else:
686
                newexe = False
687
                newkind = None
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
688
            newpath = newpath.decode("utf-8")
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
689
            if newpath == u'':
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
690
                newparent = None
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
691
                newname = u''
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
692
            else:
0.316.1 by Jelmer Vernooij
Fix iter_changes behaviour for trees in the tree root.
693
                newparentpath, newname = osutils.split(newpath)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
694
                newparent = mapping.generate_file_id(newparentpath)
0.357.3 by Jelmer Vernooij
More remove fixes.
695
        if (not include_unchanged and
696
            oldkind == 'directory' and newkind == 'directory' and
697
            oldpath == newpath):
698
            continue
0.200.959 by Jelmer Vernooij
Improve docstrings.
699
        yield (fileid, (oldpath, newpath), (oldsha != newsha),
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
700
             (oldversioned, newversioned),
0.200.959 by Jelmer Vernooij
Improve docstrings.
701
             (oldparent, newparent), (oldname, newname),
702
             (oldkind, newkind), (oldexe, newexe))
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
703
704
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
705
class InterGitTrees(_mod_tree.InterTree):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
706
    """InterTree that works between two git trees."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
707
0.200.659 by Jelmer Vernooij
Prevent tests using InterGitRevisionTrees.
708
    _matching_from_tree_format = None
709
    _matching_to_tree_format = None
710
    _test_mutable_trees_to_test_trees = None
711
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
712
    @classmethod
713
    def is_compatible(cls, source, target):
0.200.959 by Jelmer Vernooij
Improve docstrings.
714
        return (isinstance(source, GitRevisionTree) and
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
715
                isinstance(target, GitRevisionTree))
716
717
    def compare(self, want_unchanged=False, specific_files=None,
718
                extra_trees=None, require_versioned=False, include_root=False,
719
                want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
720
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
721
            changes, target_extras = self._iter_git_changes(
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
722
                    want_unchanged=want_unchanged,
723
                    require_versioned=require_versioned,
724
                    specific_files=specific_files,
725
                    extra_trees=extra_trees,
726
                    want_unversioned=want_unversioned)
727
            source_fileid_map = self.source._fileid_map
728
            target_fileid_map = self.target._fileid_map
729
            return tree_delta_from_git_changes(changes, self.target.mapping,
730
                (source_fileid_map, target_fileid_map),
0.394.1 by Jelmer Vernooij
Fix reporting of extras in TreeDelta.
731
                specific_files=specific_files, include_root=include_root,
732
                target_extras=target_extras)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
733
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
734
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
735
                     pb=None, extra_trees=[], require_versioned=True,
736
                     want_unversioned=False):
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
737
        with self.lock_read():
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
738
            changes, target_extras = self._iter_git_changes(
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
739
                    want_unchanged=include_unchanged,
740
                    require_versioned=require_versioned,
741
                    specific_files=specific_files,
742
                    extra_trees=extra_trees,
743
                    want_unversioned=want_unversioned)
744
            return changes_from_git_changes(
745
                    changes, self.target.mapping,
746
                    specific_files=specific_files,
747
                    include_unchanged=include_unchanged,
0.391.7 by Jelmer Vernooij
Fix reporting of missing files in .iter_changes.
748
                    target_extras=target_extras)
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
749
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
750
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
751
            require_versioned=False, extra_trees=None,
752
            want_unversioned=False):
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
753
        raise NotImplementedError(self._iter_git_changes)
754
755
756
class InterGitRevisionTrees(InterGitTrees):
757
    """InterTree that works between two git revision trees."""
758
759
    _matching_from_tree_format = None
760
    _matching_to_tree_format = None
761
    _test_mutable_trees_to_test_trees = None
762
763
    @classmethod
764
    def is_compatible(cls, source, target):
765
        return (isinstance(source, GitRevisionTree) and
766
                isinstance(target, GitRevisionTree))
767
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
768
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
0.391.4 by Jelmer Vernooij
Simplify InterGitTrees implementation.
769
            require_versioned=True, extra_trees=None,
770
            want_unversioned=False):
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
771
        trees = [self.source]
772
        if extra_trees is not None:
773
            trees.extend(extra_trees)
774
        if specific_files is not None:
775
            specific_files = self.target.find_related_paths_across_trees(
776
                    specific_files, trees,
777
                    require_versioned=require_versioned)
0.357.1 by Jelmer Vernooij
Fix some remove tests.
778
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
779
        if self.source._repository._git.object_store != self.target._repository._git.object_store:
0.200.1780 by Jelmer Vernooij
Fix cross-object-store tree comparison.
780
            store = OverlayObjectStore([self.source._repository._git.object_store,
781
                                        self.target._repository._git.object_store])
782
        else:
783
            store = self.source._repository._git.object_store
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
784
        return self.source._repository._git.object_store.tree_changes(
785
            self.source.tree, self.target.tree, want_unchanged=want_unchanged,
0.391.2 by Jelmer Vernooij
Pass along target_missing.
786
            include_trees=True, change_type_same=True), set()
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
787
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
788
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
789
_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
790
791
792
class MutableGitIndexTree(mutabletree.MutableTree):
793
794
    def __init__(self):
795
        self._lock_mode = None
796
        self._lock_count = 0
797
        self._versioned_dirs = None
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
798
        self._index_dirty = False
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
799
800
    def is_versioned(self, path):
801
        with self.lock_read():
802
            path = path.rstrip('/').encode('utf-8')
0.429.1 by Jelmer Vernooij
Abstract away index access.
803
            (index, subpath) = self._lookup_index(path)
804
            return (subpath in index or self._has_dir(path))
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
805
806
    def _has_dir(self, path):
807
        if path == "":
808
            return True
809
        if self._versioned_dirs is None:
810
            self._load_dirs()
811
        return path in self._versioned_dirs
812
813
    def _load_dirs(self):
0.361.3 by Jelmer Vernooij
Merge trunk,
814
        if self._lock_mode is None:
815
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
816
        self._versioned_dirs = set()
0.429.1 by Jelmer Vernooij
Abstract away index access.
817
        # TODO(jelmer): Browse over all indexes
0.429.11 by Jelmer Vernooij
Merge trunk.
818
        for p, i in self._recurse_index_entries():
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
819
            self._ensure_versioned_dir(posixpath.dirname(p))
820
821
    def _ensure_versioned_dir(self, dirname):
822
        if dirname in self._versioned_dirs:
823
            return
824
        if dirname != "":
825
            self._ensure_versioned_dir(posixpath.dirname(dirname))
826
        self._versioned_dirs.add(dirname)
827
828
    def path2id(self, path):
829
        with self.lock_read():
830
            path = path.rstrip('/')
831
            if self.is_versioned(path.rstrip('/')):
832
                return self._fileid_map.lookup_file_id(path.encode("utf-8"))
833
            return None
834
835
    def has_id(self, file_id):
836
        try:
837
            self.id2path(file_id)
838
        except errors.NoSuchId:
839
            return False
840
        else:
841
            return True
842
843
    def id2path(self, file_id):
844
        if file_id is None:
845
            return ''
0.361.3 by Jelmer Vernooij
Merge trunk,
846
        if type(file_id) is not bytes:
847
            raise TypeError(file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
848
        with self.lock_read():
849
            try:
850
                path = self._fileid_map.lookup_path(file_id)
851
            except ValueError:
852
                raise errors.NoSuchId(self, file_id)
853
            path = path.decode('utf-8')
854
            if self.is_versioned(path):
855
                return path
856
            raise errors.NoSuchId(self, file_id)
857
858
    def _set_root_id(self, file_id):
859
        self._fileid_map.set_file_id("", file_id)
860
861
    def get_root_id(self):
862
        return self.path2id("")
863
864
    def _add(self, files, ids, kinds):
865
        for (path, file_id, kind) in zip(files, ids, kinds):
866
            if file_id is not None:
867
                raise workingtree.SettingFileIdUnsupported()
0.366.1 by Jelmer Vernooij
Fix normalized filename checking in add.
868
            path, can_access = osutils.normalized_filename(path)
869
            if not can_access:
870
                raise errors.InvalidNormalization(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
871
            self._index_add_entry(path, kind)
872
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
873
    def _read_submodule_head(self, path):
874
        raise NotImplementedError(self._read_submodule_head)
875
0.429.1 by Jelmer Vernooij
Abstract away index access.
876
    def _lookup_index(self, encoded_path):
877
        if not isinstance(encoded_path, bytes):
878
            raise TypeError(encoded_path)
0.429.11 by Jelmer Vernooij
Merge trunk.
879
        # TODO(jelmer): Look in other indexes
0.429.1 by Jelmer Vernooij
Abstract away index access.
880
        return self.index, encoded_path
881
0.429.25 by Jelmer Vernooij
Merge trunk.
882
    def _index_del_entry(self, index, path):
883
        del index[path]
884
        # TODO(jelmer): Keep track of dirty per index
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
885
        self._index_dirty = True
886
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
887
    def _index_add_entry(self, path, kind, flags=0, reference_revision=None):
0.361.4 by Jelmer Vernooij
Fix assert.
888
        if not isinstance(path, basestring):
0.361.3 by Jelmer Vernooij
Merge trunk,
889
            raise TypeError(path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
890
        if kind == "directory":
891
            # Git indexes don't contain directories
892
            return
893
        if kind == "file":
894
            blob = Blob()
895
            try:
896
                file, stat_val = self.get_file_with_stat(path)
897
            except (errors.NoSuchFile, IOError):
898
                # TODO: Rather than come up with something here, use the old index
899
                file = BytesIO()
900
                stat_val = os.stat_result(
901
                    (stat.S_IFREG | 0644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
902
            blob.set_raw_string(file.read())
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
903
            # Add object to the repository if it didn't exist yet
904
            if not blob.id in self.store:
905
                self.store.add_object(blob)
906
            hexsha = blob.id
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
907
        elif kind == "symlink":
908
            blob = Blob()
909
            try:
910
                stat_val = self._lstat(path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
911
            except EnvironmentError:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
912
                # TODO: Rather than come up with something here, use the
913
                # old index
914
                stat_val = os.stat_result(
915
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
916
            blob.set_raw_string(
917
                self.get_symlink_target(path).encode("utf-8"))
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
918
            # Add object to the repository if it didn't exist yet
919
            if not blob.id in self.store:
920
                self.store.add_object(blob)
921
            hexsha = blob.id
922
        elif kind == "tree-reference":
0.429.16 by Jelmer Vernooij
Look at reference_revision on ie.
923
            if reference_revision is not None:
924
                hexsha = self.branch.lookup_bzr_revision_id(reference_revision)[0]
925
            else:
926
                hexsha = self._read_submodule_head(path)
927
                if hexsha is None:
928
                    raise errors.NoCommits(path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
929
            try:
930
                stat_val = self._lstat(path)
931
            except EnvironmentError:
932
                stat_val = os.stat_result(
933
                    (S_IFGITLINK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
934
            stat_val = os.stat_result((S_IFGITLINK, ) + stat_val[1:])
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
935
        else:
936
            raise AssertionError("unknown kind '%s'" % kind)
937
        # Add an entry to the index or update the existing entry
938
        ensure_normalized_path(path)
939
        encoded_path = path.encode("utf-8")
940
        if b'\r' in encoded_path or b'\n' in encoded_path:
941
            # TODO(jelmer): Why do we need to do this?
942
            trace.mutter('ignoring path with invalid newline in it: %r', path)
943
            return
0.429.1 by Jelmer Vernooij
Abstract away index access.
944
        (index, index_path) = self._lookup_index(encoded_path)
0.429.2 by Jelmer Vernooij
Some more work on submodule support.
945
        index[index_path] = index_entry_from_stat(stat_val, hexsha, flags)
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
946
        self._index_dirty = True
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
947
        if self._versioned_dirs is not None:
0.429.1 by Jelmer Vernooij
Abstract away index access.
948
            self._ensure_versioned_dir(index_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
949
0.429.7 by Jelmer Vernooij
Consistent file ids.
950
    def _recurse_index_entries(self, index=None, basepath=""):
951
        # Iterate over all index entries
952
        with self.lock_read():
953
            if index is None:
954
                index = self.index
955
            for path, value in index.iteritems():
956
                yield (posixpath.join(basepath, path), value)
0.429.10 by Jelmer Vernooij
use new read_submodule_head from dulwich.
957
                (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
958
                if S_ISGITLINK(mode):
0.429.7 by Jelmer Vernooij
Consistent file ids.
959
                    pass # TODO(jelmer): dive into submodule
960
961
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
962
    def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
963
        if yield_parents:
964
            raise NotImplementedError(self.iter_entries_by_dir)
965
        with self.lock_read():
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
966
            if specific_files is not None:
967
                specific_files = set(specific_files)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
968
            else:
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
969
                specific_files = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
970
            root_ie = self._get_dir_ie(u"", None)
971
            ret = {}
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
972
            if specific_files is None or u"" in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
973
                ret[(None, u"")] = root_ie
974
            dir_ids = {u"": root_ie.file_id}
0.429.7 by Jelmer Vernooij
Consistent file ids.
975
            for path, value in self._recurse_index_entries():
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
976
                if self.mapping.is_special_file(path):
977
                    continue
978
                path = path.decode("utf-8")
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
979
                if specific_files is not None and not path in specific_files:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
980
                    continue
981
                (parent, name) = posixpath.split(path)
982
                try:
983
                    file_ie = self._get_file_ie(name, path, value, None)
984
                except errors.NoSuchFile:
985
                    continue
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
986
                if yield_parents or specific_files is None:
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
987
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
988
                            dir_ids):
989
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
0.429.12 by Jelmer Vernooij
Remove revision.
990
                file_ie.parent_id = self.path2id(parent)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
991
                ret[(posixpath.dirname(path), path)] = file_ie
992
            return ((path, ie) for ((_, path), ie) in sorted(ret.items()))
993
0.429.7 by Jelmer Vernooij
Consistent file ids.
994
    def iter_references(self):
995
        # TODO(jelmer): Implement a more efficient version of this
996
        for path, entry in self.iter_entries_by_dir():
997
            if entry.kind == 'tree-reference':
0.429.20 by Jelmer Vernooij
Fix iter_references.
998
                yield path, self.mapping.generate_file_id(b'')
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
999
1000
    def _get_dir_ie(self, path, parent_id):
1001
        file_id = self.path2id(path)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1002
        return GitTreeDirectory(file_id,
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1003
            posixpath.basename(path).strip("/"), parent_id)
1004
1005
    def _get_file_ie(self, name, path, value, parent_id):
0.361.3 by Jelmer Vernooij
Merge trunk,
1006
        if type(name) is not unicode:
1007
            raise TypeError(name)
1008
        if type(path) is not unicode:
1009
            raise TypeError(path)
1010
        if not isinstance(value, tuple) or len(value) != 10:
1011
            raise TypeError(value)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1012
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
1013
        file_id = self.path2id(path)
1014
        if type(file_id) != str:
1015
            raise AssertionError
1016
        kind = mode_kind(mode)
0.365.1 by Jelmer Vernooij
Add custom GitTree{Directory,File,Symlink}.
1017
        ie = entry_factory[kind](file_id, name, parent_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1018
        if kind == 'symlink':
1019
            ie.symlink_target = self.get_symlink_target(path, file_id)
0.429.7 by Jelmer Vernooij
Consistent file ids.
1020
        elif kind == 'tree-reference':
1021
            ie.reference_revision = self.get_reference_revision(path, file_id)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1022
        else:
1023
            try:
1024
                data = self.get_file_text(path, file_id)
1025
            except errors.NoSuchFile:
1026
                data = None
1027
            except IOError as e:
1028
                if e.errno != errno.ENOENT:
1029
                    raise
1030
                data = None
1031
            if data is None:
1032
                data = self.branch.repository._git.object_store[sha].data
1033
            ie.text_sha1 = osutils.sha_string(data)
1034
            ie.text_size = len(data)
1035
            ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1036
        return ie
1037
1038
    def _add_missing_parent_ids(self, path, dir_ids):
1039
        if path in dir_ids:
1040
            return []
1041
        parent = posixpath.dirname(path).strip("/")
1042
        ret = self._add_missing_parent_ids(parent, dir_ids)
1043
        parent_id = dir_ids[parent]
1044
        ie = self._get_dir_ie(path, parent_id)
1045
        dir_ids[path] = ie.file_id
1046
        ret.append((path, ie))
1047
        return ret
1048
1049
    def _comparison_data(self, entry, path):
1050
        if entry is None:
1051
            return None, False, None
1052
        return entry.kind, entry.executable, None
1053
1054
    def _unversion_path(self, path):
0.361.3 by Jelmer Vernooij
Merge trunk,
1055
        if self._lock_mode is None:
1056
            raise errors.ObjectNotLocked(self)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1057
        encoded_path = path.encode("utf-8")
1058
        count = 0
0.429.1 by Jelmer Vernooij
Abstract away index access.
1059
        (index, subpath) = self._lookup_index(encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1060
        try:
0.429.25 by Jelmer Vernooij
Merge trunk.
1061
            self._index_del_entry(index, encoded_path)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1062
        except KeyError:
1063
            # A directory, perhaps?
0.429.1 by Jelmer Vernooij
Abstract away index access.
1064
            # TODO(jelmer): Deletes that involve submodules?
1065
            for p in list(index):
1066
                if p.startswith(subpath+b"/"):
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1067
                    count += 1
0.429.25 by Jelmer Vernooij
Merge trunk.
1068
                    self._index_del_entry(index, p)
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1069
        else:
1070
            count = 1
1071
        self._versioned_dirs = None
1072
        return count
1073
1074
    def unversion(self, paths, file_ids=None):
1075
        with self.lock_tree_write():
1076
            for path in paths:
1077
                if self._unversion_path(path) == 0:
1078
                    raise errors.NoSuchFile(path)
1079
            self._versioned_dirs = None
1080
            self.flush()
1081
1082
    def flush(self):
1083
        pass
1084
1085
    def update_basis_by_delta(self, revid, delta):
1086
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
1087
        for (old_path, new_path, file_id, ie) in delta:
0.429.1 by Jelmer Vernooij
Abstract away index access.
1088
            if old_path is not None:
1089
                (index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
1090
                if old_subpath in index:
0.429.25 by Jelmer Vernooij
Merge trunk.
1091
                    self._index_del_entry(index, old_subpath)
0.429.1 by Jelmer Vernooij
Abstract away index access.
1092
                    self._versioned_dirs = None
0.360.1 by Jelmer Vernooij
Implement GitMemoryTree.
1093
            if new_path is not None and ie.kind != 'directory':
1094
                self._index_add_entry(new_path, ie.kind)
1095
        self.flush()
1096
        self._set_merges_from_parent_ids([])
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1097
1098
    def move(self, from_paths, to_dir=None, after=None):
1099
        rename_tuples = []
1100
        with self.lock_tree_write():
1101
            to_abs = self.abspath(to_dir)
1102
            if not os.path.isdir(to_abs):
1103
                raise errors.BzrMoveFailedError('', to_dir,
1104
                    errors.NotADirectory(to_abs))
1105
1106
            for from_rel in from_paths:
1107
                from_tail = os.path.split(from_rel)[-1]
1108
                to_rel = os.path.join(to_dir, from_tail)
1109
                self.rename_one(from_rel, to_rel, after=after)
1110
                rename_tuples.append((from_rel, to_rel))
1111
            self.flush()
1112
            return rename_tuples
1113
1114
    def rename_one(self, from_rel, to_rel, after=None):
1115
        from_path = from_rel.encode("utf-8")
1116
        to_rel, can_access = osutils.normalized_filename(to_rel)
1117
        if not can_access:
1118
            raise errors.InvalidNormalization(to_rel)
1119
        to_path = to_rel.encode("utf-8")
1120
        with self.lock_tree_write():
1121
            if not after:
1122
                # Perhaps it's already moved?
1123
                after = (
1124
                    not self.has_filename(from_rel) and
1125
                    self.has_filename(to_rel) and
1126
                    not self.is_versioned(to_rel))
1127
            if after:
1128
                if not self.has_filename(to_rel):
1129
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1130
                        errors.NoSuchFile(to_rel))
1131
                if self.basis_tree().is_versioned(to_rel):
1132
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1133
                        errors.AlreadyVersionedError(to_rel))
1134
1135
                kind = self.kind(to_rel)
1136
            else:
1137
                try:
1138
                    to_kind = self.kind(to_rel)
1139
                except errors.NoSuchFile:
1140
                    exc_type = errors.BzrRenameFailedError
1141
                    to_kind = None
1142
                else:
1143
                    exc_type = errors.BzrMoveFailedError
1144
                if self.is_versioned(to_rel):
1145
                    raise exc_type(from_rel, to_rel,
1146
                        errors.AlreadyVersionedError(to_rel))
1147
                if not self.has_filename(from_rel):
1148
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1149
                        errors.NoSuchFile(from_rel))
0.388.1 by Jelmer Vernooij
Don't print error moving to an unversioned directory.
1150
                kind = self.kind(from_rel)
1151
                if not self.is_versioned(from_rel) and kind != 'directory':
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1152
                    raise exc_type(from_rel, to_rel,
1153
                        errors.NotVersionedError(from_rel))
1154
                if self.has_filename(to_rel):
1155
                    raise errors.RenameFailedFilesExist(
1156
                        from_rel, to_rel, errors.FileExists(to_rel))
1157
1158
                kind = self.kind(from_rel)
1159
0.429.1 by Jelmer Vernooij
Abstract away index access.
1160
            if not after and kind != 'directory':
1161
                (index, from_subpath) = self._lookup_index(from_path)
1162
                if from_subpath not in index:
1163
                    # It's not a file
1164
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
1165
                        errors.NotVersionedError(path=from_rel))
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1166
1167
            if not after:
1168
                try:
1169
                    self._rename_one(from_rel, to_rel)
1170
                except OSError as e:
1171
                    if e.errno == errno.ENOENT:
1172
                        raise errors.BzrMoveFailedError(from_rel, to_rel,
1173
                            errors.NoSuchFile(to_rel))
1174
                    raise
1175
            if kind != 'directory':
0.429.13 by Jelmer Vernooij
Fix regressions.
1176
                (index, from_index_path) = self._lookup_index(from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1177
                try:
0.429.25 by Jelmer Vernooij
Merge trunk.
1178
                    self._index_del_entry(index, from_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1179
                except KeyError:
1180
                    pass
1181
                self._index_add_entry(to_rel, kind)
1182
            else:
0.429.11 by Jelmer Vernooij
Merge trunk.
1183
                todo = [(p, i) for (p, i) in self._recurse_index_entries() if p.startswith(from_path+'/')]
0.429.13 by Jelmer Vernooij
Fix regressions.
1184
                for child_path, child_value in todo:
1185
                    (child_to_index, child_to_index_path) = self._lookup_index(posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
1186
                    child_to_index[child_to_index_path] = child_value
0.429.25 by Jelmer Vernooij
Merge trunk.
1187
                    # TODO(jelmer): Mark individual index as dirty
0.415.1 by Jelmer Vernooij
Only write index when it's dirty.
1188
                    self._index_dirty = True
0.429.13 by Jelmer Vernooij
Fix regressions.
1189
                    (child_from_index, child_from_index_path) = self._lookup_index(child_path)
0.429.25 by Jelmer Vernooij
Merge trunk.
1190
                    self._index_del_entry(child_from_index, child_from_index_path)
0.360.4 by Jelmer Vernooij
Implement MemoryTree.rename_one, MemoryTree.mkdir.
1191
1192
            self._versioned_dirs = None
1193
            self.flush()
0.385.1 by Jelmer Vernooij
Use specific_files argument to Tree.iter_entries_by_dir.
1194
1195
    def find_related_paths_across_trees(self, paths, trees=[],
1196
            require_versioned=True):
1197
        if paths is None:
1198
            return None
1199
1200
        if require_versioned:
1201
            trees = [self] + (trees if trees is not None else [])
1202
            unversioned = set()
1203
            for p in paths:
1204
                for t in trees:
1205
                    if t.is_versioned(p):
1206
                        break
1207
                else:
1208
                    unversioned.add(p)
1209
            if unversioned:
1210
                raise errors.PathsNotVersionedError(unversioned)
1211
1212
        return filter(self.is_versioned, paths)
0.429.5 by Jelmer Vernooij
Fix tree_content_summary test.
1213
1214
    def path_content_summary(self, path):
1215
        """See Tree.path_content_summary."""
1216
        try:
1217
            stat_result = self._lstat(path)
1218
        except OSError as e:
1219
            if getattr(e, 'errno', None) == errno.ENOENT:
1220
                # no file.
1221
                return ('missing', None, None, None)
1222
            # propagate other errors
1223
            raise
1224
        kind = mode_kind(stat_result.st_mode)
1225
        if kind == 'file':
1226
            return self._file_content_summary(path, stat_result)
1227
        elif kind == 'directory':
1228
            # perhaps it looks like a plain directory, but it's really a
1229
            # reference.
1230
            if self._directory_is_tree_reference(path):
1231
                kind = 'tree-reference'
1232
            return kind, None, None, None
1233
        elif kind == 'symlink':
1234
            target = osutils.readlink(self.abspath(path))
1235
            return ('symlink', None, None, target)
1236
        else:
1237
            return (kind, None, None, None)
1238
1239
    def kind(self, relpath, file_id=None):
0.429.15 by Jelmer Vernooij
Autodetect tree-reference based on index.
1240
        kind = osutils.file_kind(self.abspath(relpath))
1241
        if kind == 'directory':
1242
            (index, index_path) = self._lookup_index(relpath.encode('utf-8'))
1243
            try:
1244
                mode = index[index_path].mode
1245
            except KeyError:
1246
                return kind
1247
            else:
1248
                if S_ISGITLINK(mode):
1249
                    return 'tree-reference'
1250
                return 'directory'
1251
        else:
1252
            return kind