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):
212
262
If self and other have not diverged, return a list of the revisions
213
263
present in other, but missing from self.
215
>>> from bzrlib.commit import commit
216
265
>>> bzrlib.trace.silent = True
217
266
>>> br1 = ScratchBranch()
218
267
>>> br2 = ScratchBranch()
219
268
>>> br1.missing_revisions(br2)
221
>>> commit(br2, "lala!", rev_id="REVISION-ID-1")
270
>>> br2.working_tree().commit("lala!", rev_id="REVISION-ID-1")
222
271
>>> br1.missing_revisions(br2)
223
272
[u'REVISION-ID-1']
224
273
>>> br2.missing_revisions(br1)
226
>>> commit(br1, "lala!", rev_id="REVISION-ID-1")
275
>>> br1.working_tree().commit("lala!", rev_id="REVISION-ID-1")
227
276
>>> br1.missing_revisions(br2)
229
>>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
278
>>> br2.working_tree().commit("lala!", rev_id="REVISION-ID-2A")
230
279
>>> br1.missing_revisions(br2)
231
280
[u'REVISION-ID-2A']
232
>>> commit(br1, "lala!", rev_id="REVISION-ID-2B")
281
>>> br1.working_tree().commit("lala!", rev_id="REVISION-ID-2B")
233
282
>>> br1.missing_revisions(br2)
234
283
Traceback (most recent call last):
235
284
DivergedBranches: These branches have diverged. Try merge.
442
483
raise NotImplementedError('fileid_involved_by_set is abstract')
485
class BzrBranchFormat(object):
486
"""An encapsulation of the initialization and open routines for a format.
488
Formats provide three things:
489
* An initialization routine,
493
Formats are placed in an dict by their format string for reference
494
during branch opening. Its not required that these be instances, they
495
can be classes themselves with class methods - it simply depends on
496
whether state is needed for a given format or not.
498
Once a format is deprecated, just deprecate the initialize and open
499
methods on the format class. Do not deprecate the object, as the
500
object will be created every time regardless.
504
"""The known formats."""
507
def find_format(klass, transport):
508
"""Return the format registered for URL."""
510
format_string = transport.get(".bzr/branch-format").read()
511
return klass._formats[format_string]
513
raise NotBranchError(path=transport.base)
515
raise errors.UnknownFormatError(format_string)
517
def get_format_string(self):
518
"""Return the ASCII format string that identifies this format."""
519
raise NotImplementedError(self.get_format_string)
521
def _find_modes(self, t):
522
"""Determine the appropriate modes for files and directories.
524
FIXME: When this merges into, or from storage,
525
this code becomes delgatable to a LockableFiles instance.
527
For now its cribbed and returns (dir_mode, file_mode)
531
except errors.TransportNotPossible:
535
dir_mode = st.st_mode & 07777
536
# Remove the sticky and execute bits for files
537
file_mode = dir_mode & ~07111
538
if not BzrBranch._set_dir_mode:
540
if not BzrBranch._set_file_mode:
542
return dir_mode, file_mode
544
def initialize(self, url):
545
"""Create a branch of this format at url and return an open branch."""
546
t = get_transport(url)
547
from bzrlib.weavefile import write_weave_v5
548
from bzrlib.weave import Weave
550
# Create an empty weave
552
bzrlib.weavefile.write_weave_v5(Weave(), sio)
553
empty_weave = sio.getvalue()
555
# Since we don't have a .bzr directory, inherit the
556
# mode from the root directory
557
temp_control = LockableFiles(t, '')
558
temp_control._transport.mkdir('.bzr',
559
mode=temp_control._dir_mode)
560
file_mode = temp_control._file_mode
562
mutter('created control directory in ' + t.base)
563
control = t.clone('.bzr')
564
dirs = ['revision-store', 'weaves']
565
lock_file = 'branch-lock'
566
utf8_files = [('README',
567
"This is a Bazaar-NG control directory.\n"
568
"Do not change any files in this directory.\n"),
569
('branch-format', self.get_format_string()),
570
('revision-history', ''),
573
files = [('inventory.weave', StringIO(empty_weave)),
576
# FIXME: RBC 20060125 dont peek under the covers
577
# NB: no need to escape relative paths that are url safe.
578
control.put(lock_file, StringIO(), mode=file_mode)
579
control_files = LockableFiles(control, lock_file)
580
control_files.lock_write()
581
control_files._transport.mkdir_multi(dirs,
582
mode=control_files._dir_mode)
584
for file, content in utf8_files:
585
control_files.put_utf8(file, content)
586
for file, content in files:
587
control_files.put(file, content)
589
control_files.unlock()
590
return BzrBranch(t, _format=self, _control_files=control_files)
592
def is_supported(self):
593
"""Is this format supported?
595
Supported formats can be initialized and opened.
596
Unsupported formats may not support initialization or committing or
597
some other features depending on the reason for not being supported.
601
def open(self, transport):
602
"""Fill out the data in branch for the branch at url."""
603
return BzrBranch(transport, _format=self)
606
def register_format(klass, format):
607
klass._formats[format.get_format_string()] = format
610
def unregister_format(klass, format):
611
assert klass._formats[format.get_format_string()] is format
612
del klass._formats[format.get_format_string()]
615
class BzrBranchFormat4(BzrBranchFormat):
616
"""Bzr branch format 4.
620
- TextStores for texts, inventories,revisions.
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.
626
def get_format_string(self):
627
"""See BzrBranchFormat.get_format_string()."""
628
return BZR_BRANCH_FORMAT_4
630
def initialize(self, url):
631
"""Format 4 branches cannot be created."""
632
raise UninitializableFormat(self)
634
def is_supported(self):
635
"""Format 4 is not supported.
637
It is not supported because the model changed from 4 to 5 and the
638
conversion logic is expensive - so doing it on the fly was not
644
class BzrBranchFormat5(BzrBranchFormat):
645
"""Bzr branch format 5.
648
- weaves for file texts and inventory
650
- TextStores for revisions and signatures.
653
def get_format_string(self):
654
"""See BzrBranchFormat.get_format_string()."""
655
return BZR_BRANCH_FORMAT_5
658
class BzrBranchFormat6(BzrBranchFormat):
659
"""Bzr branch format 6.
662
- weaves for file texts and inventory
663
- hash subdirectory based stores.
664
- TextStores for revisions and signatures.
667
def get_format_string(self):
668
"""See BzrBranchFormat.get_format_string()."""
669
return BZR_BRANCH_FORMAT_6
672
BzrBranchFormat.register_format(BzrBranchFormat4())
673
BzrBranchFormat.register_format(BzrBranchFormat5())
674
BzrBranchFormat.register_format(BzrBranchFormat6())
676
# TODO: jam 20060108 Create a new branch format, and as part of upgrade
677
# make sure that ancestry.weave is deleted (it is never used, but
678
# used to be created)
445
681
class BzrBranch(Branch):
446
682
"""A branch stored in the actual filesystem.
502
740
assert isinstance(transport, Transport), \
503
741
"%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),
742
self._transport = transport
743
self._base = self._transport.base
744
if _control_files is None:
745
_control_files = LockableFiles(self._transport.clone(bzrlib.BZRDIR),
511
self._check_format(relax_version_check)
747
self.control_files = _control_files
748
if deprecated_passed(init):
749
warn("BzrBranch.__init__(..., init=XXX): The init parameter is "
750
"deprecated as of bzr 0.8. Please use Branch.create().",
754
# this is slower than before deprecation, oh well never mind.
756
self._initialize(transport.base)
757
self._check_format(_format)
758
if deprecated_passed(relax_version_check):
759
warn("BzrBranch.__init__(..., relax_version_check=XXX_: The "
760
"relax_version_check parameter is deprecated as of bzr 0.8. "
761
"Please use Branch.open_downlevel, or a BzrBranchFormat's "
765
if (not relax_version_check
766
and not self._branch_format.is_supported()):
767
raise errors.UnsupportedFormatError(
768
'sorry, branch format %r not supported' % fmt,
769
['use a different bzr version',
770
'or remove the .bzr directory'
771
' and "bzr init" again'])
512
772
self.repository = Repository(transport, self._branch_format)
776
def _initialize(base):
777
"""Create a bzr branch in the latest format."""
778
return BzrBranchFormat6().initialize(base)
514
780
def __str__(self):
515
781
return '%s(%r)' % (self.__class__.__name__, self.base)
563
829
"""See Branch.abspath."""
564
830
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
832
def _check_format(self, format):
833
"""Identify the branch format if needed.
835
The format is stored as a reference to the format object in
610
836
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.
838
The format parameter is either None or the branch format class
839
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'])
842
format = BzrBranchFormat.find_format(self._transport)
843
self._branch_format = format
844
mutter("got branch format %s", self._branch_format)
636
847
def get_root_id(self):
637
848
"""See Branch.get_root_id."""
638
inv = self.repository.get_inventory(self.last_revision())
639
return inv.root.file_id
849
tree = self.repository.revision_tree(self.last_revision())
850
return tree.inventory.root.file_id
641
852
def lock_write(self):
642
853
# TODO: test for failed two phase locks. This is known broken.
853
1059
os.mkdir(to_location)
854
1060
branch_to = Branch.initialize(to_location)
855
1061
mutter("copy branch from %s to %s", self, branch_to)
856
branch_to.working_tree().set_root_id(self.get_root_id())
858
1063
self.repository.copy(branch_to.repository)
860
1065
# must be done *after* history is copied across
861
1066
# FIXME duplicate code with base .clone().
862
# .. would template method be useful here. RBC 20051207
1067
# .. would template method be useful here? RBC 20051207
863
1068
branch_to.set_parent(self.base)
864
1069
branch_to.append_revision(*history)
865
# circular import protection
866
from bzrlib.merge import build_working_dir
867
build_working_dir(to_location)
1070
# FIXME: this should be in workingtree.clone
1071
WorkingTree.create(branch_to, to_location).set_root_id(self.get_root_id())
868
1072
mutter("copied")
869
1073
return branch_to
871
1075
def clone(self, to_location, revision=None, basis_branch=None, to_branch_type=None):
1076
print "FIXME: clone via create and fetch is probably faster when versioned file comes in."
872
1077
if to_branch_type is None:
873
1078
to_branch_type = BzrBranch