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):
125
92
"""A .bzr control diretory.
127
94
BzrDir instances let you create or open any of the things that can be
294
261
# copied, and finally if we are copying up to a specific
295
262
# revision_id then we can use the pending-ancestry-result which
296
263
# does not require traversing all of history to describe it.
297
if (result_repo.user_url == result.user_url
298
and not require_stacking and
264
if (result_repo.bzrdir.root_transport.base ==
265
result.root_transport.base and not require_stacking and
299
266
revision_id is not None):
300
267
fetch_spec = graph.PendingAncestryResult(
301
268
[revision_id], local_repo)
388
355
for subdir in sorted(subdirs, reverse=True):
389
356
pending.append(current_transport.clone(subdir))
391
def list_branches(self):
392
"""Return a sequence of all branches local to this control directory.
396
return [self.open_branch()]
397
except errors.NotBranchError:
401
359
def find_branches(transport):
402
360
"""Find all branches under a transport.
414
372
except errors.NoRepositoryPresent:
417
return False, ([], repository)
418
return True, (bzrdir.list_branches(), None)
420
for branches, repo in BzrDir.find_bzrdirs(transport,
375
return False, (None, repository)
377
branch = bzrdir.open_branch()
378
except errors.NotBranchError:
379
return True, (None, None)
381
return True, (branch, None)
383
for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
422
384
if repo is not None:
423
ret.extend(repo.find_branches())
424
if branches is not None:
385
branches.extend(repo.find_branches())
386
if branch is not None:
387
branches.append(branch)
428
390
def destroy_repository(self):
429
391
"""Destroy the repository in this BzrDir"""
430
392
raise NotImplementedError(self.destroy_repository)
432
def create_branch(self, name=None):
394
def create_branch(self):
433
395
"""Create a branch in this BzrDir.
435
:param name: Name of the colocated branch to create, None for
438
397
The bzrdir's format will control what branch format is created.
439
398
For more control see BranchFormatXX.create(a_bzrdir).
441
400
raise NotImplementedError(self.create_branch)
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
402
def destroy_branch(self):
403
"""Destroy the branch in this BzrDir"""
449
404
raise NotImplementedError(self.destroy_branch)
499
454
except errors.NoRepositoryPresent:
500
455
repository = None
502
if (found_bzrdir.user_url != self.user_url
503
and not repository.is_shared()):
457
if ((found_bzrdir.root_transport.base !=
458
self.root_transport.base) and not repository.is_shared()):
504
459
# Don't look higher, can't use a higher shared repo.
505
460
repository = None
621
576
:return: Tuple with old path name and new path name
623
def name_gen(base='backup.bzr'):
625
name = "%s.~%d~" % (base, counter)
626
while self.root_transport.has(name):
628
name = "%s.~%d~" % (base, counter)
631
backup_dir=name_gen()
632
578
pb = ui.ui_factory.nested_progress_bar()
634
580
# FIXME: bug 300001 -- the backup fails if the backup directory
635
581
# already exists, but it should instead either remove it or make
636
582
# a new backup directory.
584
# FIXME: bug 262450 -- the backup directory should have the same
585
# permissions as the .bzr directory (probably a bug in copy_tree)
638
586
old_path = self.root_transport.abspath('.bzr')
639
new_path = self.root_transport.abspath(backup_dir)
587
new_path = self.root_transport.abspath('backup.bzr')
640
588
ui.ui_factory.note('making backup of %s\n to %s' % (old_path, new_path,))
641
self.root_transport.copy_tree('.bzr', backup_dir)
589
self.root_transport.copy_tree('.bzr', 'backup.bzr')
642
590
return (old_path, new_path)
704
652
next_transport = found_bzrdir.root_transport.clone('..')
705
if (found_bzrdir.user_url == next_transport.base):
653
if (found_bzrdir.root_transport.base == next_transport.base):
706
654
# top of the file system
708
656
# find the next containing bzrdir
725
673
repository = found_bzrdir.open_repository()
726
674
except errors.NoRepositoryPresent:
727
675
return None, False
728
if found_bzrdir.user_url == self.user_url:
676
if found_bzrdir.root_transport.base == self.root_transport.base:
729
677
return repository, True
730
678
elif repository.is_shared():
731
679
return repository, True
737
685
raise errors.NoRepositoryPresent(self)
738
686
return found_repo
740
def get_branch_reference(self, name=None):
688
def get_branch_reference(self):
741
689
"""Return the referenced URL for the branch in this bzrdir.
743
:param name: Optional colocated branch name
744
691
:raises NotBranchError: If there is no Branch.
745
:raises NoColocatedBranchSupport: If a branch name was specified
746
but colocated branches are not supported.
747
692
:return: The URL the branch in this bzrdir references if it is a
748
693
reference branch, or None for regular branches.
751
raise errors.NoColocatedBranchSupport(self)
754
def get_branch_transport(self, branch_format, name=None):
697
def get_branch_transport(self, branch_format):
755
698
"""Get the transport for use by branch format in this BzrDir.
757
700
Note that bzr dirs that do not support format strings will raise
852
795
:param _transport: the transport this dir is based at.
854
797
self._format = _format
855
# these are also under the more standard names of
856
# control_transport and user_transport
857
798
self.transport = _transport.clone('.bzr')
858
799
self.root_transport = _transport
859
800
self._mode_check_done = False
862
def user_transport(self):
863
return self.root_transport
866
def control_transport(self):
867
return self.transport
869
802
def is_control_filename(self, filename):
870
803
"""True if filename is the name of a path which is reserved for bzrdir's.
945
878
BzrDir._check_supported(format, _unsupported)
946
879
return format.open(transport, _found=True)
948
def open_branch(self, name=None, unsupported=False,
949
ignore_fallbacks=False):
881
def open_branch(self, unsupported=False, ignore_fallbacks=False):
950
882
"""Open the branch object at this BzrDir if one is present.
952
884
If unsupported is True, then no longer supported branch formats can
999
931
raise errors.NotBranchError(path=url)
1000
932
a_transport = new_t
1002
def _get_tree_branch(self, name=None):
934
def _get_tree_branch(self):
1003
935
"""Return the branch and tree, if any, for this bzrdir.
1005
:param name: Name of colocated branch to open.
1007
937
Return None for tree if not present or inaccessible.
1008
938
Raise NotBranchError if no branch is present.
1009
939
:return: (tree, branch)
1012
942
tree = self.open_workingtree()
1013
943
except (errors.NoWorkingTree, errors.NotLocalUrl):
1015
branch = self.open_branch(name=name)
945
branch = self.open_branch()
1017
if name is not None:
1018
branch = self.open_branch(name=name)
1020
branch = tree.branch
1021
948
return tree, branch
1096
1023
raise NotImplementedError(self.open_workingtree)
1098
def has_branch(self, name=None):
1025
def has_branch(self):
1099
1026
"""Tell if this bzrdir contains a branch.
1101
1028
Note: if you're going to open the branch, you should just go ahead
1383
1310
self.create_hook(hooks.HookPoint('pre_open',
1384
1311
"Invoked before attempting to open a BzrDir with the transport "
1385
1312
"that the open will use.", (1, 14), None))
1386
self.create_hook(hooks.HookPoint('post_repo_init',
1387
"Invoked after a repository has been initialized. "
1388
"post_repo_init is called with a "
1389
"bzrlib.bzrdir.RepoInitHookParams.",
1392
1314
# install the default hooks
1393
1315
BzrDir.hooks = BzrDirHooks()
1396
class RepoInitHookParams(object):
1397
"""Object holding parameters passed to *_repo_init hooks.
1399
There are 4 fields that hooks may wish to access:
1401
:ivar repository: Repository created
1402
:ivar format: Repository format
1403
:ivar bzrdir: The bzrdir for the repository
1404
:ivar shared: The repository is shared
1407
def __init__(self, repository, format, a_bzrdir, shared):
1408
"""Create a group of RepoInitHook parameters.
1410
:param repository: Repository created
1411
:param format: Repository format
1412
:param bzrdir: The bzrdir for the repository
1413
:param shared: The repository is shared
1415
self.repository = repository
1416
self.format = format
1417
self.bzrdir = a_bzrdir
1418
self.shared = shared
1420
def __eq__(self, other):
1421
return self.__dict__ == other.__dict__
1425
return "<%s for %s>" % (self.__class__.__name__,
1428
return "<%s for %s>" % (self.__class__.__name__,
1432
1318
class BzrDirPreSplitOut(BzrDir):
1433
1319
"""A common class for the all-in-one formats."""
1473
1359
tree.clone(result)
1476
def create_branch(self, name=None):
1362
def create_branch(self):
1477
1363
"""See BzrDir.create_branch."""
1478
return self._format.get_branch_format().initialize(self, name=name)
1364
return self._format.get_branch_format().initialize(self)
1480
def destroy_branch(self, name=None):
1366
def destroy_branch(self):
1481
1367
"""See BzrDir.destroy_branch."""
1482
1368
raise errors.UnsupportedOperation(self.destroy_branch, self)
1539
1425
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1542
def get_branch_transport(self, branch_format, name=None):
1428
def get_branch_transport(self, branch_format):
1543
1429
"""See BzrDir.get_branch_transport()."""
1544
if name is not None:
1545
raise errors.NoColocatedBranchSupport(self)
1546
1430
if branch_format is None:
1547
1431
return self.transport
1581
1465
format = BzrDirFormat.get_default_format()
1582
1466
return not isinstance(self._format, format.__class__)
1584
def open_branch(self, name=None, unsupported=False,
1585
ignore_fallbacks=False):
1468
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1586
1469
"""See BzrDir.open_branch."""
1587
1470
from bzrlib.branch import BzrBranchFormat4
1588
1471
format = BzrBranchFormat4()
1589
1472
self._check_supported(format, unsupported)
1590
return format.open(self, name, _found=True)
1473
return format.open(self, _found=True)
1592
1475
def sprout(self, url, revision_id=None, force_new_repo=False,
1593
1476
possible_transports=None, accelerator_tree=None,
1710
1593
"""See BzrDir.can_convert_format()."""
1713
def create_branch(self, name=None):
1596
def create_branch(self):
1714
1597
"""See BzrDir.create_branch."""
1715
return self._format.get_branch_format().initialize(self, name=name)
1598
return self._format.get_branch_format().initialize(self)
1717
def destroy_branch(self, name=None):
1600
def destroy_branch(self):
1718
1601
"""See BzrDir.create_branch."""
1719
if name is not None:
1720
raise errors.NoColocatedBranchSupport(self)
1721
1602
self.transport.delete_tree('branch')
1723
1604
def create_repository(self, shared=False):
1746
1627
def destroy_workingtree_metadata(self):
1747
1628
self.transport.delete_tree('checkout')
1749
def find_branch_format(self, name=None):
1630
def find_branch_format(self):
1750
1631
"""Find the branch 'format' for this bzrdir.
1752
1633
This might be a synthetic object for e.g. RemoteBranch and SVN.
1754
1635
from bzrlib.branch import BranchFormat
1755
return BranchFormat.find_format(self, name=name)
1636
return BranchFormat.find_format(self)
1757
1638
def _get_mkdir_mode(self):
1758
1639
"""Figure out the mode to use when creating a bzrdir subdir."""
1760
1641
lockable_files.TransportLock)
1761
1642
return temp_control._dir_mode
1763
def get_branch_reference(self, name=None):
1644
def get_branch_reference(self):
1764
1645
"""See BzrDir.get_branch_reference()."""
1765
1646
from bzrlib.branch import BranchFormat
1766
format = BranchFormat.find_format(self, name=name)
1767
return format.get_reference(self, name=name)
1647
format = BranchFormat.find_format(self)
1648
return format.get_reference(self)
1769
def get_branch_transport(self, branch_format, name=None):
1650
def get_branch_transport(self, branch_format):
1770
1651
"""See BzrDir.get_branch_transport()."""
1771
if name is not None:
1772
raise errors.NoColocatedBranchSupport(self)
1773
1652
# XXX: this shouldn't implicitly create the directory if it's just
1774
1653
# promising to get a transport -- mbp 20090727
1775
1654
if branch_format is None:
1847
1726
except errors.NoRepositoryPresent:
1849
for branch in self.list_branches():
1850
if not isinstance(branch._format,
1729
if not isinstance(self.open_branch()._format,
1851
1730
format.get_branch_format().__class__):
1852
1731
# the branch needs an upgrade.
1733
except errors.NotBranchError:
1855
1736
my_wt = self.open_workingtree(recommend_upgrade=False)
1856
1737
if not isinstance(my_wt._format,
1864
def open_branch(self, name=None, unsupported=False,
1865
ignore_fallbacks=False):
1745
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1866
1746
"""See BzrDir.open_branch."""
1867
format = self.find_branch_format(name=name)
1747
format = self.find_branch_format()
1868
1748
self._check_supported(format, unsupported)
1869
return format.open(self, name=name,
1870
_found=True, ignore_fallbacks=ignore_fallbacks)
1749
return format.open(self, _found=True, ignore_fallbacks=ignore_fallbacks)
1872
1751
def open_repository(self, unsupported=False):
1873
1752
"""See BzrDir.open_repository."""
1905
1784
Once a format is deprecated, just deprecate the initialize and open
1906
1785
methods on the format class. Do not deprecate the object, as the
1907
1786
object will be created every system load.
1909
:cvar colocated_branches: Whether this formats supports colocated branches.
1912
1789
_default_format = None
1930
1807
_lock_file_name = 'branch-lock'
1932
colocated_branches = False
1933
"""Whether co-located branches are supported for this control dir format.
1936
1809
# _lock_class must be set in subclasses to the lock type, typ.
1937
1810
# TransportLock or LockDir
2745
2618
if isinstance(self.bzrdir.transport, local.LocalTransport):
2746
2619
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2747
2620
self._convert_to_weaves()
2748
return BzrDir.open(self.bzrdir.user_url)
2621
return BzrDir.open(self.bzrdir.root_transport.base)
2750
2623
self.pb.finished()
3126
2999
BzrDirMetaFormat1().get_format_string(),
3127
3000
mode=self.file_mode)
3128
3001
self.pb.finished()
3129
return BzrDir.open(self.bzrdir.user_url)
3002
return BzrDir.open(self.bzrdir.root_transport.base)
3131
3004
def make_lock(self, name):
3132
3005
"""Make a lock for the new control dir name."""
3181
3054
ui.ui_factory.note('starting repository conversion')
3182
3055
converter = CopyConverter(self.target_format.repository_format)
3183
3056
converter.convert(repo, pb)
3184
for branch in self.bzrdir.list_branches():
3058
branch = self.bzrdir.open_branch()
3059
except errors.NotBranchError:
3185
3062
# TODO: conversions of Branch and Tree should be done by
3186
3063
# InterXFormat lookups/some sort of registry.
3187
3064
# Avoid circular imports
3714
3591
stack_on = urlutils.rebase_url(self._stack_on,
3715
3592
self._stack_on_pwd,
3593
branch.bzrdir.root_transport.base)
3717
3594
except errors.InvalidRebaseURLs:
3718
3595
stack_on = self._get_full_stack_on()