/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/repository.py

  • Committer: Jelmer Vernooij
  • Date: 2019-03-05 07:32:38 UTC
  • mto: (7290.1.21 work)
  • mto: This revision was merged to the branch mainline in revision 7311.
  • Revision ID: jelmer@jelmer.uk-20190305073238-zlqn981opwnqsmzi
Add appveyor configuration.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
16
16
 
 
17
from __future__ import absolute_import
 
18
 
17
19
from .lazy_import import lazy_import
18
20
lazy_import(globals(), """
19
21
import time
27
29
    revision as _mod_revision,
28
30
    gpg,
29
31
    )
 
32
from breezy.bundle import serializer
30
33
from breezy.i18n import gettext
31
34
""")
32
35
 
38
41
from .decorators import only_raises
39
42
from .inter import InterObject
40
43
from .lock import _RelockDebugMixin, LogicalLockResult
 
44
from .sixish import (
 
45
    text_type,
 
46
    viewitems,
 
47
    )
41
48
from .trace import (
42
49
    log_exception_quietly, note, mutter, mutter_callsite, warning)
43
50
 
59
66
    _fmt = "Repository format does not support setting revision ids."
60
67
 
61
68
 
62
 
class FetchResult(object):
63
 
    """Result of a fetch operation.
64
 
 
65
 
    :ivar revidmap: For lossy fetches, map from source revid to target revid.
66
 
    :ivar total_fetched: Number of revisions fetched
67
 
    """
68
 
 
69
 
    def __init__(self, total_fetched=None, revidmap=None):
70
 
        self.total_fetched = total_fetched
71
 
        self.revidmap = revidmap
72
 
 
73
 
 
74
69
class CommitBuilder(object):
75
70
    """Provides an interface to build up a commit.
76
71
 
104
99
 
105
100
        if committer is None:
106
101
            self._committer = self._config_stack.get('email')
107
 
        elif not isinstance(committer, str):
 
102
        elif not isinstance(committer, text_type):
108
103
            self._committer = committer.decode()  # throw if non-ascii
109
104
        else:
110
105
            self._committer = committer
146
141
            raise ValueError('Invalid value for %s: %r' % (context, text))
147
142
 
148
143
    def _validate_revprops(self, revprops):
149
 
        for key, value in revprops.items():
 
144
        for key, value in viewitems(revprops):
150
145
            # We know that the XML serializers do not round trip '\r'
151
146
            # correctly, so refuse to accept them
152
 
            if not isinstance(value, str):
 
147
            if not isinstance(value, (text_type, str)):
153
148
                raise ValueError('revision property (%s) is not a valid'
154
149
                                 ' (unicode) string: %r' % (key, value))
155
150
            # TODO(jelmer): Make this repository-format specific
241
236
                                                      self.unlock)
242
237
 
243
238
 
244
 
class WriteGroup(object):
245
 
    """Context manager that manages a write group.
246
 
 
247
 
    Raising an exception will result in the write group being aborted.
248
 
    """
249
 
 
250
 
    def __init__(self, repository, suppress_errors=False):
251
 
        self.repository = repository
252
 
        self._suppress_errors = suppress_errors
253
 
 
254
 
    def __enter__(self):
255
 
        self.repository.start_write_group()
256
 
        return self
257
 
 
258
 
    def __exit__(self, exc_type, exc_val, exc_tb):
259
 
        if exc_type:
260
 
            self.repository.abort_write_group(self._suppress_errors)
261
 
            return False
262
 
        else:
263
 
            self.repository.commit_write_group()
264
 
 
265
 
 
266
239
######################################################################
267
240
# Repositories
268
241
 
569
542
        :param using: If True, list only branches using this repository.
570
543
        """
571
544
        if using and not self.is_shared():
572
 
            for branch in self.controldir.list_branches():
573
 
                yield branch
574
 
            return
 
545
            return self.controldir.list_branches()
575
546
 
576
547
        class Evaluator(object):
577
548
 
592
563
                value = (controldir.list_branches(), None)
593
564
                return True, value
594
565
 
 
566
        ret = []
595
567
        for branches, repository in controldir.ControlDir.find_controldirs(
596
568
                self.user_transport, evaluate=Evaluator()):
597
569
            if branches is not None:
598
 
                for branch in branches:
599
 
                    yield branch
 
570
                ret.extend(branches)
600
571
            if not using and repository is not None:
601
 
                for branch in repository.find_branches():
602
 
                    yield branch
 
572
                ret.extend(repository.find_branches())
 
573
        return ret
603
574
 
604
575
    def search_missing_revision_ids(self, other,
605
576
                                    find_ghosts=True, revision_ids=None, if_present_ids=None,
692
663
    def _resume_write_group(self, tokens):
693
664
        raise errors.UnsuspendableWriteGroup(self)
694
665
 
695
 
    def fetch(self, source, revision_id=None, find_ghosts=False, lossy=False):
 
666
    def fetch(self, source, revision_id=None, find_ghosts=False):
696
667
        """Fetch the content required to construct revision_id from source.
697
668
 
698
669
        If revision_id is None, then all content is copied.
707
678
        :param revision_id: If specified, all the content needed for this
708
679
            revision ID will be copied to the target.  Fetch will determine for
709
680
            itself which content needs to be copied.
710
 
        :return: A FetchResult object
711
681
        """
712
682
        if self.is_in_write_group():
713
683
            raise errors.InternalBzrError(
724
694
                self.get_revision(revision_id)
725
695
            return 0, []
726
696
        inter = InterRepository.get(source, self)
727
 
        return inter.fetch(
728
 
            revision_id=revision_id, find_ghosts=find_ghosts, lossy=lossy)
 
697
        return inter.fetch(revision_id=revision_id, find_ghosts=find_ghosts)
 
698
 
 
699
    def create_bundle(self, target, base, fileobj, format=None):
 
700
        return serializer.write_bundle(self, target, base, fileobj, format)
729
701
 
730
702
    def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
731
703
                           timezone=None, committer=None, revprops=None,
884
856
        """
885
857
        raise NotImplementedError(self.iter_revisions)
886
858
 
887
 
    def get_revision_delta(self, revision_id):
 
859
    def get_deltas_for_revisions(self, revisions, specific_fileids=None):
 
860
        """Produce a generator of revision deltas.
 
861
 
 
862
        Note that the input is a sequence of REVISIONS, not revision_ids.
 
863
        Trees will be held in memory until the generator exits.
 
864
        Each delta is relative to the revision's lefthand predecessor.
 
865
 
 
866
        :param specific_fileids: if not None, the result is filtered
 
867
          so that only those file-ids, their parents and their
 
868
          children are included.
 
869
        """
 
870
        raise NotImplementedError(self.get_deltas_for_revisions)
 
871
 
 
872
    def get_revision_delta(self, revision_id, specific_fileids=None):
888
873
        """Return the delta for one revision.
889
874
 
890
875
        The delta is relative to the left-hand predecessor of the
891
876
        revision.
 
877
 
 
878
        :param specific_fileids: if not None, the result is filtered
 
879
          so that only those file-ids, their parents and their
 
880
          children are included.
892
881
        """
893
882
        with self.lock_read():
894
883
            r = self.get_revision(revision_id)
895
 
            return list(self.get_revision_deltas([r]))[0]
896
 
 
897
 
    def get_revision_deltas(self, revisions, specific_files=None):
898
 
        """Produce a generator of revision deltas.
899
 
 
900
 
        Note that the input is a sequence of REVISIONS, not revision ids.
901
 
        Trees will be held in memory until the generator exits.
902
 
        Each delta is relative to the revision's lefthand predecessor.
903
 
 
904
 
        specific_files should exist in the first revision.
905
 
 
906
 
        :param specific_files: if not None, the result is filtered
907
 
          so that only those files, their parents and their
908
 
          children are included.
909
 
        """
910
 
        from .tree import InterTree
911
 
        # Get the revision-ids of interest
912
 
        required_trees = set()
913
 
        for revision in revisions:
914
 
            required_trees.add(revision.revision_id)
915
 
            required_trees.update(revision.parent_ids[:1])
916
 
 
917
 
        trees = {
918
 
            t.get_revision_id(): t
919
 
            for t in self.revision_trees(required_trees)}
920
 
 
921
 
        # Calculate the deltas
922
 
        for revision in revisions:
923
 
            if not revision.parent_ids:
924
 
                old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
925
 
            else:
926
 
                old_tree = trees[revision.parent_ids[0]]
927
 
            intertree = InterTree.get(old_tree, trees[revision.revision_id])
928
 
            yield intertree.compare(specific_files=specific_files)
929
 
            if specific_files is not None:
930
 
                specific_files = [
931
 
                    p for p in intertree.find_source_paths(
932
 
                        specific_files).values()
933
 
                    if p is not None]
 
884
            return list(self.get_deltas_for_revisions(
 
885
                [r], specific_fileids=specific_fileids))[0]
934
886
 
935
887
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
936
888
        raise NotImplementedError(self.store_revision_signature)
971
923
        partial_history = [known_revid]
972
924
        distance_from_known = known_revno - revno
973
925
        if distance_from_known < 0:
974
 
            raise errors.RevnoOutOfBounds(revno, (0, known_revno))
 
926
            raise ValueError(
 
927
                'requested revno (%d) is later than given known revno (%d)'
 
928
                % (revno, known_revno))
975
929
        try:
976
930
            _iter_for_revno(
977
931
                self, partial_history, stop_index=distance_from_known)
978
932
        except errors.RevisionNotPresent as err:
979
933
            if err.revision_id == known_revid:
980
934
                # The start revision (known_revid) wasn't found.
981
 
                raise errors.NoSuchRevision(self, known_revid)
 
935
                raise
982
936
            # This is a stacked repository with no fallbacks, or a there's a
983
937
            # left-hand ghost.  Either way, even though the revision named in
984
938
            # the error isn't in this repo, we know it's the next step in this
1071
1025
            else:
1072
1026
                query_keys.append((revision_id,))
1073
1027
        vf = self.revisions.without_fallbacks()
1074
 
        for (revision_id,), parent_keys in (
1075
 
                vf.get_parent_map(query_keys).items()):
 
1028
        for (revision_id,), parent_keys in viewitems(
 
1029
                vf.get_parent_map(query_keys)):
1076
1030
            if parent_keys:
1077
1031
                result[revision_id] = tuple([parent_revid
1078
1032
                                             for (parent_revid,) in parent_keys])
1203
1157
        # weave repositories refuse to store revisionids that are non-ascii.
1204
1158
        if revision_id is not None:
1205
1159
            # weaves require ascii revision ids.
1206
 
            if isinstance(revision_id, str):
 
1160
            if isinstance(revision_id, text_type):
1207
1161
                try:
1208
1162
                    revision_id.encode('ascii')
1209
1163
                except UnicodeEncodeError:
1529
1483
            try:
1530
1484
                self.target.set_make_working_trees(
1531
1485
                    self.source.make_working_trees())
1532
 
            except (NotImplementedError, errors.RepositoryUpgradeRequired):
 
1486
            except NotImplementedError:
1533
1487
                pass
1534
1488
            self.target.fetch(self.source, revision_id=revision_id)
1535
1489
 
1536
 
    def fetch(self, revision_id=None, find_ghosts=False, lossy=False):
 
1490
    def fetch(self, revision_id=None, find_ghosts=False):
1537
1491
        """Fetch the content required to construct revision_id.
1538
1492
 
1539
1493
        The content is copied from self.source to self.target.
1540
1494
 
1541
1495
        :param revision_id: if None all content is copied, if NULL_REVISION no
1542
1496
                            content is copied.
1543
 
        :return: FetchResult
 
1497
        :return: None.
1544
1498
        """
1545
1499
        raise NotImplementedError(self.fetch)
1546
1500
 
1626
1580
            pb.update(gettext('Creating new repository'))
1627
1581
            converted = self.target_format.initialize(self.repo_dir,
1628
1582
                                                      self.source_repo.is_shared())
1629
 
            with converted.lock_write():
 
1583
            converted.lock_write()
 
1584
            try:
1630
1585
                pb.update(gettext('Copying content'))
1631
1586
                self.source_repo.copy_content_into(converted)
 
1587
            finally:
 
1588
                converted.unlock()
1632
1589
            pb.update(gettext('Deleting old repository content'))
1633
1590
            self.repo_dir.transport.delete_tree('repository.backup')
1634
1591
            ui.ui_factory.note(gettext('repository converted'))
1639
1596
    # Filter ghosts, and null:
1640
1597
    if _mod_revision.NULL_REVISION in revision_graph:
1641
1598
        del revision_graph[_mod_revision.NULL_REVISION]
1642
 
    for key, parents in revision_graph.items():
 
1599
    for key, parents in viewitems(revision_graph):
1643
1600
        revision_graph[key] = tuple(parent for parent in parents if parent
1644
1601
                                    in revision_graph)
1645
1602
    return revision_graph