~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Vincent Ladeuil
  • Date: 2011-06-15 11:36:05 UTC
  • mto: This revision was merged to the branch mainline in revision 5975.
  • Revision ID: v.ladeuil+lp@free.fr-20110615113605-p7zyyfry9wy1hquc
Make ContentConflict resolution more robust

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
    revision as _mod_revision,
33
33
    testament as _mod_testament,
34
34
    tsort,
35
 
    gpg,
36
35
    )
37
36
from bzrlib.bundle import serializer
38
 
from bzrlib.i18n import gettext
39
37
""")
40
38
 
41
39
from bzrlib import (
281
279
                raise
282
280
            mutter('abort_write_group failed')
283
281
            log_exception_quietly()
284
 
            note(gettext('bzr: ERROR (ignored): %s'), exc)
 
282
            note('bzr: ERROR (ignored): %s', exc)
285
283
        self._write_group = None
286
284
 
287
285
    def _abort_write_group(self):
341
339
        """
342
340
        self.control_files.break_lock()
343
341
 
 
342
    @needs_read_lock
 
343
    def _eliminate_revisions_not_present(self, revision_ids):
 
344
        """Check every revision id in revision_ids to see if we have it.
 
345
 
 
346
        Returns a set of the present revisions.
 
347
        """
 
348
        result = []
 
349
        graph = self.get_graph()
 
350
        parent_map = graph.get_parent_map(revision_ids)
 
351
        # The old API returned a list, should this actually be a set?
 
352
        return parent_map.keys()
 
353
 
344
354
    @staticmethod
345
 
    def create(controldir):
346
 
        """Construct the current default format repository in controldir."""
347
 
        return RepositoryFormat.get_default_format().initialize(controldir)
 
355
    def create(a_bzrdir):
 
356
        """Construct the current default format repository in a_bzrdir."""
 
357
        return RepositoryFormat.get_default_format().initialize(a_bzrdir)
348
358
 
349
 
    def __init__(self, _format, controldir, control_files):
 
359
    def __init__(self, _format, a_bzrdir, control_files):
350
360
        """instantiate a Repository.
351
361
 
352
362
        :param _format: The format of the repository on disk.
353
 
        :param controldir: The ControlDir of the repository.
 
363
        :param a_bzrdir: The BzrDir of the repository.
354
364
        :param control_files: Control files to use for locking, etc.
355
365
        """
356
366
        # In the future we will have a single api for all stores for
359
369
        super(Repository, self).__init__()
360
370
        self._format = _format
361
371
        # the following are part of the public API for Repository:
362
 
        self.bzrdir = controldir
 
372
        self.bzrdir = a_bzrdir
363
373
        self.control_files = control_files
 
374
        self._transport = control_files._transport
 
375
        self.base = self._transport.base
364
376
        # for tests
365
377
        self._write_group = None
366
378
        # Additional places to query for data.
404
416
        """
405
417
        if self.__class__ is not other.__class__:
406
418
            return False
407
 
        return (self.control_url == other.control_url)
 
419
        return (self._transport.base == other._transport.base)
408
420
 
409
421
    def is_in_write_group(self):
410
422
        """Return True if there is an open write group.
510
522
        if revid and committers:
511
523
            result['committers'] = 0
512
524
        if revid and revid != _mod_revision.NULL_REVISION:
513
 
            graph = self.get_graph()
514
525
            if committers:
515
526
                all_committers = set()
516
 
            revisions = [r for (r, p) in graph.iter_ancestry([revid])
517
 
                        if r != _mod_revision.NULL_REVISION]
518
 
            last_revision = None
 
527
            revisions = self.get_ancestry(revid)
 
528
            # pop the leading None
 
529
            revisions.pop(0)
 
530
            first_revision = None
519
531
            if not committers:
520
532
                # ignore the revisions in the middle - just grab first and last
521
533
                revisions = revisions[0], revisions[-1]
522
534
            for revision in self.get_revisions(revisions):
523
 
                if not last_revision:
524
 
                    last_revision = revision
 
535
                if not first_revision:
 
536
                    first_revision = revision
525
537
                if committers:
526
538
                    all_committers.add(revision.committer)
527
 
            first_revision = revision
 
539
            last_revision = revision
528
540
            if committers:
529
541
                result['committers'] = len(all_committers)
530
542
            result['firstrev'] = (first_revision.timestamp,
547
559
            def __init__(self):
548
560
                self.first_call = True
549
561
 
550
 
            def __call__(self, controldir):
551
 
                # On the first call, the parameter is always the controldir
 
562
            def __call__(self, bzrdir):
 
563
                # On the first call, the parameter is always the bzrdir
552
564
                # containing the current repo.
553
565
                if not self.first_call:
554
566
                    try:
555
 
                        repository = controldir.open_repository()
 
567
                        repository = bzrdir.open_repository()
556
568
                    except errors.NoRepositoryPresent:
557
569
                        pass
558
570
                    else:
559
571
                        return False, ([], repository)
560
572
                self.first_call = False
561
 
                value = (controldir.list_branches(), None)
 
573
                value = (bzrdir.list_branches(), None)
562
574
                return True, value
563
575
 
564
576
        ret = []
565
 
        for branches, repository in controldir.ControlDir.find_bzrdirs(
 
577
        for branches, repository in bzrdir.BzrDir.find_bzrdirs(
566
578
                self.user_transport, evaluate=Evaluator()):
567
579
            if branches is not None:
568
580
                ret.extend(branches)
602
614
        For instance, if the repository is at URL/.bzr/repository,
603
615
        Repository.open(URL) -> a Repository instance.
604
616
        """
605
 
        control = controldir.ControlDir.open(base)
 
617
        control = bzrdir.BzrDir.open(base)
606
618
        return control.open_repository()
607
619
 
608
620
    def copy_content_into(self, destination, revision_id=None):
746
758
                repo.unlock()
747
759
 
748
760
    @needs_read_lock
749
 
    def clone(self, controldir, revision_id=None):
750
 
        """Clone this repository into controldir using the current format.
 
761
    def clone(self, a_bzrdir, revision_id=None):
 
762
        """Clone this repository into a_bzrdir using the current format.
751
763
 
752
764
        Currently no check is made that the format of this repository and
753
765
        the bzrdir format are compatible. FIXME RBC 20060201.
756
768
        """
757
769
        # TODO: deprecate after 0.16; cloning this with all its settings is
758
770
        # probably not very useful -- mbp 20070423
759
 
        dest_repo = self._create_sprouting_repo(
760
 
            controldir, shared=self.is_shared())
 
771
        dest_repo = self._create_sprouting_repo(a_bzrdir, shared=self.is_shared())
761
772
        self.copy_content_into(dest_repo, revision_id)
762
773
        return dest_repo
763
774
 
930
941
        parent_ids.discard(_mod_revision.NULL_REVISION)
931
942
        return parent_ids
932
943
 
 
944
    def fileids_altered_by_revision_ids(self, revision_ids):
 
945
        """Find the file ids and versions affected by revisions.
 
946
 
 
947
        :param revisions: an iterable containing revision ids.
 
948
        :return: a dictionary mapping altered file-ids to an iterable of
 
949
            revision_ids. Each altered file-ids has the exact revision_ids
 
950
            that altered it listed explicitly.
 
951
        """
 
952
        raise NotImplementedError(self.fileids_altered_by_revision_ids)
 
953
 
933
954
    def iter_files_bytes(self, desired_files):
934
955
        """Iterate through file versions.
935
956
 
981
1002
            raise AssertionError('_iter_for_revno returned too much history')
982
1003
        return (True, partial_history[-1])
983
1004
 
984
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
985
1005
    def iter_reverse_revision_history(self, revision_id):
986
1006
        """Iterate backwards through revision ids in the lefthand history
987
1007
 
1035
1055
        raise NotImplementedError(self.revision_trees)
1036
1056
 
1037
1057
    @needs_read_lock
1038
 
    @symbol_versioning.deprecated_method(
1039
 
        symbol_versioning.deprecated_in((2, 4, 0)))
1040
1058
    def get_ancestry(self, revision_id, topo_sorted=True):
1041
1059
        """Return a list of revision-ids integrated by a revision.
1042
1060
 
1046
1064
 
1047
1065
        This is topologically sorted.
1048
1066
        """
1049
 
        if 'evil' in debug.debug_flags:
1050
 
            mutter_callsite(2, "get_ancestry is linear with history.")
1051
1067
        if _mod_revision.is_null(revision_id):
1052
1068
            return [None]
1053
1069
        if not self.has_revision(revision_id):
1184
1200
        plaintext = testament.as_short_text()
1185
1201
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)
1186
1202
 
1187
 
    @needs_read_lock
1188
 
    def verify_revision(self, revision_id, gpg_strategy):
1189
 
        """Verify the signature on a revision.
1190
 
        
1191
 
        :param revision_id: the revision to verify
1192
 
        :gpg_strategy: the GPGStrategy object to used
1193
 
        
1194
 
        :return: gpg.SIGNATURE_VALID or a failed SIGNATURE_ value
1195
 
        """
1196
 
        if not self.has_signature_for_revision_id(revision_id):
1197
 
            return gpg.SIGNATURE_NOT_SIGNED, None
1198
 
        signature = self.get_signature_text(revision_id)
1199
 
 
1200
 
        testament = _mod_testament.Testament.from_revision(self, revision_id)
1201
 
        plaintext = testament.as_short_text()
1202
 
 
1203
 
        return gpg_strategy.verify(signature, plaintext)
1204
 
 
1205
1203
    def has_signature_for_revision_id(self, revision_id):
1206
1204
        """Query for a revision signature for revision_id in the repository."""
1207
1205
        raise NotImplementedError(self.has_signature_for_revision_id)
1312
1310
 
1313
1311
    def get_default(self):
1314
1312
        """Return the current default format."""
1315
 
        return controldir.format_registry.make_bzrdir('default').repository_format
 
1313
        from bzrlib import bzrdir
 
1314
        return bzrdir.format_registry.make_bzrdir('default').repository_format
1316
1315
 
1317
1316
 
1318
1317
network_format_registry = registry.FormatRegistry()
1361
1360
    created.
1362
1361
 
1363
1362
    Common instance attributes:
1364
 
    _matchingbzrdir - the controldir format that the repository format was
 
1363
    _matchingbzrdir - the bzrdir format that the repository format was
1365
1364
    originally written to work with. This can be used if manually
1366
1365
    constructing a bzrdir and repository, or more commonly for test suite
1367
1366
    parameterization.
1405
1404
    revision_graph_can_have_wrong_parents = None
1406
1405
    # Does this format support rich root data?
1407
1406
    rich_root_data = None
1408
 
    # Does this format support explicitly versioned directories?
1409
 
    supports_versioned_directories = None
1410
 
    # Can other repositories be nested into one of this format?
1411
 
    supports_nesting_repositories = None
1412
1407
 
1413
1408
    def __repr__(self):
1414
1409
        return "%s()" % self.__class__.__name__
1466
1461
        """Return the short description for this format."""
1467
1462
        raise NotImplementedError(self.get_format_description)
1468
1463
 
1469
 
    def initialize(self, controldir, shared=False):
1470
 
        """Initialize a repository of this format in controldir.
 
1464
    def initialize(self, a_bzrdir, shared=False):
 
1465
        """Initialize a repository of this format in a_bzrdir.
1471
1466
 
1472
 
        :param controldir: The controldir to put the new repository in it.
 
1467
        :param a_bzrdir: The bzrdir to put the new repository in it.
1473
1468
        :param shared: The repository should be initialized as a sharable one.
1474
1469
        :returns: The new repository object.
1475
1470
 
1476
1471
        This may raise UninitializableFormat if shared repository are not
1477
 
        compatible the controldir.
 
1472
        compatible the a_bzrdir.
1478
1473
        """
1479
1474
        raise NotImplementedError(self.initialize)
1480
1475
 
1516
1511
                'Does not support nested trees', target_format,
1517
1512
                from_format=self)
1518
1513
 
1519
 
    def open(self, controldir, _found=False):
1520
 
        """Return an instance of this format for a controldir.
 
1514
    def open(self, a_bzrdir, _found=False):
 
1515
        """Return an instance of this format for the bzrdir a_bzrdir.
1521
1516
 
1522
1517
        _found is a private parameter, do not use it.
1523
1518
        """
1524
1519
        raise NotImplementedError(self.open)
1525
1520
 
1526
 
    def _run_post_repo_init_hooks(self, repository, controldir, shared):
1527
 
        from bzrlib.controldir import ControlDir, RepoInitHookParams
1528
 
        hooks = ControlDir.hooks['post_repo_init']
 
1521
    def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
 
1522
        from bzrlib.bzrdir import BzrDir, RepoInitHookParams
 
1523
        hooks = BzrDir.hooks['post_repo_init']
1529
1524
        if not hooks:
1530
1525
            return
1531
 
        params = RepoInitHookParams(repository, self, controldir, shared)
 
1526
        params = RepoInitHookParams(repository, self, a_bzrdir, shared)
1532
1527
        for hook in hooks:
1533
1528
            hook(params)
1534
1529
 
1540
1535
    supports_tree_reference = False
1541
1536
    supports_external_lookups = False
1542
1537
    supports_leaving_lock = True
1543
 
    supports_nesting_repositories = True
1544
1538
 
1545
1539
    @property
1546
1540
    def _matchingbzrdir(self):
1587
1581
# formats which have no format string are not discoverable or independently
1588
1582
# creatable on disk, so are not registered in format_registry.  They're
1589
1583
# all in bzrlib.repofmt.knitreponow.  When an instance of one of these is
1590
 
# needed, it's constructed directly by the ControlDir.  Non-native formats where
 
1584
# needed, it's constructed directly by the BzrDir.  Non-native formats where
1591
1585
# the repository is not separately opened are similar.
1592
1586
 
1593
1587
format_registry.register_lazy(
1791
1785
        # trigger an assertion if not such
1792
1786
        repo._format.get_format_string()
1793
1787
        self.repo_dir = repo.bzrdir
1794
 
        pb.update(gettext('Moving repository to repository.backup'))
 
1788
        pb.update('Moving repository to repository.backup')
1795
1789
        self.repo_dir.transport.move('repository', 'repository.backup')
1796
1790
        backup_transport =  self.repo_dir.transport.clone('repository.backup')
1797
1791
        repo._format.check_conversion_target(self.target_format)
1798
1792
        self.source_repo = repo._format.open(self.repo_dir,
1799
1793
            _found=True,
1800
1794
            _override_transport=backup_transport)
1801
 
        pb.update(gettext('Creating new repository'))
 
1795
        pb.update('Creating new repository')
1802
1796
        converted = self.target_format.initialize(self.repo_dir,
1803
1797
                                                  self.source_repo.is_shared())
1804
1798
        converted.lock_write()
1805
1799
        try:
1806
 
            pb.update(gettext('Copying content'))
 
1800
            pb.update('Copying content')
1807
1801
            self.source_repo.copy_content_into(converted)
1808
1802
        finally:
1809
1803
            converted.unlock()
1810
 
        pb.update(gettext('Deleting old repository content'))
 
1804
        pb.update('Deleting old repository content')
1811
1805
        self.repo_dir.transport.delete_tree('repository.backup')
1812
 
        ui.ui_factory.note(gettext('repository converted'))
 
1806
        ui.ui_factory.note('repository converted')
1813
1807
        pb.finished()
1814
1808
 
1815
1809
 
1839
1833
        it is encountered, history extension will stop.
1840
1834
    """
1841
1835
    start_revision = partial_history_cache[-1]
1842
 
    graph = repo.get_graph()
1843
 
    iterator = graph.iter_lefthand_ancestry(start_revision,
1844
 
        (_mod_revision.NULL_REVISION,))
 
1836
    iterator = repo.iter_reverse_revision_history(start_revision)
1845
1837
    try:
1846
 
        # skip the last revision in the list
 
1838
        #skip the last revision in the list
1847
1839
        iterator.next()
1848
1840
        while True:
1849
1841
            if (stop_index is not None and
1881
1873
        for list_part in self.list_parts:
1882
1874
            full_list.extend(list_part)
1883
1875
        return iter(full_list)
1884
 
 
1885
 
    def __repr__(self):
1886
 
        return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
1887
 
                              self.list_parts)