/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:
0.200.705 by Jelmer Vernooij
Cope with imports.
220
            try:
221
                git_p = parent_lookup(p)
222
            except KeyError:
223
                git_p = None
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
224
            if git_p is not None:
225
                assert len(git_p) == 40, "unexpected length for %r" % git_p
226
                commit.parents.append(git_p)
227
        commit.committer = fix_person_identifier(rev.committer.encode("utf-8"))
228
        commit.author = fix_person_identifier(rev.get_apparent_authors()[0].encode("utf-8"))
229
        commit.commit_time = long(rev.timestamp)
230
        if 'author-timestamp' in rev.properties:
231
            commit.author_time = long(rev.properties['author-timestamp'])
232
        else:
233
            commit.author_time = commit.commit_time
234
        commit.commit_timezone = rev.timezone
235
        if 'author-timezone' in rev.properties:
236
            commit.author_timezone = int(rev.properties['author-timezone'])
237
        else:
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
238
            commit.author_timezone = commit.commit_timezone
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
239
        commit.message = self._encode_commit_message(rev, rev.message)
240
        return commit
241
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
242
    def import_commit(self, commit):
243
        """Convert a git commit to a bzr revision.
244
245
        :return: a `bzrlib.revision.Revision` object.
246
        """
247
        if commit is None:
248
            raise AssertionError("Commit object can't be None")
249
        rev = ForeignRevision(commit.id, self, self.revision_id_foreign_to_bzr(commit.id))
250
        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.
251
        rev.committer = str(commit.committer).decode("utf-8", "replace")
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
252
        if commit.committer != commit.author:
0.200.545 by Jelmer Vernooij
Squash revision data only if necessary.
253
            rev.properties['author'] = str(commit.author).decode("utf-8", "replace")
0.200.350 by Jelmer Vernooij
Support author_time
254
255
        if commit.commit_time != commit.author_time:
256
            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.
257
        if commit.commit_timezone != commit.author_timezone:
0.200.440 by Jelmer Vernooij
Remove silly mapping of timezones; dulwich uses offsets now as well.
258
            rev.properties['author-timezone'] = "%d" % (commit.author_timezone, )
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
259
        rev.timestamp = commit.commit_time
0.200.440 by Jelmer Vernooij
Remove silly mapping of timezones; dulwich uses offsets now as well.
260
        rev.timezone = commit.commit_timezone
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
261
        rev.message = self._decode_commit_message(rev, commit.message)
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
262
        return rev
263
0.200.97 by Jelmer Vernooij
use mapping object.
264
0.200.190 by Jelmer Vernooij
Bless current mapping as v1.
265
class BzrGitMappingv1(BzrGitMapping):
266
    revid_prefix = 'git-v1'
267
    experimental = False
268
0.200.393 by Jelmer Vernooij
Provide __str__ implementation for mapping, fix docstring for ForeignGit.
269
    def __str__(self):
270
        return self.revid_prefix
271
0.200.190 by Jelmer Vernooij
Bless current mapping as v1.
272
273
class BzrGitMappingExperimental(BzrGitMappingv1):
0.200.104 by Jelmer Vernooij
Use bzr-foreign function names for converting between git and bzr revids.
274
    revid_prefix = 'git-experimental'
275
    experimental = True
0.200.97 by Jelmer Vernooij
use mapping object.
276
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
277
    def _decode_commit_message(self, rev, message):
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
278
        message = self._extract_hg_metadata(rev, message)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
279
        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.
280
        return message.decode("utf-8", "replace")
281
282
    def _encode_commit_message(self, rev, message):
283
        ret = message.encode("utf-8")
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
284
        ret += self._generate_hg_message_tail(rev)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
285
        ret += self._generate_git_svn_metadata(rev)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
286
        return ret
287
0.200.642 by Jelmer Vernooij
In experimental mappings, set 'converted_revision' property.
288
    def import_commit(self, commit):
289
        rev = super(BzrGitMappingExperimental, self).import_commit(commit)
290
        rev.properties['converted_revision'] = "git %s\n" % commit.id
291
        return rev
292
0.200.97 by Jelmer Vernooij
use mapping object.
293
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
294
class GitMappingRegistry(VcsMappingRegistry):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
295
    """Registry with available git mappings."""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
296
297
    def revision_id_bzr_to_foreign(self, bzr_revid):
0.200.701 by Jelmer Vernooij
Fix check in git repos.
298
        if bzr_revid == NULL_REVISION:
299
            return "0" * 20, None
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
300
        if not bzr_revid.startswith("git-"):
301
            raise errors.InvalidRevisionId(bzr_revid, None)
302
        (mapping_version, git_sha) = bzr_revid.split(":", 1)
303
        mapping = self.get(mapping_version)
304
        return mapping.revision_id_bzr_to_foreign(bzr_revid)
305
306
    parse_revision_id = revision_id_bzr_to_foreign
307
308
309
mapping_registry = GitMappingRegistry()
310
mapping_registry.register_lazy('git-v1', "bzrlib.plugins.git.mapping",
311
                                   "BzrGitMappingv1")
312
mapping_registry.register_lazy('git-experimental', "bzrlib.plugins.git.mapping",
313
                                   "BzrGitMappingExperimental")
0.200.661 by Jelmer Vernooij
Set mapping back to v1.
314
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.
315
316
317
class ForeignGit(ForeignVcs):
0.200.393 by Jelmer Vernooij
Provide __str__ implementation for mapping, fix docstring for ForeignGit.
318
    """The Git Stupid Content Tracker"""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
319
0.243.1 by Jelmer Vernooij
Use foreign branch testing infrastructure.
320
    @property
321
    def branch_format(self):
322
        from bzrlib.plugins.git.branch import GitBranchFormat
323
        return GitBranchFormat()
324
0.200.657 by Jelmer Vernooij
Provide repository_format attribute, as required by newer foreign VCS tests in bzrlib.
325
    @property
326
    def repository_format(self):
327
        from bzrlib.plugins.git.repository import GitRepositoryFormat
328
        return GitRepositoryFormat()
329
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
330
    def __init__(self):
331
        super(ForeignGit, self).__init__(mapping_registry)
0.200.646 by Jelmer Vernooij
Store abbreviation in foreign branch.
332
        self.abbreviation = "git"
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
333
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
334
    @classmethod
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
335
    def serialize_foreign_revid(self, foreign_revid):
336
        return foreign_revid
337
338
    @classmethod
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
339
    def show_foreign_revid(cls, foreign_revid):
340
        return { "git commit": foreign_revid }
341
342
343
foreign_git = ForeignGit()
0.200.637 by Jelmer Vernooij
Allow single place for configuration of default mapping.
344
default_mapping = mapping_registry.get_default()()
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
345
346
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.
347
def text_to_blob(texts, entry):
0.231.2 by Jelmer Vernooij
Add -Dverify flag (not fully implemented yet).
348
    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.
349
    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).
350
    blob = Blob()
351
    blob._text = text
352
    return blob
353
354
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
355
def symlink_to_blob(entry):
356
    from dulwich.objects import Blob
357
    blob = Blob()
358
    blob._text = entry.symlink_target
359
    return blob
360
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
361
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
362
def mode_is_executable(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
363
    """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.
364
    return bool(mode & 0111)
365
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
366
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
367
def mode_kind(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
368
    """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.
369
    entry_kind = (mode & 0700000) / 0100000
370
    if entry_kind == 0:
371
        return 'directory'
372
    elif entry_kind == 1:
373
        file_kind = (mode & 070000) / 010000
374
        if file_kind == 0:
375
            return 'file'
376
        elif file_kind == 2:
377
            return 'symlink'
378
        elif file_kind == 6:
379
            return 'tree-reference'
380
        else:
381
            raise AssertionError(
382
                "Unknown file kind %d, perms=%o." % (file_kind, mode,))
383
    else:
384
        raise AssertionError(
385
            "Unknown kind, perms=%r." % (mode,))
386
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
387
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
388
def object_mode(kind, executable):
389
    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.
390
        return stat.S_IFDIR
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
391
    elif kind == 'symlink':
0.245.1 by INADA Naoki
Handle executable mode for symlink.
392
        mode = stat.S_IFLNK
393
        if executable:
0.200.703 by Jelmer Vernooij
Merge support for executable symlinks.
394
            mode |= 0111
0.245.1 by INADA Naoki
Handle executable mode for symlink.
395
        return mode
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
396
    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.
397
        mode = stat.S_IFREG | 0644
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
398
        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.
399
            mode |= 0111
400
        return mode
0.200.665 by Jelmer Vernooij
Add more checks for submodules.
401
    elif kind == 'tree-reference':
402
        from dulwich.objects import S_IFGITLINK
403
        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.
404
    else:
405
        raise AssertionError
406
407
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
408
def entry_mode(entry):
409
    """Determine the git file mode for an inventory entry."""
410
    return object_mode(entry.kind, entry.executable)
411
412
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
413
def directory_to_tree(entry, lookup_ie_sha1, unusual_modes):
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
414
    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.
415
    tree = Tree()
416
    for name in sorted(entry.children.keys()):
417
        ie = entry.children[name]
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
418
        try:
419
            mode = unusual_modes[ie.file_id]
420
        except KeyError:
421
            mode = entry_mode(ie)
0.200.588 by Jelmer Vernooij
Cope with empty directories that are not allowed in git.
422
        hexsha = lookup_ie_sha1(ie)
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
423
        if hexsha is not None:
424
            tree.add(mode, name.encode("utf-8"), hexsha)
425
    if entry.parent_id is not None and len(tree) == 0:
426
        # Only the root can be an empty tree
427
        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.
428
    tree.serialize()
429
    return tree
430
431
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
432
def extract_unusual_modes(rev):
433
    try:
434
        foreign_revid, mapping = mapping_registry.parse_revision_id(rev.revision_id)
435
    except errors.InvalidRevisionId:
436
        return {}
437
    else:
438
        return mapping.export_unusual_file_modes(rev)
439
440
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
441
def inventory_to_tree_and_blobs(inventory, texts, mapping, unusual_modes, cur=None):
0.200.355 by Jelmer Vernooij
Allow paranoia checking with -Dverify.
442
    """Convert a Bazaar tree to a Git tree.
443
444
    :return: Yields tuples with object sha1, object and path
445
    """
0.231.2 by Jelmer Vernooij
Add -Dverify flag (not fully implemented yet).
446
    from dulwich.objects import Tree
0.200.213 by Jelmer Vernooij
Move functions to mapping.
447
    import stat
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
448
    stack = []
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
449
    if cur is None:
450
        cur = ""
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
451
    tree = Tree()
452
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
453
    # stack contains the set of trees that we haven't
0.200.220 by Jelmer Vernooij
yield the right path for the tree root.
454
    # finished constructing
0.200.349 by Jelmer Vernooij
Specify inventory and texts to inventory_to_tree_and_blobs rather than full repository.
455
    for path, entry in inventory.iter_entries():
0.200.356 by Jelmer Vernooij
Fix nasty bug in inventory_to_trees_and_blobs
456
        while stack and not path.startswith(osutils.pathjoin(cur, "")):
457
            # 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.
458
            tree.serialize()
0.200.318 by Jelmer Vernooij
Use .id rather than .sha().hexdigest().
459
            sha = tree.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
460
            yield sha, tree, cur.encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
461
            mode = unusual_modes.get(cur.encode("utf-8"), stat.S_IFDIR)
462
            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.
463
            cur, tree = stack.pop()
464
            tree.add(*t)
465
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
466
        if entry.kind == "directory":
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
467
            stack.append((cur, tree))
468
            cur = path
469
            tree = Tree()
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
470
        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.
471
            if entry.kind == "file":
472
                blob = text_to_blob(texts, entry)
473
            elif entry.kind == "symlink":
474
                blob = symlink_to_blob(entry)
475
            else:
476
                raise AssertionError("Unknown kind %s" % entry.kind)
477
            sha = blob.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
478
            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.
479
            name = urlutils.basename(path).encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
480
            mode = unusual_modes.get(path.encode("utf-8"), entry_mode(entry))
481
            tree.add(mode, name, sha)
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
482
483
    while len(stack) > 1:
484
        tree.serialize()
0.200.318 by Jelmer Vernooij
Use .id rather than .sha().hexdigest().
485
        sha = tree.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
486
        yield sha, tree, cur.encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
487
        mode = unusual_modes.get(cur.encode('utf-8'), stat.S_IFDIR)
488
        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.
489
        cur, tree = stack.pop()
490
        tree.add(*t)
491
492
    tree.serialize()
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
493
    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.
494
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
495
496
def parse_git_svn_id(text):
497
    (head, uuid) = text.rsplit(" ", 1)
498
    (full_url, rev) = head.rsplit("@", 1)
0.200.653 by Jelmer Vernooij
Fix typo in git-svn-id parser, return revnum as integer.
499
    return (full_url, int(rev), uuid)