~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

Introduce BranchFormats - factoring out intialisation of Branches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
 
18
from cStringIO import StringIO
 
19
import errno
 
20
import os
18
21
import shutil
19
22
import sys
20
 
import os
21
 
import errno
22
23
from warnings import warn
23
 
from cStringIO import StringIO
24
24
 
25
25
 
26
26
import bzrlib
 
27
from bzrlib.config import TreeConfig
 
28
from bzrlib.delta import compare_trees
 
29
import bzrlib.errors as errors
 
30
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
 
31
                           NoSuchRevision, HistoryMissing, NotBranchError,
 
32
                           DivergedBranches, LockError, UnlistableStore,
 
33
                           UnlistableBranch, NoSuchFile, NotVersionedError,
 
34
                           NoWorkingTree)
27
35
import bzrlib.inventory as inventory
28
 
from bzrlib.trace import mutter, note
 
36
from bzrlib.inventory import Inventory
29
37
from bzrlib.osutils import (isdir, quotefn,
30
38
                            rename, splitpath, sha_file,
31
39
                            file_kind, abspath, normpath, pathjoin,
32
40
                            safe_unicode,
33
41
                            )
34
 
import bzrlib.errors as errors
35
 
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
36
 
                           NoSuchRevision, HistoryMissing, NotBranchError,
37
 
                           DivergedBranches, LockError, UnlistableStore,
38
 
                           UnlistableBranch, NoSuchFile, NotVersionedError,
39
 
                           NoWorkingTree)
40
42
from bzrlib.textui import show_status
 
43
from bzrlib.trace import mutter, note
 
44
from bzrlib.tree import EmptyTree, RevisionTree
41
45
from bzrlib.revision import (Revision, is_ancestor, get_intervening_revisions,
42
46
                             NULL_REVISION)
43
 
 
44
 
from bzrlib.delta import compare_trees
45
 
from bzrlib.tree import EmptyTree, RevisionTree
46
 
from bzrlib.inventory import Inventory
47
47
from bzrlib.store import copy_all
48
48
from bzrlib.store.text import TextStore
49
49
from bzrlib.store.weave import WeaveStore
52
52
from bzrlib.transport import Transport, get_transport
53
53
import bzrlib.xml5
54
54
import bzrlib.ui
55
 
from config import TreeConfig
56
55
 
57
56
 
58
57
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
508
507
        raise NotImplementedError('store_revision_signature is abstract')
509
508
 
510
509
 
 
510
class BzrBranchFormat(object):
 
511
    """An encapsulation of the initialization and open routines for a format.
 
512
 
 
513
    Formats provide three things:
 
514
     * An initialization routine,
 
515
     * a format string,
 
516
     * an open routine.
 
517
 
 
518
    Formats are placed in an dict by their format string for reference 
 
519
    during branch opening. Its not required that these be instances, they
 
520
    can be classes themselves with class methods - it simply depends on 
 
521
    whether state is needed for a given format or not.
 
522
 
 
523
    Once a format is deprecated, just deprecate the initialize and open
 
524
    methods on the format class. Do not deprecate the object, as the 
 
525
    object will be created every time regardless.
 
526
    """
 
527
 
 
528
    _formats = {}
 
529
    """The known formats."""
 
530
 
 
531
    @classmethod
 
532
    def find_format(klass, url):
 
533
        """Return the format registered for URL."""
 
534
        t = get_transport(url)
 
535
        return klass._formats[t.get(".bzr/branch-format").read()]
 
536
 
 
537
    def get_format_string(self):
 
538
        """Return the ASCII format string that identifies this format."""
 
539
        raise NotImplementedError(self.get_format_string)
 
540
 
 
541
    def _find_modes(self, t):
 
542
        """Determine the appropriate modes for files and directories.
 
543
        
 
544
        FIXME: When this merges into, or from storage,
 
545
        this code becomes delgatable to a LockableFiles instance.
 
546
 
 
547
        For now its cribbed and returns (dir_mode, file_mode)
 
548
        """
 
549
        try:
 
550
            st = t.stat('.')
 
551
        except errors.TransportNotPossible:
 
552
            dir_mode = 0755
 
553
            file_mode = 0644
 
554
        else:
 
555
            dir_mode = st.st_mode & 07777
 
556
            # Remove the sticky and execute bits for files
 
557
            file_mode = dir_mode & ~07111
 
558
        if not BzrBranch._set_dir_mode:
 
559
            dir_mode = None
 
560
        if not BzrBranch._set_file_mode:
 
561
            file_mode = None
 
562
        return dir_mode, file_mode
 
563
 
 
564
    def initialize(self, url):
 
565
        """Create a branch of this format at url and return an open branch."""
 
566
        t = get_transport(url)
 
567
        from bzrlib.inventory import Inventory
 
568
        from bzrlib.weavefile import write_weave_v5
 
569
        from bzrlib.weave import Weave
 
570
        
 
571
        # Create an empty inventory
 
572
        sio = StringIO()
 
573
        # if we want per-tree root ids then this is the place to set
 
574
        # them; they're not needed for now and so ommitted for
 
575
        # simplicity.
 
576
        bzrlib.xml5.serializer_v5.write_inventory(Inventory(), sio)
 
577
        empty_inv = sio.getvalue()
 
578
        sio = StringIO()
 
579
        bzrlib.weavefile.write_weave_v5(Weave(), sio)
 
580
        empty_weave = sio.getvalue()
 
581
 
 
582
        # Since we don't have a .bzr directory, inherit the
 
583
        # mode from the root directory
 
584
        dir_mode, file_mode = self._find_modes(t)
 
585
 
 
586
        t.mkdir('.bzr', mode=dir_mode)
 
587
        control = t.clone('.bzr')
 
588
        dirs = ['revision-store', 'weaves']
 
589
        files = [('README', 
 
590
            StringIO("This is a Bazaar-NG control directory.\n"
 
591
            "Do not change any files in this directory.\n")),
 
592
            ('branch-format', StringIO(self.get_format_string())),
 
593
            ('revision-history', StringIO('')),
 
594
            ('branch-name', StringIO('')),
 
595
            ('branch-lock', StringIO('')),
 
596
            ('pending-merges', StringIO('')),
 
597
            ('inventory', StringIO(empty_inv)),
 
598
            ('inventory.weave', StringIO(empty_weave)),
 
599
            ('ancestry.weave', StringIO(empty_weave))
 
600
        ]
 
601
        control.mkdir_multi(dirs, mode=dir_mode)
 
602
        control.put_multi(files, mode=file_mode)
 
603
        mutter('created control directory in ' + t.base)
 
604
        return BzrBranch(t)
 
605
 
 
606
    def open(self, url, branch):
 
607
        """Fill out the data in branch for the branch at url."""
 
608
        raise NotImplementedError(self.open)
 
609
 
 
610
    @classmethod
 
611
    def register_format(klass, format):
 
612
        klass._formats[format.get_format_string()] = format
 
613
 
 
614
 
 
615
class BzrBranchFormat4(BzrBranchFormat):
 
616
    """Bzr branch format 4.
 
617
 
 
618
    This format has:
 
619
     - flat stores
 
620
     - TextStores for texts, inventories,revisions.
 
621
 
 
622
    This format is deprecated: it indexes texts using a text it which is
 
623
    removed in format 5; write support for this format has been removed.
 
624
    """
 
625
 
 
626
    def get_format_string(self):
 
627
        """See BzrBranchFormat.get_format_string()."""
 
628
        return BZR_BRANCH_FORMAT_4
 
629
 
 
630
    def initialize(self, url):
 
631
        """Format 4 branches cannot be created."""
 
632
        raise NotImplementedError(self.initialize)
 
633
 
 
634
 
 
635
class BzrBranchFormat5(BzrBranchFormat):
 
636
    """Bzr branch format 5.
 
637
 
 
638
    This format has:
 
639
     - weaves for file texts and inventory
 
640
     - flat stores
 
641
     - TextStores for revisions and signatures.
 
642
    """
 
643
 
 
644
    def get_format_string(self):
 
645
        """See BzrBranchFormat.get_format_string()."""
 
646
        return BZR_BRANCH_FORMAT_5
 
647
 
 
648
 
 
649
class BzrBranchFormat6(BzrBranchFormat):
 
650
    """Bzr branch format 6.
 
651
 
 
652
    This format has:
 
653
     - weaves for file texts and inventory
 
654
     - hash subdirectory based stores.
 
655
     - TextStores for revisions and signatures.
 
656
    """
 
657
 
 
658
    def get_format_string(self):
 
659
        """See BzrBranchFormat.get_format_string()."""
 
660
        return BZR_BRANCH_FORMAT_6
 
661
 
 
662
 
 
663
BzrBranchFormat.register_format(BzrBranchFormat4())
 
664
BzrBranchFormat.register_format(BzrBranchFormat5())
 
665
BzrBranchFormat.register_format(BzrBranchFormat6())
 
666
 
511
667
class BzrBranch(Branch):
512
668
    """A branch stored in the actual filesystem.
513
669
 
563
719
        except UnlistableStore:
564
720
            raise UnlistableBranch(from_store)
565
721
 
566
 
    def __init__(self, transport, init=False,
 
722
    def __init__(self, transport, init=deprecated_nonce,
567
723
                 relax_version_check=False):
568
724
        """Create new branch object at a particular location.
569
725
 
584
740
        assert isinstance(transport, Transport), \
585
741
            "%r is not a Transport" % transport
586
742
        self._transport = transport
587
 
        if init:
588
 
            self._make_control()
 
743
        if deprecated_passed(init):
 
744
            warn("BzrBranch.__init__(..., init=XXX): The init parameter is "
 
745
                 "deprecated as of bzr 0.8. Please use Branch.initialize().",
 
746
                 DeprecationWarning)
 
747
            if init:
 
748
                # this is slower than before deprecation, oh well never mind.
 
749
                # -> its deprecated.
 
750
                self._initialize(transport.base)
589
751
        self._check_format(relax_version_check)
590
752
        self._find_modes()
591
753
 
592
754
        def get_store(name, compressed=True, prefixed=False):
593
 
            relpath = self._rel_controlfilename(unicode(name))
 
755
            relpath = self._rel_controlfilename(safe_unicode(name))
594
756
            store = TextStore(self._transport.clone(relpath),
595
757
                              dir_mode=self._dir_mode,
596
758
                              file_mode=self._file_mode,
627
789
    @staticmethod
628
790
    def _initialize(base):
629
791
        """Create a bzr branch in the latest format."""
630
 
        t = get_transport(base)
631
 
        return BzrBranch(t, init=True)
 
792
        return BzrBranchFormat6().initialize(base)
632
793
 
633
794
    def __str__(self):
634
795
        return '%s(%r)' % (self.__class__.__name__, self._transport.base)
802
963
        if not self._set_file_mode:
803
964
            self._file_mode = None
804
965
 
805
 
    def _make_control(self):
806
 
        from bzrlib.inventory import Inventory
807
 
        from bzrlib.weavefile import write_weave_v5
808
 
        from bzrlib.weave import Weave
809
 
        
810
 
        # Create an empty inventory
811
 
        sio = StringIO()
812
 
        # if we want per-tree root ids then this is the place to set
813
 
        # them; they're not needed for now and so ommitted for
814
 
        # simplicity.
815
 
        bzrlib.xml5.serializer_v5.write_inventory(Inventory(), sio)
816
 
        empty_inv = sio.getvalue()
817
 
        sio = StringIO()
818
 
        bzrlib.weavefile.write_weave_v5(Weave(), sio)
819
 
        empty_weave = sio.getvalue()
820
 
 
821
 
        cfn = self._rel_controlfilename
822
 
        # Since we don't have a .bzr directory, inherit the
823
 
        # mode from the root directory
824
 
        self._find_modes(u'.')
825
 
 
826
 
        dirs = ['', 'revision-store', 'weaves']
827
 
        files = [('README', 
828
 
            "This is a Bazaar-NG control directory.\n"
829
 
            "Do not change any files in this directory.\n"),
830
 
            ('branch-format', BZR_BRANCH_FORMAT_6),
831
 
            ('revision-history', ''),
832
 
            ('branch-name', ''),
833
 
            ('branch-lock', ''),
834
 
            ('pending-merges', ''),
835
 
            ('inventory', empty_inv),
836
 
            ('inventory.weave', empty_weave),
837
 
            ('ancestry.weave', empty_weave)
838
 
        ]
839
 
        self._transport.mkdir_multi([cfn(d) for d in dirs], mode=self._dir_mode)
840
 
        self.put_controlfiles(files)
841
 
        mutter('created control directory in ' + self._transport.base)
842
 
 
843
966
    def _check_format(self, relax_version_check):
844
967
        """Check this branch format is supported.
845
968