/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 breezy/git/mapping.py

  • Committer: Jelmer Vernooij
  • Date: 2019-06-03 23:48:08 UTC
  • mfrom: (7316 work)
  • mto: This revision was merged to the branch mainline in revision 7328.
  • Revision ID: jelmer@jelmer.uk-20190603234808-15yk5c7054tj8e2b
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
    )
47
47
from .errors import (
48
48
    NoPushSupport,
 
49
    UnknownCommitExtra,
 
50
    UnknownMercurialCommitExtra,
49
51
    )
50
52
from .hg import (
51
53
    format_hg_metadata,
55
57
    extract_bzr_metadata,
56
58
    inject_bzr_metadata,
57
59
    CommitSupplement,
 
60
    deserialize_fileid_map,
 
61
    serialize_fileid_map,
58
62
    )
59
63
 
60
64
 
71
75
ROOT_ID = b"TREE_ROOT"
72
76
 
73
77
 
74
 
class UnknownCommitExtra(errors.BzrError):
75
 
    _fmt = "Unknown extra fields in %(object)r: %(fields)r."
76
 
 
77
 
    def __init__(self, object, fields):
78
 
        errors.BzrError.__init__(self)
79
 
        self.object = object
80
 
        self.fields = ",".join(fields)
81
 
 
82
 
 
83
 
class UnknownMercurialCommitExtra(errors.BzrError):
84
 
    _fmt = "Unknown mercurial extra fields in %(object)r: %(fields)r."
85
 
 
86
 
    def __init__(self, object, fields):
87
 
        errors.BzrError.__init__(self)
88
 
        self.object = object
89
 
        self.fields = b",".join(fields)
90
 
 
91
 
 
92
78
def escape_file_id(file_id):
93
79
    file_id = file_id.replace(b'_', b'__')
94
80
    file_id = file_id.replace(b' ', b'_s')
145
131
    """Class that maps between Git and Bazaar semantics."""
146
132
    experimental = False
147
133
 
 
134
    BZR_FILE_IDS_FILE = None
 
135
 
148
136
    BZR_DUMMY_FILE = None
149
137
 
150
138
    def is_special_file(self, filename):
151
 
        return (filename in (self.BZR_DUMMY_FILE, ))
 
139
        return (filename in (self.BZR_FILE_IDS_FILE, self.BZR_DUMMY_FILE))
152
140
 
153
141
    def __init__(self):
154
142
        super(BzrGitMapping, self).__init__(foreign_vcs_git)
269
257
    def _encode_commit_message(self, rev, message, encoding):
270
258
        return message.encode(encoding)
271
259
 
 
260
    def export_fileid_map(self, fileid_map):
 
261
        """Export a file id map to a fileid map.
 
262
 
 
263
        :param fileid_map: File id map, mapping paths to file ids
 
264
        :return: A Git blob object (or None if there are no entries)
 
265
        """
 
266
        from dulwich.objects import Blob
 
267
        b = Blob()
 
268
        b.set_raw_chunks(serialize_fileid_map(fileid_map))
 
269
        return b
 
270
 
272
271
    def export_commit(self, rev, tree_sha, parent_lookup, lossy,
273
272
                      verifiers):
274
273
        """Turn a Bazaar revision in to a Git commit
332
331
            commit.author_timezone = commit.commit_timezone
333
332
        if u'git-gpg-signature' in rev.properties:
334
333
            commit.gpgsig = rev.properties[u'git-gpg-signature'].encode(
335
 
                'utf-8')
336
 
        if u'git-gpg-signature-b64' in rev.properties:
337
 
            commit.gpgsig = base64.b64decode(rev.properties[u'git-gpg-signature-b64'])
 
334
                'ascii')
338
335
        commit.message = self._encode_commit_message(rev, rev.message,
339
336
                                                     encoding)
340
337
        if not isinstance(commit.message, bytes):
347
344
            mapping_properties = set(
348
345
                [u'author', u'author-timezone', u'author-timezone-neg-utc',
349
346
                 u'commit-timezone-neg-utc', u'git-implicit-encoding',
350
 
                 u'git-gpg-signature', u'git-gpg-signature-b64',
351
 
                 u'git-explicit-encoding',
 
347
                 u'git-gpg-signature', u'git-explicit-encoding',
352
348
                 u'author-timestamp', u'file-modes'])
353
349
            for k, v in viewitems(rev.properties):
354
350
                if k not in mapping_properties:
374
370
                 for l in rev.properties[u'git-extra'].splitlines()])
375
371
        return commit
376
372
 
 
373
    def import_fileid_map(self, blob):
 
374
        """Convert a git file id map blob.
 
375
 
 
376
        :param blob: Git blob object with fileid map
 
377
        :return: Dictionary mapping paths to file ids
 
378
        """
 
379
        return deserialize_fileid_map(blob.data)
 
380
 
377
381
    def get_revision_id(self, commit):
378
382
        if commit.encoding:
379
383
            encoding = commit.encoding.decode('ascii')
380
384
        else:
381
385
            encoding = 'utf-8'
382
 
        try:
383
 
            message, metadata = self._decode_commit_message(
384
 
                None, commit.message, encoding)
385
 
        except UnicodeDecodeError:
386
 
            pass
387
 
        else:
388
 
            if metadata.revision_id:
389
 
                return metadata.revision_id
 
386
        message, metadata = self._decode_commit_message(
 
387
            None, commit.message, encoding)
 
388
        if metadata.revision_id:
 
389
            return metadata.revision_id
390
390
        return self.revision_id_foreign_to_bzr(commit.id)
391
391
 
392
 
    def import_commit(self, commit, lookup_parent_revid, strict=True):
 
392
    def import_commit(self, commit, lookup_parent_revid):
393
393
        """Convert a git commit to a bzr revision.
394
394
 
395
395
        :return: a `breezy.revision.Revision` object, foreign revid and a
430
430
        if commit._commit_timezone_neg_utc:
431
431
            rev.properties[u'commit-timezone-neg-utc'] = ""
432
432
        if commit.gpgsig:
433
 
            try:
434
 
                rev.properties[u'git-gpg-signature'] = commit.gpgsig.decode(
435
 
                    'utf-8')
436
 
            except UnicodeDecodeError:
437
 
                rev.properties[u'git-gpg-signature-b64'] = base64.b64encode(
438
 
                    commit.gpgsig)
 
433
            rev.properties[u'git-gpg-signature'] = commit.gpgsig.decode(
 
434
                'ascii')
439
435
        if commit.mergetag:
440
436
            for i, tag in enumerate(commit.mergetag):
441
437
                rev.properties[u'git-mergetag-%d' % i] = tag.as_raw_string()
467
463
                extra_lines.append(k + b' ' + v + b'\n')
468
464
            elif k == HG_EXTRA:
469
465
                hgk, hgv = v.split(b':', 1)
470
 
                if hgk not in (HG_EXTRA_AMEND_SOURCE, ) and strict:
 
466
                if hgk not in (HG_EXTRA_AMEND_SOURCE, ):
471
467
                    raise UnknownMercurialCommitExtra(commit, [hgk])
472
468
                extra_lines.append(k + b' ' + v + b'\n')
473
469
            else:
474
470
                unknown_extra_fields.append(k)
475
 
        if unknown_extra_fields and strict:
 
471
        if unknown_extra_fields:
476
472
            raise UnknownCommitExtra(
477
473
                commit,
478
474
                [f.decode('ascii', 'replace') for f in unknown_extra_fields])
480
476
            rev.properties[u'git-extra'] = b''.join(extra_lines)
481
477
        return rev, roundtrip_revid, verifiers
482
478
 
 
479
    def get_fileid_map(self, lookup_object, tree_sha):
 
480
        """Obtain a fileid map for a particular tree.
 
481
 
 
482
        :param lookup_object: Function for looking up an object
 
483
        :param tree_sha: SHA of the root tree
 
484
        :return: GitFileIdMap instance
 
485
        """
 
486
        try:
 
487
            file_id_map_sha = lookup_object(
 
488
                tree_sha)[self.BZR_FILE_IDS_FILE][1]
 
489
        except KeyError:
 
490
            file_ids = {}
 
491
        else:
 
492
            file_ids = self.import_fileid_map(lookup_object(file_id_map_sha))
 
493
        return GitFileIdMap(file_ids, self)
 
494
 
483
495
 
484
496
class BzrGitMappingv1(BzrGitMapping):
485
497
    revid_prefix = b'git-v1'
492
504
class BzrGitMappingExperimental(BzrGitMappingv1):
493
505
    revid_prefix = b'git-experimental'
494
506
    experimental = True
495
 
    roundtripping = False
 
507
    roundtripping = True
 
508
 
 
509
    BZR_FILE_IDS_FILE = '.bzrfileids'
496
510
 
497
511
    BZR_DUMMY_FILE = '.bzrdummy'
498
512
 
510
524
        ret += self._generate_git_svn_metadata(rev, encoding)
511
525
        return ret
512
526
 
513
 
    def import_commit(self, commit, lookup_parent_revid, strict=True):
 
527
    def import_commit(self, commit, lookup_parent_revid):
514
528
        rev, roundtrip_revid, verifiers = super(
515
529
            BzrGitMappingExperimental, self).import_commit(
516
 
                commit, lookup_parent_revid, strict)
 
530
                commit, lookup_parent_revid)
517
531
        rev.properties[u'converted_revision'] = "git %s\n" % commit.id
518
532
        return rev, roundtrip_revid, verifiers
519
533
 
656
670
    return (full_url, int(rev), uuid)
657
671
 
658
672
 
 
673
class GitFileIdMap(object):
 
674
 
 
675
    def __init__(self, file_ids, mapping):
 
676
        self.file_ids = file_ids
 
677
        self.paths = None
 
678
        self.mapping = mapping
 
679
 
 
680
    def set_file_id(self, path, file_id):
 
681
        if type(path) is not str:
 
682
            raise TypeError(path)
 
683
        if not isinstance(file_id, bytes):
 
684
            raise TypeError(file_id)
 
685
        self.file_ids[path] = file_id
 
686
 
 
687
    def lookup_file_id(self, path):
 
688
        if not isinstance(path, text_type):
 
689
            raise TypeError(path)
 
690
        try:
 
691
            file_id = self.file_ids[path]
 
692
        except KeyError:
 
693
            file_id = self.mapping.generate_file_id(path)
 
694
        if not isinstance(file_id, bytes):
 
695
            raise TypeError(file_id)
 
696
        return file_id
 
697
 
 
698
    def lookup_path(self, file_id):
 
699
        if self.paths is None:
 
700
            self.paths = {}
 
701
            for k, v in viewitems(self.file_ids):
 
702
                self.paths[v] = k
 
703
        try:
 
704
            path = self.paths[file_id]
 
705
        except KeyError:
 
706
            return self.mapping.parse_file_id(file_id)
 
707
        else:
 
708
            if not isinstance(path, text_type):
 
709
                raise TypeError(path)
 
710
            return path
 
711
 
 
712
    def copy(self):
 
713
        return self.__class__(dict(self.file_ids), self.mapping)
 
714
 
 
715
 
659
716
def needs_roundtripping(repo, revid):
660
717
    try:
661
718
        mapping_registry.parse_revision_id(revid)