/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to mapping.py

More work on roundtrip push support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import stat
23
23
 
24
24
from bzrlib import (
 
25
    bencode,
25
26
    errors,
26
27
    foreign,
27
28
    trace,
28
29
    )
29
 
try:
30
 
    from bzrlib import bencode
31
 
except ImportError:
32
 
    from bzrlib.util import bencode
33
30
from bzrlib.inventory import (
34
31
    ROOT_ID,
35
32
    )
95
92
                 "property. ", mode, path, commit)
96
93
 
97
94
 
98
 
def squash_revision(target_repo, rev):
99
 
    """Remove characters that can't be stored from a revision, if necessary.
100
 
 
101
 
    :param target_repo: Repository in which the revision will be stored
102
 
    :param rev: Revision object, will be modified in-place
103
 
    """
104
 
    if not getattr(target_repo._serializer, "squashes_xml_invalid_characters", True):
105
 
        return
106
 
    from bzrlib.xml_serializer import escape_invalid_chars
107
 
    rev.message, num_escaped = escape_invalid_chars(rev.message)
108
 
    if num_escaped:
109
 
        warn_escaped(rev.foreign_revid, num_escaped)
110
 
    if 'author' in rev.properties:
111
 
        rev.properties['author'], num_escaped = escape_invalid_chars(
112
 
            rev.properties['author'])
113
 
        if num_escaped:
114
 
            warn_escaped(rev.foreign_revid, num_escaped)
115
 
    rev.committer, num_escaped = escape_invalid_chars(rev.committer)
116
 
    if num_escaped:
117
 
        warn_escaped(rev.foreign_revid, num_escaped)
118
 
 
119
 
 
120
95
class BzrGitMapping(foreign.VcsMapping):
121
96
    """Class that maps between Git and Bazaar semantics."""
122
97
    experimental = False
123
98
 
124
 
    BZR_FILE_IDS_FILE = '.bzrfileids'
 
99
    BZR_FILE_IDS_FILE = None
125
100
 
126
 
    BZR_DUMMY_FILE = '.bzrdummy'
 
101
    BZR_DUMMY_FILE = None
127
102
 
128
103
    def __init__(self):
129
104
        super(BzrGitMapping, self).__init__(foreign_git)
130
105
 
131
106
    def __eq__(self, other):
132
 
        return (type(self) == type(other) and 
 
107
        return (type(self) == type(other) and
133
108
                self.revid_prefix == other.revid_prefix)
134
109
 
135
110
    @classmethod
152
127
        # We must just hope they are valid UTF-8..
153
128
        if path == "":
154
129
            return ROOT_ID
 
130
        if type(path) is unicode:
 
131
            path = path.encode("utf-8")
155
132
        return escape_file_id(path)
156
133
 
157
134
    def is_control_file(self, path):
208
185
 
209
186
    def _extract_git_svn_metadata(self, rev, message):
210
187
        lines = message.split("\n")
211
 
        if not (lines[-1] == "" and lines[-2].startswith("git-svn-id:")):
 
188
        if not (lines[-1] == "" and len(lines) >= 2 and lines[-2].startswith("git-svn-id:")):
212
189
            return message
213
190
        git_svn_id = lines[-2].split(": ", 1)[1]
214
191
        rev.properties['git-svn-id'] = git_svn_id
234
211
        return message, metadata
235
212
 
236
213
    def _decode_commit_message(self, rev, message, encoding):
237
 
        message, metadata = self._extract_bzr_metadata(rev, message)
238
 
        return message.decode(encoding), metadata
 
214
        return message.decode(encoding), BzrGitRevisionMetadata()
239
215
 
240
216
    def _encode_commit_message(self, rev, message, encoding):
241
217
        return message.encode(encoding)
251
227
        b.set_raw_chunks(serialize_fileid_map(fileid_map))
252
228
        return b
253
229
 
254
 
    def export_commit(self, rev, tree_sha, parent_lookup, roundtrip):
 
230
    def export_commit(self, rev, tree_sha, parent_lookup, roundtrip,
 
231
                      verifiers):
255
232
        """Turn a Bazaar revision in to a Git commit
256
233
 
257
234
        :param tree_sha: Tree sha for the commit
258
235
        :param parent_lookup: Function for looking up the GIT sha equiv of a
259
236
            bzr revision
 
237
        :param roundtrip: Whether to store roundtripping information.
 
238
        :param verifiers: Verifiers info
260
239
        :return dulwich.objects.Commit represent the revision:
261
240
        """
262
241
        from dulwich.objects import Commit
264
243
        commit.tree = tree_sha
265
244
        if roundtrip:
266
245
            metadata = BzrGitRevisionMetadata()
 
246
            metadata.verifiers = verifiers
267
247
        else:
268
248
            metadata = None
 
249
        parents = []
269
250
        for p in rev.parent_ids:
270
251
            try:
271
252
                git_p = parent_lookup(p)
275
256
                    metadata.explicit_parent_ids = rev.parent_ids
276
257
            if git_p is not None:
277
258
                assert len(git_p) == 40, "unexpected length for %r" % git_p
278
 
                commit.parents.append(git_p)
 
259
                parents.append(git_p)
 
260
        commit.parents = parents
279
261
        try:
280
262
            encoding = rev.properties['git-explicit-encoding']
281
263
        except KeyError:
299
281
            commit.author_timezone = commit.commit_timezone
300
282
        commit.message = self._encode_commit_message(rev, rev.message, 
301
283
            encoding)
 
284
        assert type(commit.message) == str
302
285
        if metadata is not None:
303
286
            try:
304
287
                mapping_registry.parse_revision_id(rev.revision_id)
311
294
            for k, v in rev.properties.iteritems():
312
295
                if not k in mapping_properties:
313
296
                    metadata.properties[k] = v
314
 
        commit.message = inject_bzr_metadata(commit.message, metadata)
 
297
        if self.roundtripping:
 
298
            commit.message = inject_bzr_metadata(commit.message, metadata, 
 
299
                                                 encoding)
 
300
        assert type(commit.message) == str
315
301
        return commit
316
302
 
317
303
    def import_fileid_map(self, blob):
322
308
        """
323
309
        return deserialize_fileid_map(blob.data)
324
310
 
325
 
    def import_commit(self, commit):
 
311
    def import_commit(self, commit, lookup_parent_revid):
326
312
        """Convert a git commit to a bzr revision.
327
313
 
328
 
        :return: a `bzrlib.revision.Revision` object and a 
329
 
            dictionary of path -> file ids
 
314
        :return: a `bzrlib.revision.Revision` object, foreign revid and a
 
315
            testament sha1
330
316
        """
331
317
        if commit is None:
332
318
            raise AssertionError("Commit object can't be None")
333
319
        rev = ForeignRevision(commit.id, self,
334
320
                self.revision_id_foreign_to_bzr(commit.id))
335
 
        rev.parent_ids = tuple([self.revision_id_foreign_to_bzr(p) for p in commit.parents])
 
321
        rev.parent_ids = tuple([lookup_parent_revid(p) for p in commit.parents])
336
322
        rev.git_metadata = None
337
323
        def decode_using_encoding(rev, commit, encoding):
338
324
            rev.committer = str(commit.committer).decode(encoding)
365
351
        rev.timezone = commit.commit_timezone
366
352
        if rev.git_metadata is not None:
367
353
            md = rev.git_metadata
368
 
            if md.revision_id:
369
 
                rev.revision_id = md.revision_id
 
354
            roundtrip_revid = md.revision_id
370
355
            if md.explicit_parent_ids:
371
356
                rev.parent_ids = md.explicit_parent_ids
372
357
            rev.properties.update(md.properties)
373
 
        return rev
 
358
            verifiers = md.verifiers
 
359
        else:
 
360
            roundtrip_revid = None
 
361
            verifiers = {}
 
362
        return rev, roundtrip_revid, verifiers
 
363
 
 
364
    def get_fileid_map(self, lookup_object, tree_sha):
 
365
        """Obtain a fileid map for a particular tree.
 
366
 
 
367
        :param lookup_object: Function for looking up an object
 
368
        :param tree_sha: SHA of the root tree
 
369
        :return: GitFileIdMap instance
 
370
        """
 
371
        try:
 
372
            file_id_map_sha = lookup_object(tree_sha)[self.BZR_FILE_IDS_FILE][1]
 
373
        except KeyError:
 
374
            file_ids = {}
 
375
        else:
 
376
            file_ids = self.import_fileid_map(lookup_object(file_id_map_sha))
 
377
        return GitFileIdMap(file_ids, self)
374
378
 
375
379
 
376
380
class BzrGitMappingv1(BzrGitMapping):
384
388
class BzrGitMappingExperimental(BzrGitMappingv1):
385
389
    revid_prefix = 'git-experimental'
386
390
    experimental = True
 
391
    roundtripping = True
 
392
 
 
393
    BZR_FILE_IDS_FILE = '.bzrfileids'
 
394
 
 
395
    BZR_DUMMY_FILE = '.bzrdummy'
387
396
 
388
397
    def _decode_commit_message(self, rev, message, encoding):
389
398
        message = self._extract_hg_metadata(rev, message)
397
406
        ret += self._generate_git_svn_metadata(rev, encoding)
398
407
        return ret
399
408
 
400
 
    def import_commit(self, commit):
401
 
        rev, file_ids = super(BzrGitMappingExperimental, self).import_commit(commit)
 
409
    def import_commit(self, commit, lookup_parent_revid):
 
410
        rev, roundtrip_revid, verifiers = super(BzrGitMappingExperimental, self).import_commit(commit, lookup_parent_revid)
402
411
        rev.properties['converted_revision'] = "git %s\n" % commit.id
403
 
        return rev, file_ids
 
412
        return rev, roundtrip_revid, verifiers
404
413
 
405
414
 
406
415
class GitMappingRegistry(VcsMappingRegistry):
572
581
        self.mapping = mapping
573
582
 
574
583
    def lookup_file_id(self, path):
 
584
        assert type(path) is str
575
585
        try:
576
 
            return self.file_ids[path]
 
586
            file_id = self.file_ids[path]
577
587
        except KeyError:
578
 
            return self.mapping.generate_file_id(path)
 
588
            file_id = self.mapping.generate_file_id(path)
 
589
        assert type(file_id) is str
 
590
        return file_id
579
591
 
580
592
    def lookup_path(self, file_id):
581
593
        if self.paths is None:
583
595
            for k, v in self.file_ids.iteritems():
584
596
                self.paths[v] = k
585
597
        try:
586
 
            return self.paths[file_id]
 
598
            path = self.paths[file_id]
587
599
        except KeyError:
588
600
            return self.mapping.parse_file_id(file_id)
 
601
        else:
 
602
            assert type(path) is str
 
603
            return path