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