/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
1
# Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
18
"""Git Trees."""
19
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
20
from dulwich.object_store import tree_lookup_path
21
import stat
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
22
import posixpath
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
23
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
24
from bzrlib import (
25
    delta,
26
    errors,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
27
    inventory,
28
    osutils,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
29
    revisiontree,
30
    tree,
31
    )
32
33
from bzrlib.plugins.git.mapping import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
34
    mode_is_executable,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
35
    mode_kind,
36
    )
37
38
39
class GitRevisionTree(revisiontree.RevisionTree):
0.200.959 by Jelmer Vernooij
Improve docstrings.
40
    """Revision tree implementation based on Git objects."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
41
42
    def __init__(self, repository, revision_id):
43
        self._revision_id = revision_id
44
        self._repository = repository
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
45
        self.store = repository._git.object_store
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
46
        assert isinstance(revision_id, str)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
47
        self.commit_id, self.mapping = repository.lookup_bzr_revision_id(revision_id)
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
48
        try:
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
49
            commit = self.store[self.commit_id]
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
50
        except KeyError, r:
51
            raise errors.NoSuchRevision(repository, revision_id)
52
        self.tree = commit.tree
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
53
        self.fileid_map = self.mapping.get_fileid_map(self.store.__getitem__, self.tree)
54
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
55
    def get_file_revision(self, file_id, path=None):
56
        if path is None:
57
            path = self.id2path(file_id)
58
        change_scanner = self._repository._file_change_scanner
59
        (path, commit_id) = change_scanner.find_last_change_revision(path,
60
            self.commit_id)
61
        return self._repository.lookup_foreign_revision_id(commit_id, self.mapping)
62
63
    def get_file_mtime(self, file_id, path=None):
64
        revid = self.get_file_revision(file_id, path)
65
        try:
66
            rev = self._repository.get_revision(revid)
67
        except errors.NoSuchRevision:
68
            raise errors.FileTimestampUnavailable(path)
69
        return rev.timestamp
70
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
71
    def id2path(self, file_id):
72
        return self.fileid_map.lookup_path(file_id)
73
74
    def path2id(self, path):
75
        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.
76
0.200.1204 by Jelmer Vernooij
Implement GitRevisionTree.get_root_id().
77
    def get_root_id(self):
78
        return self.path2id("")
79
0.200.1208 by Jelmer Vernooij
Add GitWorkingTree.has_id and GitWorkingTree.has_or_had_id.
80
    def has_or_had_id(self, file_id):
81
        return self.has_id(file_id)
82
83
    def has_id(self, file_id):
84
        try:
85
            path = self.id2path(file_id)
86
        except errors.NoSuchId:
87
            return False
88
        return self.has_filename(path)
89
0.200.1241 by Jelmer Vernooij
Implement GitRevisionTree.kind.
90
    def kind(self, file_id, path=None):
91
        if path is None:
0.200.1248 by Jelmer Vernooij
Fix handling of path in Tree.kind.
92
            path = self.id2path(file_id)
0.200.1283 by Jelmer Vernooij
Provide Repository.get_file_graph() and Tree.get_file_revision().
93
        try:
94
            (mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree,
95
                path)
96
        except KeyError:
97
            raise errors.NoSuchId(self, file_id)
0.200.1253 by Jelmer Vernooij
Fix Tree.kind(TREE_ROOT).
98
        if mode is None:
99
            # the tree root is a directory
100
            return "directory"
0.200.1241 by Jelmer Vernooij
Implement GitRevisionTree.kind.
101
        return mode_kind(mode)
102
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
103
    def has_filename(self, path):
104
        try:
105
            tree_lookup_path(self.store.__getitem__, self.tree,
106
                path.encode("utf-8"))
107
        except KeyError:
108
            return False
109
        else:
110
            return True
111
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
112
    def list_files(self, include_root=False, from_dir=None, recursive=True):
113
        if from_dir is None:
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
114
            from_dir = u""
115
        (mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree,
116
            from_dir.encode("utf-8"))
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
117
        if mode is None: # Root
0.264.10 by Jelmer Vernooij
Yield inventory entries.
118
            root_ie = self._get_dir_ie("", None)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
119
        else:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
120
            parent_path = posixpath.dirname(from_dir.encode("utf-8"))
121
            parent_id = self.fileid_map.lookup_file_id(parent_path)
122
            if mode_kind(mode) == 'directory':
123
                root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
124
            else:
125
                root_ie = self._get_file_ie(from_dir.encode("utf-8"),
126
                    posixpath.basename(from_dir), mode, hexsha)
127
        if from_dir != "" or include_root:
128
            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.
129
        todo = set()
0.264.10 by Jelmer Vernooij
Yield inventory entries.
130
        if root_ie.kind == 'directory':
131
            todo.add((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.
132
        while todo:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
133
            (path, hexsha, parent_id) = todo.pop()
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
134
            tree = self.store[hexsha]
135
            for name, mode, hexsha in tree.iteritems():
136
                child_path = posixpath.join(path, name)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
137
                if stat.S_ISDIR(mode):
138
                    ie = self._get_dir_ie(child_path, parent_id)
139
                    if recursive:
140
                        todo.add((child_path, hexsha, ie.file_id))
141
                else:
142
                    ie = self._get_file_ie(child_path, name, mode, hexsha, parent_id)
143
                yield child_path, "V", ie.kind, ie.file_id, ie
144
145
    def _get_file_ie(self, path, name, mode, hexsha, parent_id):
146
        kind = mode_kind(mode)
147
        file_id = self.fileid_map.lookup_file_id(path)
148
        ie = inventory.entry_factory[kind](file_id, name.decode("utf-8"), parent_id)
149
        if kind == 'symlink':
150
            ie.symlink_target = self.store[hexsha].data
151
        else:
152
            data = self.store[hexsha].data
153
            ie.text_sha1 = osutils.sha_string(data)
154
            ie.text_size = len(data)
155
            ie.executable = mode_is_executable(mode)
156
        return ie
157
158
    def _get_dir_ie(self, path, parent_id):
159
        file_id = self.fileid_map.lookup_file_id(path)
160
        return inventory.InventoryDirectory(file_id,
161
            posixpath.basename(path).decode("utf-8"), parent_id)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
162
163
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
164
        # FIXME: Support yield parents
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
165
        if specific_file_ids is not None:
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
166
            specific_paths = [self.id2path(file_id) for file_id in specific_file_ids]
167
            if specific_paths in ([u""], []):
168
                specific_paths = None
169
            else:
170
                specific_paths = set(specific_paths)
171
        else:
172
            specific_paths = None
0.264.10 by Jelmer Vernooij
Yield inventory entries.
173
        todo = set([("", self.tree, None)])
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
174
        while todo:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
175
            path, tree_sha, parent_id = todo.pop()
176
            ie = self._get_dir_ie(path, parent_id)
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
177
            if specific_paths is None or path in specific_paths:
178
                yield path, ie
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
179
            tree = self.store[tree_sha]
180
            for name, mode, hexsha  in tree.iteritems():
181
                child_path = posixpath.join(path, name)
182
                if stat.S_ISDIR(mode):
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
183
                    if (specific_paths is None or
184
                        any(filter(lambda p: p.startswith(child_path), specific_paths))):
185
                        todo.add((child_path, hexsha, ie.file_id))
186
                elif specific_paths is None or child_path in specific_paths:
0.200.1307 by Jelmer Vernooij
Formatting fixes, specify path to a couple more functions.
187
                    yield (child_path,
188
                            self._get_file_ie(child_path, name, mode, hexsha,
0.200.1285 by Jelmer Vernooij
Support specific_file_ids argument to Tree.iter_entries_by_dir.
189
                           ie.file_id))
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
190
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
191
    def get_revision_id(self):
0.200.959 by Jelmer Vernooij
Improve docstrings.
192
        """See RevisionTree.get_revision_id."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
193
        return self._revision_id
194
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
195
    def get_file_sha1(self, file_id, path=None, stat_value=None):
0.200.1255 by Jelmer Vernooij
Implement GitRevisionTree.get_file_sha1.
196
        return osutils.sha_string(self.get_file_text(file_id, path))
197
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
198
    def get_file_verifier(self, file_id, path=None, stat_value=None):
199
        if path is None:
200
            path = self.id2path(file_id)
201
        (mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree,
202
            path)
203
        return ("GIT", hexsha)
204
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
205
    def get_file_text(self, file_id, path=None):
0.200.959 by Jelmer Vernooij
Improve docstrings.
206
        """See RevisionTree.get_file_text."""
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
207
        if path is None:
208
            path = self.id2path(file_id)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
209
        (mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree, path)
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
210
        if stat.S_ISREG(mode):
211
            return self.store[hexsha].data
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
212
        else:
0.200.664 by Jelmer Vernooij
Support submodules during fetch.
213
            return ""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
214
0.264.10 by Jelmer Vernooij
Yield inventory entries.
215
    def _comparison_data(self, entry, path):
216
        if entry is None:
217
            return None, False, None
218
        return entry.kind, entry.executable, None
219
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
220
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
221
def tree_delta_from_git_changes(changes, mapping,
222
        (old_fileid_map, new_fileid_map), specific_file=None,
223
        require_versioned=False):
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
224
    """Create a TreeDelta from two git trees.
0.200.959 by Jelmer Vernooij
Improve docstrings.
225
226
    source and target are iterators over tuples with:
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
227
        (filename, sha, mode)
228
    """
229
    ret = delta.TreeDelta()
230
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
231
        if mapping.is_control_file(oldpath):
232
            oldpath = None
233
        if mapping.is_control_file(newpath):
234
            newpath = None
235
        if oldpath is None and newpath is None:
236
            continue
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
237
        if oldpath is None:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
238
            ret.added.append((newpath, new_fileid_map.lookup_file_id(newpath.encode("utf-8")), mode_kind(newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
239
        elif newpath is None:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
240
            ret.removed.append((oldpath, old_fileid_map.lookup_file_id(oldpath.encode("utf-8")), mode_kind(oldmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
241
        elif oldpath != newpath:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
242
            ret.renamed.append((oldpath, newpath, old_fileid_map.lookup_file_id(oldpath.encode("utf-8")), mode_kind(newmode), (oldsha != newsha), (oldmode != newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
243
        elif mode_kind(oldmode) != mode_kind(newmode):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
244
            ret.kind_changed.append((newpath, new_fileid_map.lookup_file_id(newpath.encode("utf-8")), mode_kind(oldmode), mode_kind(newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
245
        elif oldsha != newsha or oldmode != newmode:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
246
            ret.modified.append((newpath, new_fileid_map.lookup_file_id(newpath.encode("utf-8")), mode_kind(newmode), (oldsha != newsha), (oldmode != newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
247
        else:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
248
            ret.unchanged.append((newpath, new_fileid_map.lookup_file_id(newpath.encode("utf-8")), mode_kind(newmode)))
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
249
    return ret
250
251
0.200.959 by Jelmer Vernooij
Improve docstrings.
252
def changes_from_git_changes(changes, mapping, specific_file=None,
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
253
                                require_versioned=False):
254
    """Create a iter_changes-like generator from a git stream.
0.200.959 by Jelmer Vernooij
Improve docstrings.
255
256
    source and target are iterators over tuples with:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
257
        (filename, sha, mode)
258
    """
259
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
260
        path = (oldpath, newpath)
261
        if oldpath is None:
262
            fileid = mapping.generate_file_id(newpath)
263
            oldexe = None
264
            oldkind = None
265
            oldname = None
266
            oldparent = None
267
        else:
268
            oldexe = mode_is_executable(oldmode)
269
            oldkind = mode_kind(oldmode)
270
            try:
271
                (oldparentpath, oldname) = oldpath.rsplit("/", 1)
272
            except ValueError:
273
                oldparent = None
274
                oldname = oldpath
275
            else:
276
                oldparent = mapping.generate_file_id(oldparentpath)
277
            fileid = mapping.generate_file_id(oldpath)
278
        if newpath is None:
279
            newexe = None
280
            newkind = None
281
            newname = None
282
            newparent = None
283
        else:
284
            newexe = mode_is_executable(newmode)
285
            newkind = mode_kind(newmode)
286
            try:
287
                newparentpath, newname = newpath.rsplit("/", 1)
288
            except ValueError:
289
                newparent = None
290
                newname = newpath
291
            else:
292
                newparent = mapping.generate_file_id(newparentpath)
0.200.959 by Jelmer Vernooij
Improve docstrings.
293
        yield (fileid, (oldpath, newpath), (oldsha != newsha),
294
             (oldpath is not None, newpath is not None),
295
             (oldparent, newparent), (oldname, newname),
296
             (oldkind, newkind), (oldexe, newexe))
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
297
298
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
299
class InterGitRevisionTrees(tree.InterTree):
300
    """InterTree that works between two git revision trees."""
301
0.200.659 by Jelmer Vernooij
Prevent tests using InterGitRevisionTrees.
302
    _matching_from_tree_format = None
303
    _matching_to_tree_format = None
304
    _test_mutable_trees_to_test_trees = None
305
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
306
    @classmethod
307
    def is_compatible(cls, source, target):
0.200.959 by Jelmer Vernooij
Improve docstrings.
308
        return (isinstance(source, GitRevisionTree) and
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
309
                isinstance(target, GitRevisionTree))
310
311
    def compare(self, want_unchanged=False, specific_files=None,
312
                extra_trees=None, require_versioned=False, include_root=False,
313
                want_unversioned=False):
314
        if self.source._repository._git.object_store != self.target._repository._git.object_store:
315
            raise AssertionError
316
        changes = self.source._repository._git.object_store.tree_changes(
317
            self.source.tree, self.target.tree, want_unchanged=want_unchanged)
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
318
        source_fileid_map = self.source.mapping.get_fileid_map(
319
            self.source._repository._git.object_store.__getitem__,
320
            self.source.tree)
321
        target_fileid_map = self.target.mapping.get_fileid_map(
322
            self.target._repository._git.object_store.__getitem__,
323
            self.target.tree)
0.200.959 by Jelmer Vernooij
Improve docstrings.
324
        return tree_delta_from_git_changes(changes, self.target.mapping,
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
325
            (source_fileid_map, target_fileid_map),
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
326
            specific_file=specific_files)
327
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
328
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.200.959 by Jelmer Vernooij
Improve docstrings.
329
        pb=None, extra_trees=[], require_versioned=True,
330
        want_unversioned=False):
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
331
        if self.source._repository._git.object_store != self.target._repository._git.object_store:
332
            raise AssertionError
333
        changes = self.source._repository._git.object_store.tree_changes(
0.200.959 by Jelmer Vernooij
Improve docstrings.
334
            self.source.tree, self.target.tree,
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
335
            want_unchanged=include_unchanged)
0.200.959 by Jelmer Vernooij
Improve docstrings.
336
        return changes_from_git_changes(changes, self.target.mapping,
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
337
            specific_file=specific_files)
338
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
339
340
tree.InterTree.register_optimiser(InterGitRevisionTrees)