~ubuntu-branches/ubuntu/raring/bzr-svn/raring

« back to all changes in this revision

Viewing changes to repository.py

  • Committer: Bazaar Package Importer
  • Author(s): Jelmer Vernooij
  • Date: 2010-07-30 23:14:36 UTC
  • mfrom: (1.1.28 upstream) (3.3.4 sid)
  • Revision ID: james.westby@ubuntu.com-20100730231436-po8j0ibgjn2d6hy0
Tags: 1.0.3-1
* New upstream release.
 + Provides BranchConfig._get_change_editor. Closes: #572109
 + Supports more trunk layout levels. Closes: #573988
* Bump standards version to 3.9.1.
* Mark as supporting bzr 2.2.
* Suggest bzr-rewrite rather than bzr-rebase. LP: #481730

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
    ensure_null,
53
53
    )
54
54
from bzrlib.trace import (
55
 
    mutter,
56
55
    note,
57
56
    )
58
57
from bzrlib.transport import (
90
89
    foreign_vcs_svn,
91
90
    find_mappings_fileprops,
92
91
    find_mapping_revprops,
93
 
    is_bzr_revision_revprops, 
 
92
    is_bzr_revision_revprops,
94
93
    mapping_registry,
95
94
    parse_svn_dateprop,
96
95
    )
166
165
class SvnRepositoryFormat(RepositoryFormat):
167
166
    """Repository format for Subversion repositories (accessed using svn_ra).
168
167
    """
 
168
 
169
169
    rich_root_data = True
170
170
    supports_tree_reference = False
171
171
    _serializer = None
210
210
        self.inconsistent_stored_lhs_parent = 0
211
211
        self.invalid_fileprop_cnt = 0
212
212
        self.text_revision_in_parents_cnt = 0
213
 
        self.text_not_changed_cnt = 0
214
213
        self.paths_not_under_branch_root = 0
215
214
        self.different_uuid_cnt = 0
216
215
        self.multiple_mappings_cnt = 0
230
229
        if self.hidden_rev_cnt > 0:
231
230
            note('%6d hidden bzr-created revisions', self.hidden_rev_cnt)
232
231
        if self.inconsistent_stored_lhs_parent > 0:
233
 
            note('%6d inconsistent stored left-hand side parent revision ids', 
 
232
            note('%6d inconsistent stored left-hand side parent revision ids',
234
233
                self.inconsistent_stored_lhs_parent)
235
234
        if self.invalid_fileprop_cnt > 0:
236
 
            note('%6d invalid bzr-related file properties', 
 
235
            note('%6d invalid bzr-related file properties',
237
236
                 self.invalid_fileprop_cnt)
238
 
        if self.text_not_changed_cnt > 0:
239
 
            note('%6d files were not changed but had their revision/fileid changed',
240
 
                 self.text_not_changed_cnt)
241
237
        if self.paths_not_under_branch_root > 0:
242
238
            note('%6d files were modified that were not under the branch root',
243
239
                 self.paths_not_under_branch_root)
276
272
        mapping = revmeta.get_original_mapping()
277
273
        if mapping is None:
278
274
            return
279
 
        if (len(fileprop_mappings) > 0 and 
280
 
            find_mapping_revprops(revmeta.get_revprops()) not in 
 
275
        if (len(fileprop_mappings) > 0 and
 
276
            find_mapping_revprops(revmeta.get_revprops()) not in
281
277
                (None, fileprop_mappings[0])):
282
278
            self.inconsistent_fileprop_revprop_cnt += 1
283
279
        self.checked_roundtripped_cnt += 1
320
316
    def check_texts(self, revmeta, mapping):
321
317
        # Check for inconsistencies in text file ids/revisions
322
318
        text_revisions = revmeta.get_text_revisions(mapping)
323
 
        text_parents = revmeta.get_text_parents(mapping)
324
319
        text_ids = revmeta.get_fileid_overrides(mapping)
325
320
        fileid_map = self.repository.get_fileid_map(revmeta, mapping)
326
321
        path_changes = revmeta.get_paths()
327
 
        for path in set(text_ids.keys() + text_revisions.keys() + text_parents.keys()):
328
 
            if (path in text_revisions and
329
 
                text_revisions[path] in text_parents.get(path, [])):
330
 
                self.text_revision_in_parents_cnt += 1
 
322
        for path in set(text_ids.keys() + text_revisions.keys()):
331
323
            full_path = urlutils.join(revmeta.branch_path, path)
332
 
            if not full_path in path_changes:
333
 
                mutter('in %s text %r/%r (%r) id changed but not changed', 
334
 
                       revmeta.get_revision_id(mapping),
335
 
                       text_ids.get(path), text_revisions.get(path),
336
 
                       text_parents.get(path))
337
 
                self.text_not_changed_cnt += 1
338
 
                continue
339
 
            # TODO Check consistency against parent data 
340
 
        for path, tps in text_parents.iteritems():
341
 
            if len(tps) > len(revmeta.get_parent_ids(mapping)):
342
 
                self.invalid_text_parents_len += 1
 
324
            # TODO Check consistency against parent data
343
325
        ghost_parents = False
344
326
        parent_revmetas = []
345
327
        parent_mappings = []
355
337
                parent_fileid_map = self.repository.get_fileid_map(parent_revmeta, parent_mapping)
356
338
                parent_fileid_maps.append(parent_fileid_map)
357
339
        for path, text_revision in text_revisions.iteritems():
358
 
            # Every text revision either has to match the actual revision's 
359
 
            # revision id (if it was last changed there) or the text revisions 
 
340
            # Every text revision either has to match the actual revision's
 
341
            # revision id (if it was last changed there) or the text revisions
360
342
            # in one of the parents.
361
343
            fileid = fileid_map.lookup(mapping, path)[0]
362
344
            parent_text_revisions = []
363
345
            for parent_fileid_map, parent_mapping in zip(parent_fileid_maps, parent_mappings):
364
346
                parent_text_revisions.append(parent_fileid_map.reverse_lookup(parent_mapping, fileid))
365
 
            if (text_revision != revmeta.get_revision_id(mapping) and 
 
347
            if (text_revision != revmeta.get_revision_id(mapping) and
366
348
                    not ghost_parents and not text_revision in parent_text_revisions):
367
349
                self.invalid_text_revisions += 1
368
350
 
369
351
 
370
352
class SvnRepository(ForeignRepository):
371
353
    """
372
 
    Provides a simplified interface to a Subversion repository 
 
354
    Provides a simplified interface to a Subversion repository
373
355
    by using the RA (remote access) API from subversion
374
356
    """
375
357
    def __init__(self, bzrdir, transport, branch_path=None):
409
391
        use_cache = self.get_config().get_use_cache()
410
392
 
411
393
        if use_cache is None:
412
 
            # TODO: Don't enable log cache in some situations, e.g. 
 
394
            # TODO: Don't enable log cache in some situations, e.g.
413
395
            # for large repositories ?
414
396
            if self.base.startswith("file://"):
415
397
                # Default to no log caching for local connections
449
431
 
450
432
        self.branchprop_list = PathPropertyProvider(self._log)
451
433
 
452
 
        self._revmeta_provider = revmeta.RevisionMetadataProvider(self, 
 
434
        self._revmeta_provider = revmeta.RevisionMetadataProvider(self,
453
435
                use_cache,
454
436
                self.transport.has_capability("commit-revprops") in (True, None))
455
437
 
523
505
 
524
506
        for fileid, altered_versions in fileids.iteritems():
525
507
            yield ("file", fileid, altered_versions)
526
 
        
 
508
 
527
509
        # We're done with the files_pb.  Note that it finished by the caller,
528
510
        # just as it was created by the caller.
529
511
        del _files_pb
549
531
            return parse_svn_dateprop(self._log.revprop_list(revnum)[subvertpy.properties.PROP_REVISION_DATE])
550
532
        if committers is not None and revid is not None:
551
533
            all_committers = set()
552
 
            for rev in self.get_revisions(filter(lambda r: r is not None and r != NULL_REVISION, self.get_ancestry(revid))):
 
534
            for rev in self.get_revisions(filter(lambda r: r is not None and r != NULL_REVISION, self.has_revisions(self.get_ancestry(revid)))):
553
535
                if rev.committer != '':
554
536
                    all_committers.add(rev.committer)
555
537
            result['committers'] = len(all_committers)
568
550
        return mapping_registry.get_default()
569
551
 
570
552
    def _properties_to_set(self, mapping):
571
 
        """Determine what sort of custom properties to set when 
 
553
        """Determine what sort of custom properties to set when
572
554
        committing a new round-tripped revision.
573
 
        
574
 
        :return: tuple with two booleans: whether to use revision properties 
 
555
 
 
556
        :return: tuple with two booleans: whether to use revision properties
575
557
            and whether to use file properties.
576
558
        """
577
559
        supports_custom_revprops = self.transport.has_capability("commit-revprops")
614
596
            parent_branch_path = parentrevmeta.branch_path
615
597
            parentrevnum = parentrevmeta.revnum
616
598
            start_empty = False
617
 
        editor = TreeDeltaBuildEditor(revision.svn_meta, revision.mapping, 
618
 
                                      self.get_fileid_map(revision.svn_meta, revision.mapping), 
 
599
        editor = TreeDeltaBuildEditor(revision.svn_meta, revision.mapping,
 
600
                                      self.get_fileid_map(revision.svn_meta, revision.mapping),
619
601
                                      parentfileidmap)
620
602
        conn = self.transport.get_connection(parent_branch_path)
621
603
        try:
650
632
 
651
633
    def get_layout(self):
652
634
        """Determine layout to use for this repository.
653
 
        
654
 
        This will use whatever layout the user has specified, or 
 
635
 
 
636
        This will use whatever layout the user has specified, or
655
637
        otherwise the layout that was guessed by bzr-svn.
656
638
        """
657
639
        return self.get_layout_source()[0]
682
664
        return self._layout, self._layout_source
683
665
 
684
666
    def _find_guessed_layout(self):
685
 
        # TODO: Retrieve guessed-layout from config and see if it accepts self._hinted_branch_path
 
667
        # Retrieve guessed-layout from config and see if it accepts self._hinted_branch_path
686
668
        layoutname = self.get_config().get_guessed_layout()
687
669
        if layoutname is not None:
688
670
            config_guessed_layout = layout.layout_registry.get(layoutname)()
689
 
            if (self._hinted_branch_path is None or 
 
671
            if (self._hinted_branch_path is None or
690
672
                config_guessed_layout.is_branch(self._hinted_branch_path)):
691
673
                self._guessed_layout = config_guessed_layout
692
674
                self._guessed_appropriate_layout = config_guessed_layout
693
675
                return
694
676
        else:
695
677
            config_guessed_layout = None
 
678
        # No guessed layout stored yet or it doesn't accept self._hinted_branch_path
696
679
        revnum = self.get_latest_revnum()
697
 
        (self._guessed_layout, self._guessed_appropriate_layout) = repository_guess_layout(self, 
 
680
        (self._guessed_layout, self._guessed_appropriate_layout) = repository_guess_layout(self,
698
681
                    revnum, self._hinted_branch_path)
699
682
        if self._guessed_layout != config_guessed_layout and revnum > 200:
700
683
            self.get_config().set_guessed_layout(self._guessed_layout)
741
724
        assert revision_id != None
742
725
        return self.revision_tree(revision_id).inventory
743
726
 
744
 
    def _iter_inventories(self, revision_ids):
 
727
    def _iter_inventories(self, revision_ids, ordering):
745
728
        for revid in revision_ids:
746
729
            yield self.get_inventory(revid)
747
730
 
749
732
        return self.fileid_map.get_map(revmeta.get_foreign_revid(), mapping)
750
733
 
751
734
    def all_revision_ids(self, layout=None, mapping=None):
752
 
        """Find all revision ids in this repository, using the specified or 
 
735
        """Find all revision ids in this repository, using the specified or
753
736
        default mapping.
754
 
        
755
 
        :note: This will use the standard layout to find the revisions, 
756
 
               any revisions using non-standard branch locations (even 
757
 
               if part of the ancestry of valid revisions) won't be 
 
737
 
 
738
        :note: This will use the standard layout to find the revisions,
 
739
               any revisions using non-standard branch locations (even
 
740
               if part of the ancestry of valid revisions) won't be
758
741
               returned.
759
742
        """
760
743
        if mapping is None:
768
751
 
769
752
    def set_make_working_trees(self, new_value):
770
753
        """See Repository.set_make_working_trees()."""
771
 
        pass # ignored, nowhere to store it... 
 
754
        pass # ignored, nowhere to store it...
772
755
 
773
756
    def make_working_trees(self):
774
757
        """See Repository.make_working_trees().
775
758
 
776
 
        Always returns False, as working trees are never created inside 
 
759
        Always returns False, as working trees are never created inside
777
760
        Subversion repositories.
778
761
        """
779
762
        return False
874
857
        ancestry.reverse()
875
858
        return ancestry
876
859
 
 
860
    def get_known_graph_ancestry(self, keys):
 
861
        """Get a KnownGraph instance with the ancestry of keys."""
 
862
        # most basic implementation is a loop around get_parent_map
 
863
        pending = set(keys)
 
864
        parent_map = {}
 
865
        while pending:
 
866
            this_parent_map = self.get_parent_map(pending)
 
867
            parent_map.update(this_parent_map)
 
868
            pending = set()
 
869
            map(pending.update, this_parent_map.itervalues())
 
870
            pending = pending.difference(parent_map)
 
871
        kg = graph.KnownGraph(parent_map)
 
872
        return kg
 
873
 
877
874
    def has_revisions(self, revision_ids):
878
875
        ret = set()
879
876
        for revision_id in revision_ids:
942
939
            raise bzr_errors.InvalidRevisionId(revision_id=revision_id, branch=self)
943
940
 
944
941
        revmeta, mapping = self._get_revmeta(revision_id)
945
 
        
 
942
 
946
943
        return revmeta.get_revision(mapping)
947
944
 
948
945
    def get_revisions(self, revision_ids):
972
969
        return revmeta.get_revision_id(mapping)
973
970
 
974
971
    def generate_revision_id(self, revnum, path, mapping):
975
 
        """Generate an unambiguous revision id. 
976
 
        
 
972
        """Generate an unambiguous revision id.
 
973
 
977
974
        :param revnum: Subversion revision number.
978
975
        :param path: Branch path.
979
976
        :param mapping: Mapping to use.
984
981
        assert isinstance(revnum, int)
985
982
        return self.lookup_foreign_revision_id((self.uuid, path, revnum), mapping)
986
983
 
987
 
    def lookup_bzr_revision_id(self, revid, layout=None, ancestry=None, 
 
984
    def lookup_bzr_revision_id(self, revid, layout=None, ancestry=None,
988
985
                           project=None, foreign_sibling=None):
989
986
        """Parse an existing Subversion-based revision id.
990
987
 
991
988
        :param revid: The revision id.
992
 
        :param layout: Optional repository layout to use when searching for 
 
989
        :param layout: Optional repository layout to use when searching for
993
990
                       revisions
994
991
        :raises: NoSuchRevision
995
992
        :return: Tuple with foreign revision id and mapping.
1004
1001
            if uuid == self.uuid:
1005
1002
                return (self.uuid, branch_path, revnum), mapping
1006
1003
            # If the UUID doesn't match, this may still be a valid revision
1007
 
            # id; a revision from another SVN repository may be pushed into 
 
1004
            # id; a revision from another SVN repository may be pushed into
1008
1005
            # this one.
1009
1006
        except bzr_errors.InvalidRevisionId:
1010
1007
            pass
1019
1016
        return self.revmap.get_branch_revnum(revid, layout, project)
1020
1017
 
1021
1018
    def seen_bzr_revprops(self):
1022
 
        """Check whether bzr-specific custom revision properties are present on this 
 
1019
        """Check whether bzr-specific custom revision properties are present on this
1023
1020
        repository.
1024
1021
 
1025
1022
        """
1039
1036
        """Check whether a signature exists for a particular revision id.
1040
1037
 
1041
1038
        :param revision_id: Revision id for which the signatures should be looked up.
1042
 
        :return: False, as no signatures are stored for revisions in Subversion 
 
1039
        :return: False, as no signatures are stored for revisions in Subversion
1043
1040
            at the moment.
1044
1041
        """
1045
1042
        try:
1053
1050
    def get_signature_text(self, revision_id):
1054
1051
        """Return the signature text for a particular revision.
1055
1052
 
1056
 
        :param revision_id: Id of the revision for which to return the 
 
1053
        :param revision_id: Id of the revision for which to return the
1057
1054
                            signature.
1058
1055
        :raises NoSuchRevision: Always
1059
1056
        """
1080
1077
        This will include branches inside other branches.
1081
1078
        """
1082
1079
        from bzrlib.plugins.svn.branch import SvnBranch # avoid circular imports
1083
 
        # All branches use this repository, so the using argument can be 
 
1080
        # All branches use this repository, so the using argument can be
1084
1081
        # ignored.
1085
1082
        if layout is None:
1086
1083
            layout = self.get_layout()
1097
1094
        return branches
1098
1095
 
1099
1096
    @needs_read_lock
1100
 
    def find_tags_between(self, project, layout, mapping, from_revnum, 
 
1097
    def find_tags_between(self, project, layout, mapping, from_revnum,
1101
1098
                          to_revnum, tags=None):
1102
1099
        if tags is None:
1103
1100
            tags = {}
1156
1153
 
1157
1154
        if not layout in self._cached_tags:
1158
1155
            self._cached_tags[layout] = self.find_tags_between(project=project,
1159
 
                    layout=layout, mapping=mapping, from_revnum=0, 
 
1156
                    layout=layout, mapping=mapping, from_revnum=0,
1160
1157
                    to_revnum=revnum)
1161
1158
        return self._cached_tags[layout]
1162
1159
 
1163
1160
    def find_branchpaths(self, layout, from_revnum, to_revnum, project=None):
1164
 
        """Find all branch paths that were changed in the specified revision 
 
1161
        """Find all branch paths that were changed in the specified revision
1165
1162
        range.
1166
1163
 
1167
1164
        :note: This ignores forbidden paths.
1168
1165
 
1169
1166
        :param revnum: Revision to search for branches.
1170
 
        :return: iterator that returns tuples with (path, revision number, 
1171
 
            still exists). The revision number is the revision in which the 
 
1167
        :return: iterator that returns tuples with (path, revision number,
 
1168
            still exists). The revision number is the revision in which the
1172
1169
            branch last existed.
1173
1170
        """
1174
1171
        assert from_revnum >= to_revnum
1196
1193
                            ret.append((p, created_branches[p], False))
1197
1194
                            del created_branches[p]
1198
1195
 
1199
 
                        if paths[p][0] in ('A', 'R', 'M'): 
 
1196
                        if paths[p][0] in ('A', 'R', 'M'):
1200
1197
                            created_branches[p] = i
1201
1198
                    elif layout.is_branch_or_tag_parent(p, project):
1202
1199
                        if paths[p][0] in ('R', 'D'):
1204
1201
                            for c in k:
1205
1202
                                if c.startswith(p+"/") and c in created_branches:
1206
1203
                                    ret.append((c, created_branches[c], False))
1207
 
                                    del created_branches[c] 
 
1204
                                    del created_branches[c]
1208
1205
                        if paths[p][0] in ('A', 'R') and paths[p][1] is not None:
1209
1206
                            parents = [p]
1210
1207
                            while parents:
1237
1234
        """See Repository.get_physical_lock_status()."""
1238
1235
        return False
1239
1236
 
1240
 
    def get_commit_builder(self, branch, parents, config, timestamp=None, 
1241
 
                           timezone=None, committer=None, revprops=None, 
 
1237
    def get_commit_builder(self, branch, parents, config, timestamp=None,
 
1238
                           timezone=None, committer=None, revprops=None,
1242
1239
                           revision_id=None):
1243
1240
        """See Repository.get_commit_builder()."""
1244
1241
        from bzrlib.plugins.svn.commit import SvnCommitBuilder
1251
1248
        else:
1252
1249
            base_foreign_revid, base_mapping = \
1253
1250
                self.lookup_bzr_revision_id(parents[0], project=branch.project)
1254
 
        return SvnCommitBuilder(self, branch.get_branch_path(), parents, 
1255
 
                                config, timestamp, timezone, committer, 
1256
 
                                revprops, revision_id, 
 
1251
        return SvnCommitBuilder(self, branch.get_branch_path(), parents,
 
1252
                                config, timestamp, timezone, committer,
 
1253
                                revprops, revision_id,
1257
1254
                                base_foreign_revid, base_mapping,
1258
1255
                                append_revisions_only=append_revisions_only)
1259
1256
 
1260
 
    def find_fileprop_paths(self, layout, from_revnum, to_revnum, 
 
1257
    def find_fileprop_paths(self, layout, from_revnum, to_revnum,
1261
1258
                               project=None, check_removed=False):
1262
1259
        assert from_revnum >= to_revnum
1263
1260
        if not check_removed and to_revnum == 0:
1280
1277
        """See Repository.commit_write_group()."""
1281
1278
        if not self.is_write_locked():
1282
1279
            raise bzr_errors.NotWriteLocked(self)
1283
 
        self._write_group = None 
 
1280
        self._write_group = None