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 (
74
76
record_root_entry = True
75
77
# whether this commit builder supports the record_entry_contents interface
76
78
supports_record_entry_contents = False
79
# whether this commit builder will automatically update the branch that is
81
updates_branch = False
78
def __init__(self, repository, parents, config, timestamp=None,
83
def __init__(self, repository, parents, config_stack, timestamp=None,
79
84
timezone=None, committer=None, revprops=None,
80
85
revision_id=None, lossy=False):
81
86
"""Initiate a CommitBuilder.
90
95
:param lossy: Whether to discard data that can not be natively
91
96
represented, when pushing to a foreign VCS
98
self._config_stack = config_stack
94
99
self._lossy = lossy
96
101
if committer is None:
97
self._committer = self._config.username()
102
self._committer = self._config_stack.get('email')
98
103
elif not isinstance(committer, unicode):
99
104
self._committer = committer.decode() # throw if non-ascii
342
347
self.control_files.break_lock()
345
def create(a_bzrdir):
346
"""Construct the current default format repository in a_bzrdir."""
347
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)
349
def __init__(self, _format, a_bzrdir, control_files):
354
def __init__(self, _format, controldir, control_files):
350
355
"""instantiate a Repository.
352
357
:param _format: The format of the repository on disk.
353
:param a_bzrdir: The BzrDir of the repository.
358
:param controldir: The ControlDir of the repository.
354
359
:param control_files: Control files to use for locking, etc.
356
361
# In the future we will have a single api for all stores for
547
552
def __init__(self):
548
553
self.first_call = True
550
def __call__(self, bzrdir):
551
# 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
552
557
# containing the current repo.
553
558
if not self.first_call:
555
repository = bzrdir.open_repository()
560
repository = controldir.open_repository()
556
561
except errors.NoRepositoryPresent:
559
564
return False, ([], repository)
560
565
self.first_call = False
561
value = (bzrdir.list_branches(), None)
566
value = (controldir.list_branches(), None)
562
567
return True, value
565
for branches, repository in bzrdir.BzrDir.find_bzrdirs(
570
for branches, repository in controldir.ControlDir.find_bzrdirs(
566
571
self.user_transport, evaluate=Evaluator()):
567
572
if branches is not None:
568
573
ret.extend(branches)
602
607
For instance, if the repository is at URL/.bzr/repository,
603
608
Repository.open(URL) -> a Repository instance.
605
control = bzrdir.BzrDir.open(base)
610
control = controldir.ControlDir.open(base)
606
611
return control.open_repository()
608
613
def copy_content_into(self, destination, revision_id=None):
666
677
def _resume_write_group(self, tokens):
667
678
raise errors.UnsuspendableWriteGroup(self)
669
def fetch(self, source, revision_id=None, find_ghosts=False,
680
def fetch(self, source, revision_id=None, find_ghosts=False):
671
681
"""Fetch the content required to construct revision_id from source.
673
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.
676
685
fetch() may not be used when the repository is in a write group -
677
686
either finish the current write group before using fetch, or use
683
692
:param revision_id: If specified, all the content needed for this
684
693
revision ID will be copied to the target. Fetch will determine for
685
694
itself which content needs to be copied.
686
:param fetch_spec: If specified, a SearchResult or
687
PendingAncestryResult that describes which revisions to copy. This
688
allows copying multiple heads at once. Mutually exclusive with
691
if fetch_spec is not None and revision_id is not None:
692
raise AssertionError(
693
"fetch_spec and revision_id are mutually exclusive.")
694
696
if self.is_in_write_group():
695
697
raise errors.InternalBzrError(
696
698
"May not fetch while in a write group.")
707
708
self.get_revision(revision_id)
709
710
inter = InterRepository.get(source, self)
710
return inter.fetch(revision_id=revision_id,
711
find_ghosts=find_ghosts, fetch_spec=fetch_spec)
711
return inter.fetch(revision_id=revision_id, find_ghosts=find_ghosts)
713
713
def create_bundle(self, target, base, fileobj, format=None):
714
714
return serializer.write_bundle(self, target, base, fileobj, format)
716
def get_commit_builder(self, branch, parents, config, timestamp=None,
716
def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
717
717
timezone=None, committer=None, revprops=None,
718
718
revision_id=None, lossy=False):
719
719
"""Obtain a CommitBuilder for this repository.
721
721
:param branch: Branch to commit to.
722
722
:param parents: Revision ids of the parents of the new revision.
723
:param config: Configuration to use.
723
:param config_stack: Configuration stack to use.
724
724
:param timestamp: Optional timestamp recorded for commit.
725
725
:param timezone: Optional timezone for timestamp.
726
726
:param committer: Optional committer to set for commit.
749
def clone(self, a_bzrdir, revision_id=None):
750
"""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.
752
752
Currently no check is made that the format of this repository and
753
753
the bzrdir format are compatible. FIXME RBC 20060201.
757
757
# TODO: deprecate after 0.16; cloning this with all its settings is
758
758
# probably not very useful -- mbp 20070423
759
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())
760
761
self.copy_content_into(dest_repo, revision_id)
929
930
parent_ids.discard(_mod_revision.NULL_REVISION)
930
931
return parent_ids
932
def fileids_altered_by_revision_ids(self, revision_ids):
933
"""Find the file ids and versions affected by revisions.
935
:param revisions: an iterable containing revision ids.
936
:return: a dictionary mapping altered file-ids to an iterable of
937
revision_ids. Each altered file-ids has the exact revision_ids
938
that altered it listed explicitly.
940
raise NotImplementedError(self.fileids_altered_by_revision_ids)
942
933
def iter_files_bytes(self, desired_files):
943
934
"""Iterate through file versions.
990
981
raise AssertionError('_iter_for_revno returned too much history')
991
982
return (True, partial_history[-1])
993
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
994
def iter_reverse_revision_history(self, revision_id):
995
"""Iterate backwards through revision ids in the lefthand history
997
:param revision_id: The revision id to start with. All its lefthand
998
ancestors will be traversed.
1000
graph = self.get_graph()
1001
stop_revisions = (None, _mod_revision.NULL_REVISION)
1002
return graph.iter_lefthand_ancestry(revision_id, stop_revisions)
1004
984
def is_shared(self):
1005
985
"""Return True if this repository is flagged as a shared repository."""
1006
986
raise NotImplementedError(self.is_shared)
1044
1024
raise NotImplementedError(self.revision_trees)
1047
@symbol_versioning.deprecated_method(
1048
symbol_versioning.deprecated_in((2, 4, 0)))
1049
def get_ancestry(self, revision_id, topo_sorted=True):
1050
"""Return a list of revision-ids integrated by a revision.
1052
The first element of the list is always None, indicating the origin
1053
revision. This might change when we have history horizons, or
1054
perhaps we should have a new API.
1056
This is topologically sorted.
1058
if 'evil' in debug.debug_flags:
1059
mutter_callsite(2, "get_ancestry is linear with history.")
1060
if _mod_revision.is_null(revision_id):
1062
if not self.has_revision(revision_id):
1063
raise errors.NoSuchRevision(self, revision_id)
1064
graph = self.get_graph()
1066
search = graph._make_breadth_first_searcher([revision_id])
1069
found, ghosts = search.next_with_ghosts()
1070
except StopIteration:
1073
if _mod_revision.NULL_REVISION in keys:
1074
keys.remove(_mod_revision.NULL_REVISION)
1076
parent_map = graph.get_parent_map(keys)
1077
keys = tsort.topo_sort(parent_map)
1078
return [None] + list(keys)
1080
1026
def pack(self, hint=None, clean_obsolete_packs=False):
1081
1027
"""Compress the data within the repository.
1158
1104
[parents_provider, other_repository._make_parents_provider()])
1159
1105
return graph.Graph(parents_provider)
1161
def revision_ids_to_search_result(self, result_set):
1162
"""Convert a set of revision ids to a graph SearchResult."""
1163
result_parents = set()
1164
for parents in self.get_graph().get_parent_map(
1165
result_set).itervalues():
1166
result_parents.update(parents)
1167
included_keys = result_set.intersection(result_parents)
1168
start_keys = result_set.difference(included_keys)
1169
exclude_keys = result_parents.difference(result_set)
1170
result = graph.SearchResult(start_keys, exclude_keys,
1171
len(result_set), result_set)
1174
1107
@needs_write_lock
1175
1108
def set_make_working_trees(self, new_value):
1176
1109
"""Set the policy flag for making working trees when creating branches.
1194
1127
self.store_revision_signature(gpg_strategy, plaintext, revision_id)
1196
1129
@needs_read_lock
1197
def verify_revision(self, revision_id, gpg_strategy):
1130
def verify_revision_signature(self, revision_id, gpg_strategy):
1198
1131
"""Verify the signature on a revision.
1200
1133
:param revision_id: the revision to verify
1201
1134
:gpg_strategy: the GPGStrategy object to used
1203
1136
:return: gpg.SIGNATURE_VALID or a failed SIGNATURE_ value
1205
1138
if not self.has_signature_for_revision_id(revision_id):
1212
1145
return gpg_strategy.verify(signature, plaintext)
1148
def verify_revision_signatures(self, revision_ids, gpg_strategy):
1149
"""Verify revision signatures for a number of revisions.
1151
:param revision_id: the revision to verify
1152
:gpg_strategy: the GPGStrategy object to used
1153
:return: Iterator over tuples with revision id, result and keys
1155
for revid in revision_ids:
1156
(result, key) = self.verify_revision_signature(revid, gpg_strategy)
1157
yield revid, result, key
1214
1159
def has_signature_for_revision_id(self, revision_id):
1215
1160
"""Query for a revision signature for revision_id in the repository."""
1216
1161
raise NotImplementedError(self.has_signature_for_revision_id)
1248
1193
if branch is None:
1249
conf = config.GlobalConfig()
1194
conf = config.GlobalStack()
1251
conf = branch.get_config()
1252
if conf.suppress_warning('format_deprecation'):
1196
conf = branch.get_config_stack()
1197
if 'format_deprecation' in conf.get('suppress_warnings'):
1254
1199
warning("Format %s for %s is deprecated -"
1255
1200
" please use 'bzr upgrade' to get better performance"
1315
1260
"""Returns the policy for making working trees on new branches."""
1316
1261
return not self._transport.has('no-working-trees')
1264
def update_feature_flags(self, updated_flags):
1265
"""Update the feature flags for this branch.
1267
:param updated_flags: Dictionary mapping feature names to necessities
1268
A necessity can be None to indicate the feature should be removed
1270
self._format._update_feature_flags(updated_flags)
1271
self.control_transport.put_bytes('format', self._format.as_string())
1319
1274
class RepositoryFormatRegistry(controldir.ControlComponentFormatRegistry):
1320
1275
"""Repository format registry."""
1322
1277
def get_default(self):
1323
1278
"""Return the current default format."""
1324
from bzrlib import bzrdir
1325
return bzrdir.format_registry.make_bzrdir('default').repository_format
1279
return controldir.format_registry.make_bzrdir('default').repository_format
1328
1282
network_format_registry = registry.FormatRegistry()
1419
1373
supports_versioned_directories = None
1420
1374
# Can other repositories be nested into one of this format?
1421
1375
supports_nesting_repositories = None
1376
# Is it possible for revisions to be present without being referenced
1378
supports_unreferenced_revisions = None
1423
1380
def __repr__(self):
1424
1381
return "%s()" % self.__class__.__name__
1430
1387
def __ne__(self, other):
1431
1388
return not self == other
1434
def find_format(klass, a_bzrdir):
1435
"""Return the format for the repository object in a_bzrdir.
1437
This is used by bzr native formats that have a "format" file in
1438
the repository. Other methods may be used by different types of
1442
transport = a_bzrdir.get_repository_transport(None)
1443
format_string = transport.get_bytes("format")
1444
return format_registry.get(format_string)
1445
except errors.NoSuchFile:
1446
raise errors.NoRepositoryPresent(a_bzrdir)
1448
raise errors.UnknownFormatError(format=format_string,
1452
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1453
def register_format(klass, format):
1454
format_registry.register(format)
1457
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1458
def unregister_format(klass, format):
1459
format_registry.remove(format)
1462
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1463
def get_default_format(klass):
1464
"""Return the current default format."""
1465
return format_registry.get_default()
1467
def get_format_string(self):
1468
"""Return the ASCII format string that identifies this format.
1470
Note that in pre format ?? repositories the format string is
1471
not permitted nor written to disk.
1473
raise NotImplementedError(self.get_format_string)
1475
1390
def get_format_description(self):
1476
1391
"""Return the short description for this format."""
1477
1392
raise NotImplementedError(self.get_format_description)
1479
def initialize(self, a_bzrdir, shared=False):
1480
"""Initialize a repository of this format in a_bzrdir.
1394
def initialize(self, controldir, shared=False):
1395
"""Initialize a repository of this format in controldir.
1482
:param a_bzrdir: The bzrdir to put the new repository in it.
1397
:param controldir: The controldir to put the new repository in it.
1483
1398
:param shared: The repository should be initialized as a sharable one.
1484
1399
:returns: The new repository object.
1486
1401
This may raise UninitializableFormat if shared repository are not
1487
compatible the a_bzrdir.
1402
compatible the controldir.
1489
1404
raise NotImplementedError(self.initialize)
1526
1441
'Does not support nested trees', target_format,
1527
1442
from_format=self)
1529
def open(self, a_bzrdir, _found=False):
1530
"""Return an instance of this format for the bzrdir a_bzrdir.
1444
def open(self, controldir, _found=False):
1445
"""Return an instance of this format for a controldir.
1532
1447
_found is a private parameter, do not use it.
1534
1449
raise NotImplementedError(self.open)
1536
def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
1537
from bzrlib.bzrdir import BzrDir, RepoInitHookParams
1538
hooks = BzrDir.hooks['post_repo_init']
1451
def _run_post_repo_init_hooks(self, repository, controldir, shared):
1452
from bzrlib.controldir import ControlDir, RepoInitHookParams
1453
hooks = ControlDir.hooks['post_repo_init']
1541
params = RepoInitHookParams(repository, self, a_bzrdir, shared)
1456
params = RepoInitHookParams(repository, self, controldir, shared)
1542
1457
for hook in hooks:
1546
class MetaDirRepositoryFormat(RepositoryFormat):
1461
class RepositoryFormatMetaDir(bzrdir.BzrFormat, RepositoryFormat):
1547
1462
"""Common base class for the new repositories using the metadir layout."""
1549
1464
rich_root_data = False
1559
1474
return matching
1561
1476
def __init__(self):
1562
super(MetaDirRepositoryFormat, self).__init__()
1477
RepositoryFormat.__init__(self)
1478
bzrdir.BzrFormat.__init__(self)
1564
1480
def _create_control_files(self, a_bzrdir):
1565
1481
"""Create the required files and the initial control_files object."""
1590
1506
control_files.unlock()
1592
def network_name(self):
1593
"""Metadir formats have matching disk and network format strings."""
1594
return self.get_format_string()
1509
def find_format(klass, a_bzrdir):
1510
"""Return the format for the repository object in a_bzrdir.
1512
This is used by bzr native formats that have a "format" file in
1513
the repository. Other methods may be used by different types of
1517
transport = a_bzrdir.get_repository_transport(None)
1518
format_string = transport.get_bytes("format")
1519
except errors.NoSuchFile:
1520
raise errors.NoRepositoryPresent(a_bzrdir)
1521
return klass._find_format(format_registry, 'repository', format_string)
1523
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1525
RepositoryFormat.check_support_status(self,
1526
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
1528
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
1529
recommend_upgrade=recommend_upgrade, basedir=basedir)
1597
1532
# formats which have no format string are not discoverable or independently
1598
1533
# creatable on disk, so are not registered in format_registry. They're
1599
1534
# all in bzrlib.repofmt.knitreponow. When an instance of one of these is
1600
# needed, it's constructed directly by the BzrDir. Non-native formats where
1535
# needed, it's constructed directly by the ControlDir. Non-native formats where
1601
1536
# the repository is not separately opened are similar.
1603
1538
format_registry.register_lazy(
1714
1649
self.target.fetch(self.source, revision_id=revision_id)
1716
1651
@needs_write_lock
1717
def fetch(self, revision_id=None, find_ghosts=False,
1652
def fetch(self, revision_id=None, find_ghosts=False):
1719
1653
"""Fetch the content required to construct revision_id.
1721
1655
The content is copied from self.source to self.target.