~bzr/ubuntu/maverick/bzr-svn/bzr-ppa

« back to all changes in this revision

Viewing changes to mapping.py

  • Committer: Jelmer Vernooij
  • Date: 2008-05-11 19:29:26 UTC
  • mfrom: (220.36.144 0.4)
  • Revision ID: jelmer@samba.org-20080511192926-7mh02j45r25qmzkz
Merge 0.4 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
from bzrlib.errors import InvalidRevisionId
20
20
from bzrlib.trace import mutter
21
21
 
 
22
from bzrlib.plugins.svn import version_info
22
23
import calendar
23
24
import errors
24
 
from scheme import BranchingScheme, guess_scheme_from_branch_path
25
 
import sha
26
25
import svn
27
26
import time
28
27
import urllib
35
34
SVN_PROP_BZR_MERGE = 'bzr:merge'
36
35
SVN_PROP_BZR_REVISION_INFO = 'bzr:revision-info'
37
36
SVN_PROP_BZR_REVISION_ID = 'bzr:revision-id:v%d-' % MAPPING_VERSION
38
 
SVN_PROP_BZR_BRANCHING_SCHEME = 'bzr:branching-scheme'
39
37
 
40
38
SVN_REVPROP_BZR_COMMITTER = 'bzr:committer'
41
39
SVN_REVPROP_BZR_FILEIDS = 'bzr:file-ids'
45
43
SVN_REVPROP_BZR_REVNO = 'bzr:revno'
46
44
SVN_REVPROP_BZR_REVPROP_PREFIX = 'bzr:revprop:'
47
45
SVN_REVPROP_BZR_ROOT = 'bzr:root'
48
 
SVN_REVPROP_BZR_SCHEME = 'bzr:scheme'
49
46
SVN_REVPROP_BZR_SIGNATURE = 'bzr:gpg-signature'
50
47
SVN_REVPROP_BZR_TIMESTAMP = 'bzr:timestamp'
51
48
SVN_REVPROP_BZR_LOG = 'bzr:log'
250
247
            rev.properties[name[len(SVN_REVPROP_BZR_REVPROP_PREFIX):]] = value
251
248
 
252
249
 
253
 
class BzrSvnMapping:
 
250
class BzrSvnMapping(object):
254
251
    """Class that maps between Subversion and Bazaar semantics."""
255
252
    experimental = False
256
253
    _warned_experimental = False
257
254
 
258
255
    def __init__(self):
259
 
        if self.experimental and not BzrSvnMapping._warned_experimental:
 
256
        if (version_info[3] == 'exp' or self.experimental) and not BzrSvnMapping._warned_experimental:
260
257
            from bzrlib.trace import warning
261
258
            warning("using experimental bzr-svn mappings; output may change between revisions")
262
259
            BzrSvnMapping._warned_experimental = True
263
260
 
264
261
    @classmethod
 
262
    def from_repository(cls, repository, _hinted_branch_path=None):
 
263
        return cls()
 
264
 
 
265
    @classmethod
265
266
    def supports_roundtripping(cls):
266
267
        """Whether this mapping supports roundtripping.
267
268
        """
272
273
        """Whether this mapping can be used with custom revision properties."""
273
274
        return False
274
275
 
 
276
    def is_bzr_revision(self, revprops, fileprops):
 
277
        """Whether this is a revision that was pushed by Bazaar."""
 
278
        return False
 
279
 
275
280
    @classmethod
276
281
    def supports_custom_fileprops(cls):
277
282
        """Whether this mapping can be used with custom file properties."""
278
283
        return False
279
284
 
 
285
    def get_mandated_layout(self, repository):
 
286
        """Return the repository layout if any is mandated by this mapping, 
 
287
        None otherwise."""
 
288
        return None
 
289
 
280
290
    def parse_revision_id(self, revid):
281
291
        """Parse an existing Subversion-based revision id.
282
292
 
359
369
        """
360
370
        raise NotImplementedError(self.export_revision)
361
371
 
 
372
    def export_message(self, log, revprops, fileprops):
 
373
        raise NotImplementedError(self.export_message)
 
374
 
362
375
    def get_revision_id(self, branch_path, revprops, fileprops):
363
376
        raise NotImplementedError(self.get_revision_id)
364
377
 
430
443
    return "".join(["%s\t%s\n" % (urllib.quote(path), fileids[path]) for path in sorted(fileids.keys())])
431
444
 
432
445
 
433
 
class BzrSvnMappingv3(BzrSvnMapping):
434
 
    """The third version of the mappings as used in the 0.4.x series.
435
 
 
436
 
    """
437
 
    experimental = False
438
 
    upgrade_suffix = "-svn3"
439
 
    revid_prefix = "svn-v3-"
440
 
 
441
 
    def __init__(self, scheme):
442
 
        BzrSvnMapping.__init__(self)
443
 
        self.scheme = scheme
444
 
        assert not isinstance(scheme, str)
445
 
 
446
 
    def __repr__(self):
447
 
        return "%s(%r)" % (self.__class__.__name__, self.scheme)
448
 
 
449
 
    def generate_file_id(self, uuid, revnum, branch, inv_path):
450
 
        assert isinstance(uuid, str)
451
 
        assert isinstance(revnum, int)
452
 
        assert isinstance(branch, str)
453
 
        assert isinstance(inv_path, unicode)
454
 
        inv_path = inv_path.encode("utf-8")
455
 
        ret = "%d@%s:%s:%s" % (revnum, uuid, escape_svn_path(branch), escape_svn_path(inv_path))
456
 
        if len(ret) > 150:
457
 
            ret = "%d@%s:%s;%s" % (revnum, uuid, 
458
 
                                escape_svn_path(branch),
459
 
                                sha.new(inv_path).hexdigest())
460
 
        assert isinstance(ret, str)
461
 
        return osutils.safe_file_id(ret)
462
 
 
463
 
    @staticmethod
464
 
    def supports_roundtripping():
465
 
        return True
466
 
 
467
 
    @classmethod
468
 
    def _parse_revision_id(cls, revid):
469
 
        assert isinstance(revid, str)
470
 
 
471
 
        if not revid.startswith(cls.revid_prefix):
472
 
            raise InvalidRevisionId(revid, "")
473
 
 
474
 
        try:
475
 
            (version, uuid, branch_path, srevnum) = revid.split(":")
476
 
        except ValueError:
477
 
            raise InvalidRevisionId(revid, "")
478
 
 
479
 
        scheme = version[len(cls.revid_prefix):]
480
 
 
481
 
        branch_path = unescape_svn_path(branch_path)
482
 
 
483
 
        return (uuid, branch_path, int(srevnum), scheme)
484
 
 
485
 
    @classmethod
486
 
    def parse_revision_id(cls, revid):
487
 
        (uuid, branch_path, srevnum, scheme) = cls._parse_revision_id(revid)
488
 
        # Some older versions of bzr-svn 0.4 did not always set a branching
489
 
        # scheme but set "undefined" instead.
490
 
        if scheme == "undefined":
491
 
            scheme = guess_scheme_from_branch_path(branch_path)
492
 
        else:
493
 
            scheme = BranchingScheme.find_scheme(scheme)
494
 
 
495
 
        return (uuid, branch_path, srevnum, cls(scheme))
496
 
 
497
 
    def is_branch(self, branch_path):
498
 
        return (self.scheme.is_branch(branch_path) or 
499
 
                self.scheme.is_tag(branch_path))
500
 
 
501
 
    def is_tag(self, tag_path):
502
 
        return self.scheme.is_tag(tag_path)
503
 
 
504
 
    @classmethod
505
 
    def _generate_revision_id(cls, uuid, revnum, path, scheme):
506
 
        assert isinstance(revnum, int)
507
 
        assert isinstance(path, str)
508
 
        assert revnum >= 0
509
 
        assert revnum > 0 or path == "", \
510
 
                "Trying to generate revid for (%r,%r)" % (path, revnum)
511
 
        return "%s%s:%s:%s:%d" % (cls.revid_prefix, scheme, uuid, \
512
 
                       escape_svn_path(path.strip("/")), revnum)
513
 
 
514
 
    def generate_revision_id(self, uuid, revnum, path):
515
 
        return self._generate_revision_id(uuid, revnum, path, self.scheme)
516
 
 
517
 
    def unprefix(self, branch_path, repos_path):
518
 
        (bp, np) = self.scheme.unprefix(repos_path)
519
 
        assert branch_path == bp
520
 
        return np
521
 
 
522
 
    def __eq__(self, other):
523
 
        return type(self) == type(other) and self.scheme == other.scheme
524
 
 
525
 
 
526
 
class BzrSvnMappingFileProps:
 
446
class BzrSvnMappingFileProps(object):
527
447
    @classmethod
528
448
    def supports_custom_fileprops(cls):
529
449
        """Whether this mapping can be used with custom file properties."""
531
451
 
532
452
    def import_revision(self, svn_revprops, fileprops, rev):
533
453
        parse_svn_revprops(svn_revprops, rev)
534
 
        parse_revision_metadata(
535
 
                fileprops.get(SVN_PROP_BZR_REVISION_INFO, ""), rev)
 
454
        metadata = fileprops.get(SVN_PROP_BZR_REVISION_INFO)
 
455
        if metadata is not None:
 
456
            parse_revision_metadata(metadata, rev)
536
457
 
537
458
    def get_rhs_parents(self, branch_path, revprops, fileprops):
538
459
        bzr_merges = fileprops.get(SVN_PROP_BZR_ANCESTRY+str(self.scheme), None)
565
486
        return svnprops
566
487
 
567
488
    def export_revision(self, branch_root, timestamp, timezone, committer, revprops, revision_id, revno, merges, old_fileprops):
 
489
 
568
490
        # Keep track of what Subversion properties to set later on
569
491
        fileprops = {}
570
492
        fileprops[SVN_PROP_BZR_REVISION_INFO] = generate_revision_metadata(
581
503
 
582
504
        return ({}, fileprops)
583
505
 
 
506
    def is_bzr_revision(self, revprops, fileprops):
 
507
        return fileprops.has_key(SVN_PROP_BZR_REVISION_ID+str(self.scheme))
 
508
 
584
509
    def get_revision_id(self, branch_path, revprops, fileprops):
585
510
        # Lookup the revision from the bzr:revision-id-vX property
586
511
        text = fileprops.get(SVN_PROP_BZR_REVISION_ID+str(self.scheme), None)
604
529
        else:
605
530
            fileprops[SVN_PROP_BZR_FILEIDS] = ""
606
531
 
607
 
class BzrSvnMappingv3FileProps(BzrSvnMappingFileProps, BzrSvnMappingv3):
608
 
    pass
609
 
 
610
 
class BzrSvnMappingRevProps:
 
532
class BzrSvnMappingRevProps(object):
611
533
    @classmethod
612
534
    def supports_custom_revprops(cls):
613
535
        """Whether this mapping can be used with custom revision properties."""
628
550
            return []
629
551
        return svn_revprops.get(SVN_REVPROP_BZR_MERGE, "").splitlines()
630
552
 
 
553
    def is_bzr_revision(self, revprops, fileprops):
 
554
        return revprops.has_key(SVN_REVPROP_BZR_MAPPING_VERSION)
 
555
 
631
556
    def get_revision_id(self, branch_path, revprops, fileprops):
632
 
        if not revprops.has_key(SVN_REVPROP_BZR_MAPPING_VERSION):
 
557
        if not self.is_bzr_revision(revprops, fileprops):
633
558
            return (None, None)
634
559
        if revprops[SVN_REVPROP_BZR_ROOT] == branch_path:
635
560
            revid = revprops[SVN_REVPROP_BZR_REVISION_ID]
637
562
            return (revno, revid)
638
563
        return (None, None)
639
564
 
 
565
    def export_message(self, message, revprops, fileprops):
 
566
        revprops[SVN_REVPROP_BZR_LOG] = message.encode("utf-8")
 
567
 
640
568
    def export_revision(self, branch_root, timestamp, timezone, committer, 
641
569
                        revprops, revision_id, revno, merges, 
642
570
                        fileprops):
670
598
        raise NotImplementedError(self.get_rhs_ancestors)
671
599
 
672
600
 
673
 
class BzrSvnMappingv3RevProps(BzrSvnMappingRevProps, BzrSvnMappingv3):
674
 
    pass
675
 
 
676
 
 
677
601
class BzrSvnMappingv4(BzrSvnMappingRevProps):
678
602
    revid_prefix = "svn-v4"
679
603
    experimental = True
714
638
        return type(self) == type(other)
715
639
 
716
640
 
717
 
class BzrSvnMappingv3Hybrid(BzrSvnMappingv3):
718
 
    def __init__(self, scheme):
719
 
        BzrSvnMappingv3.__init__(self, scheme)
720
 
        self.revprops = BzrSvnMappingv3RevProps(scheme)
721
 
        self.fileprops = BzrSvnMappingv3FileProps(scheme)
722
 
 
723
 
    def get_rhs_parents(self, branch_path, svn_revprops, fileprops):
724
 
        if svn_revprops.has_key(SVN_REVPROP_BZR_MAPPING_VERSION):
725
 
            return self.revprops.get_rhs_parents(branch_path, svn_revprops, fileprops)
726
 
        else:
727
 
            return self.fileprops.get_rhs_parents(branch_path, svn_revprops, fileprops)
728
 
 
729
 
    def get_revision_id(self, branch_path, revprops, fileprops):
730
 
        if revprops.has_key(SVN_REVPROP_BZR_MAPPING_VERSION):
731
 
            return self.revprops.get_revision_id(branch_path, revprops, fileprops)
732
 
        else:
733
 
            return self.fileprops.get_revision_id(branch_path, revprops, fileprops)
734
 
 
735
 
    def import_fileid_map(self, svn_revprops, fileprops):
736
 
        if svn_revprops.has_key(SVN_REVPROP_BZR_MAPPING_VERSION):
737
 
            return self.revprops.import_fileid_map(svn_revprops, fileprops)
738
 
        else:
739
 
            return self.fileprops.import_fileid_map(svn_revprops, fileprops)
740
 
 
741
 
    def export_revision(self, branch_root, timestamp, timezone, committer, revprops, revision_id, revno, 
742
 
                        merges, fileprops):
743
 
        (_, fileprops) = self.fileprops.export_revision(branch_root, timestamp, timezone, committer, 
744
 
                                      revprops, revision_id, revno, merges, fileprops)
745
 
        (revprops, _) = self.revprops.export_revision(branch_root, timestamp, timezone, committer, 
746
 
                                      revprops, revision_id, revno, merges, fileprops)
747
 
        return (revprops, fileprops)
748
 
 
749
 
    def export_fileid_map(self, fileids, revprops, fileprops):
750
 
        self.fileprops.export_fileid_map(fileids, revprops, fileprops)
751
 
        self.revprops.export_fileid_map(fileids, revprops, fileprops)
752
 
 
753
 
    def import_revision(self, svn_revprops, fileprops, rev):
754
 
        self.fileprops.import_revision(svn_revprops, fileprops, rev)
755
 
        self.revprops.import_revision(svn_revprops, fileprops, rev)
756
 
 
757
641
class BzrSvnMappingRegistry(registry.Registry):
758
642
    """Registry for the various Bzr<->Svn mappings."""
759
643
    def register(self, key, factory, help):
769
653
 
770
654
        This method must be called once and only once.
771
655
        """
772
 
        registry.Registry.register(self, 'default', self.get(key), 
773
 
            self.get_help(key))
 
656
        self._set_default_key(key)
 
657
 
 
658
    def get_default(self):
 
659
        """Convenience function for obtaining the default mapping to use."""
 
660
        return self.get(self._get_default_key())
774
661
 
775
662
mapping_registry = BzrSvnMappingRegistry()
776
663
mapping_registry.register('v1', BzrSvnMappingv1,
777
664
        'Original bzr-svn mapping format')
778
665
mapping_registry.register('v2', BzrSvnMappingv2,
779
666
        'Second format')
780
 
mapping_registry.register('v3-revprops', BzrSvnMappingv3RevProps,
781
 
        'Third format with revision properties')
782
 
mapping_registry.register('v3-fileprops', BzrSvnMappingv3FileProps,
783
 
        'Third format with file properties')
784
 
mapping_registry.register('v3-hybrid', BzrSvnMappingv3Hybrid,
785
 
        'Hybrid third format')
786
 
mapping_registry.register('v3', BzrSvnMappingv3FileProps,
787
 
        'Default third format')
 
667
mapping_registry.register_lazy('v3-revprops', 'bzrlib.plugins.svn.mapping3', 
 
668
                               'BzrSvnMappingv3RevProps', 
 
669
                               'Third format with revision properties')
 
670
mapping_registry.register_lazy('v3-fileprops', 'bzrlib.plugins.svn.mapping3', 
 
671
                               'BzrSvnMappingv3FileProps',
 
672
                               'Third format with file properties')
 
673
mapping_registry.register_lazy('v3-hybrid', 'bzrlib.plugins.svn.mapping3', 
 
674
                               'BzrSvnMappingv3Hybrid', 'Hybrid third format')
 
675
mapping_registry.register_lazy('v3', 'bzrlib.plugins.svn.mapping3', 
 
676
                               'BzrSvnMappingv3FileProps', 
 
677
                               'Default third format')
788
678
mapping_registry.register('v4', BzrSvnMappingv4,
789
679
        'Fourth format')
790
680
mapping_registry.set_default('v3-fileprops')
791
681
 
792
 
 
793
682
def parse_revision_id(revid):
794
683
    """Try to parse a Subversion revision id.
795
684
    
802
691
    mapping = mapping_registry.get(mapping_version)
803
692
    return mapping.parse_revision_id(revid)
804
693
 
805
 
 
806
694
def get_default_mapping():
807
 
    """Convenience function for obtaining the default mapping to use."""
808
 
    return mapping_registry.get("default")
 
695
    return mapping_registry.get_default()