/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 mapping.py

Specify inventory and texts to inventory_to_tree_and_blobs rather than full repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2007 Canonical Ltd
 
2
# Copyright (C) 2008-2009 Jelmer Vernooij <jelmer@samba.org>
 
3
# Copyright (C) 2008 John Carr
2
4
#
3
5
# This program is free software; you can redistribute it and/or modify
4
6
# it under the terms of the GNU General Public License as published by
16
18
 
17
19
"""Converters, etc for going between Bazaar and Git ids."""
18
20
 
19
 
from bzrlib import errors, foreign
20
 
from bzrlib.inventory import ROOT_ID
 
21
from bzrlib import (
 
22
    errors,
 
23
    foreign,
 
24
    urlutils,
 
25
    )
 
26
from bzrlib.inventory import (
 
27
    ROOT_ID,
 
28
    )
21
29
from bzrlib.foreign import (
22
 
        ForeignRevision,
23
 
        )
 
30
    ForeignVcs, 
 
31
    VcsMappingRegistry, 
 
32
    ForeignRevision,
 
33
    )
 
34
from bzrlib.xml_serializer import (
 
35
    escape_invalid_chars,
 
36
    )
 
37
 
 
38
DEFAULT_TREE_MODE = 0040000
 
39
DEFAULT_FILE_MODE = 0100644
 
40
DEFAULT_SYMLINK_MODE = 0120000
24
41
 
25
42
 
26
43
def escape_file_id(file_id):
35
52
    """Class that maps between Git and Bazaar semantics."""
36
53
    experimental = False
37
54
 
38
 
    def revision_id_foreign_to_bzr(self, git_rev_id):
 
55
    def __init__(self):
 
56
        super(BzrGitMapping, self).__init__(foreign_git)
 
57
 
 
58
    def __eq__(self, other):
 
59
        return type(self) == type(other) and self.revid_prefix == other.revid_prefix
 
60
 
 
61
    @classmethod
 
62
    def revision_id_foreign_to_bzr(cls, git_rev_id):
39
63
        """Convert a git revision id handle to a Bazaar revision id."""
40
 
        return "%s:%s" % (self.revid_prefix, git_rev_id)
 
64
        return "%s:%s" % (cls.revid_prefix, git_rev_id)
41
65
 
42
 
    def revision_id_bzr_to_foreign(self, bzr_rev_id):
 
66
    @classmethod
 
67
    def revision_id_bzr_to_foreign(cls, bzr_rev_id):
43
68
        """Convert a Bazaar revision id to a git revision id handle."""
44
 
        if not bzr_rev_id.startswith("%s:" % self.revid_prefix):
45
 
            raise errors.InvalidRevisionId(bzr_rev_id, self)
46
 
        return bzr_rev_id[len(self.revid_prefix)+1:]
47
 
 
48
 
    def show_foreign_revid(self, foreign_revid):
49
 
        return { "git commit": foreign_revid }
 
69
        if not bzr_rev_id.startswith("%s:" % cls.revid_prefix):
 
70
            raise errors.InvalidRevisionId(bzr_rev_id, cls)
 
71
        return bzr_rev_id[len(cls.revid_prefix)+1:], cls()
50
72
 
51
73
    def generate_file_id(self, path):
 
74
        # Git paths are just bytestrings
 
75
        # We must just hope they are valid UTF-8..
 
76
        assert isinstance(path, str)
52
77
        if path == "":
53
78
            return ROOT_ID
54
 
        return escape_file_id(path.encode('utf-8'))
 
79
        return escape_file_id(path)
 
80
 
 
81
    def parse_file_id(self, file_id):
 
82
        if file_id == ROOT_ID:
 
83
            return ""
 
84
        return unescape_file_id(file_id)
55
85
 
56
86
    def import_commit(self, commit):
57
87
        """Convert a git commit to a bzr revision.
62
92
            raise AssertionError("Commit object can't be None")
63
93
        rev = ForeignRevision(commit.id, self, self.revision_id_foreign_to_bzr(commit.id))
64
94
        rev.parent_ids = tuple([self.revision_id_foreign_to_bzr(p) for p in commit.parents])
65
 
        rev.message = commit.message.decode("utf-8", "replace")
66
 
        rev.committer = str(commit.committer).decode("utf-8", "replace")
 
95
        rev.message = escape_invalid_chars(commit.message.decode("utf-8", "replace"))[0]
 
96
        rev.committer = escape_invalid_chars(str(commit.committer).decode("utf-8", "replace"))[0]
67
97
        if commit.committer != commit.author:
68
 
            rev.properties['author'] = str(commit.author).decode("utf-8", "replace")
 
98
            rev.properties['author'] = escape_invalid_chars(str(commit.author).decode("utf-8", "replace"))[0]
69
99
        rev.timestamp = commit.commit_time
70
100
        rev.timezone = 0
71
101
        return rev
72
102
 
73
103
 
74
 
class BzrGitMappingExperimental(BzrGitMapping):
 
104
class BzrGitMappingv1(BzrGitMapping):
 
105
    revid_prefix = 'git-v1'
 
106
    experimental = False
 
107
 
 
108
 
 
109
class BzrGitMappingExperimental(BzrGitMappingv1):
75
110
    revid_prefix = 'git-experimental'
76
111
    experimental = True
77
112
 
78
113
 
79
 
default_mapping = BzrGitMappingExperimental()
 
114
class GitMappingRegistry(VcsMappingRegistry):
 
115
 
 
116
    def revision_id_bzr_to_foreign(self, bzr_revid):
 
117
        if not bzr_revid.startswith("git-"):
 
118
            raise errors.InvalidRevisionId(bzr_revid, None)
 
119
        (mapping_version, git_sha) = bzr_revid.split(":", 1)
 
120
        mapping = self.get(mapping_version)
 
121
        return mapping.revision_id_bzr_to_foreign(bzr_revid)
 
122
 
 
123
    parse_revision_id = revision_id_bzr_to_foreign
 
124
 
 
125
 
 
126
mapping_registry = GitMappingRegistry()
 
127
mapping_registry.register_lazy('git-v1', "bzrlib.plugins.git.mapping",
 
128
                                   "BzrGitMappingv1")
 
129
mapping_registry.register_lazy('git-experimental', "bzrlib.plugins.git.mapping",
 
130
                                   "BzrGitMappingExperimental")
 
131
 
 
132
 
 
133
class ForeignGit(ForeignVcs):
 
134
    """Foreign Git."""
 
135
 
 
136
    def __init__(self):
 
137
        super(ForeignGit, self).__init__(mapping_registry)
 
138
 
 
139
    @classmethod
 
140
    def show_foreign_revid(cls, foreign_revid):
 
141
        return { "git commit": foreign_revid }
 
142
 
 
143
 
 
144
foreign_git = ForeignGit()
 
145
default_mapping = BzrGitMappingv1()
 
146
 
 
147
 
 
148
def text_to_blob(text):
 
149
    from dulwich.objects import Blob
 
150
    blob = Blob()
 
151
    blob._text = text
 
152
    return blob
 
153
 
 
154
 
 
155
def inventory_to_tree_and_blobs(inventory, texts, mapping):
 
156
    from dulwich.objects import Tree
 
157
    from bzrlib.inventory import InventoryDirectory, InventoryFile
 
158
    import stat
 
159
    stack = []
 
160
    cur = ""
 
161
    tree = Tree()
 
162
 
 
163
    # stack contains the set of trees that we haven't 
 
164
    # finished constructing
 
165
    for path, entry in inventory.iter_entries():
 
166
        while stack and not path.startswith(cur):
 
167
            tree.serialize()
 
168
            sha = tree.id
 
169
            yield sha, tree, cur
 
170
            t = (stat.S_IFDIR, urlutils.basename(cur).encode('UTF-8'), sha)
 
171
            cur, tree = stack.pop()
 
172
            tree.add(*t)
 
173
 
 
174
        if type(entry) == InventoryDirectory:
 
175
            stack.append((cur, tree))
 
176
            cur = path
 
177
            tree = Tree()
 
178
 
 
179
        if type(entry) == InventoryFile:
 
180
            #FIXME: We can make potentially make this Lazy to avoid shaing lots of stuff
 
181
            # and having all these objects in memory at once
 
182
            text = texts.get_record_stream([(entry.file_id, entry.revision)], 'unordered', True).next().get_bytes_as('fulltext')
 
183
            blob = text_to_blob(text)
 
184
            sha = blob.id
 
185
            yield sha, blob, path
 
186
 
 
187
            name = urlutils.basename(path).encode("utf-8")
 
188
            mode = stat.S_IFREG | 0644
 
189
            if entry.executable:
 
190
                mode |= 0111
 
191
            tree.add(mode, name, sha)
 
192
 
 
193
    while len(stack) > 1:
 
194
        tree.serialize()
 
195
        sha = tree.id
 
196
        yield sha, tree, cur
 
197
        t = (stat.S_IFDIR, urlutils.basename(cur).encode('UTF-8'), sha)
 
198
        cur, tree = stack.pop()
 
199
        tree.add(*t)
 
200
 
 
201
    tree.serialize()
 
202
    yield tree.id, tree, cur
 
203
 
 
204
 
 
205
def revision_to_commit(rev, tree_sha, parent_lookup):
 
206
    """Turn a Bazaar revision in to a Git commit
 
207
 
 
208
    :param tree_sha: Tree sha for the commit
 
209
    :param parent_lookup: Function for looking up the GIT sha equiv of a bzr revision
 
210
    :return dulwich.objects.Commit represent the revision:
 
211
    """
 
212
    from dulwich.objects import Commit
 
213
    commit = Commit()
 
214
    commit._tree = tree_sha
 
215
    for p in rev.parent_ids:
 
216
        git_p = parent_lookup(p)
 
217
        if git_p is not None:
 
218
            assert len(git_p) == 40, "unexpected length for %r" % git_p
 
219
            commit._parents.append(git_p)
 
220
    commit._message = rev.message.encode("utf-8")
 
221
    commit._committer = rev.committer.encode("utf-8")
 
222
    commit._author = rev.get_apparent_authors()[0].encode("utf-8")
 
223
    commit._commit_time = long(rev.timestamp)
 
224
    commit.serialize()
 
225
    return commit