/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.650 by Jelmer Vernooij
Use standard names for lookup functions.
47
        git_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.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
49
            commit = self.store[git_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
55
    def id2path(self, file_id):
56
        return self.fileid_map.lookup_path(file_id)
57
58
    def path2id(self, path):
59
        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.
60
0.200.1204 by Jelmer Vernooij
Implement GitRevisionTree.get_root_id().
61
    def get_root_id(self):
62
        return self.path2id("")
63
0.200.1208 by Jelmer Vernooij
Add GitWorkingTree.has_id and GitWorkingTree.has_or_had_id.
64
    def has_or_had_id(self, file_id):
65
        return self.has_id(file_id)
66
67
    def has_id(self, file_id):
68
        try:
69
            path = self.id2path(file_id)
70
        except errors.NoSuchId:
71
            return False
72
        return self.has_filename(path)
73
0.200.1241 by Jelmer Vernooij
Implement GitRevisionTree.kind.
74
    def kind(self, file_id, path=None):
75
        if path is None:
0.200.1248 by Jelmer Vernooij
Fix handling of path in Tree.kind.
76
            path = self.id2path(file_id)
0.200.1241 by Jelmer Vernooij
Implement GitRevisionTree.kind.
77
        (mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree, path)
0.200.1253 by Jelmer Vernooij
Fix Tree.kind(TREE_ROOT).
78
        if mode is None:
79
            # the tree root is a directory
80
            return "directory"
0.200.1241 by Jelmer Vernooij
Implement GitRevisionTree.kind.
81
        return mode_kind(mode)
82
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
83
    def has_filename(self, path):
84
        try:
85
            tree_lookup_path(self.store.__getitem__, self.tree,
86
                path.encode("utf-8"))
87
        except KeyError:
88
            return False
89
        else:
90
            return True
91
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
92
    def list_files(self, include_root=False, from_dir=None, recursive=True):
93
        if from_dir is None:
0.200.1197 by Jelmer Vernooij
Implement GitRevisionTree.has_filename.
94
            from_dir = u""
95
        (mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree,
96
            from_dir.encode("utf-8"))
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
97
        if mode is None: # Root
0.264.10 by Jelmer Vernooij
Yield inventory entries.
98
            root_ie = self._get_dir_ie("", None)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
99
        else:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
100
            parent_path = posixpath.dirname(from_dir.encode("utf-8"))
101
            parent_id = self.fileid_map.lookup_file_id(parent_path)
102
            if mode_kind(mode) == 'directory':
103
                root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
104
            else:
105
                root_ie = self._get_file_ie(from_dir.encode("utf-8"),
106
                    posixpath.basename(from_dir), mode, hexsha)
107
        if from_dir != "" or include_root:
108
            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.
109
        todo = set()
0.264.10 by Jelmer Vernooij
Yield inventory entries.
110
        if root_ie.kind == 'directory':
111
            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.
112
        while todo:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
113
            (path, hexsha, parent_id) = todo.pop()
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
114
            tree = self.store[hexsha]
115
            for name, mode, hexsha in tree.iteritems():
116
                child_path = posixpath.join(path, name)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
117
                if stat.S_ISDIR(mode):
118
                    ie = self._get_dir_ie(child_path, parent_id)
119
                    if recursive:
120
                        todo.add((child_path, hexsha, ie.file_id))
121
                else:
122
                    ie = self._get_file_ie(child_path, name, mode, hexsha, parent_id)
123
                yield child_path, "V", ie.kind, ie.file_id, ie
124
125
    def _get_file_ie(self, path, name, mode, hexsha, parent_id):
126
        kind = mode_kind(mode)
127
        file_id = self.fileid_map.lookup_file_id(path)
128
        ie = inventory.entry_factory[kind](file_id, name.decode("utf-8"), parent_id)
129
        if kind == 'symlink':
130
            ie.symlink_target = self.store[hexsha].data
131
        else:
132
            data = self.store[hexsha].data
133
            ie.text_sha1 = osutils.sha_string(data)
134
            ie.text_size = len(data)
135
            ie.executable = mode_is_executable(mode)
136
        return ie
137
138
    def _get_dir_ie(self, path, parent_id):
139
        file_id = self.fileid_map.lookup_file_id(path)
140
        return inventory.InventoryDirectory(file_id,
141
            posixpath.basename(path).decode("utf-8"), parent_id)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
142
143
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
144
        # FIXME: Support specific_file_ids
145
        #FIXME: yield actual inventory entries
146
        if specific_file_ids is not None:
147
            raise NotImplementedError(self.iter_entries_by_dir)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
148
        todo = set([("", self.tree, None)])
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
149
        while todo:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
150
            path, tree_sha, parent_id = todo.pop()
151
            ie = self._get_dir_ie(path, parent_id)
152
            yield path, ie
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
153
            tree = self.store[tree_sha]
154
            for name, mode, hexsha  in tree.iteritems():
155
                child_path = posixpath.join(path, name)
156
                if stat.S_ISDIR(mode):
0.264.10 by Jelmer Vernooij
Yield inventory entries.
157
                    todo.add((child_path, hexsha, ie.file_id))
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
158
                else:
0.264.10 by Jelmer Vernooij
Yield inventory entries.
159
                    yield child_path, self._get_file_ie(path, name, mode, hexsha, ie.file_id)
0.264.6 by Jelmer Vernooij
Implement custom GitRevisionTree.iter_entries_by_dir, GitRevisionTree.list_files.
160
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
161
    def get_revision_id(self):
0.200.959 by Jelmer Vernooij
Improve docstrings.
162
        """See RevisionTree.get_revision_id."""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
163
        return self._revision_id
164
0.200.1255 by Jelmer Vernooij
Implement GitRevisionTree.get_file_sha1.
165
    def get_file_sha1(self, file_id, path=None):
166
        return osutils.sha_string(self.get_file_text(file_id, path))
167
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
168
    def get_file_text(self, file_id, path=None):
0.200.959 by Jelmer Vernooij
Improve docstrings.
169
        """See RevisionTree.get_file_text."""
0.264.3 by Jelmer Vernooij
Make RevisionTree inventoryless.
170
        if path is None:
171
            path = self.id2path(file_id)
172
        (mode, hexsha)= tree_lookup_path(self.store.__getitem__, self.tree, path)
173
        if stat.S_ISREG(mode):
174
            return self.store[hexsha].data
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
175
        else:
0.200.664 by Jelmer Vernooij
Support submodules during fetch.
176
            return ""
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
177
0.264.10 by Jelmer Vernooij
Yield inventory entries.
178
    def _comparison_data(self, entry, path):
179
        if entry is None:
180
            return None, False, None
181
        return entry.kind, entry.executable, None
182
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
183
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
184
def tree_delta_from_git_changes(changes, mapping,
185
        (old_fileid_map, new_fileid_map), specific_file=None,
186
        require_versioned=False):
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
187
    """Create a TreeDelta from two git trees.
0.200.959 by Jelmer Vernooij
Improve docstrings.
188
189
    source and target are iterators over tuples with:
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
190
        (filename, sha, mode)
191
    """
192
    ret = delta.TreeDelta()
193
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
194
        if mapping.is_control_file(oldpath):
195
            oldpath = None
196
        if mapping.is_control_file(newpath):
197
            newpath = None
198
        if oldpath is None and newpath is None:
199
            continue
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
200
        if oldpath is None:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
201
            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.
202
        elif newpath is None:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
203
            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.
204
        elif oldpath != newpath:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
205
            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.
206
        elif mode_kind(oldmode) != mode_kind(newmode):
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
207
            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.
208
        elif oldsha != newsha or oldmode != newmode:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
209
            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.
210
        else:
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
211
            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.
212
    return ret
213
214
0.200.959 by Jelmer Vernooij
Improve docstrings.
215
def changes_from_git_changes(changes, mapping, specific_file=None,
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
216
                                require_versioned=False):
217
    """Create a iter_changes-like generator from a git stream.
0.200.959 by Jelmer Vernooij
Improve docstrings.
218
219
    source and target are iterators over tuples with:
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
220
        (filename, sha, mode)
221
    """
222
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
223
        path = (oldpath, newpath)
224
        if oldpath is None:
225
            fileid = mapping.generate_file_id(newpath)
226
            oldexe = None
227
            oldkind = None
228
            oldname = None
229
            oldparent = None
230
        else:
231
            oldexe = mode_is_executable(oldmode)
232
            oldkind = mode_kind(oldmode)
233
            try:
234
                (oldparentpath, oldname) = oldpath.rsplit("/", 1)
235
            except ValueError:
236
                oldparent = None
237
                oldname = oldpath
238
            else:
239
                oldparent = mapping.generate_file_id(oldparentpath)
240
            fileid = mapping.generate_file_id(oldpath)
241
        if newpath is None:
242
            newexe = None
243
            newkind = None
244
            newname = None
245
            newparent = None
246
        else:
247
            newexe = mode_is_executable(newmode)
248
            newkind = mode_kind(newmode)
249
            try:
250
                newparentpath, newname = newpath.rsplit("/", 1)
251
            except ValueError:
252
                newparent = None
253
                newname = newpath
254
            else:
255
                newparent = mapping.generate_file_id(newparentpath)
0.200.959 by Jelmer Vernooij
Improve docstrings.
256
        yield (fileid, (oldpath, newpath), (oldsha != newsha),
257
             (oldpath is not None, newpath is not None),
258
             (oldparent, newparent), (oldname, newname),
259
             (oldkind, newkind), (oldexe, newexe))
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
260
261
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
262
class InterGitRevisionTrees(tree.InterTree):
263
    """InterTree that works between two git revision trees."""
264
0.200.659 by Jelmer Vernooij
Prevent tests using InterGitRevisionTrees.
265
    _matching_from_tree_format = None
266
    _matching_to_tree_format = None
267
    _test_mutable_trees_to_test_trees = None
268
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
269
    @classmethod
270
    def is_compatible(cls, source, target):
0.200.959 by Jelmer Vernooij
Improve docstrings.
271
        return (isinstance(source, GitRevisionTree) and
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
272
                isinstance(target, GitRevisionTree))
273
274
    def compare(self, want_unchanged=False, specific_files=None,
275
                extra_trees=None, require_versioned=False, include_root=False,
276
                want_unversioned=False):
277
        if self.source._repository._git.object_store != self.target._repository._git.object_store:
278
            raise AssertionError
279
        changes = self.source._repository._git.object_store.tree_changes(
280
            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.
281
        source_fileid_map = self.source.mapping.get_fileid_map(
282
            self.source._repository._git.object_store.__getitem__,
283
            self.source.tree)
284
        target_fileid_map = self.target.mapping.get_fileid_map(
285
            self.target._repository._git.object_store.__getitem__,
286
            self.target.tree)
0.200.959 by Jelmer Vernooij
Improve docstrings.
287
        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.
288
            (source_fileid_map, target_fileid_map),
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
289
            specific_file=specific_files)
290
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
291
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.200.959 by Jelmer Vernooij
Improve docstrings.
292
        pb=None, extra_trees=[], require_versioned=True,
293
        want_unversioned=False):
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
294
        if self.source._repository._git.object_store != self.target._repository._git.object_store:
295
            raise AssertionError
296
        changes = self.source._repository._git.object_store.tree_changes(
0.200.959 by Jelmer Vernooij
Improve docstrings.
297
            self.source.tree, self.target.tree,
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
298
            want_unchanged=include_unchanged)
0.200.959 by Jelmer Vernooij
Improve docstrings.
299
        return changes_from_git_changes(changes, self.target.mapping,
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
300
            specific_file=specific_files)
301
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
302
303
tree.InterTree.register_optimiser(InterGitRevisionTrees)