/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:
312
294
            for k, v in rev.properties.iteritems():
313
295
                if not k in mapping_properties:
314
296
                    metadata.properties[k] = v
315
 
        commit.message = inject_bzr_metadata(commit.message, metadata, 
316
 
                                             encoding)
 
297
        if self.roundtripping:
 
298
            commit.message = inject_bzr_metadata(commit.message, metadata, 
 
299
                                                 encoding)
317
300
        assert type(commit.message) == str
318
301
        return commit
319
302
 
325
308
        """
326
309
        return deserialize_fileid_map(blob.data)
327
310
 
328
 
    def import_commit(self, commit):
 
311
    def import_commit(self, commit, lookup_parent_revid):
329
312
        """Convert a git commit to a bzr revision.
330
313
 
331
 
        :return: a `bzrlib.revision.Revision` object and a 
332
 
            dictionary of path -> file ids
 
314
        :return: a `bzrlib.revision.Revision` object, foreign revid and a
 
315
            testament sha1
333
316
        """
334
317
        if commit is None:
335
318
            raise AssertionError("Commit object can't be None")
336
319
        rev = ForeignRevision(commit.id, self,
337
320
                self.revision_id_foreign_to_bzr(commit.id))
338
 
        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])
339
322
        rev.git_metadata = None
340
323
        def decode_using_encoding(rev, commit, encoding):
341
324
            rev.committer = str(commit.committer).decode(encoding)
368
351
        rev.timezone = commit.commit_timezone
369
352
        if rev.git_metadata is not None:
370
353
            md = rev.git_metadata
371
 
            if md.revision_id:
372
 
                rev.revision_id = md.revision_id
 
354
            roundtrip_revid = md.revision_id
373
355
            if md.explicit_parent_ids:
374
356
                rev.parent_ids = md.explicit_parent_ids
375
357
            rev.properties.update(md.properties)
376
 
        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)
377
378
 
378
379
 
379
380
class BzrGitMappingv1(BzrGitMapping):
387
388
class BzrGitMappingExperimental(BzrGitMappingv1):
388
389
    revid_prefix = 'git-experimental'
389
390
    experimental = True
 
391
    roundtripping = True
 
392
 
 
393
    BZR_FILE_IDS_FILE = '.bzrfileids'
 
394
 
 
395
    BZR_DUMMY_FILE = '.bzrdummy'
390
396
 
391
397
    def _decode_commit_message(self, rev, message, encoding):
392
398
        message = self._extract_hg_metadata(rev, message)
400
406
        ret += self._generate_git_svn_metadata(rev, encoding)
401
407
        return ret
402
408
 
403
 
    def import_commit(self, commit):
404
 
        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)
405
411
        rev.properties['converted_revision'] = "git %s\n" % commit.id
406
 
        return rev, file_ids
 
412
        return rev, roundtrip_revid, verifiers
407
413
 
408
414
 
409
415
class GitMappingRegistry(VcsMappingRegistry):
575
581
        self.mapping = mapping
576
582
 
577
583
    def lookup_file_id(self, path):
 
584
        assert type(path) is str
578
585
        try:
579
 
            return self.file_ids[path]
 
586
            file_id = self.file_ids[path]
580
587
        except KeyError:
581
 
            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
582
591
 
583
592
    def lookup_path(self, file_id):
584
593
        if self.paths is None:
586
595
            for k, v in self.file_ids.iteritems():
587
596
                self.paths[v] = k
588
597
        try:
589
 
            return self.paths[file_id]
 
598
            path = self.paths[file_id]
590
599
        except KeyError:
591
600
            return self.mapping.parse_file_id(file_id)
 
601
        else:
 
602
            assert type(path) is str
 
603
            return path