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