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)
355
388
for subdir in sorted(subdirs, reverse=True):
356
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:
359
401
def find_branches(transport):
360
402
"""Find all branches under a transport.
372
414
except errors.NoRepositoryPresent:
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):
417
return False, ([], repository)
418
return True, (bzrdir.list_branches(), None)
420
for branches, repo in BzrDir.find_bzrdirs(transport,
384
422
if repo is not None:
385
branches.extend(repo.find_branches())
386
if branch is not None:
387
branches.append(branch)
423
ret.extend(repo.find_branches())
424
if branches is not None:
390
428
def destroy_repository(self):
391
429
"""Destroy the repository in this BzrDir"""
392
430
raise NotImplementedError(self.destroy_repository)
394
def create_branch(self):
432
def create_branch(self, name=None):
395
433
"""Create a branch in this BzrDir.
435
:param name: Name of the colocated branch to create, None for
397
438
The bzrdir's format will control what branch format is created.
398
439
For more control see BranchFormatXX.create(a_bzrdir).
400
441
raise NotImplementedError(self.create_branch)
402
def destroy_branch(self):
403
"""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
404
449
raise NotImplementedError(self.destroy_branch)
454
499
except errors.NoRepositoryPresent:
455
500
repository = None
457
if ((found_bzrdir.root_transport.base !=
458
self.root_transport.base) and not repository.is_shared()):
502
if (found_bzrdir.user_url != self.user_url
503
and not repository.is_shared()):
459
504
# Don't look higher, can't use a higher shared repo.
460
505
repository = None
576
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()
578
632
pb = ui.ui_factory.nested_progress_bar()
580
634
# FIXME: bug 300001 -- the backup fails if the backup directory
581
635
# already exists, but it should instead either remove it or make
582
636
# 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)
586
638
old_path = self.root_transport.abspath('.bzr')
587
new_path = self.root_transport.abspath('backup.bzr')
639
new_path = self.root_transport.abspath(backup_dir)
588
640
ui.ui_factory.note('making backup of %s\n to %s' % (old_path, new_path,))
589
self.root_transport.copy_tree('.bzr', 'backup.bzr')
641
self.root_transport.copy_tree('.bzr', backup_dir)
590
642
return (old_path, new_path)
652
704
next_transport = found_bzrdir.root_transport.clone('..')
653
if (found_bzrdir.root_transport.base == next_transport.base):
705
if (found_bzrdir.user_url == next_transport.base):
654
706
# top of the file system
656
708
# find the next containing bzrdir
673
725
repository = found_bzrdir.open_repository()
674
726
except errors.NoRepositoryPresent:
675
727
return None, False
676
if found_bzrdir.root_transport.base == self.root_transport.base:
728
if found_bzrdir.user_url == self.user_url:
677
729
return repository, True
678
730
elif repository.is_shared():
679
731
return repository, True
697
def get_branch_transport(self, branch_format):
749
def get_branch_transport(self, branch_format, name=None):
698
750
"""Get the transport for use by branch format in this BzrDir.
700
752
Note that bzr dirs that do not support format strings will raise
795
847
:param _transport: the transport this dir is based at.
797
849
self._format = _format
850
# these are also under the more standard names of
851
# control_transport and user_transport
798
852
self.transport = _transport.clone('.bzr')
799
853
self.root_transport = _transport
800
854
self._mode_check_done = False
857
def user_transport(self):
858
return self.root_transport
861
def control_transport(self):
862
return self.transport
802
864
def is_control_filename(self, filename):
803
865
"""True if filename is the name of a path which is reserved for bzrdir's.
878
940
BzrDir._check_supported(format, _unsupported)
879
941
return format.open(transport, _found=True)
881
def open_branch(self, unsupported=False, ignore_fallbacks=False):
943
def open_branch(self, name=None, unsupported=False,
944
ignore_fallbacks=False):
882
945
"""Open the branch object at this BzrDir if one is present.
884
947
If unsupported is True, then no longer supported branch formats can
1023
1086
raise NotImplementedError(self.open_workingtree)
1025
def has_branch(self):
1088
def has_branch(self, name=None):
1026
1089
"""Tell if this bzrdir contains a branch.
1028
1091
Note: if you're going to open the branch, you should just go ahead
1310
1373
self.create_hook(hooks.HookPoint('pre_open',
1311
1374
"Invoked before attempting to open a BzrDir with the transport "
1312
1375
"that the open will use.", (1, 14), None))
1376
self.create_hook(hooks.HookPoint('post_repo_init',
1377
"Invoked after a repository has been initialized. "
1378
"post_repo_init is called with a "
1379
"bzrlib.bzrdir.RepoInitHookParams.",
1314
1382
# install the default hooks
1315
1383
BzrDir.hooks = BzrDirHooks()
1386
class RepoInitHookParams(object):
1387
"""Object holding parameters passed to *_repo_init hooks.
1389
There are 4 fields that hooks may wish to access:
1391
:ivar repository: Repository created
1392
:ivar format: Repository format
1393
:ivar bzrdir: The bzrdir for the repository
1394
:ivar shared: The repository is shared
1397
def __init__(self, repository, format, a_bzrdir, shared):
1398
"""Create a group of RepoInitHook parameters.
1400
:param repository: Repository created
1401
:param format: Repository format
1402
:param bzrdir: The bzrdir for the repository
1403
:param shared: The repository is shared
1405
self.repository = repository
1406
self.format = format
1407
self.bzrdir = a_bzrdir
1408
self.shared = shared
1410
def __eq__(self, other):
1411
return self.__dict__ == other.__dict__
1415
return "<%s for %s>" % (self.__class__.__name__,
1418
return "<%s for %s>" % (self.__class__.__name__,
1318
1422
class BzrDirPreSplitOut(BzrDir):
1319
1423
"""A common class for the all-in-one formats."""
1359
1463
tree.clone(result)
1362
def create_branch(self):
1466
def create_branch(self, name=None):
1363
1467
"""See BzrDir.create_branch."""
1364
return self._format.get_branch_format().initialize(self)
1468
return self._format.get_branch_format().initialize(self, name=name)
1366
def destroy_branch(self):
1470
def destroy_branch(self, name=None):
1367
1471
"""See BzrDir.destroy_branch."""
1368
1472
raise errors.UnsupportedOperation(self.destroy_branch, self)
1425
1529
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1428
def get_branch_transport(self, branch_format):
1532
def get_branch_transport(self, branch_format, name=None):
1429
1533
"""See BzrDir.get_branch_transport()."""
1534
if name is not None:
1535
raise errors.NoColocatedBranchSupport(self)
1430
1536
if branch_format is None:
1431
1537
return self.transport
1465
1571
format = BzrDirFormat.get_default_format()
1466
1572
return not isinstance(self._format, format.__class__)
1468
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1574
def open_branch(self, name=None, unsupported=False,
1575
ignore_fallbacks=False):
1469
1576
"""See BzrDir.open_branch."""
1470
1577
from bzrlib.branch import BzrBranchFormat4
1471
1578
format = BzrBranchFormat4()
1472
1579
self._check_supported(format, unsupported)
1473
return format.open(self, _found=True)
1580
return format.open(self, name, _found=True)
1475
1582
def sprout(self, url, revision_id=None, force_new_repo=False,
1476
1583
possible_transports=None, accelerator_tree=None,
1593
1700
"""See BzrDir.can_convert_format()."""
1596
def create_branch(self):
1703
def create_branch(self, name=None):
1597
1704
"""See BzrDir.create_branch."""
1598
return self._format.get_branch_format().initialize(self)
1705
return self._format.get_branch_format().initialize(self, name=name)
1600
def destroy_branch(self):
1707
def destroy_branch(self, name=None):
1601
1708
"""See BzrDir.create_branch."""
1709
if name is not None:
1710
raise errors.NoColocatedBranchSupport(self)
1602
1711
self.transport.delete_tree('branch')
1604
1713
def create_repository(self, shared=False):
1647
1756
format = BranchFormat.find_format(self)
1648
1757
return format.get_reference(self)
1650
def get_branch_transport(self, branch_format):
1759
def get_branch_transport(self, branch_format, name=None):
1651
1760
"""See BzrDir.get_branch_transport()."""
1761
if name is not None:
1762
raise errors.NoColocatedBranchSupport(self)
1652
1763
# XXX: this shouldn't implicitly create the directory if it's just
1653
1764
# promising to get a transport -- mbp 20090727
1654
1765
if branch_format is None:
1726
1837
except errors.NoRepositoryPresent:
1729
if not isinstance(self.open_branch()._format,
1839
for branch in self.list_branches():
1840
if not isinstance(branch._format,
1730
1841
format.get_branch_format().__class__):
1731
1842
# the branch needs an upgrade.
1733
except errors.NotBranchError:
1736
1845
my_wt = self.open_workingtree(recommend_upgrade=False)
1737
1846
if not isinstance(my_wt._format,
1745
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1854
def open_branch(self, name=None, unsupported=False,
1855
ignore_fallbacks=False):
1746
1856
"""See BzrDir.open_branch."""
1747
1857
format = self.find_branch_format()
1748
1858
self._check_supported(format, unsupported)
1749
return format.open(self, _found=True, ignore_fallbacks=ignore_fallbacks)
1859
return format.open(self, name=name,
1860
_found=True, ignore_fallbacks=ignore_fallbacks)
1751
1862
def open_repository(self, unsupported=False):
1752
1863
"""See BzrDir.open_repository."""
1784
1895
Once a format is deprecated, just deprecate the initialize and open
1785
1896
methods on the format class. Do not deprecate the object, as the
1786
1897
object will be created every system load.
1899
:cvar colocated_branches: Whether this formats supports colocated branches.
1789
1902
_default_format = None
1807
1920
_lock_file_name = 'branch-lock'
1922
colocated_branches = False
1923
"""Whether co-located branches are supported for this control dir format.
1809
1926
# _lock_class must be set in subclasses to the lock type, typ.
1810
1927
# TransportLock or LockDir
2618
2735
if isinstance(self.bzrdir.transport, local.LocalTransport):
2619
2736
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2620
2737
self._convert_to_weaves()
2621
return BzrDir.open(self.bzrdir.root_transport.base)
2738
return BzrDir.open(self.bzrdir.user_url)
2623
2740
self.pb.finished()
2999
3116
BzrDirMetaFormat1().get_format_string(),
3000
3117
mode=self.file_mode)
3001
3118
self.pb.finished()
3002
return BzrDir.open(self.bzrdir.root_transport.base)
3119
return BzrDir.open(self.bzrdir.user_url)
3004
3121
def make_lock(self, name):
3005
3122
"""Make a lock for the new control dir name."""
3054
3171
ui.ui_factory.note('starting repository conversion')
3055
3172
converter = CopyConverter(self.target_format.repository_format)
3056
3173
converter.convert(repo, pb)
3058
branch = self.bzrdir.open_branch()
3059
except errors.NotBranchError:
3174
for branch in self.bzrdir.list_branches():
3062
3175
# TODO: conversions of Branch and Tree should be done by
3063
3176
# InterXFormat lookups/some sort of registry.
3064
3177
# Avoid circular imports
3591
3704
stack_on = urlutils.rebase_url(self._stack_on,
3592
3705
self._stack_on_pwd,
3593
branch.bzrdir.root_transport.base)
3594
3707
except errors.InvalidRebaseURLs:
3595
3708
stack_on = self._get_full_stack_on()