~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/plugins/weave_fmt/repository.py

Merge bzr.dev, update to use new hooks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2010 Canonical Ltd
 
1
# Copyright (C) 2007-2011 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
23
24
import os
24
25
from cStringIO import StringIO
25
26
import urllib
26
27
 
27
28
from bzrlib.lazy_import import lazy_import
28
29
lazy_import(globals(), """
 
30
import itertools
 
31
 
29
32
from bzrlib import (
30
33
    xml5,
31
34
    graph as _mod_graph,
 
35
    ui,
32
36
    )
33
37
""")
34
38
from bzrlib import (
35
 
    bzrdir,
36
39
    debug,
37
40
    errors,
38
41
    lockable_files,
39
42
    lockdir,
40
43
    osutils,
41
 
    revision as _mod_revision,
 
44
    symbol_versioning,
42
45
    trace,
 
46
    tuned_gzip,
43
47
    urlutils,
44
48
    versionedfile,
45
49
    weave,
47
51
    )
48
52
from bzrlib.decorators import needs_read_lock, needs_write_lock
49
53
from bzrlib.repository import (
50
 
    CommitBuilder,
51
 
    MetaDirVersionedFileRepository,
52
 
    MetaDirRepositoryFormat,
53
 
    Repository,
54
 
    RepositoryFormat,
 
54
    InterRepository,
 
55
    RepositoryFormatMetaDir,
55
56
    )
56
57
from bzrlib.store.text import TextStore
57
 
from bzrlib.tuned_gzip import GzipFile, bytes_to_gzip
58
58
from bzrlib.versionedfile import (
59
59
    AbsentContentFactory,
60
60
    FulltextContentFactory,
61
61
    VersionedFiles,
62
62
    )
63
 
 
64
 
 
65
 
class AllInOneRepository(Repository):
 
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):
66
76
    """Legacy support - the repository behaviour for all-in-one branches."""
67
77
 
68
78
    @property
140
150
 
141
151
    def get_commit_builder(self, branch, parents, config, timestamp=None,
142
152
                           timezone=None, committer=None, revprops=None,
143
 
                           revision_id=None):
 
153
                           revision_id=None, lossy=False):
144
154
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
145
 
        result = CommitBuilder(self, parents, config, timestamp, timezone,
146
 
                              committer, revprops, revision_id)
 
155
        result = VersionedFileCommitBuilder(self, parents, config, timestamp,
 
156
            timezone, committer, revprops, revision_id, lossy=lossy)
147
157
        self.start_write_group()
148
158
        return result
149
159
 
183
193
        """Returns the policy for making working trees on new branches."""
184
194
        return True
185
195
 
186
 
    def revision_graph_can_have_wrong_parents(self):
187
 
        # XXX: This is an old format that we don't support full checking on, so
188
 
        # just claim that checking for this inconsistency is not required.
189
 
        return False
190
 
 
191
196
 
192
197
class WeaveMetaDirRepository(MetaDirVersionedFileRepository):
193
198
    """A subclass of MetaDirRepository to set weave specific policy."""
234
239
 
235
240
    def get_commit_builder(self, branch, parents, config, timestamp=None,
236
241
                           timezone=None, committer=None, revprops=None,
237
 
                           revision_id=None):
 
242
                           revision_id=None, lossy=False):
238
243
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
239
 
        result = CommitBuilder(self, parents, config, timestamp, timezone,
240
 
                              committer, revprops, revision_id)
 
244
        result = VersionedFileCommitBuilder(self, parents, config, timestamp,
 
245
            timezone, committer, revprops, revision_id, lossy=lossy)
241
246
        self.start_write_group()
242
247
        return result
243
248
 
258
263
        return self.inventories.add_lines((revision_id,), final_parents, lines,
259
264
            check_content=check_content)[0]
260
265
 
261
 
    def revision_graph_can_have_wrong_parents(self):
262
 
        return False
263
 
 
264
 
 
265
 
class PreSplitOutRepositoryFormat(RepositoryFormat):
 
266
 
 
267
class PreSplitOutRepositoryFormat(VersionedFileRepositoryFormat):
266
268
    """Base class for the pre split out repository formats."""
267
269
 
268
270
    rich_root_data = False
270
272
    supports_ghosts = False
271
273
    supports_external_lookups = False
272
274
    supports_chks = False
 
275
    supports_nesting_repositories = True
273
276
    _fetch_order = 'topological'
274
277
    _fetch_reconcile = True
275
278
    fast_deltas = False
 
279
    supports_leaving_lock = False
 
280
    # XXX: This is an old format that we don't support full checking on, so
 
281
    # just claim that checking for this inconsistency is not required.
 
282
    revision_graph_can_have_wrong_parents = False
276
283
 
277
284
    def initialize(self, a_bzrdir, shared=False, _internal=False):
278
285
        """Create a weave repository."""
315
322
            raise NotImplementedError
316
323
 
317
324
        repo_transport = a_bzrdir.get_repository_transport(None)
318
 
        control_files = a_bzrdir._control_files
319
325
        result = AllInOneRepository(_format=self, a_bzrdir=a_bzrdir)
320
326
        result.revisions = self._get_revisions(repo_transport, result)
321
327
        result.signatures = self._get_signatures(repo_transport, result)
324
330
        result.chk_bytes = None
325
331
        return result
326
332
 
 
333
    def is_deprecated(self):
 
334
        return True
 
335
 
327
336
 
328
337
class RepositoryFormat4(PreSplitOutRepositoryFormat):
329
338
    """Bzr repository format 4.
337
346
    has been removed.
338
347
    """
339
348
 
340
 
    _matchingbzrdir = bzrdir.BzrDirFormat4()
 
349
    supports_funky_characters = False
 
350
 
 
351
    _matchingbzrdir = weave_bzrdir.BzrDirFormat4()
341
352
 
342
353
    def get_format_description(self):
343
354
        """See RepositoryFormat.get_format_description()."""
361
372
        return None
362
373
 
363
374
    def _get_revisions(self, repo_transport, repo):
364
 
        from bzrlib.xml4 import serializer_v4
 
375
        from bzrlib.plugins.weave_fmt.xml4 import serializer_v4
365
376
        return RevisionTextStore(repo_transport.clone('revision-store'),
366
377
            serializer_v4, True, versionedfile.PrefixMapper(),
367
378
            repo.is_locked, repo.is_write_locked)
385
396
    """
386
397
 
387
398
    _versionedfile_class = weave.WeaveFile
388
 
    _matchingbzrdir = bzrdir.BzrDirFormat5()
 
399
    _matchingbzrdir = weave_bzrdir.BzrDirFormat5()
 
400
    supports_funky_characters = False
 
401
 
389
402
    @property
390
403
    def _serializer(self):
391
404
        return xml5.serializer_v5
430
443
    """
431
444
 
432
445
    _versionedfile_class = weave.WeaveFile
433
 
    _matchingbzrdir = bzrdir.BzrDirFormat6()
 
446
    _matchingbzrdir = weave_bzrdir.BzrDirFormat6()
 
447
    supports_funky_characters = False
434
448
    @property
435
449
    def _serializer(self):
436
450
        return xml5.serializer_v5
465
479
            weave.WeaveFile, mapper, repo.is_locked)
466
480
 
467
481
 
468
 
class RepositoryFormat7(MetaDirRepositoryFormat):
 
482
class RepositoryFormat7(MetaDirVersionedFileRepositoryFormat):
469
483
    """Bzr repository 7.
470
484
 
471
485
    This repository format has:
480
494
    _versionedfile_class = weave.WeaveFile
481
495
    supports_ghosts = False
482
496
    supports_chks = False
 
497
    supports_funky_characters = False
 
498
    revision_graph_can_have_wrong_parents = False
483
499
 
484
500
    _fetch_order = 'topological'
485
501
    _fetch_reconcile = True
488
504
    def _serializer(self):
489
505
        return xml5.serializer_v5
490
506
 
491
 
    def get_format_string(self):
 
507
    @classmethod
 
508
    def get_format_string(cls):
492
509
        """See RepositoryFormat.get_format_string()."""
493
510
        return "Bazaar-NG Repository format 7"
494
511
 
545
562
                                    than normal. I.e. during 'upgrade'.
546
563
        """
547
564
        if not _found:
548
 
            format = RepositoryFormat.find_format(a_bzrdir)
 
565
            format = RepositoryFormatMetaDir.find_format(a_bzrdir)
549
566
        if _override_transport is not None:
550
567
            repo_transport = _override_transport
551
568
        else:
562
579
        result._transport = repo_transport
563
580
        return result
564
581
 
 
582
    def is_deprecated(self):
 
583
        return True
 
584
 
565
585
 
566
586
class TextVersionedFiles(VersionedFiles):
567
587
    """Just-a-bunch-of-files based VersionedFile stores."""
587
607
            raise ValueError('bad idea to put / in %r' % (key,))
588
608
        text = ''.join(lines)
589
609
        if self._compressed:
590
 
            text = bytes_to_gzip(text)
 
610
            text = tuned_gzip.bytes_to_gzip(text)
591
611
        path = self._map(key)
592
612
        self._transport.put_bytes_non_atomic(path, text, create_parent_dir=True)
593
613
 
613
633
                    record, record.get_bytes_as(record.storage_kind)))
614
634
                try:
615
635
                    self.add_lines(record.key, None, lines)
616
 
                except RevisionAlreadyPresent:
 
636
                except errors.RevisionAlreadyPresent:
617
637
                    pass
618
638
 
619
639
    def _load_text(self, key):
635
655
            else:
636
656
                return None
637
657
        if compressed:
638
 
            text = GzipFile(mode='rb', fileobj=StringIO(text)).read()
 
658
            text = gzip.GzipFile(mode='rb', fileobj=StringIO(text)).read()
639
659
        return text
640
660
 
641
661
    def _map(self, key):
738
758
        paths = list(relpaths)
739
759
        return set([self._mapper.unmap(path) for path in paths])
740
760
 
741
 
_legacy_formats = [RepositoryFormat4(),
742
 
                   RepositoryFormat5(),
743
 
                   RepositoryFormat6()]
 
761
 
 
762
class InterWeaveRepo(InterSameDataRepository):
 
763
    """Optimised code paths between Weave based repositories.
 
764
    """
 
765
 
 
766
    @classmethod
 
767
    def _get_repo_format_to_test(self):
 
768
        return RepositoryFormat7()
 
769
 
 
770
    @staticmethod
 
771
    def is_compatible(source, target):
 
772
        """Be compatible with known Weave formats.
 
773
 
 
774
        We don't test for the stores being of specific types because that
 
775
        could lead to confusing results, and there is no need to be
 
776
        overly general.
 
777
        """
 
778
        try:
 
779
            return (isinstance(source._format, (RepositoryFormat5,
 
780
                                                RepositoryFormat6,
 
781
                                                RepositoryFormat7)) and
 
782
                    isinstance(target._format, (RepositoryFormat5,
 
783
                                                RepositoryFormat6,
 
784
                                                RepositoryFormat7)))
 
785
        except AttributeError:
 
786
            return False
 
787
 
 
788
    @needs_write_lock
 
789
    def copy_content(self, revision_id=None):
 
790
        """See InterRepository.copy_content()."""
 
791
        # weave specific optimised path:
 
792
        try:
 
793
            self.target.set_make_working_trees(self.source.make_working_trees())
 
794
        except (errors.RepositoryUpgradeRequired, NotImplemented):
 
795
            pass
 
796
        # FIXME do not peek!
 
797
        if self.source._transport.listable():
 
798
            pb = ui.ui_factory.nested_progress_bar()
 
799
            try:
 
800
                self.target.texts.insert_record_stream(
 
801
                    self.source.texts.get_record_stream(
 
802
                        self.source.texts.keys(), 'topological', False))
 
803
                pb.update('Copying inventory', 0, 1)
 
804
                self.target.inventories.insert_record_stream(
 
805
                    self.source.inventories.get_record_stream(
 
806
                        self.source.inventories.keys(), 'topological', False))
 
807
                self.target.signatures.insert_record_stream(
 
808
                    self.source.signatures.get_record_stream(
 
809
                        self.source.signatures.keys(),
 
810
                        'unordered', True))
 
811
                self.target.revisions.insert_record_stream(
 
812
                    self.source.revisions.get_record_stream(
 
813
                        self.source.revisions.keys(),
 
814
                        'topological', True))
 
815
            finally:
 
816
                pb.finished()
 
817
        else:
 
818
            self.target.fetch(self.source, revision_id=revision_id)
 
819
 
 
820
    @needs_read_lock
 
821
    def search_missing_revision_ids(self,
 
822
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
823
            find_ghosts=True, revision_ids=None, if_present_ids=None,
 
824
            limit=None):
 
825
        """See InterRepository.search_missing_revision_ids()."""
 
826
        # we want all revisions to satisfy revision_id in source.
 
827
        # but we don't want to stat every file here and there.
 
828
        # we want then, all revisions other needs to satisfy revision_id
 
829
        # checked, but not those that we have locally.
 
830
        # so the first thing is to get a subset of the revisions to
 
831
        # satisfy revision_id in source, and then eliminate those that
 
832
        # we do already have.
 
833
        # this is slow on high latency connection to self, but as this
 
834
        # disk format scales terribly for push anyway due to rewriting
 
835
        # inventory.weave, this is considered acceptable.
 
836
        # - RBC 20060209
 
837
        if symbol_versioning.deprecated_passed(revision_id):
 
838
            symbol_versioning.warn(
 
839
                'search_missing_revision_ids(revision_id=...) was '
 
840
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
 
841
                DeprecationWarning, stacklevel=2)
 
842
            if revision_ids is not None:
 
843
                raise AssertionError(
 
844
                    'revision_ids is mutually exclusive with revision_id')
 
845
            if revision_id is not None:
 
846
                revision_ids = [revision_id]
 
847
        del revision_id
 
848
        source_ids_set = self._present_source_revisions_for(
 
849
            revision_ids, if_present_ids)
 
850
        # source_ids is the worst possible case we may need to pull.
 
851
        # now we want to filter source_ids against what we actually
 
852
        # have in target, but don't try to check for existence where we know
 
853
        # we do not have a revision as that would be pointless.
 
854
        target_ids = set(self.target._all_possible_ids())
 
855
        possibly_present_revisions = target_ids.intersection(source_ids_set)
 
856
        actually_present_revisions = set(
 
857
            self.target._eliminate_revisions_not_present(possibly_present_revisions))
 
858
        required_revisions = source_ids_set.difference(actually_present_revisions)
 
859
        if revision_ids is not None:
 
860
            # we used get_ancestry to determine source_ids then we are assured all
 
861
            # revisions referenced are present as they are installed in topological order.
 
862
            # and the tip revision was validated by get_ancestry.
 
863
            result_set = required_revisions
 
864
        else:
 
865
            # if we just grabbed the possibly available ids, then
 
866
            # we only have an estimate of whats available and need to validate
 
867
            # that against the revision records.
 
868
            result_set = set(
 
869
                self.source._eliminate_revisions_not_present(required_revisions))
 
870
        if limit is not None:
 
871
            topo_ordered = self.get_graph().iter_topo_order(result_set)
 
872
            result_set = set(itertools.islice(topo_ordered, limit))
 
873
        return self.source.revision_ids_to_search_result(result_set)
 
874
 
 
875
 
 
876
InterRepository.register_optimiser(InterWeaveRepo)
 
877
 
 
878
 
 
879
def get_extra_interrepo_test_combinations():
 
880
    from bzrlib.repofmt import knitrepo
 
881
    return [(InterRepository, RepositoryFormat5(),
 
882
        knitrepo.RepositoryFormatKnit3())]