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):
91
125
"""A .bzr control diretory.
93
127
BzrDir instances let you create or open any of the things that can be
260
294
# copied, and finally if we are copying up to a specific
261
295
# revision_id then we can use the pending-ancestry-result which
262
296
# does not require traversing all of history to describe it.
263
if (result_repo.bzrdir.root_transport.base ==
264
result.root_transport.base and not require_stacking and
297
if (result_repo.user_url == result.user_url
298
and not require_stacking and
265
299
revision_id is not None):
266
300
fetch_spec = graph.PendingAncestryResult(
267
301
[revision_id], local_repo)
343
377
bzrdir = BzrDir.open_from_transport(current_transport)
344
except errors.NotBranchError:
378
except (errors.NotBranchError, errors.PermissionDenied):
347
381
recurse, value = evaluate(bzrdir)
350
384
subdirs = list_current(current_transport)
351
except errors.NoSuchFile:
385
except (errors.NoSuchFile, errors.PermissionDenied):
354
388
for subdir in sorted(subdirs, reverse=True):
355
389
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, errors.NoRepositoryPresent):
358
401
def find_branches(transport):
359
402
"""Find all branches under a transport.
371
414
except errors.NoRepositoryPresent:
374
return False, (None, repository)
376
branch = bzrdir.open_branch()
377
except errors.NotBranchError:
378
return True, (None, None)
380
return True, (branch, None)
382
for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
417
return False, ([], repository)
418
return True, (bzrdir.list_branches(), None)
420
for branches, repo in BzrDir.find_bzrdirs(transport,
383
422
if repo is not None:
384
branches.extend(repo.find_branches())
385
if branch is not None:
386
branches.append(branch)
423
ret.extend(repo.find_branches())
424
if branches is not None:
389
428
def destroy_repository(self):
390
429
"""Destroy the repository in this BzrDir"""
391
430
raise NotImplementedError(self.destroy_repository)
393
def create_branch(self):
432
def create_branch(self, name=None):
394
433
"""Create a branch in this BzrDir.
435
:param name: Name of the colocated branch to create, None for
396
438
The bzrdir's format will control what branch format is created.
397
439
For more control see BranchFormatXX.create(a_bzrdir).
399
441
raise NotImplementedError(self.create_branch)
401
def destroy_branch(self):
402
"""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
403
449
raise NotImplementedError(self.destroy_branch)
453
499
except errors.NoRepositoryPresent:
454
500
repository = None
456
if ((found_bzrdir.root_transport.base !=
457
self.root_transport.base) and not repository.is_shared()):
502
if (found_bzrdir.user_url != self.user_url
503
and not repository.is_shared()):
458
504
# Don't look higher, can't use a higher shared repo.
459
505
repository = None
575
621
: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()
577
632
pb = ui.ui_factory.nested_progress_bar()
579
634
# FIXME: bug 300001 -- the backup fails if the backup directory
581
636
# a new backup directory.
583
638
old_path = self.root_transport.abspath('.bzr')
584
new_path = self.root_transport.abspath('backup.bzr')
639
new_path = self.root_transport.abspath(backup_dir)
585
640
ui.ui_factory.note('making backup of %s\n to %s' % (old_path, new_path,))
586
self.root_transport.copy_tree('.bzr', 'backup.bzr')
641
self.root_transport.copy_tree('.bzr', backup_dir)
587
642
return (old_path, new_path)
649
704
next_transport = found_bzrdir.root_transport.clone('..')
650
if (found_bzrdir.root_transport.base == next_transport.base):
705
if (found_bzrdir.user_url == next_transport.base):
651
706
# top of the file system
653
708
# find the next containing bzrdir
670
725
repository = found_bzrdir.open_repository()
671
726
except errors.NoRepositoryPresent:
672
727
return None, False
673
if found_bzrdir.root_transport.base == self.root_transport.base:
728
if found_bzrdir.user_url == self.user_url:
674
729
return repository, True
675
730
elif repository.is_shared():
676
731
return repository, True
682
737
raise errors.NoRepositoryPresent(self)
683
738
return found_repo
685
def get_branch_reference(self):
740
def get_branch_reference(self, name=None):
686
741
"""Return the referenced URL for the branch in this bzrdir.
743
:param name: Optional colocated branch name
688
744
:raises NotBranchError: If there is no Branch.
745
:raises NoColocatedBranchSupport: If a branch name was specified
746
but colocated branches are not supported.
689
747
:return: The URL the branch in this bzrdir references if it is a
690
748
reference branch, or None for regular branches.
751
raise errors.NoColocatedBranchSupport(self)
694
def get_branch_transport(self, branch_format):
754
def get_branch_transport(self, branch_format, name=None):
695
755
"""Get the transport for use by branch format in this BzrDir.
697
757
Note that bzr dirs that do not support format strings will raise
792
852
:param _transport: the transport this dir is based at.
794
854
self._format = _format
855
# these are also under the more standard names of
856
# control_transport and user_transport
795
857
self.transport = _transport.clone('.bzr')
796
858
self.root_transport = _transport
797
859
self._mode_check_done = False
862
def user_transport(self):
863
return self.root_transport
866
def control_transport(self):
867
return self.transport
799
869
def is_control_filename(self, filename):
800
870
"""True if filename is the name of a path which is reserved for bzrdir's.
875
945
BzrDir._check_supported(format, _unsupported)
876
946
return format.open(transport, _found=True)
878
def open_branch(self, unsupported=False, ignore_fallbacks=False):
948
def open_branch(self, name=None, unsupported=False,
949
ignore_fallbacks=False):
879
950
"""Open the branch object at this BzrDir if one is present.
881
952
If unsupported is True, then no longer supported branch formats can
928
999
raise errors.NotBranchError(path=url)
929
1000
a_transport = new_t
931
def _get_tree_branch(self):
1002
def _get_tree_branch(self, name=None):
932
1003
"""Return the branch and tree, if any, for this bzrdir.
1005
:param name: Name of colocated branch to open.
934
1007
Return None for tree if not present or inaccessible.
935
1008
Raise NotBranchError if no branch is present.
936
1009
:return: (tree, branch)
939
1012
tree = self.open_workingtree()
940
1013
except (errors.NoWorkingTree, errors.NotLocalUrl):
942
branch = self.open_branch()
1015
branch = self.open_branch(name=name)
1017
if name is not None:
1018
branch = self.open_branch(name=name)
1020
branch = tree.branch
945
1021
return tree, branch
1020
1096
raise NotImplementedError(self.open_workingtree)
1022
def has_branch(self):
1098
def has_branch(self, name=None):
1023
1099
"""Tell if this bzrdir contains a branch.
1025
1101
Note: if you're going to open the branch, you should just go ahead
1168
1244
repository_policy = result.determine_repository_policy(
1169
1245
force_new_repo, stacked_branch_url, require_stacking=stacked)
1170
1246
result_repo, is_new_repo = repository_policy.acquire_repository()
1171
if is_new_repo and revision_id is not None and not stacked:
1247
is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
1248
if is_new_repo and revision_id is not None and not is_stacked:
1172
1249
fetch_spec = graph.PendingAncestryResult(
1173
1250
[revision_id], source_repository)
1307
1384
self.create_hook(hooks.HookPoint('pre_open',
1308
1385
"Invoked before attempting to open a BzrDir with the transport "
1309
1386
"that the open will use.", (1, 14), None))
1387
self.create_hook(hooks.HookPoint('post_repo_init',
1388
"Invoked after a repository has been initialized. "
1389
"post_repo_init is called with a "
1390
"bzrlib.bzrdir.RepoInitHookParams.",
1311
1393
# install the default hooks
1312
1394
BzrDir.hooks = BzrDirHooks()
1397
class RepoInitHookParams(object):
1398
"""Object holding parameters passed to *_repo_init hooks.
1400
There are 4 fields that hooks may wish to access:
1402
:ivar repository: Repository created
1403
:ivar format: Repository format
1404
:ivar bzrdir: The bzrdir for the repository
1405
:ivar shared: The repository is shared
1408
def __init__(self, repository, format, a_bzrdir, shared):
1409
"""Create a group of RepoInitHook parameters.
1411
:param repository: Repository created
1412
:param format: Repository format
1413
:param bzrdir: The bzrdir for the repository
1414
:param shared: The repository is shared
1416
self.repository = repository
1417
self.format = format
1418
self.bzrdir = a_bzrdir
1419
self.shared = shared
1421
def __eq__(self, other):
1422
return self.__dict__ == other.__dict__
1426
return "<%s for %s>" % (self.__class__.__name__,
1429
return "<%s for %s>" % (self.__class__.__name__,
1315
1433
class BzrDirPreSplitOut(BzrDir):
1316
1434
"""A common class for the all-in-one formats."""
1356
1474
tree.clone(result)
1359
def create_branch(self):
1477
def create_branch(self, name=None):
1360
1478
"""See BzrDir.create_branch."""
1361
return self._format.get_branch_format().initialize(self)
1479
return self._format.get_branch_format().initialize(self, name=name)
1363
def destroy_branch(self):
1481
def destroy_branch(self, name=None):
1364
1482
"""See BzrDir.destroy_branch."""
1365
1483
raise errors.UnsupportedOperation(self.destroy_branch, self)
1422
1540
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1425
def get_branch_transport(self, branch_format):
1543
def get_branch_transport(self, branch_format, name=None):
1426
1544
"""See BzrDir.get_branch_transport()."""
1545
if name is not None:
1546
raise errors.NoColocatedBranchSupport(self)
1427
1547
if branch_format is None:
1428
1548
return self.transport
1462
1582
format = BzrDirFormat.get_default_format()
1463
1583
return not isinstance(self._format, format.__class__)
1465
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1585
def open_branch(self, name=None, unsupported=False,
1586
ignore_fallbacks=False):
1466
1587
"""See BzrDir.open_branch."""
1467
1588
from bzrlib.branch import BzrBranchFormat4
1468
1589
format = BzrBranchFormat4()
1469
1590
self._check_supported(format, unsupported)
1470
return format.open(self, _found=True)
1591
return format.open(self, name, _found=True)
1472
1593
def sprout(self, url, revision_id=None, force_new_repo=False,
1473
1594
possible_transports=None, accelerator_tree=None,
1590
1711
"""See BzrDir.can_convert_format()."""
1593
def create_branch(self):
1714
def create_branch(self, name=None):
1594
1715
"""See BzrDir.create_branch."""
1595
return self._format.get_branch_format().initialize(self)
1716
return self._format.get_branch_format().initialize(self, name=name)
1597
def destroy_branch(self):
1718
def destroy_branch(self, name=None):
1598
1719
"""See BzrDir.create_branch."""
1720
if name is not None:
1721
raise errors.NoColocatedBranchSupport(self)
1599
1722
self.transport.delete_tree('branch')
1601
1724
def create_repository(self, shared=False):
1624
1747
def destroy_workingtree_metadata(self):
1625
1748
self.transport.delete_tree('checkout')
1627
def find_branch_format(self):
1750
def find_branch_format(self, name=None):
1628
1751
"""Find the branch 'format' for this bzrdir.
1630
1753
This might be a synthetic object for e.g. RemoteBranch and SVN.
1632
1755
from bzrlib.branch import BranchFormat
1633
return BranchFormat.find_format(self)
1756
return BranchFormat.find_format(self, name=name)
1635
1758
def _get_mkdir_mode(self):
1636
1759
"""Figure out the mode to use when creating a bzrdir subdir."""
1638
1761
lockable_files.TransportLock)
1639
1762
return temp_control._dir_mode
1641
def get_branch_reference(self):
1764
def get_branch_reference(self, name=None):
1642
1765
"""See BzrDir.get_branch_reference()."""
1643
1766
from bzrlib.branch import BranchFormat
1644
format = BranchFormat.find_format(self)
1645
return format.get_reference(self)
1767
format = BranchFormat.find_format(self, name=name)
1768
return format.get_reference(self, name=name)
1647
def get_branch_transport(self, branch_format):
1770
def get_branch_transport(self, branch_format, name=None):
1648
1771
"""See BzrDir.get_branch_transport()."""
1772
if name is not None:
1773
raise errors.NoColocatedBranchSupport(self)
1649
1774
# XXX: this shouldn't implicitly create the directory if it's just
1650
1775
# promising to get a transport -- mbp 20090727
1651
1776
if branch_format is None:
1723
1848
except errors.NoRepositoryPresent:
1726
if not isinstance(self.open_branch()._format,
1850
for branch in self.list_branches():
1851
if not isinstance(branch._format,
1727
1852
format.get_branch_format().__class__):
1728
1853
# the branch needs an upgrade.
1730
except errors.NotBranchError:
1733
1856
my_wt = self.open_workingtree(recommend_upgrade=False)
1734
1857
if not isinstance(my_wt._format,
1742
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1865
def open_branch(self, name=None, unsupported=False,
1866
ignore_fallbacks=False):
1743
1867
"""See BzrDir.open_branch."""
1744
format = self.find_branch_format()
1868
format = self.find_branch_format(name=name)
1745
1869
self._check_supported(format, unsupported)
1746
return format.open(self, _found=True, ignore_fallbacks=ignore_fallbacks)
1870
return format.open(self, name=name,
1871
_found=True, ignore_fallbacks=ignore_fallbacks)
1748
1873
def open_repository(self, unsupported=False):
1749
1874
"""See BzrDir.open_repository."""
1781
1906
Once a format is deprecated, just deprecate the initialize and open
1782
1907
methods on the format class. Do not deprecate the object, as the
1783
1908
object will be created every system load.
1910
:cvar colocated_branches: Whether this formats supports colocated branches.
1786
1913
_default_format = None
1804
1931
_lock_file_name = 'branch-lock'
1933
colocated_branches = False
1934
"""Whether co-located branches are supported for this control dir format.
1806
1937
# _lock_class must be set in subclasses to the lock type, typ.
1807
1938
# TransportLock or LockDir
2607
2737
def convert(self, to_convert, pb):
2608
2738
"""See Converter.convert()."""
2609
2739
self.bzrdir = to_convert
2611
ui.ui_factory.note('starting upgrade from format 4 to 5')
2612
if isinstance(self.bzrdir.transport, local.LocalTransport):
2613
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2614
self._convert_to_weaves()
2615
return BzrDir.open(self.bzrdir.root_transport.base)
2741
warnings.warn("pb parameter to convert() is deprecated")
2742
self.pb = ui.ui_factory.nested_progress_bar()
2744
ui.ui_factory.note('starting upgrade from format 4 to 5')
2745
if isinstance(self.bzrdir.transport, local.LocalTransport):
2746
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2747
self._convert_to_weaves()
2748
return BzrDir.open(self.bzrdir.user_url)
2617
2752
def _convert_to_weaves(self):
2618
2753
ui.ui_factory.note('note: upgrade may be faster if all store files are ungzipped first')
2738
2873
self.revisions[rev_id] = rev
2740
2875
def _load_old_inventory(self, rev_id):
2741
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2876
f = self.branch.repository.inventory_store.get(rev_id)
2878
old_inv_xml = f.read()
2742
2881
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2743
2882
inv.revision_id = rev_id
2744
2883
rev = self.revisions[rev_id]
2822
2961
ie.revision = previous_ie.revision
2824
2963
if ie.has_text():
2825
text = self.branch.repository._text_store.get(ie.text_id)
2826
file_lines = text.readlines()
2964
f = self.branch.repository._text_store.get(ie.text_id)
2966
file_lines = f.readlines()
2827
2969
w.add_lines(rev_id, previous_revisions, file_lines)
2828
2970
self.text_count += 1
2859
3001
def convert(self, to_convert, pb):
2860
3002
"""See Converter.convert()."""
2861
3003
self.bzrdir = to_convert
2863
ui.ui_factory.note('starting upgrade from format 5 to 6')
2864
self._convert_to_prefixed()
2865
return BzrDir.open(self.bzrdir.root_transport.base)
3004
pb = ui.ui_factory.nested_progress_bar()
3006
ui.ui_factory.note('starting upgrade from format 5 to 6')
3007
self._convert_to_prefixed()
3008
return BzrDir.open(self.bzrdir.user_url)
2867
3012
def _convert_to_prefixed(self):
2868
3013
from bzrlib.store import TransportStore
2901
3046
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2902
3047
from bzrlib.branch import BzrBranchFormat5
2903
3048
self.bzrdir = to_convert
3049
self.pb = ui.ui_factory.nested_progress_bar()
2906
3051
self.total = 20 # the steps we know about
2907
3052
self.garbage_inventories = []
2987
3132
'branch-format',
2988
3133
BzrDirMetaFormat1().get_format_string(),
2989
3134
mode=self.file_mode)
2990
return BzrDir.open(self.bzrdir.root_transport.base)
3136
return BzrDir.open(self.bzrdir.user_url)
2992
3138
def make_lock(self, name):
2993
3139
"""Make a lock for the new control dir name."""
3028
3174
def convert(self, to_convert, pb):
3029
3175
"""See Converter.convert()."""
3030
3176
self.bzrdir = to_convert
3177
self.pb = ui.ui_factory.nested_progress_bar()
3034
3180
self.step('checking repository format')
3042
3188
ui.ui_factory.note('starting repository conversion')
3043
3189
converter = CopyConverter(self.target_format.repository_format)
3044
3190
converter.convert(repo, pb)
3046
branch = self.bzrdir.open_branch()
3047
except errors.NotBranchError:
3191
for branch in self.bzrdir.list_branches():
3050
3192
# TODO: conversions of Branch and Tree should be done by
3051
3193
# InterXFormat lookups/some sort of registry.
3052
3194
# Avoid circular imports
3109
3252
# XXX: It's a bit ugly that the network name is here, because we'd
3110
3253
# like to believe that format objects are stateless or at least
3111
3254
# immutable, However, we do at least avoid mutating the name after
3112
# it's returned. See <https://bugs.edge.launchpad.net/bzr/+bug/504102>
3255
# it's returned. See <https://bugs.launchpad.net/bzr/+bug/504102>
3113
3256
self._network_name = None
3115
3258
def __repr__(self):
3578
3721
stack_on = urlutils.rebase_url(self._stack_on,
3579
3722
self._stack_on_pwd,
3580
branch.bzrdir.root_transport.base)
3581
3724
except errors.InvalidRebaseURLs:
3582
3725
stack_on = self._get_full_stack_on()
3770
3913
help='New in 0.92: Pack-based format with data compatible with '
3771
3914
'dirstate-tags format repositories. Interoperates with '
3772
3915
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3773
'Previously called knitpack-experimental. '
3774
'For more information, see '
3775
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
3776
3917
branch_format='bzrlib.branch.BzrBranchFormat6',
3777
3918
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3781
3922
help='New in 0.92: Pack-based format with data compatible with '
3782
3923
'dirstate-with-subtree format repositories. Interoperates with '
3783
3924
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3784
'Previously called knitpack-experimental. '
3785
'For more information, see '
3786
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
3787
3926
branch_format='bzrlib.branch.BzrBranchFormat6',
3788
3927
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3851
3990
'to and from rich-root-pack (and anything compatible with '
3852
3991
'rich-root-pack) format repositories. Repositories and branches in '
3853
3992
'this format can only be read by bzr.dev. Please read '
3854
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3993
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3856
3995
branch_format='bzrlib.branch.BzrBranchFormat7',
3857
3996
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3865
4004
'from pack-0.92-subtree (and anything compatible with '
3866
4005
'pack-0.92-subtree) format repositories. Repositories and branches in '
3867
4006
'this format can only be read by bzr.dev. Please read '
3868
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
4007
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3870
4009
branch_format='bzrlib.branch.BzrBranchFormat7',
3871
4010
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3881
4020
'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',
3882
4021
help='pack-1.9 with 255-way hashed CHK inv, group compress, rich roots '
3884
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
4023
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3886
4025
branch_format='bzrlib.branch.BzrBranchFormat7',
3887
4026
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3893
4032
'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK2',
3894
4033
help='pack-1.9 with 255-way hashed CHK inv, bencode revision, group compress, '
3895
4034
'rich roots. Please read '
3896
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
4035
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3898
4037
branch_format='bzrlib.branch.BzrBranchFormat7',
3899
4038
tree_format='bzrlib.workingtree.WorkingTreeFormat6',