91
class ControlComponent(object):
92
"""Abstract base class for control directory components.
94
This provides interfaces that are common across bzrdirs,
95
repositories, branches, and workingtree control directories.
97
They all expose two urls and transports: the *user* URL is the
98
one that stops above the control directory (eg .bzr) and that
99
should normally be used in messages, and the *control* URL is
100
under that in eg .bzr/checkout and is used to read the control
103
This can be used as a mixin and is intended to fit with
108
def control_transport(self):
109
raise NotImplementedError
112
def control_url(self):
113
return self.control_transport.base
116
def user_transport(self):
117
raise NotImplementedError
121
return self.user_transport.base
124
class BzrDir(ControlComponent):
92
125
"""A .bzr control diretory.
94
127
BzrDir instances let you create or open any of the things that can be
261
294
# copied, and finally if we are copying up to a specific
262
295
# revision_id then we can use the pending-ancestry-result which
263
296
# does not require traversing all of history to describe it.
264
if (result_repo.bzrdir.root_transport.base ==
265
result.root_transport.base and not require_stacking and
297
if (result_repo.user_url == result.user_url
298
and not require_stacking and
266
299
revision_id is not None):
267
300
fetch_spec = graph.PendingAncestryResult(
268
301
[revision_id], local_repo)
344
377
bzrdir = BzrDir.open_from_transport(current_transport)
345
except errors.NotBranchError:
378
except (errors.NotBranchError, errors.PermissionDenied):
348
381
recurse, value = evaluate(bzrdir)
351
384
subdirs = list_current(current_transport)
352
except errors.NoSuchFile:
385
except (errors.NoSuchFile, errors.PermissionDenied):
355
388
for subdir in sorted(subdirs, reverse=True):
396
429
"""Destroy the repository in this BzrDir"""
397
430
raise NotImplementedError(self.destroy_repository)
399
def create_branch(self):
432
def create_branch(self, name=None):
400
433
"""Create a branch in this BzrDir.
435
:param name: Name of the colocated branch to create, None for
402
438
The bzrdir's format will control what branch format is created.
403
439
For more control see BranchFormatXX.create(a_bzrdir).
405
441
raise NotImplementedError(self.create_branch)
407
def destroy_branch(self):
408
"""Destroy the branch in this BzrDir"""
443
def destroy_branch(self, name=None):
444
"""Destroy a branch in this BzrDir.
446
:param name: Name of the branch to destroy, None for the default
409
449
raise NotImplementedError(self.destroy_branch)
459
499
except errors.NoRepositoryPresent:
460
500
repository = None
462
if ((found_bzrdir.root_transport.base !=
463
self.root_transport.base) and not repository.is_shared()):
502
if (found_bzrdir.user_url != self.user_url
503
and not repository.is_shared()):
464
504
# Don't look higher, can't use a higher shared repo.
465
505
repository = None
576
616
raise NotImplementedError(self.create_workingtree)
618
def generate_backup_name(self, base):
619
"""Generate a non-existing backup file name based on base."""
621
name = "%s.~%d~" % (base, counter)
622
while self.root_transport.has(name):
624
name = "%s.~%d~" % (base, counter)
578
627
def backup_bzrdir(self):
579
628
"""Backup this bzr control directory.
581
630
:return: Tuple with old path name and new path name
633
backup_dir=self.generate_backup_name('backup.bzr')
583
634
pb = ui.ui_factory.nested_progress_bar()
585
636
# FIXME: bug 300001 -- the backup fails if the backup directory
586
637
# already exists, but it should instead either remove it or make
587
638
# a new backup directory.
589
# FIXME: bug 262450 -- the backup directory should have the same
590
# permissions as the .bzr directory (probably a bug in copy_tree)
591
640
old_path = self.root_transport.abspath('.bzr')
592
new_path = self.root_transport.abspath('backup.bzr')
641
new_path = self.root_transport.abspath(backup_dir)
593
642
ui.ui_factory.note('making backup of %s\n to %s' % (old_path, new_path,))
594
self.root_transport.copy_tree('.bzr', 'backup.bzr')
643
self.root_transport.copy_tree('.bzr', backup_dir)
595
644
return (old_path, new_path)
657
706
next_transport = found_bzrdir.root_transport.clone('..')
658
if (found_bzrdir.root_transport.base == next_transport.base):
707
if (found_bzrdir.user_url == next_transport.base):
659
708
# top of the file system
661
710
# find the next containing bzrdir
678
727
repository = found_bzrdir.open_repository()
679
728
except errors.NoRepositoryPresent:
680
729
return None, False
681
if found_bzrdir.root_transport.base == self.root_transport.base:
730
if found_bzrdir.user_url == self.user_url:
682
731
return repository, True
683
732
elif repository.is_shared():
684
733
return repository, True
690
739
raise errors.NoRepositoryPresent(self)
691
740
return found_repo
693
def get_branch_reference(self):
742
def get_branch_reference(self, name=None):
694
743
"""Return the referenced URL for the branch in this bzrdir.
745
:param name: Optional colocated branch name
696
746
:raises NotBranchError: If there is no Branch.
747
:raises NoColocatedBranchSupport: If a branch name was specified
748
but colocated branches are not supported.
697
749
:return: The URL the branch in this bzrdir references if it is a
698
750
reference branch, or None for regular branches.
753
raise errors.NoColocatedBranchSupport(self)
702
def get_branch_transport(self, branch_format):
756
def get_branch_transport(self, branch_format, name=None):
703
757
"""Get the transport for use by branch format in this BzrDir.
705
759
Note that bzr dirs that do not support format strings will raise
800
854
:param _transport: the transport this dir is based at.
802
856
self._format = _format
857
# these are also under the more standard names of
858
# control_transport and user_transport
803
859
self.transport = _transport.clone('.bzr')
804
860
self.root_transport = _transport
805
861
self._mode_check_done = False
864
def user_transport(self):
865
return self.root_transport
868
def control_transport(self):
869
return self.transport
807
871
def is_control_filename(self, filename):
808
872
"""True if filename is the name of a path which is reserved for bzrdir's.
883
947
BzrDir._check_supported(format, _unsupported)
884
948
return format.open(transport, _found=True)
886
def open_branch(self, unsupported=False, ignore_fallbacks=False):
950
def open_branch(self, name=None, unsupported=False,
951
ignore_fallbacks=False):
887
952
"""Open the branch object at this BzrDir if one is present.
889
954
If unsupported is True, then no longer supported branch formats can
936
1001
raise errors.NotBranchError(path=url)
937
1002
a_transport = new_t
939
def _get_tree_branch(self):
1004
def _get_tree_branch(self, name=None):
940
1005
"""Return the branch and tree, if any, for this bzrdir.
1007
:param name: Name of colocated branch to open.
942
1009
Return None for tree if not present or inaccessible.
943
1010
Raise NotBranchError if no branch is present.
944
1011
:return: (tree, branch)
947
1014
tree = self.open_workingtree()
948
1015
except (errors.NoWorkingTree, errors.NotLocalUrl):
950
branch = self.open_branch()
1017
branch = self.open_branch(name=name)
1019
if name is not None:
1020
branch = self.open_branch(name=name)
1022
branch = tree.branch
953
1023
return tree, branch
1028
1098
raise NotImplementedError(self.open_workingtree)
1030
def has_branch(self):
1100
def has_branch(self, name=None):
1031
1101
"""Tell if this bzrdir contains a branch.
1033
1103
Note: if you're going to open the branch, you should just go ahead
1176
1246
repository_policy = result.determine_repository_policy(
1177
1247
force_new_repo, stacked_branch_url, require_stacking=stacked)
1178
1248
result_repo, is_new_repo = repository_policy.acquire_repository()
1179
if is_new_repo and revision_id is not None and not stacked:
1249
is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
1250
if is_new_repo and revision_id is not None and not is_stacked:
1180
1251
fetch_spec = graph.PendingAncestryResult(
1181
1252
[revision_id], source_repository)
1315
1386
self.create_hook(hooks.HookPoint('pre_open',
1316
1387
"Invoked before attempting to open a BzrDir with the transport "
1317
1388
"that the open will use.", (1, 14), None))
1389
self.create_hook(hooks.HookPoint('post_repo_init',
1390
"Invoked after a repository has been initialized. "
1391
"post_repo_init is called with a "
1392
"bzrlib.bzrdir.RepoInitHookParams.",
1319
1395
# install the default hooks
1320
1396
BzrDir.hooks = BzrDirHooks()
1399
class RepoInitHookParams(object):
1400
"""Object holding parameters passed to *_repo_init hooks.
1402
There are 4 fields that hooks may wish to access:
1404
:ivar repository: Repository created
1405
:ivar format: Repository format
1406
:ivar bzrdir: The bzrdir for the repository
1407
:ivar shared: The repository is shared
1410
def __init__(self, repository, format, a_bzrdir, shared):
1411
"""Create a group of RepoInitHook parameters.
1413
:param repository: Repository created
1414
:param format: Repository format
1415
:param bzrdir: The bzrdir for the repository
1416
:param shared: The repository is shared
1418
self.repository = repository
1419
self.format = format
1420
self.bzrdir = a_bzrdir
1421
self.shared = shared
1423
def __eq__(self, other):
1424
return self.__dict__ == other.__dict__
1428
return "<%s for %s>" % (self.__class__.__name__,
1431
return "<%s for %s>" % (self.__class__.__name__,
1323
1435
class BzrDirPreSplitOut(BzrDir):
1324
1436
"""A common class for the all-in-one formats."""
1364
1476
tree.clone(result)
1367
def create_branch(self):
1479
def create_branch(self, name=None):
1368
1480
"""See BzrDir.create_branch."""
1369
return self._format.get_branch_format().initialize(self)
1481
return self._format.get_branch_format().initialize(self, name=name)
1371
def destroy_branch(self):
1483
def destroy_branch(self, name=None):
1372
1484
"""See BzrDir.destroy_branch."""
1373
1485
raise errors.UnsupportedOperation(self.destroy_branch, self)
1430
1542
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1433
def get_branch_transport(self, branch_format):
1545
def get_branch_transport(self, branch_format, name=None):
1434
1546
"""See BzrDir.get_branch_transport()."""
1547
if name is not None:
1548
raise errors.NoColocatedBranchSupport(self)
1435
1549
if branch_format is None:
1436
1550
return self.transport
1470
1584
format = BzrDirFormat.get_default_format()
1471
1585
return not isinstance(self._format, format.__class__)
1473
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1587
def open_branch(self, name=None, unsupported=False,
1588
ignore_fallbacks=False):
1474
1589
"""See BzrDir.open_branch."""
1475
1590
from bzrlib.branch import BzrBranchFormat4
1476
1591
format = BzrBranchFormat4()
1477
1592
self._check_supported(format, unsupported)
1478
return format.open(self, _found=True)
1593
return format.open(self, name, _found=True)
1480
1595
def sprout(self, url, revision_id=None, force_new_repo=False,
1481
1596
possible_transports=None, accelerator_tree=None,
1598
1713
"""See BzrDir.can_convert_format()."""
1601
def create_branch(self):
1716
def create_branch(self, name=None):
1602
1717
"""See BzrDir.create_branch."""
1603
return self._format.get_branch_format().initialize(self)
1718
return self._format.get_branch_format().initialize(self, name=name)
1605
def destroy_branch(self):
1720
def destroy_branch(self, name=None):
1606
1721
"""See BzrDir.create_branch."""
1722
if name is not None:
1723
raise errors.NoColocatedBranchSupport(self)
1607
1724
self.transport.delete_tree('branch')
1609
1726
def create_repository(self, shared=False):
1632
1749
def destroy_workingtree_metadata(self):
1633
1750
self.transport.delete_tree('checkout')
1635
def find_branch_format(self):
1752
def find_branch_format(self, name=None):
1636
1753
"""Find the branch 'format' for this bzrdir.
1638
1755
This might be a synthetic object for e.g. RemoteBranch and SVN.
1640
1757
from bzrlib.branch import BranchFormat
1641
return BranchFormat.find_format(self)
1758
return BranchFormat.find_format(self, name=name)
1643
1760
def _get_mkdir_mode(self):
1644
1761
"""Figure out the mode to use when creating a bzrdir subdir."""
1646
1763
lockable_files.TransportLock)
1647
1764
return temp_control._dir_mode
1649
def get_branch_reference(self):
1766
def get_branch_reference(self, name=None):
1650
1767
"""See BzrDir.get_branch_reference()."""
1651
1768
from bzrlib.branch import BranchFormat
1652
format = BranchFormat.find_format(self)
1653
return format.get_reference(self)
1769
format = BranchFormat.find_format(self, name=name)
1770
return format.get_reference(self, name=name)
1655
def get_branch_transport(self, branch_format):
1772
def get_branch_transport(self, branch_format, name=None):
1656
1773
"""See BzrDir.get_branch_transport()."""
1774
if name is not None:
1775
raise errors.NoColocatedBranchSupport(self)
1657
1776
# XXX: this shouldn't implicitly create the directory if it's just
1658
1777
# promising to get a transport -- mbp 20090727
1659
1778
if branch_format is None:
1731
1850
except errors.NoRepositoryPresent:
1734
if not isinstance(self.open_branch()._format,
1852
for branch in self.list_branches():
1853
if not isinstance(branch._format,
1735
1854
format.get_branch_format().__class__):
1736
1855
# the branch needs an upgrade.
1738
except errors.NotBranchError:
1741
1858
my_wt = self.open_workingtree(recommend_upgrade=False)
1742
1859
if not isinstance(my_wt._format,
1750
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1867
def open_branch(self, name=None, unsupported=False,
1868
ignore_fallbacks=False):
1751
1869
"""See BzrDir.open_branch."""
1752
format = self.find_branch_format()
1870
format = self.find_branch_format(name=name)
1753
1871
self._check_supported(format, unsupported)
1754
return format.open(self, _found=True, ignore_fallbacks=ignore_fallbacks)
1872
return format.open(self, name=name,
1873
_found=True, ignore_fallbacks=ignore_fallbacks)
1756
1875
def open_repository(self, unsupported=False):
1757
1876
"""See BzrDir.open_repository."""
1789
1908
Once a format is deprecated, just deprecate the initialize and open
1790
1909
methods on the format class. Do not deprecate the object, as the
1791
1910
object will be created every system load.
1912
:cvar colocated_branches: Whether this formats supports colocated branches.
1794
1915
_default_format = None
1812
1933
_lock_file_name = 'branch-lock'
1935
colocated_branches = False
1936
"""Whether co-located branches are supported for this control dir format.
1814
1939
# _lock_class must be set in subclasses to the lock type, typ.
1815
1940
# TransportLock or LockDir
2623
2747
if isinstance(self.bzrdir.transport, local.LocalTransport):
2624
2748
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2625
2749
self._convert_to_weaves()
2626
return BzrDir.open(self.bzrdir.root_transport.base)
2750
return BzrDir.open(self.bzrdir.user_url)
2628
2752
self.pb.finished()
2751
2875
self.revisions[rev_id] = rev
2753
2877
def _load_old_inventory(self, rev_id):
2754
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2878
f = self.branch.repository.inventory_store.get(rev_id)
2880
old_inv_xml = f.read()
2755
2883
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2756
2884
inv.revision_id = rev_id
2757
2885
rev = self.revisions[rev_id]
2835
2963
ie.revision = previous_ie.revision
2837
2965
if ie.has_text():
2838
text = self.branch.repository._text_store.get(ie.text_id)
2839
file_lines = text.readlines()
2966
f = self.branch.repository._text_store.get(ie.text_id)
2968
file_lines = f.readlines()
2840
2971
w.add_lines(rev_id, previous_revisions, file_lines)
2841
2972
self.text_count += 1
3004
3135
BzrDirMetaFormat1().get_format_string(),
3005
3136
mode=self.file_mode)
3006
3137
self.pb.finished()
3007
return BzrDir.open(self.bzrdir.root_transport.base)
3138
return BzrDir.open(self.bzrdir.user_url)
3009
3140
def make_lock(self, name):
3010
3141
"""Make a lock for the new control dir name."""
3123
3254
# XXX: It's a bit ugly that the network name is here, because we'd
3124
3255
# like to believe that format objects are stateless or at least
3125
3256
# immutable, However, we do at least avoid mutating the name after
3126
# it's returned. See <https://bugs.edge.launchpad.net/bzr/+bug/504102>
3257
# it's returned. See <https://bugs.launchpad.net/bzr/+bug/504102>
3127
3258
self._network_name = None
3129
3260
def __repr__(self):
3592
3723
stack_on = urlutils.rebase_url(self._stack_on,
3593
3724
self._stack_on_pwd,
3594
branch.bzrdir.root_transport.base)
3595
3726
except errors.InvalidRebaseURLs:
3596
3727
stack_on = self._get_full_stack_on()