34
from bzrlib.trace import mutter, note
35
from bzrlib.osutils import (isdir, quotefn,
36
rename, splitpath, sha_file,
37
file_kind, abspath, normpath, pathjoin)
37
from bzrlib.config import TreeConfig
38
from bzrlib.decorators import needs_read_lock, needs_write_lock
39
from bzrlib.delta import compare_trees
38
40
import bzrlib.errors as errors
39
41
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
40
42
NoSuchRevision, HistoryMissing, NotBranchError,
41
DivergedBranches, LockError, UnlistableStore,
43
DivergedBranches, LockError,
44
UninitializableFormat,
42
46
UnlistableBranch, NoSuchFile, NotVersionedError,
44
from bzrlib.textui import show_status
45
from bzrlib.config import TreeConfig
46
from bzrlib.decorators import needs_read_lock, needs_write_lock
47
from bzrlib.delta import compare_trees
48
48
import bzrlib.inventory as inventory
49
49
from bzrlib.inventory import Inventory
50
50
from bzrlib.lockable_files import LockableFiles
51
from bzrlib.osutils import (isdir, quotefn,
52
rename, splitpath, sha_file,
53
file_kind, abspath, normpath, pathjoin,
56
from bzrlib.textui import show_status
57
from bzrlib.trace import mutter, note
58
from bzrlib.tree import EmptyTree, RevisionTree
59
from bzrlib.repository import Repository
51
60
from bzrlib.revision import (Revision, is_ancestor, get_intervening_revisions)
52
from bzrlib.repository import Repository
53
61
from bzrlib.store import copy_all
62
from bzrlib.symbol_versioning import *
54
63
import bzrlib.transactions as transactions
55
64
from bzrlib.transport import Transport, get_transport
56
65
from bzrlib.tree import EmptyTree, RevisionTree
82
91
Base directory/url of the branch.
93
# this is really an instance variable - FIXME move it there
97
_default_initializer = None
98
"""The default initializer for making new branches."""
86
100
def __init__(self, *ignored, **ignored_too):
87
101
raise NotImplementedError('The Branch class is abstract')
90
104
def open_downlevel(base):
91
"""Open a branch which may be of an old format.
93
Only local branches are supported."""
94
return BzrBranch(get_transport(base), relax_version_check=True)
105
"""Open a branch which may be of an old format."""
106
return Branch.open(base, _unsupported=True)
98
"""Open an existing branch, rooted at 'base' (url)"""
109
def open(base, _unsupported=False):
110
"""Open an existing branch, rooted at 'base' (url)
112
_unsupported is a private parameter to the Branch class.
99
114
t = get_transport(base)
100
115
mutter("trying to open %r with transport %r", base, t)
116
format = BzrBranchFormat.find_format(t)
117
if not _unsupported and not format.is_supported():
118
# see open_downlevel to open legacy branches.
119
raise errors.UnsupportedFormatError(
120
'sorry, branch format %s not supported' % format,
121
['use a different bzr version',
122
'or remove the .bzr directory'
123
' and "bzr init" again'])
124
return format.open(t)
104
127
def open_containing(url):
155
"""Create a new Branch at the url 'bzr'.
157
This will call the current default initializer with base
158
as the only parameter.
160
return Branch._default_initializer(safe_unicode(base))
163
@deprecated_function(zero_eight)
126
164
def initialize(base):
127
"""Create a new branch, rooted at 'base' (url)"""
128
t = get_transport(unicode(base))
129
return BzrBranch(t, init=True)
165
"""Create a new working tree and branch, rooted at 'base' (url)
167
NOTE: This will soon be deprecated in favour of creation
170
# imported here to prevent scope creep as this is going.
171
from bzrlib.workingtree import WorkingTree
172
return WorkingTree.create_standalone(safe_unicode(base)).branch
175
def get_default_initializer():
176
"""Return the initializer being used for new branches."""
177
return Branch._default_initializer
180
def set_default_initializer(initializer):
181
"""Set the initializer to be used for new branches."""
182
Branch._default_initializer = staticmethod(initializer)
131
184
def setup_caching(self, cache_root):
132
185
"""Subclasses that care about caching should override this, and set
212
265
If self and other have not diverged, return a list of the revisions
213
266
present in other, but missing from self.
215
>>> from bzrlib.commit import commit
216
268
>>> bzrlib.trace.silent = True
217
269
>>> br1 = ScratchBranch()
218
270
>>> br2 = ScratchBranch()
219
271
>>> br1.missing_revisions(br2)
221
>>> commit(br2, "lala!", rev_id="REVISION-ID-1")
273
>>> br2.working_tree().commit("lala!", rev_id="REVISION-ID-1")
222
274
>>> br1.missing_revisions(br2)
223
275
[u'REVISION-ID-1']
224
276
>>> br2.missing_revisions(br1)
226
>>> commit(br1, "lala!", rev_id="REVISION-ID-1")
278
>>> br1.working_tree().commit("lala!", rev_id="REVISION-ID-1")
227
279
>>> br1.missing_revisions(br2)
229
>>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
281
>>> br2.working_tree().commit("lala!", rev_id="REVISION-ID-2A")
230
282
>>> br1.missing_revisions(br2)
231
283
[u'REVISION-ID-2A']
232
>>> commit(br1, "lala!", rev_id="REVISION-ID-2B")
284
>>> br1.working_tree().commit("lala!", rev_id="REVISION-ID-2B")
233
285
>>> br1.missing_revisions(br2)
234
286
Traceback (most recent call last):
235
287
DivergedBranches: These branches have diverged. Try merge.
442
486
raise NotImplementedError('fileid_involved_by_set is abstract')
488
class BzrBranchFormat(object):
489
"""An encapsulation of the initialization and open routines for a format.
491
Formats provide three things:
492
* An initialization routine,
496
Formats are placed in an dict by their format string for reference
497
during branch opening. Its not required that these be instances, they
498
can be classes themselves with class methods - it simply depends on
499
whether state is needed for a given format or not.
501
Once a format is deprecated, just deprecate the initialize and open
502
methods on the format class. Do not deprecate the object, as the
503
object will be created every time regardless.
507
"""The known formats."""
510
def find_format(klass, transport):
511
"""Return the format registered for URL."""
513
format_string = transport.get(".bzr/branch-format").read()
514
return klass._formats[format_string]
516
raise NotBranchError(path=transport.base)
518
raise errors.UnknownFormatError(format_string)
520
def get_format_string(self):
521
"""Return the ASCII format string that identifies this format."""
522
raise NotImplementedError(self.get_format_string)
524
def _find_modes(self, t):
525
"""Determine the appropriate modes for files and directories.
527
FIXME: When this merges into, or from storage,
528
this code becomes delgatable to a LockableFiles instance.
530
For now its cribbed and returns (dir_mode, file_mode)
534
except errors.TransportNotPossible:
538
dir_mode = st.st_mode & 07777
539
# Remove the sticky and execute bits for files
540
file_mode = dir_mode & ~07111
541
if not BzrBranch._set_dir_mode:
543
if not BzrBranch._set_file_mode:
545
return dir_mode, file_mode
547
def initialize(self, url):
548
"""Create a branch of this format at url and return an open branch."""
549
t = get_transport(url)
550
from bzrlib.weavefile import write_weave_v5
551
from bzrlib.weave import Weave
553
# Create an empty weave
555
bzrlib.weavefile.write_weave_v5(Weave(), sio)
556
empty_weave = sio.getvalue()
558
# Since we don't have a .bzr directory, inherit the
559
# mode from the root directory
560
temp_control = LockableFiles(t, '')
561
temp_control._transport.mkdir('.bzr',
562
mode=temp_control._dir_mode)
563
file_mode = temp_control._file_mode
565
mutter('created control directory in ' + t.base)
566
control = t.clone('.bzr')
567
dirs = ['revision-store', 'weaves']
568
lock_file = 'branch-lock'
569
utf8_files = [('README',
570
"This is a Bazaar-NG control directory.\n"
571
"Do not change any files in this directory.\n"),
572
('branch-format', self.get_format_string()),
573
('revision-history', ''),
576
files = [('inventory.weave', StringIO(empty_weave)),
579
# FIXME: RBC 20060125 dont peek under the covers
580
# NB: no need to escape relative paths that are url safe.
581
control.put(lock_file, StringIO(), mode=file_mode)
582
control_files = LockableFiles(control, lock_file)
583
control_files.lock_write()
584
control_files._transport.mkdir_multi(dirs,
585
mode=control_files._dir_mode)
587
for file, content in utf8_files:
588
control_files.put_utf8(file, content)
589
for file, content in files:
590
control_files.put(file, content)
592
control_files.unlock()
593
return BzrBranch(t, _format=self, _control_files=control_files)
595
def is_supported(self):
596
"""Is this format supported?
598
Supported formats can be initialized and opened.
599
Unsupported formats may not support initialization or committing or
600
some other features depending on the reason for not being supported.
604
def open(self, transport):
605
"""Fill out the data in branch for the branch at url."""
606
return BzrBranch(transport, _format=self)
609
def register_format(klass, format):
610
klass._formats[format.get_format_string()] = format
613
def unregister_format(klass, format):
614
assert klass._formats[format.get_format_string()] is format
615
del klass._formats[format.get_format_string()]
618
class BzrBranchFormat4(BzrBranchFormat):
619
"""Bzr branch format 4.
623
- TextStores for texts, inventories,revisions.
625
This format is deprecated: it indexes texts using a text it which is
626
removed in format 5; write support for this format has been removed.
629
def get_format_string(self):
630
"""See BzrBranchFormat.get_format_string()."""
631
return BZR_BRANCH_FORMAT_4
633
def initialize(self, url):
634
"""Format 4 branches cannot be created."""
635
raise UninitializableFormat(self)
637
def is_supported(self):
638
"""Format 4 is not supported.
640
It is not supported because the model changed from 4 to 5 and the
641
conversion logic is expensive - so doing it on the fly was not
647
class BzrBranchFormat5(BzrBranchFormat):
648
"""Bzr branch format 5.
651
- weaves for file texts and inventory
653
- TextStores for revisions and signatures.
656
def get_format_string(self):
657
"""See BzrBranchFormat.get_format_string()."""
658
return BZR_BRANCH_FORMAT_5
661
class BzrBranchFormat6(BzrBranchFormat):
662
"""Bzr branch format 6.
665
- weaves for file texts and inventory
666
- hash subdirectory based stores.
667
- TextStores for revisions and signatures.
670
def get_format_string(self):
671
"""See BzrBranchFormat.get_format_string()."""
672
return BZR_BRANCH_FORMAT_6
675
BzrBranchFormat.register_format(BzrBranchFormat4())
676
BzrBranchFormat.register_format(BzrBranchFormat5())
677
BzrBranchFormat.register_format(BzrBranchFormat6())
679
# TODO: jam 20060108 Create a new branch format, and as part of upgrade
680
# make sure that ancestry.weave is deleted (it is never used, but
681
# used to be created)
445
684
class BzrBranch(Branch):
446
685
"""A branch stored in the actual filesystem.
502
743
assert isinstance(transport, Transport), \
503
744
"%r is not a Transport" % transport
504
# TODO: jam 20060103 We create a clone of this transport at .bzr/
505
# and then we forget about it, should we keep a handle to it?
506
self._base = transport.base
507
self.control_files = LockableFiles(transport.clone(bzrlib.BZRDIR),
745
self._transport = transport
746
self._base = self._transport.base
747
if _control_files is None:
748
_control_files = LockableFiles(self._transport.clone(bzrlib.BZRDIR),
511
self._check_format(relax_version_check)
750
self.control_files = _control_files
751
if deprecated_passed(init):
752
warn("BzrBranch.__init__(..., init=XXX): The init parameter is "
753
"deprecated as of bzr 0.8. Please use Branch.create().",
757
# this is slower than before deprecation, oh well never mind.
759
self._initialize(transport.base)
760
self._check_format(_format)
761
if deprecated_passed(relax_version_check):
762
warn("BzrBranch.__init__(..., relax_version_check=XXX_: The "
763
"relax_version_check parameter is deprecated as of bzr 0.8. "
764
"Please use Branch.open_downlevel, or a BzrBranchFormat's "
768
if (not relax_version_check
769
and not self._branch_format.is_supported()):
770
raise errors.UnsupportedFormatError(
771
'sorry, branch format %r not supported' % fmt,
772
['use a different bzr version',
773
'or remove the .bzr directory'
774
' and "bzr init" again'])
512
775
self.repository = Repository(transport, self._branch_format)
779
def _initialize(base):
780
"""Create a bzr branch in the latest format."""
781
return BzrBranchFormat6().initialize(base)
514
783
def __str__(self):
515
784
return '%s(%r)' % (self.__class__.__name__, self.base)
563
832
"""See Branch.abspath."""
564
833
return self.control_files._transport.abspath(name)
566
def _make_control(self):
567
from bzrlib.inventory import Inventory
568
from bzrlib.weavefile import write_weave_v5
569
from bzrlib.weave import Weave
571
# Create an empty inventory
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
576
bzrlib.xml5.serializer_v5.write_inventory(Inventory(), sio)
577
empty_inv = sio.getvalue()
579
bzrlib.weavefile.write_weave_v5(Weave(), sio)
580
empty_weave = sio.getvalue()
582
dirs = ['', 'revision-store', 'weaves']
584
"This is a Bazaar-NG control directory.\n"
585
"Do not change any files in this directory.\n"),
586
('branch-format', BZR_BRANCH_FORMAT_6),
587
('revision-history', ''),
590
('pending-merges', ''),
591
('inventory', empty_inv),
592
('inventory.weave', empty_weave),
594
cfe = self.control_files._escape
595
# FIXME: RBC 20060125 dont peek under the covers
596
self.control_files._transport.mkdir_multi([cfe(d) for d in dirs],
597
mode=self.control_files._dir_mode)
598
self.control_files.lock_write()
600
for file, content in files:
601
self.control_files.put_utf8(file, content)
602
mutter('created control directory in ' + self.base)
604
self.control_files.unlock()
606
def _check_format(self, relax_version_check):
607
"""Check this branch format is supported.
609
The format level is stored, as an integer, in
835
def _check_format(self, format):
836
"""Identify the branch format if needed.
838
The format is stored as a reference to the format object in
610
839
self._branch_format for code that needs to check it later.
612
In the future, we might need different in-memory Branch
613
classes to support downlevel branches. But not yet.
841
The format parameter is either None or the branch format class
842
used to open this branch.
616
fmt = self.control_files.get_utf8('branch-format').read()
618
raise NotBranchError(path=self.base)
619
mutter("got branch format %r", fmt)
620
if fmt == BZR_BRANCH_FORMAT_6:
621
self._branch_format = 6
622
elif fmt == BZR_BRANCH_FORMAT_5:
623
self._branch_format = 5
624
elif fmt == BZR_BRANCH_FORMAT_4:
625
self._branch_format = 4
627
if (not relax_version_check
628
and self._branch_format not in (5, 6)):
629
raise errors.UnsupportedFormatError(
630
'sorry, branch format %r not supported' % fmt,
631
['use a different bzr version',
632
'or remove the .bzr directory'
633
' and "bzr init" again'])
845
format = BzrBranchFormat.find_format(self._transport)
846
self._branch_format = format
847
mutter("got branch format %s", self._branch_format)
636
850
def get_root_id(self):
637
851
"""See Branch.get_root_id."""
638
inv = self.repository.get_inventory(self.last_revision())
639
return inv.root.file_id
852
tree = self.repository.revision_tree(self.last_revision())
853
return tree.inventory.root.file_id
641
855
def lock_write(self):
642
856
# TODO: test for failed two phase locks. This is known broken.
853
1062
os.mkdir(to_location)
854
1063
branch_to = Branch.initialize(to_location)
855
1064
mutter("copy branch from %s to %s", self, branch_to)
856
branch_to.working_tree().set_root_id(self.get_root_id())
858
1066
self.repository.copy(branch_to.repository)
860
1068
# must be done *after* history is copied across
861
1069
# FIXME duplicate code with base .clone().
862
# .. would template method be useful here. RBC 20051207
1070
# .. would template method be useful here? RBC 20051207
863
1071
branch_to.set_parent(self.base)
864
1072
branch_to.append_revision(*history)
865
# circular import protection
866
from bzrlib.merge import build_working_dir
867
build_working_dir(to_location)
1073
# FIXME: this should be in workingtree.clone
1074
WorkingTree.create(branch_to, to_location).set_root_id(self.get_root_id())
868
1075
mutter("copied")
869
1076
return branch_to
871
1078
def clone(self, to_location, revision=None, basis_branch=None, to_branch_type=None):
1079
print "FIXME: clone via create and fetch is probably faster when versioned file comes in."
872
1080
if to_branch_type is None:
873
1081
to_branch_type = BzrBranch