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