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