/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
20
from bzrlib import (
21
    delta,
22
    errors,
23
    revisiontree,
24
    tree,
25
    )
26
27
from bzrlib.plugins.git.inventory import (
28
    GitInventory,
29
    )
30
from bzrlib.plugins.git.mapping import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
31
    mode_is_executable,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
32
    mode_kind,
33
    )
34
35
36
class GitRevisionTree(revisiontree.RevisionTree):
37
38
    def __init__(self, repository, revision_id):
39
        self._revision_id = revision_id
40
        self._repository = repository
41
        store = repository._git.object_store
42
        assert isinstance(revision_id, str)
43
        git_id, self.mapping = repository.lookup_git_revid(revision_id)
44
        try:
45
            commit = store[git_id]
46
        except KeyError, r:
47
            raise errors.NoSuchRevision(repository, revision_id)
48
        self.tree = commit.tree
49
        self._inventory = GitInventory(self.tree, self.mapping, store, 
50
                                       revision_id)
51
52
    def get_revision_id(self):
53
        return self._revision_id
54
55
    def get_file_text(self, file_id, path=None):
56
        if path is not None:
57
            entry = self._inventory._get_ie(path)
58
        else:
59
            entry = self._inventory[file_id]
60
        if entry.kind == 'directory': return ""
61
        return entry.object.data
62
63
64
def tree_delta_from_git_changes(changes, mapping, specific_file=None, 
65
                                require_versioned=False):
66
    """Create a TreeDelta from two git trees.
67
    
68
    source and target are iterators over tuples with: 
69
        (filename, sha, mode)
70
    """
71
    ret = delta.TreeDelta()
72
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
73
        if oldpath is None:
74
            ret.added.append((newpath, mapping.generate_file_id(newpath), mode_kind(newmode)))
75
        elif newpath is None:
76
            ret.removed.append((oldpath, mapping.generate_file_id(oldpath), mode_kind(oldmode)))
77
        elif oldpath != newpath:
78
            ret.renamed.append((oldpath, newpath, mapping.generate_file_id(oldpath), mode_kind(newmode), (oldsha != newsha), (oldmode != newmode)))
79
        elif mode_kind(oldmode) != mode_kind(newmode):
80
            ret.kind_changed.append((newpath, mapping.generate_file_id(newpath), mode_kind(oldmode), mode_kind(newmode)))
81
        elif oldsha != newsha or oldmode != newmode:
82
            ret.modified.append((newpath, mapping.generate_file_id(newpath), mode_kind(newmode), (oldsha != newsha), (oldmode != newmode)))
83
        else:
84
            ret.unchanged.append((newpath, mapping.generate_file_id(newpath), mode_kind(newmode)))
85
    return ret
86
87
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
88
def changes_from_git_changes(changes, mapping, specific_file=None, 
89
                                require_versioned=False):
90
    """Create a iter_changes-like generator from a git stream.
91
    
92
    source and target are iterators over tuples with: 
93
        (filename, sha, mode)
94
    """
95
    for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
96
        path = (oldpath, newpath)
97
        if oldpath is None:
98
            fileid = mapping.generate_file_id(newpath)
99
            oldexe = None
100
            oldkind = None
101
            oldname = None
102
            oldparent = None
103
        else:
104
            oldexe = mode_is_executable(oldmode)
105
            oldkind = mode_kind(oldmode)
106
            try:
107
                (oldparentpath, oldname) = oldpath.rsplit("/", 1)
108
            except ValueError:
109
                oldparent = None
110
                oldname = oldpath
111
            else:
112
                oldparent = mapping.generate_file_id(oldparentpath)
113
            fileid = mapping.generate_file_id(oldpath)
114
        if newpath is None:
115
            newexe = None
116
            newkind = None
117
            newname = None
118
            newparent = None
119
        else:
120
            newexe = mode_is_executable(newmode)
121
            newkind = mode_kind(newmode)
122
            try:
123
                newparentpath, newname = newpath.rsplit("/", 1)
124
            except ValueError:
125
                newparent = None
126
                newname = newpath
127
            else:
128
                newparent = mapping.generate_file_id(newparentpath)
129
        yield fileid, (oldpath, newpath), (oldsha != newsha), (oldpath is not None, newpath is not None), (oldparent, newparent), (oldname, newname), (oldkind, newkind), (oldexe, newexe)
130
131
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
132
class InterGitRevisionTrees(tree.InterTree):
133
    """InterTree that works between two git revision trees."""
134
135
    @classmethod
136
    def is_compatible(cls, source, target):
137
        return (isinstance(source, GitRevisionTree) and 
138
                isinstance(target, GitRevisionTree))
139
140
    def compare(self, want_unchanged=False, specific_files=None,
141
                extra_trees=None, require_versioned=False, include_root=False,
142
                want_unversioned=False):
143
        if self.source._repository._git.object_store != self.target._repository._git.object_store:
144
            raise AssertionError
145
        changes = self.source._repository._git.object_store.tree_changes(
146
            self.source.tree, self.target.tree, want_unchanged=want_unchanged)
147
        return tree_delta_from_git_changes(changes, self.target.mapping, 
148
            specific_file=specific_files)
149
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
150
    def iter_changes(self, include_unchanged=False, specific_files=None,
151
        pb=None, extra_trees=[], require_versioned=True, want_unversioned=False):
152
        if self.source._repository._git.object_store != self.target._repository._git.object_store:
153
            raise AssertionError
154
        changes = self.source._repository._git.object_store.tree_changes(
155
            self.source.tree, self.target.tree, 
156
            want_unchanged=include_unchanged)
157
        return changes_from_git_changes(changes, self.target.mapping, 
158
            specific_file=specific_files)
159
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
160
161
tree.InterTree.register_optimiser(InterGitRevisionTrees)