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