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