388
448
policy = self.determine_repository_policy(force_new_repo)
389
449
return policy.acquire_repository()[0]
391
def _find_source_repo(self, add_cleanup, source_branch):
392
"""Find the source branch and repo for a sprout operation.
394
This is helper intended for use by _sprout.
396
:returns: (source_branch, source_repository). Either or both may be
397
None. If not None, they will be read-locked (and their unlock(s)
398
scheduled via the add_cleanup param).
400
if source_branch is not None:
401
add_cleanup(source_branch.lock_read().unlock)
402
return source_branch, source_branch.repository
404
source_branch = self.open_branch()
405
source_repository = source_branch.repository
406
except errors.NotBranchError:
409
source_repository = self.open_repository()
410
except errors.NoRepositoryPresent:
411
source_repository = None
413
add_cleanup(source_repository.lock_read().unlock)
415
add_cleanup(source_branch.lock_read().unlock)
416
return source_branch, source_repository
418
def sprout(self, url, revision_id=None, force_new_repo=False,
419
recurse='down', possible_transports=None,
420
accelerator_tree=None, hardlink=False, stacked=False,
421
source_branch=None, create_tree_if_local=True):
422
"""Create a copy of this controldir prepared for use as a new line of
425
If url's last component does not exist, it will be created.
427
Attributes related to the identity of the source branch like
428
branch nickname will be cleaned, a working tree is created
429
whether one existed before or not; and a local branch is always
432
if revision_id is not None, then the clone operation may tune
433
itself to download less data.
434
:param accelerator_tree: A tree which can be used for retrieving file
435
contents more quickly than the revision tree, i.e. a workingtree.
436
The revision tree will be used for cases where accelerator_tree's
437
content is different.
438
:param hardlink: If true, hard-link files from accelerator_tree,
440
:param stacked: If true, create a stacked branch referring to the
441
location of this control directory.
442
:param create_tree_if_local: If true, a working-tree will be created
443
when working locally.
445
operation = cleanup.OperationWithCleanups(self._sprout)
446
return operation.run(url, revision_id=revision_id,
447
force_new_repo=force_new_repo, recurse=recurse,
448
possible_transports=possible_transports,
449
accelerator_tree=accelerator_tree, hardlink=hardlink,
450
stacked=stacked, source_branch=source_branch,
451
create_tree_if_local=create_tree_if_local)
453
def _sprout(self, op, url, revision_id=None, force_new_repo=False,
454
recurse='down', possible_transports=None,
455
accelerator_tree=None, hardlink=False, stacked=False,
456
source_branch=None, create_tree_if_local=True):
457
add_cleanup = op.add_cleanup
458
fetch_spec_factory = fetch.FetchSpecFactory()
459
if revision_id is not None:
460
fetch_spec_factory.add_revision_ids([revision_id])
461
fetch_spec_factory.source_branch_stop_revision_id = revision_id
462
target_transport = _mod_transport.get_transport(url,
464
target_transport.ensure_base()
465
cloning_format = self.cloning_metadir(stacked)
466
# Create/update the result branch
467
result = cloning_format.initialize_on_transport(target_transport)
468
source_branch, source_repository = self._find_source_repo(
469
add_cleanup, source_branch)
470
fetch_spec_factory.source_branch = source_branch
471
# if a stacked branch wasn't requested, we don't create one
472
# even if the origin was stacked
473
if stacked and source_branch is not None:
474
stacked_branch_url = self.root_transport.base
476
stacked_branch_url = None
477
repository_policy = result.determine_repository_policy(
478
force_new_repo, stacked_branch_url, require_stacking=stacked)
479
result_repo, is_new_repo = repository_policy.acquire_repository()
480
add_cleanup(result_repo.lock_write().unlock)
481
fetch_spec_factory.source_repo = source_repository
482
fetch_spec_factory.target_repo = result_repo
483
if stacked or (len(result_repo._fallback_repositories) != 0):
484
target_repo_kind = fetch.TargetRepoKinds.STACKED
486
target_repo_kind = fetch.TargetRepoKinds.EMPTY
488
target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
489
fetch_spec_factory.target_repo_kind = target_repo_kind
490
if source_repository is not None:
491
fetch_spec = fetch_spec_factory.make_fetch_spec()
492
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
494
if source_branch is None:
495
# this is for sprouting a controldir without a branch; is that
497
# Not especially, but it's part of the contract.
498
result_branch = result.create_branch()
500
result_branch = source_branch.sprout(result,
501
revision_id=revision_id, repository_policy=repository_policy,
502
repository=result_repo)
503
mutter("created new branch %r" % (result_branch,))
505
# Create/update the result working tree
506
if (create_tree_if_local and
507
isinstance(target_transport, local.LocalTransport) and
508
(result_repo is None or result_repo.make_working_trees())):
509
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
510
hardlink=hardlink, from_branch=result_branch)
513
if wt.path2id('') is None:
515
wt.set_root_id(self.open_workingtree.get_root_id())
516
except errors.NoWorkingTree:
522
if recurse == 'down':
525
basis = wt.basis_tree()
526
elif result_branch is not None:
527
basis = result_branch.basis_tree()
528
elif source_branch is not None:
529
basis = source_branch.basis_tree()
530
if basis is not None:
531
add_cleanup(basis.lock_read().unlock)
532
subtrees = basis.iter_references()
535
for path, file_id in subtrees:
536
target = urlutils.join(url, urlutils.escape(path))
537
sublocation = source_branch.reference_parent(file_id, path)
538
sublocation.bzrdir.sprout(target,
539
basis.get_reference_revision(file_id, path),
540
force_new_repo=force_new_repo, recurse=recurse,
547
452
def create_branch_convenience(base, force_new_repo=False,
548
453
force_new_tree=None, format=None,
1001
class BzrDirPreSplitOut(BzrDir):
1002
"""A common class for the all-in-one formats."""
1004
def __init__(self, _transport, _format):
1005
"""See BzrDir.__init__."""
1006
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
1007
self._control_files = lockable_files.LockableFiles(
1008
self.get_branch_transport(None),
1009
self._format._lock_file_name,
1010
self._format._lock_class)
1012
def break_lock(self):
1013
"""Pre-splitout bzrdirs do not suffer from stale locks."""
1014
raise NotImplementedError(self.break_lock)
1016
def cloning_metadir(self, require_stacking=False):
1017
"""Produce a metadir suitable for cloning with."""
1018
if require_stacking:
1019
return controldir.format_registry.make_bzrdir('1.6')
1020
return self._format.__class__()
1022
def clone(self, url, revision_id=None, force_new_repo=False,
1023
preserve_stacking=False):
1024
"""See BzrDir.clone().
1026
force_new_repo has no effect, since this family of formats always
1027
require a new repository.
1028
preserve_stacking has no effect, since no source branch using this
1029
family of formats can be stacked, so there is no stacking to preserve.
1031
self._make_tail(url)
1032
result = self._format._initialize_for_clone(url)
1033
self.open_repository().clone(result, revision_id=revision_id)
1034
from_branch = self.open_branch()
1035
from_branch.clone(result, revision_id=revision_id)
1037
tree = self.open_workingtree()
1038
except errors.NotLocalUrl:
1039
# make a new one, this format always has to have one.
1040
result._init_workingtree()
1045
def create_branch(self, name=None):
1046
"""See BzrDir.create_branch."""
1047
return self._format.get_branch_format().initialize(self, name=name)
1049
def destroy_branch(self, name=None):
1050
"""See BzrDir.destroy_branch."""
1051
raise errors.UnsupportedOperation(self.destroy_branch, self)
1053
def create_repository(self, shared=False):
1054
"""See BzrDir.create_repository."""
1056
raise errors.IncompatibleFormat('shared repository', self._format)
1057
return self.open_repository()
1059
def destroy_repository(self):
1060
"""See BzrDir.destroy_repository."""
1061
raise errors.UnsupportedOperation(self.destroy_repository, self)
1063
def create_workingtree(self, revision_id=None, from_branch=None,
1064
accelerator_tree=None, hardlink=False):
1065
"""See BzrDir.create_workingtree."""
1066
# The workingtree is sometimes created when the bzrdir is created,
1067
# but not when cloning.
1069
# this looks buggy but is not -really-
1070
# because this format creates the workingtree when the bzrdir is
1072
# clone and sprout will have set the revision_id
1073
# and that will have set it for us, its only
1074
# specific uses of create_workingtree in isolation
1075
# that can do wonky stuff here, and that only
1076
# happens for creating checkouts, which cannot be
1077
# done on this format anyway. So - acceptable wart.
1079
warning("can't support hardlinked working trees in %r"
1082
result = self.open_workingtree(recommend_upgrade=False)
1083
except errors.NoSuchFile:
1084
result = self._init_workingtree()
1085
if revision_id is not None:
1086
if revision_id == _mod_revision.NULL_REVISION:
1087
result.set_parent_ids([])
1089
result.set_parent_ids([revision_id])
1092
def _init_workingtree(self):
1093
from bzrlib.workingtree import WorkingTreeFormat2
1095
return WorkingTreeFormat2().initialize(self)
1096
except errors.NotLocalUrl:
1097
# Even though we can't access the working tree, we need to
1098
# create its control files.
1099
return WorkingTreeFormat2()._stub_initialize_on_transport(
1100
self.transport, self._control_files._file_mode)
1102
def destroy_workingtree(self):
1103
"""See BzrDir.destroy_workingtree."""
1104
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1106
def destroy_workingtree_metadata(self):
1107
"""See BzrDir.destroy_workingtree_metadata."""
1108
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1111
def get_branch_transport(self, branch_format, name=None):
1112
"""See BzrDir.get_branch_transport()."""
1113
if name is not None:
1114
raise errors.NoColocatedBranchSupport(self)
1115
if branch_format is None:
1116
return self.transport
1118
branch_format.get_format_string()
1119
except NotImplementedError:
1120
return self.transport
1121
raise errors.IncompatibleFormat(branch_format, self._format)
1123
def get_repository_transport(self, repository_format):
1124
"""See BzrDir.get_repository_transport()."""
1125
if repository_format is None:
1126
return self.transport
1128
repository_format.get_format_string()
1129
except NotImplementedError:
1130
return self.transport
1131
raise errors.IncompatibleFormat(repository_format, self._format)
1133
def get_workingtree_transport(self, workingtree_format):
1134
"""See BzrDir.get_workingtree_transport()."""
1135
if workingtree_format is None:
1136
return self.transport
1138
workingtree_format.get_format_string()
1139
except NotImplementedError:
1140
return self.transport
1141
raise errors.IncompatibleFormat(workingtree_format, self._format)
1143
def needs_format_conversion(self, format=None):
1144
"""See BzrDir.needs_format_conversion()."""
1145
# if the format is not the same as the system default,
1146
# an upgrade is needed.
1148
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1149
% 'needs_format_conversion(format=None)')
1150
format = BzrDirFormat.get_default_format()
1151
return not isinstance(self._format, format.__class__)
1153
def open_branch(self, name=None, unsupported=False,
1154
ignore_fallbacks=False):
1155
"""See BzrDir.open_branch."""
1156
from bzrlib.branch import BzrBranchFormat4
1157
format = BzrBranchFormat4()
1158
self._check_supported(format, unsupported)
1159
return format.open(self, name, _found=True)
1161
def sprout(self, url, revision_id=None, force_new_repo=False,
1162
possible_transports=None, accelerator_tree=None,
1163
hardlink=False, stacked=False, create_tree_if_local=True,
1164
source_branch=None):
1165
"""See BzrDir.sprout()."""
1166
if source_branch is not None:
1167
my_branch = self.open_branch()
1168
if source_branch.base != my_branch.base:
1169
raise AssertionError(
1170
"source branch %r is not within %r with branch %r" %
1171
(source_branch, self, my_branch))
1173
raise errors.UnstackableBranchFormat(
1174
self._format, self.root_transport.base)
1175
if not create_tree_if_local:
1176
raise errors.MustHaveWorkingTree(
1177
self._format, self.root_transport.base)
1178
from bzrlib.workingtree import WorkingTreeFormat2
1179
self._make_tail(url)
1180
result = self._format._initialize_for_clone(url)
1182
self.open_repository().clone(result, revision_id=revision_id)
1183
except errors.NoRepositoryPresent:
1186
self.open_branch().sprout(result, revision_id=revision_id)
1187
except errors.NotBranchError:
1190
# we always want a working tree
1191
WorkingTreeFormat2().initialize(result,
1192
accelerator_tree=accelerator_tree,
1197
class BzrDir4(BzrDirPreSplitOut):
1198
"""A .bzr version 4 control object.
1200
This is a deprecated format and may be removed after sept 2006.
1203
def create_repository(self, shared=False):
1204
"""See BzrDir.create_repository."""
1205
return self._format.repository_format.initialize(self, shared)
1207
def needs_format_conversion(self, format=None):
1208
"""Format 4 dirs are always in need of conversion."""
1210
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1211
% 'needs_format_conversion(format=None)')
1214
def open_repository(self):
1215
"""See BzrDir.open_repository."""
1216
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1217
return RepositoryFormat4().open(self, _found=True)
1220
class BzrDir5(BzrDirPreSplitOut):
1221
"""A .bzr version 5 control object.
1223
This is a deprecated format and may be removed after sept 2006.
1226
def has_workingtree(self):
1227
"""See BzrDir.has_workingtree."""
1230
def open_repository(self):
1231
"""See BzrDir.open_repository."""
1232
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1233
return RepositoryFormat5().open(self, _found=True)
1235
def open_workingtree(self, _unsupported=False,
1236
recommend_upgrade=True):
1237
"""See BzrDir.create_workingtree."""
1238
from bzrlib.workingtree import WorkingTreeFormat2
1239
wt_format = WorkingTreeFormat2()
1240
# we don't warn here about upgrades; that ought to be handled for the
1242
return wt_format.open(self, _found=True)
1245
class BzrDir6(BzrDirPreSplitOut):
1246
"""A .bzr version 6 control object.
1248
This is a deprecated format and may be removed after sept 2006.
1251
def has_workingtree(self):
1252
"""See BzrDir.has_workingtree."""
1255
def open_repository(self):
1256
"""See BzrDir.open_repository."""
1257
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1258
return RepositoryFormat6().open(self, _found=True)
1260
def open_workingtree(self, _unsupported=False,
1261
recommend_upgrade=True):
1262
"""See BzrDir.create_workingtree."""
1263
# we don't warn here about upgrades; that ought to be handled for the
1265
from bzrlib.workingtree import WorkingTreeFormat2
1266
return WorkingTreeFormat2().open(self, _found=True)
1133
1269
class BzrDirMeta1(BzrDir):
1134
1270
"""A .bzr meta version 1 control object.
1738
def unregister_format(klass, format):
1739
BzrProber.unregister_bzrdir_format(format)
1740
controldir.ControlDirFormat.unregister_format(format)
1741
controldir.network_format_registry.remove(format.get_format_string())
1744
class BzrDirFormat4(BzrDirFormat):
1745
"""Bzr dir format 4.
1747
This format is a combined format for working tree, branch and repository.
1749
- Format 1 working trees [always]
1750
- Format 4 branches [always]
1751
- Format 4 repositories [always]
1753
This format is deprecated: it indexes texts using a text it which is
1754
removed in format 5; write support for this format has been removed.
1757
_lock_class = lockable_files.TransportLock
1759
def get_format_string(self):
1760
"""See BzrDirFormat.get_format_string()."""
1761
return "Bazaar-NG branch, format 0.0.4\n"
1763
def get_format_description(self):
1764
"""See BzrDirFormat.get_format_description()."""
1765
return "All-in-one format 4"
1767
def get_converter(self, format=None):
1768
"""See BzrDirFormat.get_converter()."""
1769
# there is one and only one upgrade path here.
1770
return ConvertBzrDir4To5()
1772
def initialize_on_transport(self, transport):
1773
"""Format 4 branches cannot be created."""
1774
raise errors.UninitializableFormat(self)
1776
def is_supported(self):
1777
"""Format 4 is not supported.
1779
It is not supported because the model changed from 4 to 5 and the
1780
conversion logic is expensive - so doing it on the fly was not
1785
def network_name(self):
1786
return self.get_format_string()
1788
def _open(self, transport):
1789
"""See BzrDirFormat._open."""
1790
return BzrDir4(transport, self)
1792
def __return_repository_format(self):
1793
"""Circular import protection."""
1794
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1795
return RepositoryFormat4()
1796
repository_format = property(__return_repository_format)
1799
class BzrDirFormatAllInOne(BzrDirFormat):
1800
"""Common class for formats before meta-dirs."""
1802
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1803
create_prefix=False, force_new_repo=False, stacked_on=None,
1804
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1806
"""See BzrDirFormat.initialize_on_transport_ex."""
1807
require_stacking = (stacked_on is not None)
1808
# Format 5 cannot stack, but we've been asked to - actually init
1810
if require_stacking:
1811
format = BzrDirMetaFormat1()
1812
return format.initialize_on_transport_ex(transport,
1813
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1814
force_new_repo=force_new_repo, stacked_on=stacked_on,
1815
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1816
make_working_trees=make_working_trees, shared_repo=shared_repo)
1817
return BzrDirFormat.initialize_on_transport_ex(self, transport,
1818
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1819
force_new_repo=force_new_repo, stacked_on=stacked_on,
1820
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1821
make_working_trees=make_working_trees, shared_repo=shared_repo)
1824
class BzrDirFormat5(BzrDirFormatAllInOne):
1825
"""Bzr control format 5.
1827
This format is a combined format for working tree, branch and repository.
1829
- Format 2 working trees [always]
1830
- Format 4 branches [always]
1831
- Format 5 repositories [always]
1832
Unhashed stores in the repository.
1835
_lock_class = lockable_files.TransportLock
1837
def get_format_string(self):
1838
"""See BzrDirFormat.get_format_string()."""
1839
return "Bazaar-NG branch, format 5\n"
1841
def get_branch_format(self):
1842
from bzrlib import branch
1843
return branch.BzrBranchFormat4()
1845
def get_format_description(self):
1846
"""See BzrDirFormat.get_format_description()."""
1847
return "All-in-one format 5"
1849
def get_converter(self, format=None):
1850
"""See BzrDirFormat.get_converter()."""
1851
# there is one and only one upgrade path here.
1852
return ConvertBzrDir5To6()
1854
def _initialize_for_clone(self, url):
1855
return self.initialize_on_transport(get_transport(url), _cloning=True)
1857
def initialize_on_transport(self, transport, _cloning=False):
1858
"""Format 5 dirs always have working tree, branch and repository.
1860
Except when they are being cloned.
1862
from bzrlib.branch import BzrBranchFormat4
1863
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1864
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1865
RepositoryFormat5().initialize(result, _internal=True)
1867
branch = BzrBranchFormat4().initialize(result)
1868
result._init_workingtree()
1871
def network_name(self):
1872
return self.get_format_string()
1874
def _open(self, transport):
1875
"""See BzrDirFormat._open."""
1876
return BzrDir5(transport, self)
1878
def __return_repository_format(self):
1879
"""Circular import protection."""
1880
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1881
return RepositoryFormat5()
1882
repository_format = property(__return_repository_format)
1885
class BzrDirFormat6(BzrDirFormatAllInOne):
1886
"""Bzr control format 6.
1888
This format is a combined format for working tree, branch and repository.
1890
- Format 2 working trees [always]
1891
- Format 4 branches [always]
1892
- Format 6 repositories [always]
1895
_lock_class = lockable_files.TransportLock
1897
def get_format_string(self):
1898
"""See BzrDirFormat.get_format_string()."""
1899
return "Bazaar-NG branch, format 6\n"
1901
def get_format_description(self):
1902
"""See BzrDirFormat.get_format_description()."""
1903
return "All-in-one format 6"
1905
def get_branch_format(self):
1906
from bzrlib import branch
1907
return branch.BzrBranchFormat4()
1909
def get_converter(self, format=None):
1910
"""See BzrDirFormat.get_converter()."""
1911
# there is one and only one upgrade path here.
1912
return ConvertBzrDir6ToMeta()
1914
def _initialize_for_clone(self, url):
1915
return self.initialize_on_transport(get_transport(url), _cloning=True)
1917
def initialize_on_transport(self, transport, _cloning=False):
1918
"""Format 6 dirs always have working tree, branch and repository.
1920
Except when they are being cloned.
1922
from bzrlib.branch import BzrBranchFormat4
1923
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1924
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1925
RepositoryFormat6().initialize(result, _internal=True)
1927
branch = BzrBranchFormat4().initialize(result)
1928
result._init_workingtree()
1931
def network_name(self):
1932
return self.get_format_string()
1934
def _open(self, transport):
1935
"""See BzrDirFormat._open."""
1936
return BzrDir6(transport, self)
1938
def __return_repository_format(self):
1939
"""Circular import protection."""
1940
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1941
return RepositoryFormat6()
1942
repository_format = property(__return_repository_format)
1613
1945
class BzrDirMetaFormat1(BzrDirFormat):
1614
1946
"""Bzr meta control format 1
1824
2150
# Register bzr formats
1825
BzrProber.formats.register(BzrDirMetaFormat1.get_format_string(),
1827
controldir.ControlDirFormat._default_format = BzrDirMetaFormat1()
1830
class ConvertMetaToMeta(controldir.Converter):
2151
BzrDirFormat.register_format(BzrDirFormat4())
2152
BzrDirFormat.register_format(BzrDirFormat5())
2153
BzrDirFormat.register_format(BzrDirFormat6())
2154
__default_format = BzrDirMetaFormat1()
2155
BzrDirFormat.register_format(__default_format)
2156
controldir.ControlDirFormat._default_format = __default_format
2159
class Converter(object):
2160
"""Converts a disk format object from one format to another."""
2162
def convert(self, to_convert, pb):
2163
"""Perform the conversion of to_convert, giving feedback via pb.
2165
:param to_convert: The disk object to convert.
2166
:param pb: a progress bar to use for progress information.
2169
def step(self, message):
2170
"""Update the pb by a step."""
2172
self.pb.update(message, self.count, self.total)
2175
class ConvertBzrDir4To5(Converter):
2176
"""Converts format 4 bzr dirs to format 5."""
2179
super(ConvertBzrDir4To5, self).__init__()
2180
self.converted_revs = set()
2181
self.absent_revisions = set()
2185
def convert(self, to_convert, pb):
2186
"""See Converter.convert()."""
2187
self.bzrdir = to_convert
2189
warnings.warn("pb parameter to convert() is deprecated")
2190
self.pb = ui.ui_factory.nested_progress_bar()
2192
ui.ui_factory.note('starting upgrade from format 4 to 5')
2193
if isinstance(self.bzrdir.transport, local.LocalTransport):
2194
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2195
self._convert_to_weaves()
2196
return BzrDir.open(self.bzrdir.user_url)
2200
def _convert_to_weaves(self):
2201
ui.ui_factory.note('note: upgrade may be faster if all store files are ungzipped first')
2204
stat = self.bzrdir.transport.stat('weaves')
2205
if not S_ISDIR(stat.st_mode):
2206
self.bzrdir.transport.delete('weaves')
2207
self.bzrdir.transport.mkdir('weaves')
2208
except errors.NoSuchFile:
2209
self.bzrdir.transport.mkdir('weaves')
2210
# deliberately not a WeaveFile as we want to build it up slowly.
2211
self.inv_weave = Weave('inventory')
2212
# holds in-memory weaves for all files
2213
self.text_weaves = {}
2214
self.bzrdir.transport.delete('branch-format')
2215
self.branch = self.bzrdir.open_branch()
2216
self._convert_working_inv()
2217
rev_history = self.branch.revision_history()
2218
# to_read is a stack holding the revisions we still need to process;
2219
# appending to it adds new highest-priority revisions
2220
self.known_revisions = set(rev_history)
2221
self.to_read = rev_history[-1:]
2223
rev_id = self.to_read.pop()
2224
if (rev_id not in self.revisions
2225
and rev_id not in self.absent_revisions):
2226
self._load_one_rev(rev_id)
2228
to_import = self._make_order()
2229
for i, rev_id in enumerate(to_import):
2230
self.pb.update('converting revision', i, len(to_import))
2231
self._convert_one_rev(rev_id)
2233
self._write_all_weaves()
2234
self._write_all_revs()
2235
ui.ui_factory.note('upgraded to weaves:')
2236
ui.ui_factory.note(' %6d revisions and inventories' % len(self.revisions))
2237
ui.ui_factory.note(' %6d revisions not present' % len(self.absent_revisions))
2238
ui.ui_factory.note(' %6d texts' % self.text_count)
2239
self._cleanup_spare_files_after_format4()
2240
self.branch._transport.put_bytes(
2242
BzrDirFormat5().get_format_string(),
2243
mode=self.bzrdir._get_file_mode())
2245
def _cleanup_spare_files_after_format4(self):
2246
# FIXME working tree upgrade foo.
2247
for n in 'merged-patches', 'pending-merged-patches':
2249
## assert os.path.getsize(p) == 0
2250
self.bzrdir.transport.delete(n)
2251
except errors.NoSuchFile:
2253
self.bzrdir.transport.delete_tree('inventory-store')
2254
self.bzrdir.transport.delete_tree('text-store')
2256
def _convert_working_inv(self):
2257
inv = xml4.serializer_v4.read_inventory(
2258
self.branch._transport.get('inventory'))
2259
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2260
self.branch._transport.put_bytes('inventory', new_inv_xml,
2261
mode=self.bzrdir._get_file_mode())
2263
def _write_all_weaves(self):
2264
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2265
weave_transport = self.bzrdir.transport.clone('weaves')
2266
weaves = WeaveStore(weave_transport, prefixed=False)
2267
transaction = WriteTransaction()
2271
for file_id, file_weave in self.text_weaves.items():
2272
self.pb.update('writing weave', i, len(self.text_weaves))
2273
weaves._put_weave(file_id, file_weave, transaction)
2275
self.pb.update('inventory', 0, 1)
2276
controlweaves._put_weave('inventory', self.inv_weave, transaction)
2277
self.pb.update('inventory', 1, 1)
2281
def _write_all_revs(self):
2282
"""Write all revisions out in new form."""
2283
self.bzrdir.transport.delete_tree('revision-store')
2284
self.bzrdir.transport.mkdir('revision-store')
2285
revision_transport = self.bzrdir.transport.clone('revision-store')
2287
from bzrlib.xml5 import serializer_v5
2288
from bzrlib.repofmt.weaverepo import RevisionTextStore
2289
revision_store = RevisionTextStore(revision_transport,
2290
serializer_v5, False, versionedfile.PrefixMapper(),
2291
lambda:True, lambda:True)
2293
for i, rev_id in enumerate(self.converted_revs):
2294
self.pb.update('write revision', i, len(self.converted_revs))
2295
text = serializer_v5.write_revision_to_string(
2296
self.revisions[rev_id])
2298
revision_store.add_lines(key, None, osutils.split_lines(text))
2302
def _load_one_rev(self, rev_id):
2303
"""Load a revision object into memory.
2305
Any parents not either loaded or abandoned get queued to be
2307
self.pb.update('loading revision',
2308
len(self.revisions),
2309
len(self.known_revisions))
2310
if not self.branch.repository.has_revision(rev_id):
2312
ui.ui_factory.note('revision {%s} not present in branch; '
2313
'will be converted as a ghost' %
2315
self.absent_revisions.add(rev_id)
2317
rev = self.branch.repository.get_revision(rev_id)
2318
for parent_id in rev.parent_ids:
2319
self.known_revisions.add(parent_id)
2320
self.to_read.append(parent_id)
2321
self.revisions[rev_id] = rev
2323
def _load_old_inventory(self, rev_id):
2324
f = self.branch.repository.inventory_store.get(rev_id)
2326
old_inv_xml = f.read()
2329
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2330
inv.revision_id = rev_id
2331
rev = self.revisions[rev_id]
2334
def _load_updated_inventory(self, rev_id):
2335
inv_xml = self.inv_weave.get_text(rev_id)
2336
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2339
def _convert_one_rev(self, rev_id):
2340
"""Convert revision and all referenced objects to new format."""
2341
rev = self.revisions[rev_id]
2342
inv = self._load_old_inventory(rev_id)
2343
present_parents = [p for p in rev.parent_ids
2344
if p not in self.absent_revisions]
2345
self._convert_revision_contents(rev, inv, present_parents)
2346
self._store_new_inv(rev, inv, present_parents)
2347
self.converted_revs.add(rev_id)
2349
def _store_new_inv(self, rev, inv, present_parents):
2350
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2351
new_inv_sha1 = sha_string(new_inv_xml)
2352
self.inv_weave.add_lines(rev.revision_id,
2354
new_inv_xml.splitlines(True))
2355
rev.inventory_sha1 = new_inv_sha1
2357
def _convert_revision_contents(self, rev, inv, present_parents):
2358
"""Convert all the files within a revision.
2360
Also upgrade the inventory to refer to the text revision ids."""
2361
rev_id = rev.revision_id
2362
mutter('converting texts of revision {%s}',
2364
parent_invs = map(self._load_updated_inventory, present_parents)
2365
entries = inv.iter_entries()
2367
for path, ie in entries:
2368
self._convert_file_version(rev, ie, parent_invs)
2370
def _convert_file_version(self, rev, ie, parent_invs):
2371
"""Convert one version of one file.
2373
The file needs to be added into the weave if it is a merge
2374
of >=2 parents or if it's changed from its parent.
2376
file_id = ie.file_id
2377
rev_id = rev.revision_id
2378
w = self.text_weaves.get(file_id)
2381
self.text_weaves[file_id] = w
2382
text_changed = False
2383
parent_candiate_entries = ie.parent_candidates(parent_invs)
2384
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2385
# XXX: Note that this is unordered - and this is tolerable because
2386
# the previous code was also unordered.
2387
previous_entries = dict((head, parent_candiate_entries[head]) for head
2389
self.snapshot_ie(previous_entries, ie, w, rev_id)
2391
def get_parent_map(self, revision_ids):
2392
"""See graph.StackedParentsProvider.get_parent_map"""
2393
return dict((revision_id, self.revisions[revision_id])
2394
for revision_id in revision_ids
2395
if revision_id in self.revisions)
2397
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2398
# TODO: convert this logic, which is ~= snapshot to
2399
# a call to:. This needs the path figured out. rather than a work_tree
2400
# a v4 revision_tree can be given, or something that looks enough like
2401
# one to give the file content to the entry if it needs it.
2402
# and we need something that looks like a weave store for snapshot to
2404
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2405
if len(previous_revisions) == 1:
2406
previous_ie = previous_revisions.values()[0]
2407
if ie._unchanged(previous_ie):
2408
ie.revision = previous_ie.revision
2411
f = self.branch.repository._text_store.get(ie.text_id)
2413
file_lines = f.readlines()
2416
w.add_lines(rev_id, previous_revisions, file_lines)
2417
self.text_count += 1
2419
w.add_lines(rev_id, previous_revisions, [])
2420
ie.revision = rev_id
2422
def _make_order(self):
2423
"""Return a suitable order for importing revisions.
2425
The order must be such that an revision is imported after all
2426
its (present) parents.
2428
todo = set(self.revisions.keys())
2429
done = self.absent_revisions.copy()
2432
# scan through looking for a revision whose parents
2434
for rev_id in sorted(list(todo)):
2435
rev = self.revisions[rev_id]
2436
parent_ids = set(rev.parent_ids)
2437
if parent_ids.issubset(done):
2438
# can take this one now
2439
order.append(rev_id)
2445
class ConvertBzrDir5To6(Converter):
2446
"""Converts format 5 bzr dirs to format 6."""
2448
def convert(self, to_convert, pb):
2449
"""See Converter.convert()."""
2450
self.bzrdir = to_convert
2451
pb = ui.ui_factory.nested_progress_bar()
2453
ui.ui_factory.note('starting upgrade from format 5 to 6')
2454
self._convert_to_prefixed()
2455
return BzrDir.open(self.bzrdir.user_url)
2459
def _convert_to_prefixed(self):
2460
from bzrlib.store import TransportStore
2461
self.bzrdir.transport.delete('branch-format')
2462
for store_name in ["weaves", "revision-store"]:
2463
ui.ui_factory.note("adding prefixes to %s" % store_name)
2464
store_transport = self.bzrdir.transport.clone(store_name)
2465
store = TransportStore(store_transport, prefixed=True)
2466
for urlfilename in store_transport.list_dir('.'):
2467
filename = urlutils.unescape(urlfilename)
2468
if (filename.endswith(".weave") or
2469
filename.endswith(".gz") or
2470
filename.endswith(".sig")):
2471
file_id, suffix = os.path.splitext(filename)
2475
new_name = store._mapper.map((file_id,)) + suffix
2476
# FIXME keep track of the dirs made RBC 20060121
2478
store_transport.move(filename, new_name)
2479
except errors.NoSuchFile: # catches missing dirs strangely enough
2480
store_transport.mkdir(osutils.dirname(new_name))
2481
store_transport.move(filename, new_name)
2482
self.bzrdir.transport.put_bytes(
2484
BzrDirFormat6().get_format_string(),
2485
mode=self.bzrdir._get_file_mode())
2488
class ConvertBzrDir6ToMeta(Converter):
2489
"""Converts format 6 bzr dirs to metadirs."""
2491
def convert(self, to_convert, pb):
2492
"""See Converter.convert()."""
2493
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2494
from bzrlib.branch import BzrBranchFormat5
2495
self.bzrdir = to_convert
2496
self.pb = ui.ui_factory.nested_progress_bar()
2498
self.total = 20 # the steps we know about
2499
self.garbage_inventories = []
2500
self.dir_mode = self.bzrdir._get_dir_mode()
2501
self.file_mode = self.bzrdir._get_file_mode()
2503
ui.ui_factory.note('starting upgrade from format 6 to metadir')
2504
self.bzrdir.transport.put_bytes(
2506
"Converting to format 6",
2507
mode=self.file_mode)
2508
# its faster to move specific files around than to open and use the apis...
2509
# first off, nuke ancestry.weave, it was never used.
2511
self.step('Removing ancestry.weave')
2512
self.bzrdir.transport.delete('ancestry.weave')
2513
except errors.NoSuchFile:
2515
# find out whats there
2516
self.step('Finding branch files')
2517
last_revision = self.bzrdir.open_branch().last_revision()
2518
bzrcontents = self.bzrdir.transport.list_dir('.')
2519
for name in bzrcontents:
2520
if name.startswith('basis-inventory.'):
2521
self.garbage_inventories.append(name)
2522
# create new directories for repository, working tree and branch
2523
repository_names = [('inventory.weave', True),
2524
('revision-store', True),
2526
self.step('Upgrading repository ')
2527
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2528
self.make_lock('repository')
2529
# we hard code the formats here because we are converting into
2530
# the meta format. The meta format upgrader can take this to a
2531
# future format within each component.
2532
self.put_format('repository', RepositoryFormat7())
2533
for entry in repository_names:
2534
self.move_entry('repository', entry)
2536
self.step('Upgrading branch ')
2537
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2538
self.make_lock('branch')
2539
self.put_format('branch', BzrBranchFormat5())
2540
branch_files = [('revision-history', True),
2541
('branch-name', True),
2543
for entry in branch_files:
2544
self.move_entry('branch', entry)
2546
checkout_files = [('pending-merges', True),
2547
('inventory', True),
2548
('stat-cache', False)]
2549
# If a mandatory checkout file is not present, the branch does not have
2550
# a functional checkout. Do not create a checkout in the converted
2552
for name, mandatory in checkout_files:
2553
if mandatory and name not in bzrcontents:
2554
has_checkout = False
2558
if not has_checkout:
2559
ui.ui_factory.note('No working tree.')
2560
# If some checkout files are there, we may as well get rid of them.
2561
for name, mandatory in checkout_files:
2562
if name in bzrcontents:
2563
self.bzrdir.transport.delete(name)
2565
from bzrlib.workingtree import WorkingTreeFormat3
2566
self.step('Upgrading working tree')
2567
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2568
self.make_lock('checkout')
2570
'checkout', WorkingTreeFormat3())
2571
self.bzrdir.transport.delete_multi(
2572
self.garbage_inventories, self.pb)
2573
for entry in checkout_files:
2574
self.move_entry('checkout', entry)
2575
if last_revision is not None:
2576
self.bzrdir.transport.put_bytes(
2577
'checkout/last-revision', last_revision)
2578
self.bzrdir.transport.put_bytes(
2580
BzrDirMetaFormat1().get_format_string(),
2581
mode=self.file_mode)
2583
return BzrDir.open(self.bzrdir.user_url)
2585
def make_lock(self, name):
2586
"""Make a lock for the new control dir name."""
2587
self.step('Make %s lock' % name)
2588
ld = lockdir.LockDir(self.bzrdir.transport,
2590
file_modebits=self.file_mode,
2591
dir_modebits=self.dir_mode)
2594
def move_entry(self, new_dir, entry):
2595
"""Move then entry name into new_dir."""
2597
mandatory = entry[1]
2598
self.step('Moving %s' % name)
2600
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2601
except errors.NoSuchFile:
2605
def put_format(self, dirname, format):
2606
self.bzrdir.transport.put_bytes('%s/format' % dirname,
2607
format.get_format_string(),
2611
class ConvertMetaToMeta(Converter):
1831
2612
"""Converts the components of metadirs."""
1833
2614
def __init__(self, target_format):
1905
2687
return to_convert
2690
# This is not in remote.py because it's relatively small, and needs to be
2691
# registered. Putting it in remote.py creates a circular import problem.
2692
# we can make it a lazy object if the control formats is turned into something
2694
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2695
"""Format representing bzrdirs accessed via a smart server"""
2698
BzrDirMetaFormat1.__init__(self)
2699
# XXX: It's a bit ugly that the network name is here, because we'd
2700
# like to believe that format objects are stateless or at least
2701
# immutable, However, we do at least avoid mutating the name after
2702
# it's returned. See <https://bugs.launchpad.net/bzr/+bug/504102>
2703
self._network_name = None
2706
return "%s(_network_name=%r)" % (self.__class__.__name__,
2709
def get_format_description(self):
2710
if self._network_name:
2711
real_format = controldir.network_format_registry.get(self._network_name)
2712
return 'Remote: ' + real_format.get_format_description()
2713
return 'bzr remote bzrdir'
2715
def get_format_string(self):
2716
raise NotImplementedError(self.get_format_string)
2718
def network_name(self):
2719
if self._network_name:
2720
return self._network_name
2722
raise AssertionError("No network name set.")
2724
def initialize_on_transport(self, transport):
2726
# hand off the request to the smart server
2727
client_medium = transport.get_smart_medium()
2728
except errors.NoSmartMedium:
2729
# TODO: lookup the local format from a server hint.
2730
local_dir_format = BzrDirMetaFormat1()
2731
return local_dir_format.initialize_on_transport(transport)
2732
client = _SmartClient(client_medium)
2733
path = client.remote_path_from_transport(transport)
2735
response = client.call('BzrDirFormat.initialize', path)
2736
except errors.ErrorFromSmartServer, err:
2737
remote._translate_error(err, path=path)
2738
if response[0] != 'ok':
2739
raise errors.SmartProtocolError('unexpected response code %s' % (response,))
2740
format = RemoteBzrDirFormat()
2741
self._supply_sub_formats_to(format)
2742
return remote.RemoteBzrDir(transport, format)
2744
def parse_NoneTrueFalse(self, arg):
2751
raise AssertionError("invalid arg %r" % arg)
2753
def _serialize_NoneTrueFalse(self, arg):
2760
def _serialize_NoneString(self, arg):
2763
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
2764
create_prefix=False, force_new_repo=False, stacked_on=None,
2765
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
2768
# hand off the request to the smart server
2769
client_medium = transport.get_smart_medium()
2770
except errors.NoSmartMedium:
2773
# Decline to open it if the server doesn't support our required
2774
# version (3) so that the VFS-based transport will do it.
2775
if client_medium.should_probe():
2777
server_version = client_medium.protocol_version()
2778
if server_version != '2':
2782
except errors.SmartProtocolError:
2783
# Apparently there's no usable smart server there, even though
2784
# the medium supports the smart protocol.
2789
client = _SmartClient(client_medium)
2790
path = client.remote_path_from_transport(transport)
2791
if client_medium._is_remote_before((1, 16)):
2794
# TODO: lookup the local format from a server hint.
2795
local_dir_format = BzrDirMetaFormat1()
2796
self._supply_sub_formats_to(local_dir_format)
2797
return local_dir_format.initialize_on_transport_ex(transport,
2798
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
2799
force_new_repo=force_new_repo, stacked_on=stacked_on,
2800
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
2801
make_working_trees=make_working_trees, shared_repo=shared_repo,
2803
return self._initialize_on_transport_ex_rpc(client, path, transport,
2804
use_existing_dir, create_prefix, force_new_repo, stacked_on,
2805
stack_on_pwd, repo_format_name, make_working_trees, shared_repo)
2807
def _initialize_on_transport_ex_rpc(self, client, path, transport,
2808
use_existing_dir, create_prefix, force_new_repo, stacked_on,
2809
stack_on_pwd, repo_format_name, make_working_trees, shared_repo):
2811
args.append(self._serialize_NoneTrueFalse(use_existing_dir))
2812
args.append(self._serialize_NoneTrueFalse(create_prefix))
2813
args.append(self._serialize_NoneTrueFalse(force_new_repo))
2814
args.append(self._serialize_NoneString(stacked_on))
2815
# stack_on_pwd is often/usually our transport
2818
stack_on_pwd = transport.relpath(stack_on_pwd)
2819
if not stack_on_pwd:
2821
except errors.PathNotChild:
2823
args.append(self._serialize_NoneString(stack_on_pwd))
2824
args.append(self._serialize_NoneString(repo_format_name))
2825
args.append(self._serialize_NoneTrueFalse(make_working_trees))
2826
args.append(self._serialize_NoneTrueFalse(shared_repo))
2827
request_network_name = self._network_name or \
2828
BzrDirFormat.get_default_format().network_name()
2830
response = client.call('BzrDirFormat.initialize_ex_1.16',
2831
request_network_name, path, *args)
2832
except errors.UnknownSmartMethod:
2833
client._medium._remember_remote_is_before((1,16))
2834
local_dir_format = BzrDirMetaFormat1()
2835
self._supply_sub_formats_to(local_dir_format)
2836
return local_dir_format.initialize_on_transport_ex(transport,
2837
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
2838
force_new_repo=force_new_repo, stacked_on=stacked_on,
2839
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
2840
make_working_trees=make_working_trees, shared_repo=shared_repo,
2842
except errors.ErrorFromSmartServer, err:
2843
remote._translate_error(err, path=path)
2844
repo_path = response[0]
2845
bzrdir_name = response[6]
2846
require_stacking = response[7]
2847
require_stacking = self.parse_NoneTrueFalse(require_stacking)
2848
format = RemoteBzrDirFormat()
2849
format._network_name = bzrdir_name
2850
self._supply_sub_formats_to(format)
2851
bzrdir = remote.RemoteBzrDir(transport, format, _client=client)
2853
repo_format = remote.response_tuple_to_repo_format(response[1:])
2854
if repo_path == '.':
2857
repo_bzrdir_format = RemoteBzrDirFormat()
2858
repo_bzrdir_format._network_name = response[5]
2859
repo_bzr = remote.RemoteBzrDir(transport.clone(repo_path),
2863
final_stack = response[8] or None
2864
final_stack_pwd = response[9] or None
2866
final_stack_pwd = urlutils.join(
2867
transport.base, final_stack_pwd)
2868
remote_repo = remote.RemoteRepository(repo_bzr, repo_format)
2869
if len(response) > 10:
2870
# Updated server verb that locks remotely.
2871
repo_lock_token = response[10] or None
2872
remote_repo.lock_write(repo_lock_token, _skip_rpc=True)
2874
remote_repo.dont_leave_lock_in_place()
2876
remote_repo.lock_write()
2877
policy = UseExistingRepository(remote_repo, final_stack,
2878
final_stack_pwd, require_stacking)
2879
policy.acquire_repository()
2883
bzrdir._format.set_branch_format(self.get_branch_format())
2884
if require_stacking:
2885
# The repo has already been created, but we need to make sure that
2886
# we'll make a stackable branch.
2887
bzrdir._format.require_stacking(_skip_repo=True)
2888
return remote_repo, bzrdir, require_stacking, policy
2890
def _open(self, transport):
2891
return remote.RemoteBzrDir(transport, self)
2893
def __eq__(self, other):
2894
if not isinstance(other, RemoteBzrDirFormat):
2896
return self.get_format_description() == other.get_format_description()
2898
def __return_repository_format(self):
2899
# Always return a RemoteRepositoryFormat object, but if a specific bzr
2900
# repository format has been asked for, tell the RemoteRepositoryFormat
2901
# that it should use that for init() etc.
2902
result = remote.RemoteRepositoryFormat()
2903
custom_format = getattr(self, '_repository_format', None)
2905
if isinstance(custom_format, remote.RemoteRepositoryFormat):
2906
return custom_format
2908
# We will use the custom format to create repositories over the
2909
# wire; expose its details like rich_root_data for code to
2911
result._custom_format = custom_format
2914
def get_branch_format(self):
2915
result = BzrDirMetaFormat1.get_branch_format(self)
2916
if not isinstance(result, remote.RemoteBranchFormat):
2917
new_result = remote.RemoteBranchFormat()
2918
new_result._custom_format = result
2920
self.set_branch_format(new_result)
2924
repository_format = property(__return_repository_format,
2925
BzrDirMetaFormat1._set_repository_format) #.im_func)
1908
2928
controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)