/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.657 by Jelmer Vernooij
Provide repository_format attribute, as required by newer foreign VCS tests in bzrlib.
302
mapping_registry.set_default('git-experimental')
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.657 by Jelmer Vernooij
Provide repository_format attribute, as required by newer foreign VCS tests in bzrlib.
313
    @property
314
    def repository_format(self):
315
        from bzrlib.plugins.git.repository import GitRepositoryFormat
316
        return GitRepositoryFormat()
317
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
318
    def __init__(self):
319
        super(ForeignGit, self).__init__(mapping_registry)
0.200.646 by Jelmer Vernooij
Store abbreviation in foreign branch.
320
        self.abbreviation = "git"
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
321
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
322
    @classmethod
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
323
    def serialize_foreign_revid(self, foreign_revid):
324
        return foreign_revid
325
326
    @classmethod
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
327
    def show_foreign_revid(cls, foreign_revid):
328
        return { "git commit": foreign_revid }
329
330
331
foreign_git = ForeignGit()
0.200.637 by Jelmer Vernooij
Allow single place for configuration of default mapping.
332
default_mapping = mapping_registry.get_default()()
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
333
334
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.
335
def text_to_blob(texts, entry):
0.231.2 by Jelmer Vernooij
Add -Dverify flag (not fully implemented yet).
336
    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.
337
    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).
338
    blob = Blob()
339
    blob._text = text
340
    return blob
341
342
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
343
def symlink_to_blob(entry):
344
    from dulwich.objects import Blob
345
    blob = Blob()
346
    blob._text = entry.symlink_target
347
    return blob
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_is_executable(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
351
    """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.
352
    return bool(mode & 0111)
353
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
354
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
355
def mode_kind(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
356
    """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.
357
    entry_kind = (mode & 0700000) / 0100000
358
    if entry_kind == 0:
359
        return 'directory'
360
    elif entry_kind == 1:
361
        file_kind = (mode & 070000) / 010000
362
        if file_kind == 0:
363
            return 'file'
364
        elif file_kind == 2:
365
            return 'symlink'
366
        elif file_kind == 6:
367
            return 'tree-reference'
368
        else:
369
            raise AssertionError(
370
                "Unknown file kind %d, perms=%o." % (file_kind, mode,))
371
    else:
372
        raise AssertionError(
373
            "Unknown kind, perms=%r." % (mode,))
374
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
375
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
376
def object_mode(kind, executable):
377
    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.
378
        return stat.S_IFDIR
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
379
    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.
380
        return stat.S_IFLNK
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
381
    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.
382
        mode = stat.S_IFREG | 0644
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
383
        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.
384
            mode |= 0111
385
        return mode
386
    else:
387
        raise AssertionError
388
389
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
390
def entry_mode(entry):
391
    """Determine the git file mode for an inventory entry."""
392
    return object_mode(entry.kind, entry.executable)
393
394
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
395
def directory_to_tree(entry, lookup_ie_sha1, unusual_modes):
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
396
    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.
397
    tree = Tree()
398
    for name in sorted(entry.children.keys()):
399
        ie = entry.children[name]
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
400
        try:
401
            mode = unusual_modes[ie.file_id]
402
        except KeyError:
403
            mode = entry_mode(ie)
0.200.588 by Jelmer Vernooij
Cope with empty directories that are not allowed in git.
404
        hexsha = lookup_ie_sha1(ie)
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
405
        if hexsha is not None:
406
            tree.add(mode, name.encode("utf-8"), hexsha)
407
    if entry.parent_id is not None and len(tree) == 0:
408
        # Only the root can be an empty tree
409
        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.
410
    tree.serialize()
411
    return tree
412
413
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
414
def extract_unusual_modes(rev):
415
    try:
416
        foreign_revid, mapping = mapping_registry.parse_revision_id(rev.revision_id)
417
    except errors.InvalidRevisionId:
418
        return {}
419
    else:
420
        return mapping.export_unusual_file_modes(rev)
421
422
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
423
def inventory_to_tree_and_blobs(inventory, texts, mapping, unusual_modes, cur=None):
0.200.355 by Jelmer Vernooij
Allow paranoia checking with -Dverify.
424
    """Convert a Bazaar tree to a Git tree.
425
426
    :return: Yields tuples with object sha1, object and path
427
    """
0.231.2 by Jelmer Vernooij
Add -Dverify flag (not fully implemented yet).
428
    from dulwich.objects import Tree
0.200.213 by Jelmer Vernooij
Move functions to mapping.
429
    import stat
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
430
    stack = []
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
431
    if cur is None:
432
        cur = ""
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
433
    tree = Tree()
434
0.200.220 by Jelmer Vernooij
yield the right path for the tree root.
435
    # stack contains the set of trees that we haven't 
436
    # finished constructing
0.200.349 by Jelmer Vernooij
Specify inventory and texts to inventory_to_tree_and_blobs rather than full repository.
437
    for path, entry in inventory.iter_entries():
0.200.356 by Jelmer Vernooij
Fix nasty bug in inventory_to_trees_and_blobs
438
        while stack and not path.startswith(osutils.pathjoin(cur, "")):
439
            # 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.
440
            tree.serialize()
0.200.318 by Jelmer Vernooij
Use .id rather than .sha().hexdigest().
441
            sha = tree.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
442
            yield sha, tree, cur.encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
443
            mode = unusual_modes.get(cur.encode("utf-8"), stat.S_IFDIR)
444
            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.
445
            cur, tree = stack.pop()
446
            tree.add(*t)
447
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
448
        if entry.kind == "directory":
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
449
            stack.append((cur, tree))
450
            cur = path
451
            tree = Tree()
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
452
        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.
453
            if entry.kind == "file":
454
                blob = text_to_blob(texts, entry)
455
            elif entry.kind == "symlink":
456
                blob = symlink_to_blob(entry)
457
            else:
458
                raise AssertionError("Unknown kind %s" % entry.kind)
459
            sha = blob.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
460
            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.
461
            name = urlutils.basename(path).encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
462
            mode = unusual_modes.get(path.encode("utf-8"), entry_mode(entry))
463
            tree.add(mode, name, sha)
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
464
465
    while len(stack) > 1:
466
        tree.serialize()
0.200.318 by Jelmer Vernooij
Use .id rather than .sha().hexdigest().
467
        sha = tree.id
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
468
        yield sha, tree, cur.encode("utf-8")
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
469
        mode = unusual_modes.get(cur.encode('utf-8'), stat.S_IFDIR)
470
        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.
471
        cur, tree = stack.pop()
472
        tree.add(*t)
473
474
    tree.serialize()
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
475
    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.
476
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
477
478
def parse_git_svn_id(text):
479
    (head, uuid) = text.rsplit(" ", 1)
480
    (full_url, rev) = head.rsplit("@", 1)
0.200.653 by Jelmer Vernooij
Fix typo in git-svn-id parser, return revnum as integer.
481
    return (full_url, int(rev), uuid)