/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to fetch.py

  • Committer: Robert Collins
  • Date: 2010-05-06 07:48:22 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506074822-0bsgf2j4h8jx0xkk
Added ``bzrlib.tests.matchers`` as a place to put matchers, along with
our first in-tree matcher. See the module docstring for details.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2008 Canonical Ltd
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
 
from bzrlib import osutils, urlutils
18
 
from bzrlib.errors import InvalidRevisionId
19
 
from bzrlib.inventory import Inventory
20
 
from bzrlib.repository import InterRepository
21
 
from bzrlib.trace import info
22
 
 
23
 
from bzrlib.plugins.git import git
24
 
from bzrlib.plugins.git.repository import LocalGitRepository, GitRepository, GitFormat
25
 
from bzrlib.plugins.git.remote import RemoteGitRepository
26
 
 
27
 
from dulwich.objects import Commit
28
 
 
29
 
from cStringIO import StringIO
30
 
 
31
 
 
32
 
class BzrFetchGraphWalker(object):
33
 
 
34
 
    def __init__(self, repository, mapping):
35
 
        self.repository = repository
36
 
        self.mapping = mapping
37
 
        self.done = set()
38
 
        self.heads = set(repository.all_revision_ids())
39
 
        self.parents = {}
40
 
 
41
 
    def ack(self, sha):
42
 
        revid = self.mapping.revision_id_foreign_to_bzr(sha)
43
 
        self.remove(revid)
44
 
 
45
 
    def remove(self, revid):
46
 
        self.done.add(revid)
47
 
        if ref in self.heads:
48
 
            self.heads.remove(revid)
49
 
        if revid in self.parents:
50
 
            for p in self.parents[revid]:
51
 
                self.remove(p)
52
 
 
53
 
    def next(self):
54
 
        while self.heads:
55
 
            ret = self.heads.pop()
56
 
            ps = self.repository.get_parent_map([ret])[ret]
57
 
            self.parents[ret] = ps
58
 
            self.heads.update([p for p in ps if not p in self.done])
59
 
            try:
60
 
                self.done.add(ret)
61
 
                return self.mapping.revision_id_bzr_to_foreign(ret)
62
 
            except InvalidRevisionId:
63
 
                pass
64
 
        return None
65
 
 
66
 
 
67
 
def import_git_blob(repo, mapping, path, blob, inv):
68
 
    """Import a git blob object into a bzr repository.
69
 
 
70
 
    :param repo: bzr repository
71
 
    :param path: Path in the tree
72
 
    :param blob: A git blob
73
 
    """
74
 
    file_id = mapping.generate_file_id(path)
75
 
    repo.texts.add_lines((file_id, blob.id),
76
 
        [], #FIXME 
77
 
        osutils.split_lines(blob.data))
78
 
    ie = inv.add_path(path, "file", file_id)
79
 
 
80
 
 
81
 
def import_git_tree(repo, mapping, path, tree, inv, lookup_object):
82
 
    """Import a git tree object into a bzr repository.
83
 
 
84
 
    :param repo: A Bzr repository object
85
 
    :param path: Path in the tree
86
 
    :param tree: A git tree object
87
 
    :param inv: Inventory object
88
 
    """
89
 
    file_id = mapping.generate_file_id(path)
90
 
    repo.texts.add_lines((file_id, tree.id),
91
 
        [], #FIXME 
92
 
        [])
93
 
    inv.add_path(path, "directory", file_id)
94
 
    for mode, name, hexsha in tree.entries():
95
 
        entry_kind = (mode & 0700000) / 0100000
96
 
        basename = name.decode("utf-8")
97
 
        if path == "":
98
 
            child_path = name
99
 
        else:
100
 
            child_path = urlutils.join(path, name)
101
 
        if entry_kind == 0:
102
 
            tree = lookup_object(hexsha)
103
 
            import_git_tree(repo, mapping, child_path, tree, inv, lookup_object)
104
 
        elif entry_kind == 1:
105
 
            blob = lookup_object(hexsha)
106
 
            import_git_blob(repo, mapping, child_path, blob, inv)
107
 
        else:
108
 
            raise AssertionError("Unknown blob kind, perms=%r." % (mode,))
109
 
 
110
 
 
111
 
def import_git_objects(repo, mapping, object_iter):
112
 
    """Import a set of git objects into a bzr repository.
113
 
 
114
 
    :param repo: Bazaar repository
115
 
    :param mapping: Mapping to use
116
 
    :param object_iter: Iterator over Git objects.
117
 
    """
118
 
    # TODO: a more (memory-)efficient implementation of this
119
 
    objects = {}
120
 
    for o in object_iter:
121
 
        objects[o.id] = o
122
 
    root_trees = {}
123
 
    # Find and convert commit objects
124
 
    for o in objects.itervalues():
125
 
        if isinstance(o, Commit):
126
 
            rev = mapping.import_commit(o)
127
 
            root_trees[rev] = objects[o.tree]
128
 
    # Create the inventory objects
129
 
    for rev, root_tree in root_trees.iteritems():
130
 
        # We have to do this here, since we have to walk the tree and 
131
 
        # we need to make sure to import the blobs / trees with the riht 
132
 
        # path; this may involve adding them more than once.
133
 
        inv = Inventory()
134
 
        inv.revision_id = rev.revision_id
135
 
        def lookup_object(sha):
136
 
            if sha in objects:
137
 
                return objects[sha]
138
 
            return reconstruct_git_object(repo, mapping, sha)
139
 
        import_git_tree(repo, mapping, "", root_tree, inv, lookup_object)
140
 
        repo.add_revision(rev.revision_id, rev, inv)
141
 
 
142
 
 
143
 
def reconstruct_git_commit(repo, rev):
144
 
    raise NotImplementedError(self.reconstruct_git_commit)
145
 
 
146
 
 
147
 
def reconstruct_git_object(repo, mapping, sha):
148
 
    # Commit
149
 
    revid = mapping.revision_id_foreign_to_bzr(sha)
150
 
    try:
151
 
        rev = repo.get_revision(revid)
152
 
    except NoSuchRevision:
153
 
        pass
154
 
    else:
155
 
        return reconstruct_git_commit(rev)
156
 
 
157
 
    # TODO: Tree
158
 
    # TODO: Blob
159
 
    raise KeyError("No such object %s" % sha)
160
 
 
161
 
 
162
 
class InterGitRepository(InterRepository):
163
 
 
164
 
    _matching_repo_format = GitFormat()
165
 
 
166
 
    @staticmethod
167
 
    def _get_repo_format_to_test():
168
 
        return None
169
 
 
170
 
    def copy_content(self, revision_id=None, pb=None):
171
 
        """See InterRepository.copy_content."""
172
 
        self.fetch(revision_id, pb, find_ghosts=False)
173
 
 
174
 
    def fetch(self, revision_id=None, pb=None, find_ghosts=False, 
175
 
              mapping=None):
176
 
        if mapping is None:
177
 
            mapping = self.source.get_mapping()
178
 
        def progress(text):
179
 
            if pb is not None:
180
 
                pb.note("git: %s" % text)
181
 
            else:
182
 
                info("git: %s" % text)
183
 
        def determine_wants(heads):
184
 
            if revision_id is None:
185
 
                ret = heads.values()
186
 
            else:
187
 
                ret = [mapping.revision_id_bzr_to_foreign(revision_id)]
188
 
            return [rev for rev in ret if not self.target.has_revision(mapping.revision_id_foreign_to_bzr(rev))]
189
 
        graph_walker = BzrFetchGraphWalker(self.target, mapping)
190
 
        self.target.lock_write()
191
 
        try:
192
 
            self.target.start_write_group()
193
 
            try:
194
 
                import_git_objects(self.target, mapping,
195
 
                    iter(self.source.fetch_objects(determine_wants, graph_walker, 
196
 
                        progress)))
197
 
            finally:
198
 
                self.target.commit_write_group()
199
 
        finally:
200
 
            self.target.unlock()
201
 
 
202
 
    @staticmethod
203
 
    def is_compatible(source, target):
204
 
        """Be compatible with GitRepository."""
205
 
        # FIXME: Also check target uses VersionedFile
206
 
        return (isinstance(source, LocalGitRepository) and 
207
 
                target.supports_rich_root())