~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/weaverepo.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-03-25 00:02:51 UTC
  • mfrom: (5106.1.1 version-bump)
  • Revision ID: pqm@pqm.ubuntu.com-20100325000251-bwsv5c5d3l9x3lnn
(Jelmer) Bump API version for 2.2.0.

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