/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
0.252.32 by Jelmer Vernooij
update copyright
2
# Copyright (C) 2008-2010 Jelmer Vernooij <jelmer@samba.org>
0.200.252 by Jelmer Vernooij
Clarify history, copyright.
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 (
0.200.926 by Jelmer Vernooij
Fix formatting, drop support for Bazaar < 2.0.
25
    bencode,
0.200.292 by Jelmer Vernooij
Fix formatting.
26
    errors,
27
    foreign,
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
    )
30
from bzrlib.inventory import (
31
    ROOT_ID,
32
    )
0.200.152 by Jelmer Vernooij
Fix syntax errors.
33
from bzrlib.foreign import (
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
34
    ForeignVcs,
35
    VcsMappingRegistry,
0.200.292 by Jelmer Vernooij
Fix formatting.
36
    ForeignRevision,
37
    )
0.200.701 by Jelmer Vernooij
Fix check in git repos.
38
from bzrlib.revision import (
39
    NULL_REVISION,
40
    )
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
41
from bzrlib.plugins.git.hg import (
42
    format_hg_metadata,
43
    extract_hg_metadata,
44
    )
0.252.2 by Jelmer Vernooij
Add functions for adding metadata to revision messages.
45
from bzrlib.plugins.git.roundtrip import (
46
    extract_bzr_metadata,
0.252.4 by Jelmer Vernooij
More work on roundtripping.
47
    inject_bzr_metadata,
0.200.1324 by Jelmer Vernooij
More work on roundtripping support.
48
    CommitSupplement,
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
49
    deserialize_fileid_map,
50
    serialize_fileid_map,
0.252.2 by Jelmer Vernooij
Add functions for adding metadata to revision messages.
51
    )
0.200.309 by Jelmer Vernooij
Add XML escaping to work around serialization bug in bzr.
52
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.
53
DEFAULT_FILE_MODE = stat.S_IFREG | 0644
0.200.345 by Jelmer Vernooij
Keep track of file modes to use.
54
0.206.1 by Jelmer Vernooij
Use foreign utility functions.
55
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
56
def escape_file_id(file_id):
57
    return file_id.replace('_', '__').replace(' ', '_s')
58
59
60
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.
61
    ret = []
62
    i = 0
63
    while i < len(file_id):
64
        if file_id[i] != '_':
65
            ret.append(file_id[i])
66
        else:
67
            if file_id[i+1] == '_':
68
                ret.append("_")
69
            elif file_id[i+1] == 's':
70
                ret.append(" ")
71
            else:
0.200.826 by Jelmer Vernooij
Fix some long lines.
72
                raise AssertionError("unknown escape character %s" %
73
                    file_id[i+1])
0.200.390 by Jelmer Vernooij
Fix file id unescape function when there are other underscores in the file id.
74
            i += 1
75
        i += 1
76
    return "".join(ret)
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
77
78
0.200.376 by Jelmer Vernooij
Make sure author and committer names pushed to git contain < and >, otherwise the git parser barfs.
79
def fix_person_identifier(text):
80
    if "<" in text and ">" in text:
81
        return text
82
    return "%s <%s>" % (text, text)
83
84
0.200.490 by Jelmer Vernooij
Warn about unusual modes and escaped XML-invalid characters.
85
def warn_escaped(commit, num_escaped):
86
    trace.warning("Escaped %d XML-invalid characters in %s. Will be unable "
87
                  "to regenerate the SHA map.", num_escaped, commit)
88
89
90
def warn_unusual_mode(commit, path, mode):
0.200.826 by Jelmer Vernooij
Fix some long lines.
91
    trace.mutter("Unusual file mode %o for %s in %s. Storing as revision "
92
                 "property. ", mode, path, commit)
0.200.490 by Jelmer Vernooij
Warn about unusual modes and escaped XML-invalid characters.
93
94
0.206.1 by Jelmer Vernooij
Use foreign utility functions.
95
class BzrGitMapping(foreign.VcsMapping):
0.200.97 by Jelmer Vernooij
use mapping object.
96
    """Class that maps between Git and Bazaar semantics."""
97
    experimental = False
98
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
99
    BZR_FILE_IDS_FILE = None
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
100
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
101
    BZR_DUMMY_FILE = None
0.252.26 by Jelmer Vernooij
Add is_control_file method to BzrGitMapping.
102
0.200.1328 by Jelmer Vernooij
More test fixes.
103
    def is_special_file(self, filename):
104
        return (filename in (self.BZR_FILE_IDS_FILE, self.BZR_DUMMY_FILE))
105
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
106
    def __init__(self):
0.200.1263 by Jelmer Vernooij
Fix foreign_vcs_git.
107
        super(BzrGitMapping, self).__init__(foreign_vcs_git)
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
108
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
109
    def __eq__(self, other):
0.200.1020 by Jelmer Vernooij
Store testament-sha1 in metadata.
110
        return (type(self) == type(other) and
0.200.726 by Jelmer Vernooij
Factor out conversion of branch names to refs.
111
                self.revid_prefix == other.revid_prefix)
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
112
113
    @classmethod
114
    def revision_id_foreign_to_bzr(cls, git_rev_id):
0.200.97 by Jelmer Vernooij
use mapping object.
115
        """Convert a git revision id handle to a Bazaar revision id."""
0.200.891 by Jelmer Vernooij
Use ZERO_SHA constant where possible.
116
        from dulwich.protocol import ZERO_SHA
117
        if git_rev_id == ZERO_SHA:
0.200.769 by Jelmer Vernooij
Cope with open_branch() actually checking whether there is a branch present.
118
            return NULL_REVISION
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
119
        return "%s:%s" % (cls.revid_prefix, git_rev_id)
0.200.97 by Jelmer Vernooij
use mapping object.
120
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
121
    @classmethod
122
    def revision_id_bzr_to_foreign(cls, bzr_rev_id):
0.200.97 by Jelmer Vernooij
use mapping object.
123
        """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.
124
        if not bzr_rev_id.startswith("%s:" % cls.revid_prefix):
125
            raise errors.InvalidRevisionId(bzr_rev_id, cls)
126
        return bzr_rev_id[len(cls.revid_prefix)+1:], cls()
0.200.97 by Jelmer Vernooij
use mapping object.
127
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
128
    def generate_file_id(self, path):
0.200.297 by Jelmer Vernooij
Cope with non-ascii characters in filenames (needs a test..).
129
        # Git paths are just bytestrings
130
        # We must just hope they are valid UTF-8..
0.200.157 by Jelmer Vernooij
Fix some bit of fetching.
131
        if path == "":
132
            return ROOT_ID
0.200.973 by Jelmer Vernooij
Add tests for generate_file_id.
133
        if type(path) is unicode:
134
            path = path.encode("utf-8")
0.200.297 by Jelmer Vernooij
Cope with non-ascii characters in filenames (needs a test..).
135
        return escape_file_id(path)
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
136
0.252.26 by Jelmer Vernooij
Add is_control_file method to BzrGitMapping.
137
    def is_control_file(self, path):
138
        return path in (self.BZR_FILE_IDS_FILE, self.BZR_DUMMY_FILE)
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.252.31 by Jelmer Vernooij
Properly escape revids when using them in ref names.
145
    def revid_as_refname(self, revid):
146
        import urllib
147
        return "refs/bzr/%s" % urllib.quote(revid)
148
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
149
    def import_unusual_file_modes(self, rev, unusual_file_modes):
150
        if unusual_file_modes:
0.200.878 by Jelmer Vernooij
Fix determining of unusual file modes.
151
            ret = [(path, unusual_file_modes[path])
152
                   for path in sorted(unusual_file_modes.keys())]
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
153
            rev.properties['file-modes'] = bencode.bencode(ret)
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
154
0.200.547 by Jelmer Vernooij
Support getting unusual file modes out of revision properties.
155
    def export_unusual_file_modes(self, rev):
156
        try:
0.200.894 by Jelmer Vernooij
Simplify formatting a bit.
157
            file_modes = rev.properties['file-modes']
0.200.547 by Jelmer Vernooij
Support getting unusual file modes out of revision properties.
158
        except KeyError:
159
            return {}
0.200.894 by Jelmer Vernooij
Simplify formatting a bit.
160
        else:
161
            return dict([(self.generate_file_id(path), mode) for (path, mode) in bencode.bdecode(file_modes.encode("utf-8"))])
0.200.547 by Jelmer Vernooij
Support getting unusual file modes out of revision properties.
162
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
163
    def _generate_git_svn_metadata(self, rev, encoding):
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
164
        try:
0.200.894 by Jelmer Vernooij
Simplify formatting a bit.
165
            git_svn_id = rev.properties["git-svn-id"]
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
166
        except KeyError:
167
            return ""
0.200.894 by Jelmer Vernooij
Simplify formatting a bit.
168
        else:
169
            return "\ngit-svn-id: %s\n" % git_svn_id.encode(encoding)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
170
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
171
    def _generate_hg_message_tail(self, rev):
172
        extra = {}
173
        renames = []
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
174
        branch = 'default'
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
175
        for name in rev.properties:
176
            if name == 'hg:extra:branch':
177
                branch = rev.properties['hg:extra:branch']
178
            elif name.startswith('hg:extra'):
0.200.826 by Jelmer Vernooij
Fix some long lines.
179
                extra[name[len('hg:extra:'):]] = base64.b64decode(
180
                    rev.properties[name])
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
181
            elif name == 'hg:renames':
0.200.826 by Jelmer Vernooij
Fix some long lines.
182
                renames = bencode.bdecode(base64.b64decode(
183
                    rev.properties['hg:renames']))
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
184
            # TODO: Export other properties as 'bzr:' extras?
0.200.660 by Jelmer Vernooij
Fix encoding issues.
185
        ret = format_hg_metadata(renames, branch, extra)
186
        assert isinstance(ret, str)
187
        return ret
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
188
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
189
    def _extract_git_svn_metadata(self, rev, message):
190
        lines = message.split("\n")
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
191
        if not (lines[-1] == "" and len(lines) >= 2 and lines[-2].startswith("git-svn-id:")):
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
192
            return message
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
193
        git_svn_id = lines[-2].split(": ", 1)[1]
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
194
        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.
195
        (url, rev, uuid) = parse_git_svn_id(git_svn_id)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
196
        # FIXME: Convert this to converted-from property somehow..
0.200.660 by Jelmer Vernooij
Fix encoding issues.
197
        ret = "\n".join(lines[:-2])
198
        assert isinstance(ret, str)
199
        return ret
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
200
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
201
    def _extract_hg_metadata(self, rev, message):
202
        (message, renames, branch, extra) = extract_hg_metadata(message)
203
        if branch is not None:
204
            rev.properties['hg:extra:branch'] = branch
205
        for name, value in extra.iteritems():
206
            rev.properties['hg:extra:' + name] = base64.b64encode(value)
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
207
        if renames:
0.200.826 by Jelmer Vernooij
Fix some long lines.
208
            rev.properties['hg:renames'] = base64.b64encode(bencode.bencode(
209
                [(new, old) for (old, new) in renames.iteritems()]))
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
210
        return message
211
0.252.2 by Jelmer Vernooij
Add functions for adding metadata to revision messages.
212
    def _extract_bzr_metadata(self, rev, message):
213
        (message, metadata) = extract_bzr_metadata(message)
0.252.4 by Jelmer Vernooij
More work on roundtripping.
214
        return message, metadata
0.252.2 by Jelmer Vernooij
Add functions for adding metadata to revision messages.
215
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
216
    def _decode_commit_message(self, rev, message, encoding):
0.200.1324 by Jelmer Vernooij
More work on roundtripping support.
217
        return message.decode(encoding), CommitSupplement()
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
218
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
219
    def _encode_commit_message(self, rev, message, encoding):
220
        return message.encode(encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
221
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
222
    def export_fileid_map(self, fileid_map):
223
        """Export a file id map to a fileid map.
224
225
        :param fileid_map: File id map, mapping paths to file ids
226
        :return: A Git blob object
227
        """
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
228
        from dulwich.objects import Blob
229
        b = Blob()
230
        b.set_raw_chunks(serialize_fileid_map(fileid_map))
231
        return b
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
232
0.200.1023 by Jelmer Vernooij
Set and verify testament.
233
    def export_commit(self, rev, tree_sha, parent_lookup, roundtrip,
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
234
                      verifiers):
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
235
        """Turn a Bazaar revision in to a Git commit
236
237
        :param tree_sha: Tree sha for the commit
0.200.826 by Jelmer Vernooij
Fix some long lines.
238
        :param parent_lookup: Function for looking up the GIT sha equiv of a
239
            bzr revision
0.200.1023 by Jelmer Vernooij
Set and verify testament.
240
        :param roundtrip: Whether to store roundtripping information.
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
241
        :param verifiers: Verifiers info
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
242
        :return dulwich.objects.Commit represent the revision:
243
        """
244
        from dulwich.objects import Commit
245
        commit = Commit()
246
        commit.tree = tree_sha
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
247
        if roundtrip:
0.200.1324 by Jelmer Vernooij
More work on roundtripping support.
248
            metadata = CommitSupplement()
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
249
            metadata.verifiers = verifiers
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
250
        else:
251
            metadata = None
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
252
        parents = []
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
253
        for p in rev.parent_ids:
0.200.705 by Jelmer Vernooij
Cope with imports.
254
            try:
255
                git_p = parent_lookup(p)
256
            except KeyError:
257
                git_p = None
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
258
                if metadata is not None:
259
                    metadata.explicit_parent_ids = rev.parent_ids
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
260
            if git_p is not None:
261
                assert len(git_p) == 40, "unexpected length for %r" % git_p
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
262
                parents.append(git_p)
263
        commit.parents = parents
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
264
        try:
265
            encoding = rev.properties['git-explicit-encoding']
266
        except KeyError:
267
            encoding = rev.properties.get('git-implicit-encoding', 'utf-8')
268
        commit.encoding = rev.properties.get('git-explicit-encoding')
269
        commit.committer = fix_person_identifier(rev.committer.encode(
270
            encoding))
271
        commit.author = fix_person_identifier(
272
            rev.get_apparent_authors()[0].encode(encoding))
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
273
        commit.commit_time = long(rev.timestamp)
274
        if 'author-timestamp' in rev.properties:
275
            commit.author_time = long(rev.properties['author-timestamp'])
276
        else:
277
            commit.author_time = commit.commit_time
0.200.884 by Jelmer Vernooij
Cope with -0000 as timezone in Git commits.
278
        commit._commit_timezone_neg_utc = "commit-timezone-neg-utc" in rev.properties
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
279
        commit.commit_timezone = rev.timezone
0.200.884 by Jelmer Vernooij
Cope with -0000 as timezone in Git commits.
280
        commit._author_timezone_neg_utc = "author-timezone-neg-utc" in rev.properties
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
281
        if 'author-timezone' in rev.properties:
282
            commit.author_timezone = int(rev.properties['author-timezone'])
283
        else:
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
284
            commit.author_timezone = commit.commit_timezone
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
285
        commit.message = self._encode_commit_message(rev, rev.message, 
286
            encoding)
0.252.40 by Jelmer Vernooij
Checks for roundtripping.
287
        assert type(commit.message) == str
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
288
        if metadata is not None:
0.252.4 by Jelmer Vernooij
More work on roundtripping.
289
            try:
290
                mapping_registry.parse_revision_id(rev.revision_id)
291
            except errors.InvalidRevisionId:
292
                metadata.revision_id = rev.revision_id
0.252.10 by Jelmer Vernooij
Support roundtripping custom revision properties.
293
            mapping_properties = set(
294
                ['author', 'author-timezone', 'author-timezone-neg-utc',
295
                 'commit-timezone-neg-utc', 'git-implicit-encoding',
0.252.15 by Jelmer Vernooij
Add file-modes to list of mapping properties.
296
                 'git-explicit-encoding', 'author-timestamp', 'file-modes'])
0.252.10 by Jelmer Vernooij
Support roundtripping custom revision properties.
297
            for k, v in rev.properties.iteritems():
298
                if not k in mapping_properties:
299
                    metadata.properties[k] = v
0.200.912 by Jelmer Vernooij
Merge roundtrip support.
300
        if self.roundtripping:
301
            commit.message = inject_bzr_metadata(commit.message, metadata, 
302
                                                 encoding)
0.252.40 by Jelmer Vernooij
Checks for roundtripping.
303
        assert type(commit.message) == str
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
304
        return commit
305
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
306
    def import_fileid_map(self, blob):
307
        """Convert a git file id map blob.
308
309
        :param blob: Git blob object with fileid map
310
        :return: Dictionary mapping paths to file ids
311
        """
0.252.35 by Jelmer Vernooij
Ignore control files in inventories.
312
        return deserialize_fileid_map(blob.data)
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
313
0.252.44 by Jelmer Vernooij
Properly look up Bazaar revision ids for revision parents in case they are round-tripped.
314
    def import_commit(self, commit, lookup_parent_revid):
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
315
        """Convert a git commit to a bzr revision.
316
0.200.1021 by Jelmer Vernooij
Put testament sha1 in revisions.
317
        :return: a `bzrlib.revision.Revision` object, foreign revid and a
318
            testament sha1
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
319
        """
320
        if commit is None:
321
            raise AssertionError("Commit object can't be None")
0.200.826 by Jelmer Vernooij
Fix some long lines.
322
        rev = ForeignRevision(commit.id, self,
323
                self.revision_id_foreign_to_bzr(commit.id))
0.252.4 by Jelmer Vernooij
More work on roundtripping.
324
        rev.git_metadata = None
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
325
        def decode_using_encoding(rev, commit, encoding):
326
            rev.committer = str(commit.committer).decode(encoding)
327
            if commit.committer != commit.author:
328
                rev.properties['author'] = str(commit.author).decode(encoding)
0.252.4 by Jelmer Vernooij
More work on roundtripping.
329
            rev.message, rev.git_metadata = self._decode_commit_message(
330
                rev, commit.message, encoding)
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
331
        if commit.encoding is not None:
332
            rev.properties['git-explicit-encoding'] = commit.encoding
333
            decode_using_encoding(rev, commit, commit.encoding)
334
        else:
335
            for encoding in ('utf-8', 'latin1'):
336
                try:
337
                    decode_using_encoding(rev, commit, encoding)
338
                except UnicodeDecodeError:
339
                    pass
340
                else:
341
                    if encoding != 'utf-8':
342
                        rev.properties['git-implicit-encoding'] = encoding
343
                    break
0.200.350 by Jelmer Vernooij
Support author_time
344
        if commit.commit_time != commit.author_time:
345
            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.
346
        if commit.commit_timezone != commit.author_timezone:
0.200.826 by Jelmer Vernooij
Fix some long lines.
347
            rev.properties['author-timezone'] = "%d" % commit.author_timezone
0.200.884 by Jelmer Vernooij
Cope with -0000 as timezone in Git commits.
348
        if commit._author_timezone_neg_utc:
349
            rev.properties['author-timezone-neg-utc'] = ""
350
        if commit._commit_timezone_neg_utc:
351
            rev.properties['commit-timezone-neg-utc'] = ""
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
352
        rev.timestamp = commit.commit_time
0.200.440 by Jelmer Vernooij
Remove silly mapping of timezones; dulwich uses offsets now as well.
353
        rev.timezone = commit.commit_timezone
0.261.5 by Jelmer Vernooij
Fix looking up of parents during fetch.
354
        rev.parent_ids = None
0.252.4 by Jelmer Vernooij
More work on roundtripping.
355
        if rev.git_metadata is not None:
0.252.6 by Jelmer Vernooij
Roundtripping support for revision ids works.
356
            md = rev.git_metadata
0.200.1021 by Jelmer Vernooij
Put testament sha1 in revisions.
357
            roundtrip_revid = md.revision_id
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
358
            if md.explicit_parent_ids:
359
                rev.parent_ids = md.explicit_parent_ids
0.252.10 by Jelmer Vernooij
Support roundtripping custom revision properties.
360
            rev.properties.update(md.properties)
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
361
            verifiers = md.verifiers
0.200.1021 by Jelmer Vernooij
Put testament sha1 in revisions.
362
        else:
363
            roundtrip_revid = None
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
364
            verifiers = {}
0.261.5 by Jelmer Vernooij
Fix looking up of parents during fetch.
365
        if rev.parent_ids is None:
366
            rev.parent_ids = tuple([lookup_parent_revid(p) for p in commit.parents])
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
367
        return rev, roundtrip_revid, verifiers
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
368
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
369
    def get_fileid_map(self, lookup_object, tree_sha):
370
        """Obtain a fileid map for a particular tree.
371
372
        :param lookup_object: Function for looking up an object
373
        :param tree_sha: SHA of the root tree
374
        :return: GitFileIdMap instance
375
        """
376
        try:
377
            file_id_map_sha = lookup_object(tree_sha)[self.BZR_FILE_IDS_FILE][1]
378
        except KeyError:
379
            file_ids = {}
380
        else:
381
            file_ids = self.import_fileid_map(lookup_object(file_id_map_sha))
382
        return GitFileIdMap(file_ids, self)
383
0.200.97 by Jelmer Vernooij
use mapping object.
384
0.200.190 by Jelmer Vernooij
Bless current mapping as v1.
385
class BzrGitMappingv1(BzrGitMapping):
386
    revid_prefix = 'git-v1'
387
    experimental = False
388
0.200.393 by Jelmer Vernooij
Provide __str__ implementation for mapping, fix docstring for ForeignGit.
389
    def __str__(self):
390
        return self.revid_prefix
391
0.200.190 by Jelmer Vernooij
Bless current mapping as v1.
392
393
class BzrGitMappingExperimental(BzrGitMappingv1):
0.200.104 by Jelmer Vernooij
Use bzr-foreign function names for converting between git and bzr revids.
394
    revid_prefix = 'git-experimental'
395
    experimental = True
0.200.912 by Jelmer Vernooij
Merge roundtrip support.
396
    roundtripping = True
0.200.97 by Jelmer Vernooij
use mapping object.
397
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
398
    BZR_FILE_IDS_FILE = '.bzrfileids'
399
400
    BZR_DUMMY_FILE = '.bzrdummy'
401
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
402
    def _decode_commit_message(self, rev, message, encoding):
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
403
        message = self._extract_hg_metadata(rev, message)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
404
        message = self._extract_git_svn_metadata(rev, message)
0.252.4 by Jelmer Vernooij
More work on roundtripping.
405
        message, metadata = self._extract_bzr_metadata(rev, message)
406
        return message.decode(encoding), metadata
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
407
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
408
    def _encode_commit_message(self, rev, message, encoding):
409
        ret = message.encode(encoding)
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
410
        ret += self._generate_hg_message_tail(rev)
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
411
        ret += self._generate_git_svn_metadata(rev, encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
412
        return ret
413
0.252.44 by Jelmer Vernooij
Properly look up Bazaar revision ids for revision parents in case they are round-tripped.
414
    def import_commit(self, commit, lookup_parent_revid):
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
415
        rev, roundtrip_revid, verifiers = super(BzrGitMappingExperimental, self).import_commit(commit, lookup_parent_revid)
0.200.642 by Jelmer Vernooij
In experimental mappings, set 'converted_revision' property.
416
        rev.properties['converted_revision'] = "git %s\n" % commit.id
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
417
        return rev, roundtrip_revid, verifiers
0.200.642 by Jelmer Vernooij
In experimental mappings, set 'converted_revision' property.
418
0.200.97 by Jelmer Vernooij
use mapping object.
419
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
420
class GitMappingRegistry(VcsMappingRegistry):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
421
    """Registry with available git mappings."""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
422
423
    def revision_id_bzr_to_foreign(self, bzr_revid):
0.200.701 by Jelmer Vernooij
Fix check in git repos.
424
        if bzr_revid == NULL_REVISION:
0.200.892 by Jelmer Vernooij
Lazy import ZERO_SHA.
425
            from dulwich.protocol import ZERO_SHA
0.200.891 by Jelmer Vernooij
Use ZERO_SHA constant where possible.
426
            return ZERO_SHA, None
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
427
        if not bzr_revid.startswith("git-"):
428
            raise errors.InvalidRevisionId(bzr_revid, None)
429
        (mapping_version, git_sha) = bzr_revid.split(":", 1)
430
        mapping = self.get(mapping_version)
431
        return mapping.revision_id_bzr_to_foreign(bzr_revid)
432
433
    parse_revision_id = revision_id_bzr_to_foreign
434
435
436
mapping_registry = GitMappingRegistry()
437
mapping_registry.register_lazy('git-v1', "bzrlib.plugins.git.mapping",
0.200.826 by Jelmer Vernooij
Fix some long lines.
438
    "BzrGitMappingv1")
439
mapping_registry.register_lazy('git-experimental',
440
    "bzrlib.plugins.git.mapping", "BzrGitMappingExperimental")
0.200.1324 by Jelmer Vernooij
More work on roundtripping support.
441
# mapping_registry.set_default('git-experimental')
0.200.661 by Jelmer Vernooij
Set mapping back to v1.
442
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.
443
444
445
class ForeignGit(ForeignVcs):
0.200.393 by Jelmer Vernooij
Provide __str__ implementation for mapping, fix docstring for ForeignGit.
446
    """The Git Stupid Content Tracker"""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
447
0.243.1 by Jelmer Vernooij
Use foreign branch testing infrastructure.
448
    @property
449
    def branch_format(self):
450
        from bzrlib.plugins.git.branch import GitBranchFormat
451
        return GitBranchFormat()
452
0.200.657 by Jelmer Vernooij
Provide repository_format attribute, as required by newer foreign VCS tests in bzrlib.
453
    @property
454
    def repository_format(self):
455
        from bzrlib.plugins.git.repository import GitRepositoryFormat
456
        return GitRepositoryFormat()
457
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
458
    def __init__(self):
459
        super(ForeignGit, self).__init__(mapping_registry)
0.200.646 by Jelmer Vernooij
Store abbreviation in foreign branch.
460
        self.abbreviation = "git"
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
461
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
462
    @classmethod
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
463
    def serialize_foreign_revid(self, foreign_revid):
464
        return foreign_revid
465
466
    @classmethod
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
467
    def show_foreign_revid(cls, foreign_revid):
468
        return { "git commit": foreign_revid }
469
470
0.200.1263 by Jelmer Vernooij
Fix foreign_vcs_git.
471
foreign_vcs_git = ForeignGit()
0.200.637 by Jelmer Vernooij
Allow single place for configuration of default mapping.
472
default_mapping = mapping_registry.get_default()()
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
473
474
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
475
def symlink_to_blob(entry):
476
    from dulwich.objects import Blob
477
    blob = Blob()
0.200.795 by Jelmer Vernooij
simplify sha extraction for blobs, process multiple blobs at once.
478
    symlink_target = entry.symlink_target
479
    if type(symlink_target) == unicode:
480
        symlink_target = symlink_target.encode('utf-8')
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
481
    blob.data = symlink_target
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
482
    return blob
483
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
484
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
485
def mode_is_executable(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
486
    """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.
487
    return bool(mode & 0111)
488
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
489
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
490
def mode_kind(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
491
    """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.
492
    entry_kind = (mode & 0700000) / 0100000
493
    if entry_kind == 0:
494
        return 'directory'
495
    elif entry_kind == 1:
496
        file_kind = (mode & 070000) / 010000
497
        if file_kind == 0:
498
            return 'file'
499
        elif file_kind == 2:
500
            return 'symlink'
501
        elif file_kind == 6:
502
            return 'tree-reference'
503
        else:
504
            raise AssertionError(
505
                "Unknown file kind %d, perms=%o." % (file_kind, mode,))
506
    else:
507
        raise AssertionError(
508
            "Unknown kind, perms=%r." % (mode,))
509
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
510
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
511
def object_mode(kind, executable):
512
    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.
513
        return stat.S_IFDIR
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
514
    elif kind == 'symlink':
0.245.1 by INADA Naoki
Handle executable mode for symlink.
515
        mode = stat.S_IFLNK
516
        if executable:
0.200.703 by Jelmer Vernooij
Merge support for executable symlinks.
517
            mode |= 0111
0.245.1 by INADA Naoki
Handle executable mode for symlink.
518
        return mode
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
519
    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.
520
        mode = stat.S_IFREG | 0644
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
521
        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.
522
            mode |= 0111
523
        return mode
0.200.665 by Jelmer Vernooij
Add more checks for submodules.
524
    elif kind == 'tree-reference':
525
        from dulwich.objects import S_IFGITLINK
526
        return S_IFGITLINK
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
527
    else:
528
        raise AssertionError
529
530
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
531
def entry_mode(entry):
532
    """Determine the git file mode for an inventory entry."""
533
    return object_mode(entry.kind, entry.executable)
534
535
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
536
def directory_to_tree(entry, lookup_ie_sha1, unusual_modes, empty_file_name):
537
    """Create a Git Tree object from a Bazaar directory.
538
539
    :param entry: Inventory entry
540
    :param lookup_ie_sha1: Lookup the Git SHA1 for a inventory entry
541
    :param unusual_modes: Dictionary with unusual file modes by file ids
542
    :param empty_file_name: Name to use for dummy files in empty directories,
543
        None to ignore empty directories.
544
    """
545
    from dulwich.objects import Blob, 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.
546
    tree = Tree()
0.200.807 by Jelmer Vernooij
Fix test, remove unnecessary sort.
547
    for name, value in entry.children.iteritems():
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.
548
        ie = entry.children[name]
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
549
        try:
550
            mode = unusual_modes[ie.file_id]
551
        except KeyError:
552
            mode = entry_mode(ie)
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
553
        hexsha = lookup_ie_sha1(ie)
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
554
        if hexsha is not None:
0.200.1152 by Jelmer Vernooij
Require dulwich 0.7.1.
555
            tree.add(name.encode("utf-8"), mode, hexsha)
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
556
    if entry.parent_id is not None and len(tree) == 0:
557
        # Only the root can be an empty tree
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
558
        if empty_file_name is not None:
0.200.1152 by Jelmer Vernooij
Require dulwich 0.7.1.
559
            tree.add(empty_file_name, stat.S_IFREG | 0644, Blob().id)
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
560
        else:
561
            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.
562
    return tree
563
564
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
565
def extract_unusual_modes(rev):
566
    try:
0.200.826 by Jelmer Vernooij
Fix some long lines.
567
        foreign_revid, mapping = mapping_registry.parse_revision_id(
568
            rev.revision_id)
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
569
    except errors.InvalidRevisionId:
570
        return {}
571
    else:
572
        return mapping.export_unusual_file_modes(rev)
573
574
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
575
def parse_git_svn_id(text):
576
    (head, uuid) = text.rsplit(" ", 1)
577
    (full_url, rev) = head.rsplit("@", 1)
0.200.653 by Jelmer Vernooij
Fix typo in git-svn-id parser, return revnum as integer.
578
    return (full_url, int(rev), uuid)
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
579
580
581
class GitFileIdMap(object):
582
583
    def __init__(self, file_ids, mapping):
584
        self.file_ids = file_ids
585
        self.paths = None
586
        self.mapping = mapping
587
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
588
    def set_file_id(self, path, file_id):
0.200.1209 by Jelmer Vernooij
Check for types in file id map.
589
        assert type(path) is str
590
        assert type(file_id) is str
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
591
        self.file_ids[path] = file_id
592
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
593
    def lookup_file_id(self, path):
0.200.984 by Jelmer Vernooij
Handle non-ascii characters in filenames.
594
        assert type(path) is str
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
595
        try:
0.200.973 by Jelmer Vernooij
Add tests for generate_file_id.
596
            file_id = self.file_ids[path]
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
597
        except KeyError:
0.200.973 by Jelmer Vernooij
Add tests for generate_file_id.
598
            file_id = self.mapping.generate_file_id(path)
599
        assert type(file_id) is str
600
        return file_id
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
601
602
    def lookup_path(self, file_id):
603
        if self.paths is None:
604
            self.paths = {}
605
            for k, v in self.file_ids.iteritems():
606
                self.paths[v] = k
607
        try:
0.200.984 by Jelmer Vernooij
Handle non-ascii characters in filenames.
608
            path = self.paths[file_id]
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
609
        except KeyError:
610
            return self.mapping.parse_file_id(file_id)
0.200.984 by Jelmer Vernooij
Handle non-ascii characters in filenames.
611
        else:
612
            assert type(path) is str
613
            return path
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
614
615
    def copy(self):
616
        return self.__class__(dict(self.file_ids), self.mapping)