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