~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
60
60
_deprecation_warning_done = False
61
61
 
62
62
 
 
63
######################################################################
 
64
# Repositories
 
65
 
63
66
class Repository(object):
64
67
    """Repository holding history for one or more branches.
65
68
 
78
81
        )
79
82
 
80
83
    @needs_write_lock
81
 
    def add_inventory(self, revid, inv, parents):
82
 
        """Add the inventory inv to the repository as revid.
 
84
    def add_inventory(self, revision_id, inv, parents):
 
85
        """Add the inventory inv to the repository as revision_id.
83
86
        
84
 
        :param parents: The revision ids of the parents that revid
 
87
        :param parents: The revision ids of the parents that revision_id
85
88
                        is known to have and are in the repository already.
86
89
 
87
90
        returns the sha1 of the serialized inventory.
88
91
        """
89
 
        _mod_revision.check_not_reserved_id(revid)
90
 
        assert inv.revision_id is None or inv.revision_id == revid, \
 
92
        revision_id = osutils.safe_revision_id(revision_id)
 
93
        _mod_revision.check_not_reserved_id(revision_id)
 
94
        assert inv.revision_id is None or inv.revision_id == revision_id, \
91
95
            "Mismatch between inventory revision" \
92
 
            " id and insertion revid (%r, %r)" % (inv.revision_id, revid)
 
96
            " id and insertion revid (%r, %r)" % (inv.revision_id, revision_id)
93
97
        assert inv.root is not None
94
98
        inv_text = self.serialise_inventory(inv)
95
99
        inv_sha1 = osutils.sha_string(inv_text)
96
100
        inv_vf = self.control_weaves.get_weave('inventory',
97
101
                                               self.get_transaction())
98
 
        self._inventory_add_lines(inv_vf, revid, parents, osutils.split_lines(inv_text))
 
102
        self._inventory_add_lines(inv_vf, revision_id, parents,
 
103
                                  osutils.split_lines(inv_text))
99
104
        return inv_sha1
100
105
 
101
 
    def _inventory_add_lines(self, inv_vf, revid, parents, lines):
 
106
    def _inventory_add_lines(self, inv_vf, revision_id, parents, lines):
102
107
        final_parents = []
103
108
        for parent in parents:
104
109
            if parent in inv_vf:
105
110
                final_parents.append(parent)
106
111
 
107
 
        inv_vf.add_lines(revid, final_parents, lines)
 
112
        inv_vf.add_lines(revision_id, final_parents, lines)
108
113
 
109
114
    @needs_write_lock
110
 
    def add_revision(self, rev_id, rev, inv=None, config=None):
111
 
        """Add rev to the revision store as rev_id.
 
115
    def add_revision(self, revision_id, rev, inv=None, config=None):
 
116
        """Add rev to the revision store as revision_id.
112
117
 
113
 
        :param rev_id: the revision id to use.
 
118
        :param revision_id: the revision id to use.
114
119
        :param rev: The revision object.
115
120
        :param inv: The inventory for the revision. if None, it will be looked
116
121
                    up in the inventory storer
118
123
                       If supplied its signature_needed method will be used
119
124
                       to determine if a signature should be made.
120
125
        """
121
 
        _mod_revision.check_not_reserved_id(rev_id)
 
126
        revision_id = osutils.safe_revision_id(revision_id)
 
127
        # TODO: jam 20070210 Shouldn't we check rev.revision_id and
 
128
        #       rev.parent_ids?
 
129
        _mod_revision.check_not_reserved_id(revision_id)
122
130
        if config is not None and config.signature_needed():
123
131
            if inv is None:
124
 
                inv = self.get_inventory(rev_id)
 
132
                inv = self.get_inventory(revision_id)
125
133
            plaintext = Testament(rev, inv).as_short_text()
126
134
            self.store_revision_signature(
127
 
                gpg.GPGStrategy(config), plaintext, rev_id)
128
 
        if not rev_id in self.get_inventory_weave():
 
135
                gpg.GPGStrategy(config), plaintext, revision_id)
 
136
        if not revision_id in self.get_inventory_weave():
129
137
            if inv is None:
130
 
                raise errors.WeaveRevisionNotPresent(rev_id,
 
138
                raise errors.WeaveRevisionNotPresent(revision_id,
131
139
                                                     self.get_inventory_weave())
132
140
            else:
133
141
                # yes, this is not suitable for adding with ghosts.
134
 
                self.add_inventory(rev_id, inv, rev.parent_ids)
 
142
                self.add_inventory(revision_id, inv, rev.parent_ids)
135
143
        self._revision_store.add_revision(rev, self.get_transaction())
136
144
 
137
145
    @needs_read_lock
159
167
        if self._revision_store.text_store.listable():
160
168
            return self._revision_store.all_revision_ids(self.get_transaction())
161
169
        result = self._all_possible_ids()
 
170
        # TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
 
171
        #       ids. (It should, since _revision_store's API should change to
 
172
        #       return utf8 revision_ids)
162
173
        return self._eliminate_revisions_not_present(result)
163
174
 
164
175
    def break_lock(self):
287
298
 
288
299
        revision_id: only return revision ids included by revision_id.
289
300
        """
 
301
        revision_id = osutils.safe_revision_id(revision_id)
290
302
        return InterRepository.get(other, self).missing_revision_ids(revision_id)
291
303
 
292
304
    @staticmethod
305
317
        This is a destructive operation! Do not use it on existing 
306
318
        repositories.
307
319
        """
 
320
        revision_id = osutils.safe_revision_id(revision_id)
308
321
        return InterRepository.get(self, destination).copy_content(revision_id, basis)
309
322
 
310
323
    def fetch(self, source, revision_id=None, pb=None):
312
325
 
313
326
        If revision_id is None all content is copied.
314
327
        """
 
328
        revision_id = osutils.safe_revision_id(revision_id)
315
329
        return InterRepository.get(source, self).fetch(revision_id=revision_id,
316
330
                                                       pb=pb)
317
331
 
329
343
        :param revprops: Optional dictionary of revision properties.
330
344
        :param revision_id: Optional revision id.
331
345
        """
 
346
        revision_id = osutils.safe_revision_id(revision_id)
332
347
        return _CommitBuilder(self, parents, config, timestamp, timezone,
333
348
                              committer, revprops, revision_id)
334
349
 
360
375
    @needs_read_lock
361
376
    def has_revision(self, revision_id):
362
377
        """True if this repository has a copy of the revision."""
 
378
        revision_id = osutils.safe_revision_id(revision_id)
363
379
        return self._revision_store.has_revision_id(revision_id,
364
380
                                                    self.get_transaction())
365
381
 
375
391
        if not revision_id or not isinstance(revision_id, basestring):
376
392
            raise errors.InvalidRevisionId(revision_id=revision_id,
377
393
                                           branch=self)
378
 
        return self._revision_store.get_revisions([revision_id],
379
 
                                                  self.get_transaction())[0]
 
394
        return self.get_revisions([revision_id])[0]
 
395
 
380
396
    @needs_read_lock
381
397
    def get_revisions(self, revision_ids):
382
 
        return self._revision_store.get_revisions(revision_ids,
 
398
        revision_ids = [osutils.safe_revision_id(r) for r in revision_ids]
 
399
        revs = self._revision_store.get_revisions(revision_ids,
383
400
                                                  self.get_transaction())
 
401
        for rev in revs:
 
402
            assert not isinstance(rev.revision_id, unicode)
 
403
            for parent_id in rev.parent_ids:
 
404
                assert not isinstance(parent_id, unicode)
 
405
        return revs
384
406
 
385
407
    @needs_read_lock
386
408
    def get_revision_xml(self, revision_id):
387
 
        rev = self.get_revision(revision_id) 
 
409
        # TODO: jam 20070210 This shouldn't be necessary since get_revision
 
410
        #       would have already do it.
 
411
        # TODO: jam 20070210 Just use _serializer.write_revision_to_string()
 
412
        revision_id = osutils.safe_revision_id(revision_id)
 
413
        rev = self.get_revision(revision_id)
388
414
        rev_tmp = StringIO()
389
415
        # the current serializer..
390
416
        self._revision_store._serializer.write_revision(rev, rev_tmp)
394
420
    @needs_read_lock
395
421
    def get_revision(self, revision_id):
396
422
        """Return the Revision object for a named revision"""
 
423
        # TODO: jam 20070210 get_revision_reconcile should do this for us
 
424
        revision_id = osutils.safe_revision_id(revision_id)
397
425
        r = self.get_revision_reconcile(revision_id)
398
426
        # weave corruption can lead to absent revision markers that should be
399
427
        # present.
455
483
 
456
484
    @needs_write_lock
457
485
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
 
486
        revision_id = osutils.safe_revision_id(revision_id)
458
487
        signature = gpg_strategy.sign(plaintext)
459
488
        self._revision_store.add_revision_signature_text(revision_id,
460
489
                                                         signature,
471
500
        assert self._serializer.support_altered_by_hack, \
472
501
            ("fileids_altered_by_revision_ids only supported for branches " 
473
502
             "which store inventory as unnested xml, not on %r" % self)
474
 
        selected_revision_ids = set(revision_ids)
 
503
        selected_revision_ids = set(osutils.safe_revision_id(r)
 
504
                                    for r in revision_ids)
475
505
        w = self.get_inventory_weave()
476
506
        result = {}
477
507
 
541
571
    @needs_read_lock
542
572
    def get_inventory(self, revision_id):
543
573
        """Get Inventory object by hash."""
 
574
        # TODO: jam 20070210 Technically we don't need to sanitize, since all
 
575
        #       called functions must sanitize.
 
576
        revision_id = osutils.safe_revision_id(revision_id)
544
577
        return self.deserialise_inventory(
545
578
            revision_id, self.get_inventory_xml(revision_id))
546
579
 
550
583
        :param revision_id: The expected revision id of the inventory.
551
584
        :param xml: A serialised inventory.
552
585
        """
 
586
        revision_id = osutils.safe_revision_id(revision_id)
553
587
        result = self._serializer.read_inventory_from_string(xml)
554
588
        result.root.revision = revision_id
555
589
        return result
560
594
    @needs_read_lock
561
595
    def get_inventory_xml(self, revision_id):
562
596
        """Get inventory XML as a file object."""
 
597
        revision_id = osutils.safe_revision_id(revision_id)
563
598
        try:
564
 
            assert isinstance(revision_id, basestring), type(revision_id)
 
599
            assert isinstance(revision_id, str), type(revision_id)
565
600
            iw = self.get_inventory_weave()
566
601
            return iw.get_text(revision_id)
567
602
        except IndexError:
571
606
    def get_inventory_sha1(self, revision_id):
572
607
        """Return the sha1 hash of the inventory entry
573
608
        """
 
609
        # TODO: jam 20070210 Shouldn't this be deprecated / removed?
 
610
        revision_id = osutils.safe_revision_id(revision_id)
574
611
        return self.get_revision(revision_id).inventory_sha1
575
612
 
576
613
    @needs_read_lock
585
622
        # special case NULL_REVISION
586
623
        if revision_id == _mod_revision.NULL_REVISION:
587
624
            return {}
 
625
        revision_id = osutils.safe_revision_id(revision_id)
588
626
        a_weave = self.get_inventory_weave()
589
627
        all_revisions = self._eliminate_revisions_not_present(
590
628
                                a_weave.versions())
618
656
            pending = set(self.all_revision_ids())
619
657
            required = set([])
620
658
        else:
621
 
            pending = set(revision_ids)
 
659
            pending = set(osutils.safe_revision_id(r) for r in revision_ids)
622
660
            # special case NULL_REVISION
623
661
            if _mod_revision.NULL_REVISION in pending:
624
662
                pending.remove(_mod_revision.NULL_REVISION)
657
695
        :param revision_id: The revision id to start with.  All its lefthand
658
696
            ancestors will be traversed.
659
697
        """
 
698
        revision_id = osutils.safe_revision_id(revision_id)
660
699
        if revision_id in (None, _mod_revision.NULL_REVISION):
661
700
            return
662
701
        next_id = revision_id
710
749
            return RevisionTree(self, Inventory(root_id=None), 
711
750
                                _mod_revision.NULL_REVISION)
712
751
        else:
 
752
            revision_id = osutils.safe_revision_id(revision_id)
713
753
            inv = self.get_revision_inventory(revision_id)
714
754
            return RevisionTree(self, inv, revision_id)
715
755
 
737
777
        """
738
778
        if revision_id is None:
739
779
            return [None]
 
780
        revision_id = osutils.safe_revision_id(revision_id)
740
781
        if not self.has_revision(revision_id):
741
782
            raise errors.NoSuchRevision(self, revision_id)
742
783
        w = self.get_inventory_weave()
751
792
        - it writes to stdout, it assumes that that is valid etc. Fix
752
793
        by creating a new more flexible convenience function.
753
794
        """
 
795
        revision_id = osutils.safe_revision_id(revision_id)
754
796
        tree = self.revision_tree(revision_id)
755
797
        # use inventory as it was in that revision
756
798
        file_id = tree.inventory.path2id(file)
764
806
    def get_transaction(self):
765
807
        return self.control_files.get_transaction()
766
808
 
767
 
    def revision_parents(self, revid):
768
 
        return self.get_inventory_weave().parent_names(revid)
 
809
    def revision_parents(self, revision_id):
 
810
        revision_id = osutils.safe_revision_id(revision_id)
 
811
        return self.get_inventory_weave().parent_names(revision_id)
769
812
 
770
813
    @needs_write_lock
771
814
    def set_make_working_trees(self, new_value):
785
828
 
786
829
    @needs_write_lock
787
830
    def sign_revision(self, revision_id, gpg_strategy):
 
831
        revision_id = osutils.safe_revision_id(revision_id)
788
832
        plaintext = Testament.from_revision(self, revision_id).as_short_text()
789
833
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)
790
834
 
791
835
    @needs_read_lock
792
836
    def has_signature_for_revision_id(self, revision_id):
793
837
        """Query for a revision signature for revision_id in the repository."""
 
838
        revision_id = osutils.safe_revision_id(revision_id)
794
839
        return self._revision_store.has_signature(revision_id,
795
840
                                                  self.get_transaction())
796
841
 
797
842
    @needs_read_lock
798
843
    def get_signature_text(self, revision_id):
799
844
        """Return the text for a signature."""
 
845
        revision_id = osutils.safe_revision_id(revision_id)
800
846
        return self._revision_store.get_signature_text(revision_id,
801
847
                                                       self.get_transaction())
802
848
 
812
858
        if not revision_ids:
813
859
            raise ValueError("revision_ids must be non-empty in %s.check" 
814
860
                    % (self,))
 
861
        revision_ids = [osutils.safe_revision_id(r) for r in revision_ids]
815
862
        return self._check(revision_ids)
816
863
 
817
864
    def _check(self, revision_ids):
840
887
                    revision_id.encode('ascii')
841
888
                except UnicodeEncodeError:
842
889
                    raise errors.NonAsciiRevisionId(method, self)
 
890
            else:
 
891
                try:
 
892
                    revision_id.decode('ascii')
 
893
                except UnicodeDecodeError:
 
894
                    raise errors.NonAsciiRevisionId(method, self)
843
895
 
844
896
 
845
897
 
987
1039
"""
988
1040
 
989
1041
 
 
1042
#####################################################################
 
1043
# Repository Formats
 
1044
 
990
1045
class RepositoryFormat(object):
991
1046
    """A repository format.
992
1047
 
1084
1139
        from bzrlib.store.revision.text import TextRevisionStore
1085
1140
        dir_mode = control_files._dir_mode
1086
1141
        file_mode = control_files._file_mode
1087
 
        text_store =TextStore(transport.clone(name),
 
1142
        text_store = TextStore(transport.clone(name),
1088
1143
                              prefixed=prefixed,
1089
1144
                              compressed=compressed,
1090
1145
                              dir_mode=dir_mode,
1253
1308
        # generic, possibly worst case, slow code path.
1254
1309
        target_ids = set(self.target.all_revision_ids())
1255
1310
        if revision_id is not None:
 
1311
            # TODO: jam 20070210 InterRepository is internal enough that it
 
1312
            #       should assume revision_ids are already utf-8
 
1313
            revision_id = osutils.safe_revision_id(revision_id)
1256
1314
            source_ids = self.source.get_ancestry(revision_id)
1257
1315
            assert source_ids[0] is None
1258
1316
            source_ids.pop(0)
1302
1360
            self.target.set_make_working_trees(self.source.make_working_trees())
1303
1361
        except NotImplementedError:
1304
1362
            pass
 
1363
        # TODO: jam 20070210 This is fairly internal, so we should probably
 
1364
        #       just assert that revision_id is not unicode.
 
1365
        revision_id = osutils.safe_revision_id(revision_id)
1305
1366
        # grab the basis available data
1306
1367
        if basis is not None:
1307
1368
            self.target.fetch(basis, revision_id=revision_id)
1318
1379
        mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1319
1380
               self.source, self.source._format, self.target, 
1320
1381
               self.target._format)
 
1382
        # TODO: jam 20070210 This should be an assert, not a translate
 
1383
        revision_id = osutils.safe_revision_id(revision_id)
1321
1384
        f = GenericRepoFetcher(to_repository=self.target,
1322
1385
                               from_repository=self.source,
1323
1386
                               last_revision=revision_id,
1360
1423
    def copy_content(self, revision_id=None, basis=None):
1361
1424
        """See InterRepository.copy_content()."""
1362
1425
        # weave specific optimised path:
 
1426
        # TODO: jam 20070210 Internal, should be an assert, not translate
 
1427
        revision_id = osutils.safe_revision_id(revision_id)
1363
1428
        if basis is not None:
1364
1429
            # copy the basis in, then fetch remaining data.
1365
1430
            basis.copy_content_into(self.target, revision_id)
1402
1467
        from bzrlib.fetch import GenericRepoFetcher
1403
1468
        mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1404
1469
               self.source, self.source._format, self.target, self.target._format)
 
1470
        # TODO: jam 20070210 This should be an assert, not a translate
 
1471
        revision_id = osutils.safe_revision_id(revision_id)
1405
1472
        f = GenericRepoFetcher(to_repository=self.target,
1406
1473
                               from_repository=self.source,
1407
1474
                               last_revision=revision_id,
1479
1546
        from bzrlib.fetch import KnitRepoFetcher
1480
1547
        mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1481
1548
               self.source, self.source._format, self.target, self.target._format)
 
1549
        # TODO: jam 20070210 This should be an assert, not a translate
 
1550
        revision_id = osutils.safe_revision_id(revision_id)
1482
1551
        f = KnitRepoFetcher(to_repository=self.target,
1483
1552
                            from_repository=self.source,
1484
1553
                            last_revision=revision_id,
1537
1606
    def fetch(self, revision_id=None, pb=None):
1538
1607
        """See InterRepository.fetch()."""
1539
1608
        from bzrlib.fetch import Model1toKnit2Fetcher
 
1609
        # TODO: jam 20070210 This should be an assert, not a translate
 
1610
        revision_id = osutils.safe_revision_id(revision_id)
1540
1611
        f = Model1toKnit2Fetcher(to_repository=self.target,
1541
1612
                                 from_repository=self.source,
1542
1613
                                 last_revision=revision_id,
1558
1629
            self.target.set_make_working_trees(self.source.make_working_trees())
1559
1630
        except NotImplementedError:
1560
1631
            pass
 
1632
        # TODO: jam 20070210 Internal, assert, don't translate
 
1633
        revision_id = osutils.safe_revision_id(revision_id)
1561
1634
        # grab the basis available data
1562
1635
        if basis is not None:
1563
1636
            self.target.fetch(basis, revision_id=revision_id)
1593
1666
        mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1594
1667
               self.source, self.source._format, self.target, 
1595
1668
               self.target._format)
 
1669
        # TODO: jam 20070210 This should be an assert, not a translate
 
1670
        revision_id = osutils.safe_revision_id(revision_id)
1596
1671
        f = Knit1to2Fetcher(to_repository=self.target,
1597
1672
                            from_repository=self.source,
1598
1673
                            last_revision=revision_id,
1780
1855
            self._committer = committer
1781
1856
 
1782
1857
        self.new_inventory = Inventory(None)
1783
 
        self._new_revision_id = revision_id
 
1858
        self._new_revision_id = osutils.safe_revision_id(revision_id)
1784
1859
        self.parents = parents
1785
1860
        self.repository = repository
1786
1861
 
2012
2087
 
2013
2088
 
2014
2089
def _unescaper(match, _map=_unescape_map):
2015
 
    return _map[match.group(1)]
 
2090
    code = match.group(1)
 
2091
    try:
 
2092
        return _map[code]
 
2093
    except KeyError:
 
2094
        if not code.startswith('#'):
 
2095
            raise
 
2096
        return unichr(int(code[1:])).encode('utf8')
2016
2097
 
2017
2098
 
2018
2099
_unescape_re = None