~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/weaverepo.py

  • Committer: Andrew Bennetts
  • Date: 2009-04-02 05:53:12 UTC
  • mto: This revision was merged to the branch mainline in revision 4242.
  • Revision ID: andrew.bennetts@canonical.com-20090402055312-h7mvgumvm7e620mj
Fix nits in spelling and naming.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
20
20
ghosts.
21
21
"""
22
22
 
23
 
import gzip
24
23
import os
25
24
from cStringIO import StringIO
26
25
import urllib
27
26
 
28
27
from bzrlib.lazy_import import lazy_import
29
28
lazy_import(globals(), """
30
 
import itertools
31
 
 
32
29
from bzrlib import (
33
30
    xml5,
34
 
    graph as _mod_graph,
35
 
    ui,
36
31
    )
37
32
""")
38
33
from bzrlib import (
 
34
    bzrdir,
39
35
    debug,
40
36
    errors,
41
37
    lockable_files,
42
38
    lockdir,
43
39
    osutils,
44
 
    symbol_versioning,
45
 
    trace,
46
 
    tuned_gzip,
 
40
    revision as _mod_revision,
47
41
    urlutils,
48
42
    versionedfile,
49
43
    weave,
51
45
    )
52
46
from bzrlib.decorators import needs_read_lock, needs_write_lock
53
47
from bzrlib.repository import (
54
 
    InterRepository,
 
48
    CommitBuilder,
 
49
    MetaDirVersionedFileRepository,
 
50
    MetaDirRepositoryFormat,
 
51
    Repository,
55
52
    RepositoryFormat,
56
53
    )
57
54
from bzrlib.store.text import TextStore
 
55
from bzrlib.trace import mutter
 
56
from bzrlib.tuned_gzip import GzipFile, bytes_to_gzip
58
57
from bzrlib.versionedfile import (
59
58
    AbsentContentFactory,
60
59
    FulltextContentFactory,
61
60
    VersionedFiles,
62
61
    )
63
 
from bzrlib.vf_repository import (
64
 
    InterSameDataRepository,
65
 
    VersionedFileCommitBuilder,
66
 
    VersionedFileRepository,
67
 
    VersionedFileRepositoryFormat,
68
 
    MetaDirVersionedFileRepository,
69
 
    MetaDirVersionedFileRepositoryFormat,
70
 
    )
71
 
 
72
 
from bzrlib.plugins.weave_fmt import bzrdir as weave_bzrdir
73
 
 
74
 
 
75
 
class AllInOneRepository(VersionedFileRepository):
 
62
 
 
63
 
 
64
class AllInOneRepository(Repository):
76
65
    """Legacy support - the repository behaviour for all-in-one branches."""
77
66
 
78
67
    @property
116
105
    def _all_possible_ids(self):
117
106
        """Return all the possible revisions that we could find."""
118
107
        if 'evil' in debug.debug_flags:
119
 
            trace.mutter_callsite(
120
 
                3, "_all_possible_ids scales with size of history.")
 
108
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
121
109
        return [key[-1] for key in self.inventories.keys()]
122
110
 
123
111
    @needs_read_lock
150
138
 
151
139
    def get_commit_builder(self, branch, parents, config, timestamp=None,
152
140
                           timezone=None, committer=None, revprops=None,
153
 
                           revision_id=None, lossy=False):
 
141
                           revision_id=None):
154
142
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
155
 
        result = VersionedFileCommitBuilder(self, parents, config, timestamp,
156
 
            timezone, committer, revprops, revision_id, lossy=lossy)
 
143
        result = CommitBuilder(self, parents, config, timestamp, timezone,
 
144
                              committer, revprops, revision_id)
157
145
        self.start_write_group()
158
146
        return result
159
147
 
187
175
        :param new_value: True to restore the default, False to disable making
188
176
                          working trees.
189
177
        """
190
 
        raise errors.RepositoryUpgradeRequired(self.user_url)
 
178
        raise errors.RepositoryUpgradeRequired(self.bzrdir.root_transport.base)
191
179
 
192
180
    def make_working_trees(self):
193
181
        """Returns the policy for making working trees on new branches."""
194
182
        return True
195
183
 
 
184
    def revision_graph_can_have_wrong_parents(self):
 
185
        # XXX: This is an old format that we don't support full checking on, so
 
186
        # just claim that checking for this inconsistency is not required.
 
187
        return False
 
188
 
196
189
 
197
190
class WeaveMetaDirRepository(MetaDirVersionedFileRepository):
198
191
    """A subclass of MetaDirRepository to set weave specific policy."""
205
198
    def _all_possible_ids(self):
206
199
        """Return all the possible revisions that we could find."""
207
200
        if 'evil' in debug.debug_flags:
208
 
            trace.mutter_callsite(
209
 
                3, "_all_possible_ids scales with size of history.")
 
201
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
210
202
        return [key[-1] for key in self.inventories.keys()]
211
203
 
212
204
    @needs_read_lock
239
231
 
240
232
    def get_commit_builder(self, branch, parents, config, timestamp=None,
241
233
                           timezone=None, committer=None, revprops=None,
242
 
                           revision_id=None, lossy=False):
 
234
                           revision_id=None):
243
235
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
244
 
        result = VersionedFileCommitBuilder(self, parents, config, timestamp,
245
 
            timezone, committer, revprops, revision_id, lossy=lossy)
 
236
        result = CommitBuilder(self, parents, config, timestamp, timezone,
 
237
                              committer, revprops, revision_id)
246
238
        self.start_write_group()
247
239
        return result
248
240
 
263
255
        return self.inventories.add_lines((revision_id,), final_parents, lines,
264
256
            check_content=check_content)[0]
265
257
 
266
 
 
267
 
class PreSplitOutRepositoryFormat(VersionedFileRepositoryFormat):
 
258
    def revision_graph_can_have_wrong_parents(self):
 
259
        return False
 
260
 
 
261
 
 
262
class PreSplitOutRepositoryFormat(RepositoryFormat):
268
263
    """Base class for the pre split out repository formats."""
269
264
 
270
265
    rich_root_data = False
271
266
    supports_tree_reference = False
272
267
    supports_ghosts = False
273
268
    supports_external_lookups = False
274
 
    supports_chks = False
275
269
    _fetch_order = 'topological'
276
270
    _fetch_reconcile = True
277
271
    fast_deltas = False
278
 
    supports_leaving_lock = False
279
 
    # XXX: This is an old format that we don't support full checking on, so
280
 
    # just claim that checking for this inconsistency is not required.
281
 
    revision_graph_can_have_wrong_parents = False
282
272
 
283
273
    def initialize(self, a_bzrdir, shared=False, _internal=False):
284
274
        """Create a weave repository."""
294
284
        weavefile.write_weave_v5(weave.Weave(), sio)
295
285
        empty_weave = sio.getvalue()
296
286
 
297
 
        trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
 
287
        mutter('creating repository in %s.', a_bzrdir.transport.base)
298
288
 
299
289
        # FIXME: RBC 20060125 don't peek under the covers
300
290
        # NB: no need to escape relative paths that are url safe.
310
300
                mode=a_bzrdir._get_file_mode())
311
301
        finally:
312
302
            control_files.unlock()
313
 
        repository = self.open(a_bzrdir, _found=True)
314
 
        self._run_post_repo_init_hooks(repository, a_bzrdir, shared)
315
 
        return repository
 
303
        return self.open(a_bzrdir, _found=True)
316
304
 
317
305
    def open(self, a_bzrdir, _found=False):
318
306
        """See RepositoryFormat.open()."""
327
315
        result.signatures = self._get_signatures(repo_transport, result)
328
316
        result.inventories = self._get_inventories(repo_transport, result)
329
317
        result.texts = self._get_texts(repo_transport, result)
330
 
        result.chk_bytes = None
331
318
        return result
332
319
 
333
 
    def is_deprecated(self):
334
 
        return True
 
320
    def check_conversion_target(self, target_format):
 
321
        pass
335
322
 
336
323
 
337
324
class RepositoryFormat4(PreSplitOutRepositoryFormat):
346
333
    has been removed.
347
334
    """
348
335
 
349
 
    supports_funky_characters = False
350
 
 
351
 
    _matchingbzrdir = weave_bzrdir.BzrDirFormat4()
 
336
    _matchingbzrdir = bzrdir.BzrDirFormat4()
352
337
 
353
338
    def get_format_description(self):
354
339
        """See RepositoryFormat.get_format_description()."""
372
357
        return None
373
358
 
374
359
    def _get_revisions(self, repo_transport, repo):
375
 
        from bzrlib.plugins.weave_fmt.xml4 import serializer_v4
 
360
        from bzrlib.xml4 import serializer_v4
376
361
        return RevisionTextStore(repo_transport.clone('revision-store'),
377
362
            serializer_v4, True, versionedfile.PrefixMapper(),
378
363
            repo.is_locked, repo.is_write_locked)
396
381
    """
397
382
 
398
383
    _versionedfile_class = weave.WeaveFile
399
 
    _matchingbzrdir = weave_bzrdir.BzrDirFormat5()
400
 
    supports_funky_characters = False
401
 
 
 
384
    _matchingbzrdir = bzrdir.BzrDirFormat5()
402
385
    @property
403
386
    def _serializer(self):
404
387
        return xml5.serializer_v5
443
426
    """
444
427
 
445
428
    _versionedfile_class = weave.WeaveFile
446
 
    _matchingbzrdir = weave_bzrdir.BzrDirFormat6()
447
 
    supports_funky_characters = False
 
429
    _matchingbzrdir = bzrdir.BzrDirFormat6()
448
430
    @property
449
431
    def _serializer(self):
450
432
        return xml5.serializer_v5
479
461
            weave.WeaveFile, mapper, repo.is_locked)
480
462
 
481
463
 
482
 
class RepositoryFormat7(MetaDirVersionedFileRepositoryFormat):
 
464
class RepositoryFormat7(MetaDirRepositoryFormat):
483
465
    """Bzr repository 7.
484
466
 
485
467
    This repository format has:
493
475
 
494
476
    _versionedfile_class = weave.WeaveFile
495
477
    supports_ghosts = False
496
 
    supports_chks = False
497
 
    supports_funky_characters = False
498
 
    revision_graph_can_have_wrong_parents = False
499
 
 
500
478
    _fetch_order = 'topological'
501
479
    _fetch_reconcile = True
502
480
    fast_deltas = False
512
490
        """See RepositoryFormat.get_format_description()."""
513
491
        return "Weave repository format 7"
514
492
 
 
493
    def check_conversion_target(self, target_format):
 
494
        pass
 
495
 
515
496
    def _get_inventories(self, repo_transport, repo, name='inventory'):
516
497
        mapper = versionedfile.ConstantMapper(name)
517
498
        return versionedfile.ThunkedVersionedFiles(repo_transport,
544
525
        weavefile.write_weave_v5(weave.Weave(), sio)
545
526
        empty_weave = sio.getvalue()
546
527
 
547
 
        trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
 
528
        mutter('creating repository in %s.', a_bzrdir.transport.base)
548
529
        dirs = ['revision-store', 'weaves']
549
530
        files = [('inventory.weave', StringIO(empty_weave)),
550
531
                 ]
574
555
        result.signatures = self._get_signatures(repo_transport, result)
575
556
        result.inventories = self._get_inventories(repo_transport, result)
576
557
        result.texts = self._get_texts(repo_transport, result)
577
 
        result.chk_bytes = None
578
558
        result._transport = repo_transport
579
559
        return result
580
560
 
581
 
    def is_deprecated(self):
582
 
        return True
583
 
 
584
561
 
585
562
class TextVersionedFiles(VersionedFiles):
586
563
    """Just-a-bunch-of-files based VersionedFile stores."""
606
583
            raise ValueError('bad idea to put / in %r' % (key,))
607
584
        text = ''.join(lines)
608
585
        if self._compressed:
609
 
            text = tuned_gzip.bytes_to_gzip(text)
 
586
            text = bytes_to_gzip(text)
610
587
        path = self._map(key)
611
588
        self._transport.put_bytes_non_atomic(path, text, create_parent_dir=True)
612
589
 
632
609
                    record, record.get_bytes_as(record.storage_kind)))
633
610
                try:
634
611
                    self.add_lines(record.key, None, lines)
635
 
                except errors.RevisionAlreadyPresent:
 
612
                except RevisionAlreadyPresent:
636
613
                    pass
637
614
 
638
615
    def _load_text(self, key):
654
631
            else:
655
632
                return None
656
633
        if compressed:
657
 
            text = gzip.GzipFile(mode='rb', fileobj=StringIO(text)).read()
 
634
            text = GzipFile(mode='rb', fileobj=StringIO(text)).read()
658
635
        return text
659
636
 
660
637
    def _map(self, key):
687
664
            result[key] = parents
688
665
        return result
689
666
 
690
 
    def get_known_graph_ancestry(self, keys):
691
 
        """Get a KnownGraph instance with the ancestry of keys."""
692
 
        keys = self.keys()
693
 
        parent_map = self.get_parent_map(keys)
694
 
        kg = _mod_graph.KnownGraph(parent_map)
695
 
        return kg
696
 
 
697
667
    def get_record_stream(self, keys, sort_order, include_delta_closure):
698
668
        for key in keys:
699
669
            text, parents = self._load_text_parents(key)
711
681
            path, ext = os.path.splitext(relpath)
712
682
            if ext == '.gz':
713
683
                relpath = path
714
 
            if not relpath.endswith('.sig'):
 
684
            if '.sig' not in relpath:
715
685
                relpaths.add(relpath)
716
686
        paths = list(relpaths)
717
687
        return set([self._mapper.unmap(path) for path in paths])
757
727
        paths = list(relpaths)
758
728
        return set([self._mapper.unmap(path) for path in paths])
759
729
 
760
 
 
761
 
class InterWeaveRepo(InterSameDataRepository):
762
 
    """Optimised code paths between Weave based repositories.
763
 
    """
764
 
 
765
 
    @classmethod
766
 
    def _get_repo_format_to_test(self):
767
 
        return RepositoryFormat7()
768
 
 
769
 
    @staticmethod
770
 
    def is_compatible(source, target):
771
 
        """Be compatible with known Weave formats.
772
 
 
773
 
        We don't test for the stores being of specific types because that
774
 
        could lead to confusing results, and there is no need to be
775
 
        overly general.
776
 
        """
777
 
        try:
778
 
            return (isinstance(source._format, (RepositoryFormat5,
779
 
                                                RepositoryFormat6,
780
 
                                                RepositoryFormat7)) and
781
 
                    isinstance(target._format, (RepositoryFormat5,
782
 
                                                RepositoryFormat6,
783
 
                                                RepositoryFormat7)))
784
 
        except AttributeError:
785
 
            return False
786
 
 
787
 
    @needs_write_lock
788
 
    def copy_content(self, revision_id=None):
789
 
        """See InterRepository.copy_content()."""
790
 
        # weave specific optimised path:
791
 
        try:
792
 
            self.target.set_make_working_trees(self.source.make_working_trees())
793
 
        except (errors.RepositoryUpgradeRequired, NotImplemented):
794
 
            pass
795
 
        # FIXME do not peek!
796
 
        if self.source._transport.listable():
797
 
            pb = ui.ui_factory.nested_progress_bar()
798
 
            try:
799
 
                self.target.texts.insert_record_stream(
800
 
                    self.source.texts.get_record_stream(
801
 
                        self.source.texts.keys(), 'topological', False))
802
 
                pb.update('Copying inventory', 0, 1)
803
 
                self.target.inventories.insert_record_stream(
804
 
                    self.source.inventories.get_record_stream(
805
 
                        self.source.inventories.keys(), 'topological', False))
806
 
                self.target.signatures.insert_record_stream(
807
 
                    self.source.signatures.get_record_stream(
808
 
                        self.source.signatures.keys(),
809
 
                        'unordered', True))
810
 
                self.target.revisions.insert_record_stream(
811
 
                    self.source.revisions.get_record_stream(
812
 
                        self.source.revisions.keys(),
813
 
                        'topological', True))
814
 
            finally:
815
 
                pb.finished()
816
 
        else:
817
 
            self.target.fetch(self.source, revision_id=revision_id)
818
 
 
819
 
    @needs_read_lock
820
 
    def search_missing_revision_ids(self,
821
 
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
822
 
            find_ghosts=True, revision_ids=None, if_present_ids=None,
823
 
            limit=None):
824
 
        """See InterRepository.search_missing_revision_ids()."""
825
 
        # we want all revisions to satisfy revision_id in source.
826
 
        # but we don't want to stat every file here and there.
827
 
        # we want then, all revisions other needs to satisfy revision_id
828
 
        # checked, but not those that we have locally.
829
 
        # so the first thing is to get a subset of the revisions to
830
 
        # satisfy revision_id in source, and then eliminate those that
831
 
        # we do already have.
832
 
        # this is slow on high latency connection to self, but as this
833
 
        # disk format scales terribly for push anyway due to rewriting
834
 
        # inventory.weave, this is considered acceptable.
835
 
        # - RBC 20060209
836
 
        if symbol_versioning.deprecated_passed(revision_id):
837
 
            symbol_versioning.warn(
838
 
                'search_missing_revision_ids(revision_id=...) was '
839
 
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
840
 
                DeprecationWarning, stacklevel=2)
841
 
            if revision_ids is not None:
842
 
                raise AssertionError(
843
 
                    'revision_ids is mutually exclusive with revision_id')
844
 
            if revision_id is not None:
845
 
                revision_ids = [revision_id]
846
 
        del revision_id
847
 
        source_ids_set = self._present_source_revisions_for(
848
 
            revision_ids, if_present_ids)
849
 
        # source_ids is the worst possible case we may need to pull.
850
 
        # now we want to filter source_ids against what we actually
851
 
        # have in target, but don't try to check for existence where we know
852
 
        # we do not have a revision as that would be pointless.
853
 
        target_ids = set(self.target._all_possible_ids())
854
 
        possibly_present_revisions = target_ids.intersection(source_ids_set)
855
 
        actually_present_revisions = set(
856
 
            self.target._eliminate_revisions_not_present(possibly_present_revisions))
857
 
        required_revisions = source_ids_set.difference(actually_present_revisions)
858
 
        if revision_ids is not None:
859
 
            # we used get_ancestry to determine source_ids then we are assured all
860
 
            # revisions referenced are present as they are installed in topological order.
861
 
            # and the tip revision was validated by get_ancestry.
862
 
            result_set = required_revisions
863
 
        else:
864
 
            # if we just grabbed the possibly available ids, then
865
 
            # we only have an estimate of whats available and need to validate
866
 
            # that against the revision records.
867
 
            result_set = set(
868
 
                self.source._eliminate_revisions_not_present(required_revisions))
869
 
        if limit is not None:
870
 
            topo_ordered = self.get_graph().iter_topo_order(result_set)
871
 
            result_set = set(itertools.islice(topo_ordered, limit))
872
 
        return self.source.revision_ids_to_search_result(result_set)
873
 
 
874
 
 
875
 
InterRepository.register_optimiser(InterWeaveRepo)
876
 
 
877
 
 
878
 
def get_extra_interrepo_test_combinations():
879
 
    from bzrlib.repofmt import knitrepo
880
 
    return [(InterRepository, RepositoryFormat5(),
881
 
        knitrepo.RepositoryFormatKnit3())]
 
730
_legacy_formats = [RepositoryFormat4(),
 
731
                   RepositoryFormat5(),
 
732
                   RepositoryFormat6()]