15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from copy import deepcopy
19
from cStringIO import StringIO
24
from unittest import TestSuite
22
25
from warnings import warn
23
from cStringIO import StringIO
27
import bzrlib.inventory as inventory
28
from bzrlib.trace import mutter, note
29
from bzrlib.osutils import (isdir, quotefn,
30
rename, splitpath, sha_file,
31
file_kind, abspath, normpath, pathjoin)
29
from bzrlib.config import TreeConfig
30
from bzrlib.delta import compare_trees
32
31
import bzrlib.errors as errors
33
32
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
34
33
NoSuchRevision, HistoryMissing, NotBranchError,
35
DivergedBranches, LockError, UnlistableStore,
34
DivergedBranches, LockError,
35
UninitializableFormat,
36
37
UnlistableBranch, NoSuchFile, NotVersionedError,
39
import bzrlib.inventory as inventory
40
from bzrlib.inventory import Inventory
41
from bzrlib.osutils import (isdir, quotefn,
42
rename, splitpath, sha_file,
43
file_kind, abspath, normpath, pathjoin,
38
46
from bzrlib.textui import show_status
47
from bzrlib.trace import mutter, note
48
from bzrlib.tree import EmptyTree, RevisionTree
39
49
from bzrlib.revision import (Revision, is_ancestor, get_intervening_revisions,
42
from bzrlib.delta import compare_trees
43
from bzrlib.tree import EmptyTree, RevisionTree
44
from bzrlib.inventory import Inventory
45
51
from bzrlib.store import copy_all
46
52
from bzrlib.store.text import TextStore
47
53
from bzrlib.store.weave import WeaveStore
54
from bzrlib.symbol_versioning import deprecated_nonce, deprecated_passed
48
55
from bzrlib.testament import Testament
49
56
import bzrlib.transactions as transactions
50
57
from bzrlib.transport import Transport, get_transport
53
from config import TreeConfig
56
62
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
101
107
Base directory/url of the branch.
109
# this is really an instance variable - FIXME move it there
113
_default_initializer = None
114
"""The default initializer for making new branches."""
105
116
def __init__(self, *ignored, **ignored_too):
106
117
raise NotImplementedError('The Branch class is abstract')
109
120
def open_downlevel(base):
110
"""Open a branch which may be of an old format.
112
Only local branches are supported."""
113
return BzrBranch(get_transport(base), relax_version_check=True)
121
"""Open a branch which may be of an old format."""
122
return Branch.open(base, _unsupported=True)
117
"""Open an existing branch, rooted at 'base' (url)"""
125
def open(base, _unsupported=False):
126
"""Open an existing branch, rooted at 'base' (url)
128
_unsupported is a private parameter to the Branch class.
118
130
t = get_transport(base)
119
131
mutter("trying to open %r with transport %r", base, t)
132
format = BzrBranchFormat.find_format(t)
133
if not _unsupported and not format.is_supported():
134
# see open_downlevel to open legacy branches.
135
raise errors.UnsupportedFormatError(
136
'sorry, branch format %s not supported' % format,
137
['use a different bzr version',
138
'or remove the .bzr directory'
139
' and "bzr init" again'])
140
return format.open(t)
123
143
def open_containing(url):
487
524
def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
488
525
raise NotImplementedError('store_revision_signature is abstract')
528
class BzrBranchFormat(object):
529
"""An encapsulation of the initialization and open routines for a format.
531
Formats provide three things:
532
* An initialization routine,
536
Formats are placed in an dict by their format string for reference
537
during branch opening. Its not required that these be instances, they
538
can be classes themselves with class methods - it simply depends on
539
whether state is needed for a given format or not.
541
Once a format is deprecated, just deprecate the initialize and open
542
methods on the format class. Do not deprecate the object, as the
543
object will be created every time regardless.
547
"""The known formats."""
550
def find_format(klass, transport):
551
"""Return the format registered for URL."""
553
format_string = transport.get(".bzr/branch-format").read()
554
return klass._formats[format_string]
556
raise NotBranchError(path=transport.base)
558
raise errors.UnknownFormatError(format_string)
560
def get_format_string(self):
561
"""Return the ASCII format string that identifies this format."""
562
raise NotImplementedError(self.get_format_string)
564
def _find_modes(self, t):
565
"""Determine the appropriate modes for files and directories.
567
FIXME: When this merges into, or from storage,
568
this code becomes delgatable to a LockableFiles instance.
570
For now its cribbed and returns (dir_mode, file_mode)
574
except errors.TransportNotPossible:
578
dir_mode = st.st_mode & 07777
579
# Remove the sticky and execute bits for files
580
file_mode = dir_mode & ~07111
581
if not BzrBranch._set_dir_mode:
583
if not BzrBranch._set_file_mode:
585
return dir_mode, file_mode
587
def initialize(self, url):
588
"""Create a branch of this format at url and return an open branch."""
589
t = get_transport(url)
590
from bzrlib.inventory import Inventory
591
from bzrlib.weavefile import write_weave_v5
592
from bzrlib.weave import Weave
594
# Create an empty inventory
596
# if we want per-tree root ids then this is the place to set
597
# them; they're not needed for now and so ommitted for
599
bzrlib.xml5.serializer_v5.write_inventory(Inventory(), sio)
600
empty_inv = sio.getvalue()
602
bzrlib.weavefile.write_weave_v5(Weave(), sio)
603
empty_weave = sio.getvalue()
605
# Since we don't have a .bzr directory, inherit the
606
# mode from the root directory
607
dir_mode, file_mode = self._find_modes(t)
609
t.mkdir('.bzr', mode=dir_mode)
610
control = t.clone('.bzr')
611
dirs = ['revision-store', 'weaves']
613
StringIO("This is a Bazaar-NG control directory.\n"
614
"Do not change any files in this directory.\n")),
615
('branch-format', StringIO(self.get_format_string())),
616
('revision-history', StringIO('')),
617
('branch-name', StringIO('')),
618
('branch-lock', StringIO('')),
619
('pending-merges', StringIO('')),
620
('inventory', StringIO(empty_inv)),
621
('inventory.weave', StringIO(empty_weave)),
622
('ancestry.weave', StringIO(empty_weave))
624
control.mkdir_multi(dirs, mode=dir_mode)
625
control.put_multi(files, mode=file_mode)
626
mutter('created control directory in ' + t.base)
627
return BzrBranch(t, format=self)
629
def is_supported(self):
630
"""Is this format supported?
632
Supported formats can be initialized and opened.
633
Unsupported formats may not support initialization or committing or
634
some other features depending on the reason for not being supported.
638
def open(self, transport):
639
"""Fill out the data in branch for the branch at url."""
640
return BzrBranch(transport, format=self)
643
def register_format(klass, format):
644
klass._formats[format.get_format_string()] = format
647
def unregister_format(klass, format):
648
assert klass._formats[format.get_format_string()] is format
649
del klass._formats[format.get_format_string()]
652
class BzrBranchFormat4(BzrBranchFormat):
653
"""Bzr branch format 4.
657
- TextStores for texts, inventories,revisions.
659
This format is deprecated: it indexes texts using a text it which is
660
removed in format 5; write support for this format has been removed.
663
def get_format_string(self):
664
"""See BzrBranchFormat.get_format_string()."""
665
return BZR_BRANCH_FORMAT_4
667
def initialize(self, url):
668
"""Format 4 branches cannot be created."""
669
raise UninitializableFormat(self)
671
def is_supported(self):
672
"""Format 4 is not supported.
674
It is not supported because the model changed from 4 to 5 and the
675
conversion logic is expensive - so doing it on the fly was not
681
class BzrBranchFormat5(BzrBranchFormat):
682
"""Bzr branch format 5.
685
- weaves for file texts and inventory
687
- TextStores for revisions and signatures.
690
def get_format_string(self):
691
"""See BzrBranchFormat.get_format_string()."""
692
return BZR_BRANCH_FORMAT_5
695
class BzrBranchFormat6(BzrBranchFormat):
696
"""Bzr branch format 6.
699
- weaves for file texts and inventory
700
- hash subdirectory based stores.
701
- TextStores for revisions and signatures.
704
def get_format_string(self):
705
"""See BzrBranchFormat.get_format_string()."""
706
return BZR_BRANCH_FORMAT_6
709
BzrBranchFormat.register_format(BzrBranchFormat4())
710
BzrBranchFormat.register_format(BzrBranchFormat5())
711
BzrBranchFormat.register_format(BzrBranchFormat6())
490
714
class BzrBranch(Branch):
491
715
"""A branch stored in the actual filesystem.
563
788
assert isinstance(transport, Transport), \
564
789
"%r is not a Transport" % transport
565
790
self._transport = transport
568
self._check_format(relax_version_check)
791
if deprecated_passed(init):
792
warn("BzrBranch.__init__(..., init=XXX): The init parameter is "
793
"deprecated as of bzr 0.8. Please use Branch.initialize().",
796
# this is slower than before deprecation, oh well never mind.
798
self._initialize(transport.base)
569
799
self._find_modes()
800
self._check_format(format)
801
if deprecated_passed(relax_version_check):
802
warn("BzrBranch.__init__(..., relax_version_check=XXX_: The "
803
"relax_version_check parameter is deprecated as of bzr 0.8. "
804
"Please use Branch.open_downlevel, or a BzrBranchFormat's "
805
"open() method.", DeprecationWarning)
806
if (not relax_version_check
807
and not self._branch_format.is_supported()):
808
raise errors.UnsupportedFormatError(
809
'sorry, branch format %r not supported' % fmt,
810
['use a different bzr version',
811
'or remove the .bzr directory'
812
' and "bzr init" again'])
571
814
def get_store(name, compressed=True, prefixed=False):
572
relpath = self._rel_controlfilename(unicode(name))
815
relpath = self._rel_controlfilename(safe_unicode(name))
573
816
store = TextStore(self._transport.clone(relpath),
574
817
dir_mode=self._dir_mode,
575
818
file_mode=self._file_mode,
775
1023
if not self._set_file_mode:
776
1024
self._file_mode = None
778
def _make_control(self):
779
from bzrlib.inventory import Inventory
780
from bzrlib.weavefile import write_weave_v5
781
from bzrlib.weave import Weave
783
# Create an empty inventory
785
# if we want per-tree root ids then this is the place to set
786
# them; they're not needed for now and so ommitted for
788
bzrlib.xml5.serializer_v5.write_inventory(Inventory(), sio)
789
empty_inv = sio.getvalue()
791
bzrlib.weavefile.write_weave_v5(Weave(), sio)
792
empty_weave = sio.getvalue()
794
cfn = self._rel_controlfilename
795
# Since we don't have a .bzr directory, inherit the
796
# mode from the root directory
797
self._find_modes(u'.')
799
dirs = ['', 'revision-store', 'weaves']
801
"This is a Bazaar-NG control directory.\n"
802
"Do not change any files in this directory.\n"),
803
('branch-format', BZR_BRANCH_FORMAT_6),
804
('revision-history', ''),
807
('pending-merges', ''),
808
('inventory', empty_inv),
809
('inventory.weave', empty_weave),
810
('ancestry.weave', empty_weave)
812
self._transport.mkdir_multi([cfn(d) for d in dirs], mode=self._dir_mode)
813
self.put_controlfiles(files)
814
mutter('created control directory in ' + self._transport.base)
816
def _check_format(self, relax_version_check):
817
"""Check this branch format is supported.
819
The format level is stored, as an integer, in
1026
def _check_format(self, format):
1027
"""Identify the branch format if needed.
1029
The format is stored as a reference to the format object in
820
1030
self._branch_format for code that needs to check it later.
822
In the future, we might need different in-memory Branch
823
classes to support downlevel branches. But not yet.
1032
The format parameter is either None or the branch format class
1033
used to open this branch.
826
fmt = self.controlfile('branch-format', 'r').read()
828
raise NotBranchError(path=self.base)
829
mutter("got branch format %r", fmt)
830
if fmt == BZR_BRANCH_FORMAT_6:
831
self._branch_format = 6
832
elif fmt == BZR_BRANCH_FORMAT_5:
833
self._branch_format = 5
834
elif fmt == BZR_BRANCH_FORMAT_4:
835
self._branch_format = 4
837
if (not relax_version_check
838
and self._branch_format not in (5, 6)):
839
raise errors.UnsupportedFormatError(
840
'sorry, branch format %r not supported' % fmt,
841
['use a different bzr version',
842
'or remove the .bzr directory'
843
' and "bzr init" again'])
1036
format = BzrBranchFormat.find_format(self._transport)
1037
self._branch_format = format
1038
mutter("got branch format %s", self._branch_format)
845
1040
@needs_read_lock
846
1041
def get_root_id(self):