/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.200.252 by Jelmer Vernooij
Clarify history, copyright.
1
# Copyright (C) 2007 Canonical Ltd
2
# Copyright (C) 2008-2009 Jelmer Vernooij <jelmer@samba.org>
3
# Copyright (C) 2008 John Carr
0.200.18 by John Arbash Meinel
Start splitting up the Git{Branch,Dir,Repository} into separate modules, etc.
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
"""Converters, etc for going between Bazaar and Git ids."""
20
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
21
import base64
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
22
import stat
23
0.200.292 by Jelmer Vernooij
Fix formatting.
24
from bzrlib import (
25
    errors,
26
    foreign,
0.200.356 by Jelmer Vernooij
Fix nasty bug in inventory_to_trees_and_blobs
27
    osutils,
0.200.490 by Jelmer Vernooij
Warn about unusual modes and escaped XML-invalid characters.
28
    trace,
0.200.292 by Jelmer Vernooij
Fix formatting.
29
    urlutils,
30
    )
0.200.550 by Jelmer Vernooij
Fix import.
31
try:
32
    from bzrlib import bencode
33
except ImportError:
34
    from bzrlib.util import bencode
0.200.292 by Jelmer Vernooij
Fix formatting.
35
from bzrlib.inventory import (
36
    ROOT_ID,
37
    )
0.200.152 by Jelmer Vernooij
Fix syntax errors.
38
from bzrlib.foreign import (
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
39
    ForeignVcs,
40
    VcsMappingRegistry,
0.200.292 by Jelmer Vernooij
Fix formatting.
41
    ForeignRevision,
42
    )
0.200.701 by Jelmer Vernooij
Fix check in git repos.
43
from bzrlib.revision import (
44
    NULL_REVISION,
45
    )
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
46
from bzrlib.plugins.git.hg import (
47
    format_hg_metadata,
48
    extract_hg_metadata,
49
    )
0.200.309 by Jelmer Vernooij
Add XML escaping to work around serialization bug in bzr.
50
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
51
DEFAULT_FILE_MODE = stat.S_IFREG | 0644
0.200.345 by Jelmer Vernooij
Keep track of file modes to use.
52
0.206.1 by Jelmer Vernooij
Use foreign utility functions.
53
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
54
def escape_file_id(file_id):
55
    return file_id.replace('_', '__').replace(' ', '_s')
56
57
58
def unescape_file_id(file_id):
0.200.390 by Jelmer Vernooij
Fix file id unescape function when there are other underscores in the file id.
59
    ret = []
60
    i = 0
61
    while i < len(file_id):
62
        if file_id[i] != '_':
63
            ret.append(file_id[i])
64
        else:
65
            if file_id[i+1] == '_':
66
                ret.append("_")
67
            elif file_id[i+1] == 's':
68
                ret.append(" ")
69
            else:
0.200.826 by Jelmer Vernooij
Fix some long lines.
70
                raise AssertionError("unknown escape character %s" %
71
                    file_id[i+1])
0.200.390 by Jelmer Vernooij
Fix file id unescape function when there are other underscores in the file id.
72
            i += 1
73
        i += 1
74
    return "".join(ret)
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
75
76
0.200.376 by Jelmer Vernooij
Make sure author and committer names pushed to git contain < and >, otherwise the git parser barfs.
77
def fix_person_identifier(text):
78
    if "<" in text and ">" in text:
79
        return text
80
    return "%s <%s>" % (text, text)
81
82
0.200.490 by Jelmer Vernooij
Warn about unusual modes and escaped XML-invalid characters.
83
def warn_escaped(commit, num_escaped):
84
    trace.warning("Escaped %d XML-invalid characters in %s. Will be unable "
85
                  "to regenerate the SHA map.", num_escaped, commit)
86
87
88
def warn_unusual_mode(commit, path, mode):
0.200.826 by Jelmer Vernooij
Fix some long lines.
89
    trace.mutter("Unusual file mode %o for %s in %s. Storing as revision "
90
                 "property. ", mode, path, commit)
0.200.490 by Jelmer Vernooij
Warn about unusual modes and escaped XML-invalid characters.
91
92
0.200.545 by Jelmer Vernooij
Squash revision data only if necessary.
93
def squash_revision(target_repo, rev):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
94
    """Remove characters that can't be stored from a revision, if necessary.
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
95
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
96
    :param target_repo: Repository in which the revision will be stored
97
    :param rev: Revision object, will be modified in-place
98
    """
0.200.545 by Jelmer Vernooij
Squash revision data only if necessary.
99
    if not getattr(target_repo._serializer, "squashes_xml_invalid_characters", True):
100
        return
101
    from bzrlib.xml_serializer import escape_invalid_chars
102
    rev.message, num_escaped = escape_invalid_chars(rev.message)
103
    if num_escaped:
104
        warn_escaped(rev.foreign_revid, num_escaped)
105
    if 'author' in rev.properties:
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
106
        rev.properties['author'], num_escaped = escape_invalid_chars(
107
            rev.properties['author'])
0.200.545 by Jelmer Vernooij
Squash revision data only if necessary.
108
        if num_escaped:
109
            warn_escaped(rev.foreign_revid, num_escaped)
110
    rev.committer, num_escaped = escape_invalid_chars(rev.committer)
111
    if num_escaped:
112
        warn_escaped(rev.foreign_revid, num_escaped)
113
114
0.206.1 by Jelmer Vernooij
Use foreign utility functions.
115
class BzrGitMapping(foreign.VcsMapping):
0.200.97 by Jelmer Vernooij
use mapping object.
116
    """Class that maps between Git and Bazaar semantics."""
117
    experimental = False
118
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
119
    def __init__(self):
120
        super(BzrGitMapping, self).__init__(foreign_git)
121
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
122
    def __eq__(self, other):
0.200.726 by Jelmer Vernooij
Factor out conversion of branch names to refs.
123
        return (type(self) == type(other) and 
124
                self.revid_prefix == other.revid_prefix)
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
125
126
    @classmethod
127
    def revision_id_foreign_to_bzr(cls, git_rev_id):
0.200.97 by Jelmer Vernooij
use mapping object.
128
        """Convert a git revision id handle to a Bazaar revision id."""
0.200.769 by Jelmer Vernooij
Cope with open_branch() actually checking whether there is a branch present.
129
        if git_rev_id == "0" * 40:
130
            return NULL_REVISION
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
131
        return "%s:%s" % (cls.revid_prefix, git_rev_id)
0.200.97 by Jelmer Vernooij
use mapping object.
132
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
133
    @classmethod
134
    def revision_id_bzr_to_foreign(cls, bzr_rev_id):
0.200.97 by Jelmer Vernooij
use mapping object.
135
        """Convert a Bazaar revision id to a git revision id handle."""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
136
        if not bzr_rev_id.startswith("%s:" % cls.revid_prefix):
137
            raise errors.InvalidRevisionId(bzr_rev_id, cls)
138
        return bzr_rev_id[len(cls.revid_prefix)+1:], cls()
0.200.97 by Jelmer Vernooij
use mapping object.
139
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
140
    def generate_file_id(self, path):
0.200.297 by Jelmer Vernooij
Cope with non-ascii characters in filenames (needs a test..).
141
        # Git paths are just bytestrings
142
        # We must just hope they are valid UTF-8..
0.200.157 by Jelmer Vernooij
Fix some bit of fetching.
143
        if path == "":
144
            return ROOT_ID
0.200.297 by Jelmer Vernooij
Cope with non-ascii characters in filenames (needs a test..).
145
        return escape_file_id(path)
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
146
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
147
    def parse_file_id(self, file_id):
148
        if file_id == ROOT_ID:
149
            return ""
150
        return unescape_file_id(file_id)
151
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
152
    def import_unusual_file_modes(self, rev, unusual_file_modes):
153
        if unusual_file_modes:
0.200.878 by Jelmer Vernooij
Fix determining of unusual file modes.
154
            ret = [(path, unusual_file_modes[path])
155
                   for path in sorted(unusual_file_modes.keys())]
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
156
            rev.properties['file-modes'] = bencode.bencode(ret)
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
157
0.200.547 by Jelmer Vernooij
Support getting unusual file modes out of revision properties.
158
    def export_unusual_file_modes(self, rev):
159
        try:
0.200.673 by Jelmer Vernooij
Fix encoding.
160
            return dict([(self.generate_file_id(path), mode) for (path, mode) in bencode.bdecode(rev.properties['file-modes'].encode("utf-8"))])
0.200.547 by Jelmer Vernooij
Support getting unusual file modes out of revision properties.
161
        except KeyError:
162
            return {}
163
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
164
    def _generate_git_svn_metadata(self, rev, encoding):
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
165
        try:
0.200.826 by Jelmer Vernooij
Fix some long lines.
166
            return "\ngit-svn-id: %s\n" % rev.properties["git-svn-id"].encode(
167
                encoding)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
168
        except KeyError:
169
            return ""
170
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
171
    def _generate_hg_message_tail(self, rev):
172
        extra = {}
173
        renames = []
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
174
        branch = 'default'
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
175
        for name in rev.properties:
176
            if name == 'hg:extra:branch':
177
                branch = rev.properties['hg:extra:branch']
178
            elif name.startswith('hg:extra'):
0.200.826 by Jelmer Vernooij
Fix some long lines.
179
                extra[name[len('hg:extra:'):]] = base64.b64decode(
180
                    rev.properties[name])
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
181
            elif name == 'hg:renames':
0.200.826 by Jelmer Vernooij
Fix some long lines.
182
                renames = bencode.bdecode(base64.b64decode(
183
                    rev.properties['hg:renames']))
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
184
            # TODO: Export other properties as 'bzr:' extras?
0.200.660 by Jelmer Vernooij
Fix encoding issues.
185
        ret = format_hg_metadata(renames, branch, extra)
186
        assert isinstance(ret, str)
187
        return ret
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
188
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
189
    def _extract_git_svn_metadata(self, rev, message):
190
        lines = message.split("\n")
0.200.653 by Jelmer Vernooij
Fix typo in git-svn-id parser, return revnum as integer.
191
        if not (lines[-1] == "" and lines[-2].startswith("git-svn-id:")):
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
192
            return message
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
193
        git_svn_id = lines[-2].split(": ", 1)[1]
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
194
        rev.properties['git-svn-id'] = git_svn_id
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
195
        (url, rev, uuid) = parse_git_svn_id(git_svn_id)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
196
        # FIXME: Convert this to converted-from property somehow..
0.200.660 by Jelmer Vernooij
Fix encoding issues.
197
        ret = "\n".join(lines[:-2])
198
        assert isinstance(ret, str)
199
        return ret
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
200
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
201
    def _extract_hg_metadata(self, rev, message):
202
        (message, renames, branch, extra) = extract_hg_metadata(message)
203
        if branch is not None:
204
            rev.properties['hg:extra:branch'] = branch
205
        for name, value in extra.iteritems():
206
            rev.properties['hg:extra:' + name] = base64.b64encode(value)
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
207
        if renames:
0.200.826 by Jelmer Vernooij
Fix some long lines.
208
            rev.properties['hg:renames'] = base64.b64encode(bencode.bencode(
209
                [(new, old) for (old, new) in renames.iteritems()]))
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
210
        return message
211
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
212
    def _decode_commit_message(self, rev, message, encoding):
213
        return message.decode(encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
214
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
215
    def _encode_commit_message(self, rev, message, encoding):
216
        return message.encode(encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
217
218
    def export_commit(self, rev, tree_sha, parent_lookup):
219
        """Turn a Bazaar revision in to a Git commit
220
221
        :param tree_sha: Tree sha for the commit
0.200.826 by Jelmer Vernooij
Fix some long lines.
222
        :param parent_lookup: Function for looking up the GIT sha equiv of a
223
            bzr revision
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
224
        :return dulwich.objects.Commit represent the revision:
225
        """
226
        from dulwich.objects import Commit
227
        commit = Commit()
228
        commit.tree = tree_sha
229
        for p in rev.parent_ids:
0.200.705 by Jelmer Vernooij
Cope with imports.
230
            try:
231
                git_p = parent_lookup(p)
232
            except KeyError:
233
                git_p = None
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
234
            if git_p is not None:
235
                assert len(git_p) == 40, "unexpected length for %r" % git_p
236
                commit.parents.append(git_p)
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
237
        try:
238
            encoding = rev.properties['git-explicit-encoding']
239
        except KeyError:
240
            encoding = rev.properties.get('git-implicit-encoding', 'utf-8')
241
        commit.encoding = rev.properties.get('git-explicit-encoding')
242
        commit.committer = fix_person_identifier(rev.committer.encode(
243
            encoding))
244
        commit.author = fix_person_identifier(
245
            rev.get_apparent_authors()[0].encode(encoding))
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
246
        commit.commit_time = long(rev.timestamp)
247
        if 'author-timestamp' in rev.properties:
248
            commit.author_time = long(rev.properties['author-timestamp'])
249
        else:
250
            commit.author_time = commit.commit_time
251
        commit.commit_timezone = rev.timezone
252
        if 'author-timezone' in rev.properties:
253
            commit.author_timezone = int(rev.properties['author-timezone'])
254
        else:
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
255
            commit.author_timezone = commit.commit_timezone
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
256
        commit.message = self._encode_commit_message(rev, rev.message, 
257
            encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
258
        return commit
259
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
260
    def import_commit(self, commit):
261
        """Convert a git commit to a bzr revision.
262
263
        :return: a `bzrlib.revision.Revision` object.
264
        """
265
        if commit is None:
266
            raise AssertionError("Commit object can't be None")
0.200.826 by Jelmer Vernooij
Fix some long lines.
267
        rev = ForeignRevision(commit.id, self,
268
                self.revision_id_foreign_to_bzr(commit.id))
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
269
        rev.parent_ids = tuple([self.revision_id_foreign_to_bzr(p) for p in commit.parents])
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
270
        def decode_using_encoding(rev, commit, encoding):
271
            rev.committer = str(commit.committer).decode(encoding)
272
            if commit.committer != commit.author:
273
                rev.properties['author'] = str(commit.author).decode(encoding)
274
            rev.message = self._decode_commit_message(rev, commit.message, 
275
                encoding)
276
        if commit.encoding is not None:
277
            rev.properties['git-explicit-encoding'] = commit.encoding
278
            decode_using_encoding(rev, commit, commit.encoding)
279
        else:
280
            for encoding in ('utf-8', 'latin1'):
281
                try:
282
                    decode_using_encoding(rev, commit, encoding)
283
                except UnicodeDecodeError:
284
                    pass
285
                else:
286
                    if encoding != 'utf-8':
287
                        rev.properties['git-implicit-encoding'] = encoding
288
                    break
0.200.350 by Jelmer Vernooij
Support author_time
289
        if commit.commit_time != commit.author_time:
290
            rev.properties['author-timestamp'] = str(commit.author_time)
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
291
        if commit.commit_timezone != commit.author_timezone:
0.200.826 by Jelmer Vernooij
Fix some long lines.
292
            rev.properties['author-timezone'] = "%d" % commit.author_timezone
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
293
        rev.timestamp = commit.commit_time
0.200.440 by Jelmer Vernooij
Remove silly mapping of timezones; dulwich uses offsets now as well.
294
        rev.timezone = commit.commit_timezone
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
295
        return rev
296
0.200.97 by Jelmer Vernooij
use mapping object.
297
0.200.190 by Jelmer Vernooij
Bless current mapping as v1.
298
class BzrGitMappingv1(BzrGitMapping):
299
    revid_prefix = 'git-v1'
300
    experimental = False
301
0.200.393 by Jelmer Vernooij
Provide __str__ implementation for mapping, fix docstring for ForeignGit.
302
    def __str__(self):
303
        return self.revid_prefix
304
0.200.190 by Jelmer Vernooij
Bless current mapping as v1.
305
306
class BzrGitMappingExperimental(BzrGitMappingv1):
0.200.104 by Jelmer Vernooij
Use bzr-foreign function names for converting between git and bzr revids.
307
    revid_prefix = 'git-experimental'
308
    experimental = True
0.200.97 by Jelmer Vernooij
use mapping object.
309
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
310
    def _decode_commit_message(self, rev, message, encoding):
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
311
        message = self._extract_hg_metadata(rev, message)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
312
        message = self._extract_git_svn_metadata(rev, message)
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
313
        return message.decode(encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
314
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
315
    def _encode_commit_message(self, rev, message, encoding):
316
        ret = message.encode(encoding)
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
317
        ret += self._generate_hg_message_tail(rev)
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
318
        ret += self._generate_git_svn_metadata(rev, encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
319
        return ret
320
0.200.642 by Jelmer Vernooij
In experimental mappings, set 'converted_revision' property.
321
    def import_commit(self, commit):
322
        rev = super(BzrGitMappingExperimental, self).import_commit(commit)
323
        rev.properties['converted_revision'] = "git %s\n" % commit.id
324
        return rev
325
0.200.97 by Jelmer Vernooij
use mapping object.
326
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
327
class GitMappingRegistry(VcsMappingRegistry):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
328
    """Registry with available git mappings."""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
329
330
    def revision_id_bzr_to_foreign(self, bzr_revid):
0.200.701 by Jelmer Vernooij
Fix check in git repos.
331
        if bzr_revid == NULL_REVISION:
332
            return "0" * 20, None
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
333
        if not bzr_revid.startswith("git-"):
334
            raise errors.InvalidRevisionId(bzr_revid, None)
335
        (mapping_version, git_sha) = bzr_revid.split(":", 1)
336
        mapping = self.get(mapping_version)
337
        return mapping.revision_id_bzr_to_foreign(bzr_revid)
338
339
    parse_revision_id = revision_id_bzr_to_foreign
340
341
342
mapping_registry = GitMappingRegistry()
343
mapping_registry.register_lazy('git-v1', "bzrlib.plugins.git.mapping",
0.200.826 by Jelmer Vernooij
Fix some long lines.
344
    "BzrGitMappingv1")
345
mapping_registry.register_lazy('git-experimental',
346
    "bzrlib.plugins.git.mapping", "BzrGitMappingExperimental")
0.200.661 by Jelmer Vernooij
Set mapping back to v1.
347
mapping_registry.set_default('git-v1')
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
348
349
350
class ForeignGit(ForeignVcs):
0.200.393 by Jelmer Vernooij
Provide __str__ implementation for mapping, fix docstring for ForeignGit.
351
    """The Git Stupid Content Tracker"""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
352
0.243.1 by Jelmer Vernooij
Use foreign branch testing infrastructure.
353
    @property
354
    def branch_format(self):
355
        from bzrlib.plugins.git.branch import GitBranchFormat
356
        return GitBranchFormat()
357
0.200.657 by Jelmer Vernooij
Provide repository_format attribute, as required by newer foreign VCS tests in bzrlib.
358
    @property
359
    def repository_format(self):
360
        from bzrlib.plugins.git.repository import GitRepositoryFormat
361
        return GitRepositoryFormat()
362
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
363
    def __init__(self):
364
        super(ForeignGit, self).__init__(mapping_registry)
0.200.646 by Jelmer Vernooij
Store abbreviation in foreign branch.
365
        self.abbreviation = "git"
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
366
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
367
    @classmethod
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
368
    def serialize_foreign_revid(self, foreign_revid):
369
        return foreign_revid
370
371
    @classmethod
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
372
    def show_foreign_revid(cls, foreign_revid):
373
        return { "git commit": foreign_revid }
374
375
376
foreign_git = ForeignGit()
0.200.637 by Jelmer Vernooij
Allow single place for configuration of default mapping.
377
default_mapping = mapping_registry.get_default()()
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
378
379
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
380
def symlink_to_blob(entry):
381
    from dulwich.objects import Blob
382
    blob = Blob()
0.200.795 by Jelmer Vernooij
simplify sha extraction for blobs, process multiple blobs at once.
383
    symlink_target = entry.symlink_target
384
    if type(symlink_target) == unicode:
385
        symlink_target = symlink_target.encode('utf-8')
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
386
    blob.data = symlink_target
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
387
    return blob
388
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
389
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
390
def mode_is_executable(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
391
    """Check if mode should be considered executable."""
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
392
    return bool(mode & 0111)
393
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
394
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
395
def mode_kind(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
396
    """Determine the Bazaar inventory kind based on Unix file mode."""
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
397
    entry_kind = (mode & 0700000) / 0100000
398
    if entry_kind == 0:
399
        return 'directory'
400
    elif entry_kind == 1:
401
        file_kind = (mode & 070000) / 010000
402
        if file_kind == 0:
403
            return 'file'
404
        elif file_kind == 2:
405
            return 'symlink'
406
        elif file_kind == 6:
407
            return 'tree-reference'
408
        else:
409
            raise AssertionError(
410
                "Unknown file kind %d, perms=%o." % (file_kind, mode,))
411
    else:
412
        raise AssertionError(
413
            "Unknown kind, perms=%r." % (mode,))
414
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
415
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
416
def object_mode(kind, executable):
417
    if kind == 'directory':
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
418
        return stat.S_IFDIR
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
419
    elif kind == 'symlink':
0.245.1 by INADA Naoki
Handle executable mode for symlink.
420
        mode = stat.S_IFLNK
421
        if executable:
0.200.703 by Jelmer Vernooij
Merge support for executable symlinks.
422
            mode |= 0111
0.245.1 by INADA Naoki
Handle executable mode for symlink.
423
        return mode
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
424
    elif kind == 'file':
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
425
        mode = stat.S_IFREG | 0644
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
426
        if executable:
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
427
            mode |= 0111
428
        return mode
0.200.665 by Jelmer Vernooij
Add more checks for submodules.
429
    elif kind == 'tree-reference':
430
        from dulwich.objects import S_IFGITLINK
431
        return S_IFGITLINK
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
432
    else:
433
        raise AssertionError
434
435
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
436
def entry_mode(entry):
437
    """Determine the git file mode for an inventory entry."""
438
    return object_mode(entry.kind, entry.executable)
439
440
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
441
def directory_to_tree(entry, lookup_ie_sha1, unusual_modes):
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
442
    from dulwich.objects import Tree
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
443
    tree = Tree()
0.200.807 by Jelmer Vernooij
Fix test, remove unnecessary sort.
444
    for name, value in entry.children.iteritems():
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
445
        ie = entry.children[name]
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
446
        try:
447
            mode = unusual_modes[ie.file_id]
448
        except KeyError:
449
            mode = entry_mode(ie)
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
450
        hexsha = lookup_ie_sha1(ie)
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
451
        if hexsha is not None:
452
            tree.add(mode, name.encode("utf-8"), hexsha)
453
    if entry.parent_id is not None and len(tree) == 0:
454
        # Only the root can be an empty tree
455
        return None
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
456
    return tree
457
458
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
459
def extract_unusual_modes(rev):
460
    try:
0.200.826 by Jelmer Vernooij
Fix some long lines.
461
        foreign_revid, mapping = mapping_registry.parse_revision_id(
462
            rev.revision_id)
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
463
    except errors.InvalidRevisionId:
464
        return {}
465
    else:
466
        return mapping.export_unusual_file_modes(rev)
467
468
0.200.826 by Jelmer Vernooij
Fix some long lines.
469
def inventory_to_tree_and_blobs(inventory, texts, mapping, unusual_modes,
470
                                cur=None):
0.200.355 by Jelmer Vernooij
Allow paranoia checking with -Dverify.
471
    """Convert a Bazaar tree to a Git tree.
472
473
    :return: Yields tuples with object sha1, object and path
474
    """
0.231.2 by Jelmer Vernooij
Add -Dverify flag (not fully implemented yet).
475
    from dulwich.objects import Tree
0.200.213 by Jelmer Vernooij
Move functions to mapping.
476
    import stat
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
477
    stack = []
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
478
    if cur is None:
479
        cur = ""
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
480
    tree = Tree()
481
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
482
    # stack contains the set of trees that we haven't
0.200.220 by Jelmer Vernooij
yield the right path for the tree root.
483
    # finished constructing
0.200.349 by Jelmer Vernooij
Specify inventory and texts to inventory_to_tree_and_blobs rather than full repository.
484
    for path, entry in inventory.iter_entries():
0.200.356 by Jelmer Vernooij
Fix nasty bug in inventory_to_trees_and_blobs
485
        while stack and not path.startswith(osutils.pathjoin(cur, "")):
486
            # We've hit a file that's not a child of the previous path
0.200.318 by Jelmer Vernooij
Use .id rather than .sha().hexdigest().
487
            sha = tree.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
488
            yield sha, tree, cur.encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
489
            mode = unusual_modes.get(cur.encode("utf-8"), stat.S_IFDIR)
490
            t = (mode, urlutils.basename(cur).encode('UTF-8'), sha)
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
491
            cur, tree = stack.pop()
492
            tree.add(*t)
493
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
494
        if entry.kind == "directory":
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
495
            stack.append((cur, tree))
496
            cur = path
497
            tree = Tree()
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
498
        else:
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
499
            if entry.kind == "file":
0.200.810 by Jelmer Vernooij
Inline text_to_blob.
500
                from dulwich.objects import Blob
0.200.826 by Jelmer Vernooij
Fix some long lines.
501
                stream = texts.get_record_stream(
502
                    [(entry.file_id, entry.revision)], 'unordered', True)
0.200.810 by Jelmer Vernooij
Inline text_to_blob.
503
                blob = Blob()
0.200.851 by Jelmer Vernooij
Use blob.chunked.
504
                blob.chunked = stream.next().get_bytes_as('chunks')
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
505
            elif entry.kind == "symlink":
506
                blob = symlink_to_blob(entry)
507
            else:
508
                raise AssertionError("Unknown kind %s" % entry.kind)
509
            sha = blob.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
510
            yield sha, blob, path.encode("utf-8")
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
511
            name = urlutils.basename(path).encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
512
            mode = unusual_modes.get(path.encode("utf-8"), entry_mode(entry))
513
            tree.add(mode, name, sha)
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
514
515
    while len(stack) > 1:
0.200.318 by Jelmer Vernooij
Use .id rather than .sha().hexdigest().
516
        sha = tree.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
517
        yield sha, tree, cur.encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
518
        mode = unusual_modes.get(cur.encode('utf-8'), stat.S_IFDIR)
519
        t = (mode, urlutils.basename(cur).encode('UTF-8'), sha)
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
520
        cur, tree = stack.pop()
521
        tree.add(*t)
522
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
523
    yield tree.id, tree, cur.encode("utf-8")
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
524
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
525
526
def parse_git_svn_id(text):
527
    (head, uuid) = text.rsplit(" ", 1)
528
    (full_url, rev) = head.rsplit("@", 1)
0.200.653 by Jelmer Vernooij
Fix typo in git-svn-id parser, return revnum as integer.
529
    return (full_url, int(rev), uuid)