14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
17
19
from bzrlib.lazy_import import lazy_import
18
20
lazy_import(globals(), """
22
24
from bzrlib import (
73
76
record_root_entry = True
74
77
# whether this commit builder supports the record_entry_contents interface
75
78
supports_record_entry_contents = False
79
# whether this commit builder will automatically update the branch that is
81
updates_branch = False
77
def __init__(self, repository, parents, config, timestamp=None,
83
def __init__(self, repository, parents, config_stack, timestamp=None,
78
84
timezone=None, committer=None, revprops=None,
79
85
revision_id=None, lossy=False):
80
86
"""Initiate a CommitBuilder.
89
95
:param lossy: Whether to discard data that can not be natively
90
96
represented, when pushing to a foreign VCS
98
self._config_stack = config_stack
93
99
self._lossy = lossy
95
101
if committer is None:
96
self._committer = self._config.username()
102
self._committer = self._config_stack.get('email')
97
103
elif not isinstance(committer, unicode):
98
104
self._committer = committer.decode() # throw if non-ascii
281
287
mutter('abort_write_group failed')
282
288
log_exception_quietly()
283
note('bzr: ERROR (ignored): %s', exc)
289
note(gettext('bzr: ERROR (ignored): %s'), exc)
284
290
self._write_group = None
286
292
def _abort_write_group(self):
341
347
self.control_files.break_lock()
344
def create(a_bzrdir):
345
"""Construct the current default format repository in a_bzrdir."""
346
return RepositoryFormat.get_default_format().initialize(a_bzrdir)
350
def create(controldir):
351
"""Construct the current default format repository in controldir."""
352
return RepositoryFormat.get_default_format().initialize(controldir)
348
def __init__(self, _format, a_bzrdir, control_files):
354
def __init__(self, _format, controldir, control_files):
349
355
"""instantiate a Repository.
351
357
:param _format: The format of the repository on disk.
352
:param a_bzrdir: The BzrDir of the repository.
358
:param controldir: The ControlDir of the repository.
353
359
:param control_files: Control files to use for locking, etc.
355
361
# In the future we will have a single api for all stores for
358
364
super(Repository, self).__init__()
359
365
self._format = _format
360
366
# the following are part of the public API for Repository:
361
self.bzrdir = a_bzrdir
367
self.bzrdir = controldir
362
368
self.control_files = control_files
363
self._transport = control_files._transport
364
self.base = self._transport.base
366
370
self._write_group = None
367
371
# Additional places to query for data.
406
410
if self.__class__ is not other.__class__:
408
return (self._transport.base == other._transport.base)
412
return (self.control_url == other.control_url)
410
414
def is_in_write_group(self):
411
415
"""Return True if there is an open write group.
548
552
def __init__(self):
549
553
self.first_call = True
551
def __call__(self, bzrdir):
552
# On the first call, the parameter is always the bzrdir
555
def __call__(self, controldir):
556
# On the first call, the parameter is always the controldir
553
557
# containing the current repo.
554
558
if not self.first_call:
556
repository = bzrdir.open_repository()
560
repository = controldir.open_repository()
557
561
except errors.NoRepositoryPresent:
560
564
return False, ([], repository)
561
565
self.first_call = False
562
value = (bzrdir.list_branches(), None)
566
value = (controldir.list_branches(), None)
563
567
return True, value
566
for branches, repository in bzrdir.BzrDir.find_bzrdirs(
570
for branches, repository in controldir.ControlDir.find_bzrdirs(
567
571
self.user_transport, evaluate=Evaluator()):
568
572
if branches is not None:
569
573
ret.extend(branches)
603
607
For instance, if the repository is at URL/.bzr/repository,
604
608
Repository.open(URL) -> a Repository instance.
606
control = bzrdir.BzrDir.open(base)
610
control = controldir.ControlDir.open(base)
607
611
return control.open_repository()
609
613
def copy_content_into(self, destination, revision_id=None):
667
677
def _resume_write_group(self, tokens):
668
678
raise errors.UnsuspendableWriteGroup(self)
670
def fetch(self, source, revision_id=None, find_ghosts=False,
680
def fetch(self, source, revision_id=None, find_ghosts=False):
672
681
"""Fetch the content required to construct revision_id from source.
674
If revision_id is None and fetch_spec is None, then all content is
683
If revision_id is None, then all content is copied.
677
685
fetch() may not be used when the repository is in a write group -
678
686
either finish the current write group before using fetch, or use
684
692
:param revision_id: If specified, all the content needed for this
685
693
revision ID will be copied to the target. Fetch will determine for
686
694
itself which content needs to be copied.
687
:param fetch_spec: If specified, a SearchResult or
688
PendingAncestryResult that describes which revisions to copy. This
689
allows copying multiple heads at once. Mutually exclusive with
692
if fetch_spec is not None and revision_id is not None:
693
raise AssertionError(
694
"fetch_spec and revision_id are mutually exclusive.")
695
696
if self.is_in_write_group():
696
697
raise errors.InternalBzrError(
697
698
"May not fetch while in a write group.")
699
700
# TODO: lift out to somewhere common with RemoteRepository
700
701
# <https://bugs.launchpad.net/bzr/+bug/401646>
701
702
if (self.has_same_location(source)
702
and fetch_spec is None
703
703
and self._has_same_fallbacks(source)):
704
704
# check that last_revision is in 'from' and then return a
708
708
self.get_revision(revision_id)
710
710
inter = InterRepository.get(source, self)
711
return inter.fetch(revision_id=revision_id,
712
find_ghosts=find_ghosts, fetch_spec=fetch_spec)
711
return inter.fetch(revision_id=revision_id, find_ghosts=find_ghosts)
714
713
def create_bundle(self, target, base, fileobj, format=None):
715
714
return serializer.write_bundle(self, target, base, fileobj, format)
717
def get_commit_builder(self, branch, parents, config, timestamp=None,
716
def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
718
717
timezone=None, committer=None, revprops=None,
719
718
revision_id=None, lossy=False):
720
719
"""Obtain a CommitBuilder for this repository.
722
721
:param branch: Branch to commit to.
723
722
:param parents: Revision ids of the parents of the new revision.
724
:param config: Configuration to use.
723
:param config_stack: Configuration stack to use.
725
724
:param timestamp: Optional timestamp recorded for commit.
726
725
:param timezone: Optional timezone for timestamp.
727
726
:param committer: Optional committer to set for commit.
750
def clone(self, a_bzrdir, revision_id=None):
751
"""Clone this repository into a_bzrdir using the current format.
749
def clone(self, controldir, revision_id=None):
750
"""Clone this repository into controldir using the current format.
753
752
Currently no check is made that the format of this repository and
754
753
the bzrdir format are compatible. FIXME RBC 20060201.
758
757
# TODO: deprecate after 0.16; cloning this with all its settings is
759
758
# probably not very useful -- mbp 20070423
760
dest_repo = self._create_sprouting_repo(a_bzrdir, shared=self.is_shared())
759
dest_repo = self._create_sprouting_repo(
760
controldir, shared=self.is_shared())
761
761
self.copy_content_into(dest_repo, revision_id)
930
930
parent_ids.discard(_mod_revision.NULL_REVISION)
931
931
return parent_ids
933
def fileids_altered_by_revision_ids(self, revision_ids):
934
"""Find the file ids and versions affected by revisions.
936
:param revisions: an iterable containing revision ids.
937
:return: a dictionary mapping altered file-ids to an iterable of
938
revision_ids. Each altered file-ids has the exact revision_ids
939
that altered it listed explicitly.
941
raise NotImplementedError(self.fileids_altered_by_revision_ids)
943
933
def iter_files_bytes(self, desired_files):
944
934
"""Iterate through file versions.
1159
1149
[parents_provider, other_repository._make_parents_provider()])
1160
1150
return graph.Graph(parents_provider)
1162
def revision_ids_to_search_result(self, result_set):
1163
"""Convert a set of revision ids to a graph SearchResult."""
1164
result_parents = set()
1165
for parents in self.get_graph().get_parent_map(
1166
result_set).itervalues():
1167
result_parents.update(parents)
1168
included_keys = result_set.intersection(result_parents)
1169
start_keys = result_set.difference(included_keys)
1170
exclude_keys = result_parents.difference(result_set)
1171
result = graph.SearchResult(start_keys, exclude_keys,
1172
len(result_set), result_set)
1175
1152
@needs_write_lock
1176
1153
def set_make_working_trees(self, new_value):
1177
1154
"""Set the policy flag for making working trees when creating branches.
1195
1172
self.store_revision_signature(gpg_strategy, plaintext, revision_id)
1197
1174
@needs_read_lock
1198
def verify_revision(self, revision_id, gpg_strategy):
1175
def verify_revision_signature(self, revision_id, gpg_strategy):
1199
1176
"""Verify the signature on a revision.
1201
1178
:param revision_id: the revision to verify
1316
1293
"""Returns the policy for making working trees on new branches."""
1317
1294
return not self._transport.has('no-working-trees')
1297
def update_feature_flags(self, updated_flags):
1298
"""Update the feature flags for this branch.
1300
:param updated_flags: Dictionary mapping feature names to necessities
1301
A necessity can be None to indicate the feature should be removed
1303
self._format._update_feature_flags(updated_flags)
1304
self.control_transport.put_bytes('format', self._format.as_string())
1320
1307
class RepositoryFormatRegistry(controldir.ControlComponentFormatRegistry):
1321
1308
"""Repository format registry."""
1323
1310
def get_default(self):
1324
1311
"""Return the current default format."""
1325
from bzrlib import bzrdir
1326
return bzrdir.format_registry.make_bzrdir('default').repository_format
1312
return controldir.format_registry.make_bzrdir('default').repository_format
1329
1315
network_format_registry = registry.FormatRegistry()
1374
1360
Common instance attributes:
1375
_matchingbzrdir - the bzrdir format that the repository format was
1361
_matchingbzrdir - the controldir format that the repository format was
1376
1362
originally written to work with. This can be used if manually
1377
1363
constructing a bzrdir and repository, or more commonly for test suite
1378
1364
parameterization.
1418
1404
rich_root_data = None
1419
1405
# Does this format support explicitly versioned directories?
1420
1406
supports_versioned_directories = None
1407
# Can other repositories be nested into one of this format?
1408
supports_nesting_repositories = None
1409
# Is it possible for revisions to be present without being referenced
1411
supports_unreferenced_revisions = None
1422
1413
def __repr__(self):
1423
1414
return "%s()" % self.__class__.__name__
1430
1421
return not self == other
1433
def find_format(klass, a_bzrdir):
1434
"""Return the format for the repository object in a_bzrdir.
1436
This is used by bzr native formats that have a "format" file in
1437
the repository. Other methods may be used by different types of
1441
transport = a_bzrdir.get_repository_transport(None)
1442
format_string = transport.get_bytes("format")
1443
return format_registry.get(format_string)
1444
except errors.NoSuchFile:
1445
raise errors.NoRepositoryPresent(a_bzrdir)
1447
raise errors.UnknownFormatError(format=format_string,
1451
1424
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1452
1425
def register_format(klass, format):
1453
1426
format_registry.register(format)
1463
1436
"""Return the current default format."""
1464
1437
return format_registry.get_default()
1466
def get_format_string(self):
1467
"""Return the ASCII format string that identifies this format.
1469
Note that in pre format ?? repositories the format string is
1470
not permitted nor written to disk.
1472
raise NotImplementedError(self.get_format_string)
1474
1439
def get_format_description(self):
1475
1440
"""Return the short description for this format."""
1476
1441
raise NotImplementedError(self.get_format_description)
1478
def initialize(self, a_bzrdir, shared=False):
1479
"""Initialize a repository of this format in a_bzrdir.
1443
def initialize(self, controldir, shared=False):
1444
"""Initialize a repository of this format in controldir.
1481
:param a_bzrdir: The bzrdir to put the new repository in it.
1446
:param controldir: The controldir to put the new repository in it.
1482
1447
:param shared: The repository should be initialized as a sharable one.
1483
1448
:returns: The new repository object.
1485
1450
This may raise UninitializableFormat if shared repository are not
1486
compatible the a_bzrdir.
1451
compatible the controldir.
1488
1453
raise NotImplementedError(self.initialize)
1525
1490
'Does not support nested trees', target_format,
1526
1491
from_format=self)
1528
def open(self, a_bzrdir, _found=False):
1529
"""Return an instance of this format for the bzrdir a_bzrdir.
1493
def open(self, controldir, _found=False):
1494
"""Return an instance of this format for a controldir.
1531
1496
_found is a private parameter, do not use it.
1533
1498
raise NotImplementedError(self.open)
1535
def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
1536
from bzrlib.bzrdir import BzrDir, RepoInitHookParams
1537
hooks = BzrDir.hooks['post_repo_init']
1500
def _run_post_repo_init_hooks(self, repository, controldir, shared):
1501
from bzrlib.controldir import ControlDir, RepoInitHookParams
1502
hooks = ControlDir.hooks['post_repo_init']
1540
params = RepoInitHookParams(repository, self, a_bzrdir, shared)
1505
params = RepoInitHookParams(repository, self, controldir, shared)
1541
1506
for hook in hooks:
1545
class MetaDirRepositoryFormat(RepositoryFormat):
1510
class RepositoryFormatMetaDir(bzrdir.BzrFormat, RepositoryFormat):
1546
1511
"""Common base class for the new repositories using the metadir layout."""
1548
1513
rich_root_data = False
1549
1514
supports_tree_reference = False
1550
1515
supports_external_lookups = False
1551
1516
supports_leaving_lock = True
1517
supports_nesting_repositories = True
1554
1520
def _matchingbzrdir(self):
1557
1523
return matching
1559
1525
def __init__(self):
1560
super(MetaDirRepositoryFormat, self).__init__()
1526
RepositoryFormat.__init__(self)
1527
bzrdir.BzrFormat.__init__(self)
1562
1529
def _create_control_files(self, a_bzrdir):
1563
1530
"""Create the required files and the initial control_files object."""
1588
1555
control_files.unlock()
1590
def network_name(self):
1591
"""Metadir formats have matching disk and network format strings."""
1592
return self.get_format_string()
1558
def find_format(klass, a_bzrdir):
1559
"""Return the format for the repository object in a_bzrdir.
1561
This is used by bzr native formats that have a "format" file in
1562
the repository. Other methods may be used by different types of
1566
transport = a_bzrdir.get_repository_transport(None)
1567
format_string = transport.get_bytes("format")
1568
except errors.NoSuchFile:
1569
raise errors.NoRepositoryPresent(a_bzrdir)
1570
return klass._find_format(format_registry, 'repository', format_string)
1572
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1574
RepositoryFormat.check_support_status(self,
1575
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
1577
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
1578
recommend_upgrade=recommend_upgrade, basedir=basedir)
1595
1581
# formats which have no format string are not discoverable or independently
1596
1582
# creatable on disk, so are not registered in format_registry. They're
1597
1583
# all in bzrlib.repofmt.knitreponow. When an instance of one of these is
1598
# needed, it's constructed directly by the BzrDir. Non-native formats where
1584
# needed, it's constructed directly by the ControlDir. Non-native formats where
1599
1585
# the repository is not separately opened are similar.
1601
1587
format_registry.register_lazy(
1712
1698
self.target.fetch(self.source, revision_id=revision_id)
1714
1700
@needs_write_lock
1715
def fetch(self, revision_id=None, find_ghosts=False,
1701
def fetch(self, revision_id=None, find_ghosts=False):
1717
1702
"""Fetch the content required to construct revision_id.
1719
1704
The content is copied from self.source to self.target.
1799
1784
# trigger an assertion if not such
1800
1785
repo._format.get_format_string()
1801
1786
self.repo_dir = repo.bzrdir
1802
pb.update('Moving repository to repository.backup')
1787
pb.update(gettext('Moving repository to repository.backup'))
1803
1788
self.repo_dir.transport.move('repository', 'repository.backup')
1804
1789
backup_transport = self.repo_dir.transport.clone('repository.backup')
1805
1790
repo._format.check_conversion_target(self.target_format)
1806
1791
self.source_repo = repo._format.open(self.repo_dir,
1808
1793
_override_transport=backup_transport)
1809
pb.update('Creating new repository')
1794
pb.update(gettext('Creating new repository'))
1810
1795
converted = self.target_format.initialize(self.repo_dir,
1811
1796
self.source_repo.is_shared())
1812
1797
converted.lock_write()
1814
pb.update('Copying content')
1799
pb.update(gettext('Copying content'))
1815
1800
self.source_repo.copy_content_into(converted)
1817
1802
converted.unlock()
1818
pb.update('Deleting old repository content')
1803
pb.update(gettext('Deleting old repository content'))
1819
1804
self.repo_dir.transport.delete_tree('repository.backup')
1820
ui.ui_factory.note('repository converted')
1805
ui.ui_factory.note(gettext('repository converted'))