~bzr-pqm/bzr/bzr.dev

3350.6.10 by Martin Pool
VersionedFiles review cleanups
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
2803.2.1 by Robert Collins
* CommitBuilder now advertises itself as requiring the root entry to be
17
"""Deprecated weave-based repository formats.
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
18
2803.2.1 by Robert Collins
* CommitBuilder now advertises itself as requiring the root entry to be
19
Weave based formats scaled linearly with history size and could not represent
20
ghosts.
21
"""
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
22
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
23
import os
24
from cStringIO import StringIO
25
import urllib
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
26
3224.5.1 by Andrew Bennetts
Lots of assorted hackery to reduce the number of imports for common operations. Improves 'rocks', 'st' and 'help' times by ~50ms on my laptop.
27
from bzrlib.lazy_import import lazy_import
28
lazy_import(globals(), """
29
from bzrlib import (
30
    xml5,
31
    )
32
""")
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
33
from bzrlib import (
34
    bzrdir,
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
35
    debug,
36
    errors,
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
37
    lockable_files,
38
    lockdir,
2803.2.1 by Robert Collins
* CommitBuilder now advertises itself as requiring the root entry to be
39
    osutils,
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
40
    revision as _mod_revision,
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
41
    versionedfile,
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
42
    weave,
43
    weavefile,
3224.5.4 by Andrew Bennetts
Fix test suite, mainly weeding out uses of bzrlib.user_encoding.
44
    )
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
45
from bzrlib.decorators import needs_read_lock, needs_write_lock
46
from bzrlib.repository import (
2803.2.1 by Robert Collins
* CommitBuilder now advertises itself as requiring the root entry to be
47
    CommitBuilder,
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
48
    MetaDirVersionedFileRepository,
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
49
    MetaDirRepositoryFormat,
50
    Repository,
51
    RepositoryFormat,
52
    )
53
from bzrlib.store.text import TextStore
54
from bzrlib.trace import mutter
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
55
from bzrlib.tuned_gzip import GzipFile, bytes_to_gzip
56
from bzrlib.versionedfile import (
57
    AbsentContentFactory,
58
    FulltextContentFactory,
59
    VersionedFiles,
60
    )
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
61
62
63
class AllInOneRepository(Repository):
64
    """Legacy support - the repository behaviour for all-in-one branches."""
65
3224.5.1 by Andrew Bennetts
Lots of assorted hackery to reduce the number of imports for common operations. Improves 'rocks', 'st' and 'help' times by ~50ms on my laptop.
66
    @property
67
    def _serializer(self):
68
        return xml5.serializer_v5
2241.1.8 by Martin Pool
Set the repository's serializer in the places it's needed, not in the base class
69
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
70
    def __init__(self, _format, a_bzrdir):
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
71
        # we reuse one control files instance.
3416.2.3 by Martin Pool
typo
72
        dir_mode = a_bzrdir._get_dir_mode()
73
        file_mode = a_bzrdir._get_file_mode()
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
74
75
        def get_store(name, compressed=True, prefixed=False):
76
            # FIXME: This approach of assuming stores are all entirely compressed
77
            # or entirely uncompressed is tidy, but breaks upgrade from 
78
            # some existing branches where there's a mixture; we probably 
79
            # still want the option to look for both.
80
            relpath = a_bzrdir._control_files._escape(name)
3407.2.13 by Martin Pool
Remove indirection through control_files to get transports
81
            store = TextStore(a_bzrdir.transport.clone(relpath),
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
82
                              prefixed=prefixed, compressed=compressed,
83
                              dir_mode=dir_mode,
84
                              file_mode=file_mode)
85
            return store
86
87
        # not broken out yet because the controlweaves|inventory_store
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
88
        # and texts bits are still different.
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
89
        if isinstance(_format, RepositoryFormat4):
90
            # cannot remove these - there is still no consistent api 
91
            # which allows access to this old info.
92
            self.inventory_store = get_store('inventory-store')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
93
            self._text_store = get_store('text-store')
94
        super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
95
        self._fetch_order = 'topological'
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
96
        self._fetch_reconcile = True
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
97
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
98
    @needs_read_lock
99
    def _all_possible_ids(self):
100
        """Return all the possible revisions that we could find."""
101
        if 'evil' in debug.debug_flags:
102
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
103
        return [key[-1] for key in self.inventories.keys()]
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
104
105
    @needs_read_lock
106
    def _all_revision_ids(self):
107
        """Returns a list of all the revision ids in the repository. 
108
109
        These are in as much topological order as the underlying store can 
110
        present: for weaves ghosts may lead to a lack of correctness until
111
        the reweave updates the parents list.
112
        """
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
113
        return [key[-1] for key in self.revisions.keys()]
114
115
    def _activate_new_inventory(self):
116
        """Put a replacement inventory.new into use as inventories."""
117
        # Copy the content across
118
        t = self.bzrdir._control_files._transport
119
        t.copy('inventory.new.weave', 'inventory.weave')
120
        # delete the temp inventory
121
        t.delete('inventory.new.weave')
122
        # Check we can parse the new weave properly as a sanity check
123
        self.inventories.keys()
124
125
    def _backup_inventory(self):
126
        t = self.bzrdir._control_files._transport
127
        t.copy('inventory.weave', 'inventory.backup.weave')
128
129
    def _temp_inventories(self):
130
        t = self.bzrdir._control_files._transport
131
        return self._format._get_inventories(t, self, 'inventory.new')
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
132
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
133
    def get_commit_builder(self, branch, parents, config, timestamp=None,
134
                           timezone=None, committer=None, revprops=None,
135
                           revision_id=None):
136
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
137
        result = CommitBuilder(self, parents, config, timestamp, timezone,
2803.2.1 by Robert Collins
* CommitBuilder now advertises itself as requiring the root entry to be
138
                              committer, revprops, revision_id)
139
        self.start_write_group()
140
        return result
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
141
142
    @needs_read_lock
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
143
    def get_revisions(self, revision_ids):
144
        revs = self._get_revisions(revision_ids)
145
        return revs
146
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
147
    def _inventory_add_lines(self, revision_id, parents, lines,
148
        check_content=True):
149
        """Store lines in inv_vf and return the sha1 of the inventory."""
150
        present_parents = self.get_graph().get_parent_map(parents)
151
        final_parents = []
152
        for parent in parents:
153
            if parent in present_parents:
154
                final_parents.append((parent,))
155
        return self.inventories.add_lines((revision_id,), final_parents, lines,
156
            check_content=check_content)[0]
3172.3.1 by Robert Collins
Repository has a new method ``has_revisions`` which signals the presence
157
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
158
    def is_shared(self):
159
        """AllInOne repositories cannot be shared."""
160
        return False
161
162
    @needs_write_lock
163
    def set_make_working_trees(self, new_value):
164
        """Set the policy flag for making working trees when creating branches.
165
166
        This only applies to branches that use this repository.
167
168
        The default is 'True'.
169
        :param new_value: True to restore the default, False to disable making
170
                          working trees.
171
        """
3349.1.2 by Aaron Bentley
Change ValueError to RepositoryUpgradeRequired
172
        raise errors.RepositoryUpgradeRequired(self.bzrdir.root_transport.base)
3349.1.1 by Aaron Bentley
Enable setting and getting make_working_trees for all repositories
173
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
174
    def make_working_trees(self):
175
        """Returns the policy for making working trees on new branches."""
176
        return True
177
2819.2.4 by Andrew Bennetts
Add a 'revision_graph_can_have_wrong_parents' method to repository.
178
    def revision_graph_can_have_wrong_parents(self):
179
        # XXX: This is an old format that we don't support full checking on, so
180
        # just claim that checking for this inconsistency is not required.
181
        return False
182
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
183
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
184
class WeaveMetaDirRepository(MetaDirVersionedFileRepository):
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
185
    """A subclass of MetaDirRepository to set weave specific policy."""
186
3224.5.1 by Andrew Bennetts
Lots of assorted hackery to reduce the number of imports for common operations. Improves 'rocks', 'st' and 'help' times by ~50ms on my laptop.
187
    @property
188
    def _serializer(self):
189
        return xml5.serializer_v5
2241.1.8 by Martin Pool
Set the repository's serializer in the places it's needed, not in the base class
190
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
191
    def __init__(self, _format, a_bzrdir, control_files):
192
        super(WeaveMetaDirRepository, self).__init__(_format, a_bzrdir, control_files)
193
        self._fetch_order = 'topological'
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
194
        self._fetch_reconcile = True
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
195
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
196
    @needs_read_lock
197
    def _all_possible_ids(self):
198
        """Return all the possible revisions that we could find."""
199
        if 'evil' in debug.debug_flags:
200
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
201
        return [key[-1] for key in self.inventories.keys()]
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
202
203
    @needs_read_lock
204
    def _all_revision_ids(self):
205
        """Returns a list of all the revision ids in the repository. 
206
207
        These are in as much topological order as the underlying store can 
208
        present: for weaves ghosts may lead to a lack of correctness until
209
        the reweave updates the parents list.
210
        """
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
211
        return [key[-1] for key in self.revisions.keys()]
212
213
    def _activate_new_inventory(self):
214
        """Put a replacement inventory.new into use as inventories."""
215
        # Copy the content across
216
        t = self._transport
217
        t.copy('inventory.new.weave', 'inventory.weave')
218
        # delete the temp inventory
219
        t.delete('inventory.new.weave')
220
        # Check we can parse the new weave properly as a sanity check
221
        self.inventories.keys()
222
223
    def _backup_inventory(self):
224
        t = self._transport
225
        t.copy('inventory.weave', 'inventory.backup.weave')
226
227
    def _temp_inventories(self):
228
        t = self._transport
229
        return self._format._get_inventories(t, self, 'inventory.new')
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
230
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
231
    def get_commit_builder(self, branch, parents, config, timestamp=None,
232
                           timezone=None, committer=None, revprops=None,
233
                           revision_id=None):
234
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
235
        result = CommitBuilder(self, parents, config, timestamp, timezone,
2803.2.1 by Robert Collins
* CommitBuilder now advertises itself as requiring the root entry to be
236
                              committer, revprops, revision_id)
237
        self.start_write_group()
238
        return result
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
239
2850.3.1 by Robert Collins
Move various weave specific code out of the base Repository class to weaverepo.py.
240
    @needs_read_lock
241
    def get_revision(self, revision_id):
242
        """Return the Revision object for a named revision"""
243
        r = self.get_revision_reconcile(revision_id)
244
        return r
245
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
246
    def _inventory_add_lines(self, revision_id, parents, lines,
247
        check_content=True):
248
        """Store lines in inv_vf and return the sha1 of the inventory."""
249
        present_parents = self.get_graph().get_parent_map(parents)
250
        final_parents = []
251
        for parent in parents:
252
            if parent in present_parents:
253
                final_parents.append((parent,))
254
        return self.inventories.add_lines((revision_id,), final_parents, lines,
255
            check_content=check_content)[0]
3172.3.1 by Robert Collins
Repository has a new method ``has_revisions`` which signals the presence
256
2819.2.4 by Andrew Bennetts
Add a 'revision_graph_can_have_wrong_parents' method to repository.
257
    def revision_graph_can_have_wrong_parents(self):
258
        return False
259
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
260
261
class PreSplitOutRepositoryFormat(RepositoryFormat):
262
    """Base class for the pre split out repository formats."""
263
264
    rich_root_data = False
2323.5.17 by Martin Pool
Add supports_tree_reference to all repo formats (robert)
265
    supports_tree_reference = False
2949.1.2 by Robert Collins
* Fetch with pack repositories will no longer read the entire history graph.
266
    supports_ghosts = False
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
267
    supports_external_lookups = False
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
268
269
    def initialize(self, a_bzrdir, shared=False, _internal=False):
2949.1.2 by Robert Collins
* Fetch with pack repositories will no longer read the entire history graph.
270
        """Create a weave repository."""
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
271
        if shared:
272
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
273
274
        if not _internal:
275
            # always initialized when the bzrdir is.
276
            return self.open(a_bzrdir, _found=True)
277
        
278
        # Create an empty weave
279
        sio = StringIO()
280
        weavefile.write_weave_v5(weave.Weave(), sio)
281
        empty_weave = sio.getvalue()
282
283
        mutter('creating repository in %s.', a_bzrdir.transport.base)
284
        
285
        # FIXME: RBC 20060125 don't peek under the covers
286
        # NB: no need to escape relative paths that are url safe.
287
        control_files = lockable_files.LockableFiles(a_bzrdir.transport,
3407.2.4 by Martin Pool
Small cleanups to initial creation of repository files
288
            'branch-lock', lockable_files.TransportLock)
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
289
        control_files.create_lock()
290
        control_files.lock_write()
3407.2.13 by Martin Pool
Remove indirection through control_files to get transports
291
        transport = a_bzrdir.transport
3407.2.4 by Martin Pool
Small cleanups to initial creation of repository files
292
        try:
293
            transport.mkdir_multi(['revision-store', 'weaves'],
3446.1.1 by Martin Pool
merge further LockableFile deprecations
294
                mode=a_bzrdir._get_dir_mode())
3407.2.4 by Martin Pool
Small cleanups to initial creation of repository files
295
            transport.put_bytes_non_atomic('inventory.weave', empty_weave)
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
296
        finally:
297
            control_files.unlock()
298
        return self.open(a_bzrdir, _found=True)
299
300
    def open(self, a_bzrdir, _found=False):
301
        """See RepositoryFormat.open()."""
302
        if not _found:
303
            # we are being called directly and must probe.
304
            raise NotImplementedError
305
306
        repo_transport = a_bzrdir.get_repository_transport(None)
307
        control_files = a_bzrdir._control_files
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
308
        result = AllInOneRepository(_format=self, a_bzrdir=a_bzrdir)
309
        result.revisions = self._get_revisions(repo_transport, result)
310
        result.signatures = self._get_signatures(repo_transport, result)
311
        result.inventories = self._get_inventories(repo_transport, result)
312
        result.texts = self._get_texts(repo_transport, result)
313
        return result
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
314
315
    def check_conversion_target(self, target_format):
316
        pass
317
318
319
class RepositoryFormat4(PreSplitOutRepositoryFormat):
320
    """Bzr repository format 4.
321
322
    This repository format has:
323
     - flat stores
324
     - TextStores for texts, inventories,revisions.
325
326
    This format is deprecated: it indexes texts using a text id which is
327
    removed in format 5; initialization and write support for this format
328
    has been removed.
329
    """
330
2241.1.11 by Martin Pool
Get rid of RepositoryFormat*_instance objects. Instead the format
331
    _matchingbzrdir = bzrdir.BzrDirFormat4()
332
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
333
    def __init__(self):
334
        super(RepositoryFormat4, self).__init__()
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
335
        self._fetch_order = 'topological'
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
336
        self._fetch_reconcile = True
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
337
338
    def get_format_description(self):
339
        """See RepositoryFormat.get_format_description()."""
340
        return "Repository format 4"
341
342
    def initialize(self, url, shared=False, _internal=False):
343
        """Format 4 branches cannot be created."""
344
        raise errors.UninitializableFormat(self)
345
346
    def is_supported(self):
347
        """Format 4 is not supported.
348
349
        It is not supported because the model changed from 4 to 5 and the
350
        conversion logic is expensive - so doing it on the fly was not 
351
        feasible.
352
        """
353
        return False
354
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
355
    def _get_inventories(self, repo_transport, repo, name='inventory'):
356
        # No inventories store written so far.
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
357
        return None
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
358
359
    def _get_revisions(self, repo_transport, repo):
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
360
        from bzrlib.xml4 import serializer_v4
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
361
        return RevisionTextStore(repo_transport.clone('revision-store'),
362
            serializer_v4, True, versionedfile.PrefixMapper(),
363
            repo.is_locked, repo.is_write_locked)
364
365
    def _get_signatures(self, repo_transport, repo):
366
        return SignatureTextStore(repo_transport.clone('revision-store'),
367
            False, versionedfile.PrefixMapper(),
368
            repo.is_locked, repo.is_write_locked)
369
370
    def _get_texts(self, repo_transport, repo):
371
        return None
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
372
373
374
class RepositoryFormat5(PreSplitOutRepositoryFormat):
375
    """Bzr control format 5.
376
377
    This repository format has:
378
     - weaves for file texts and inventory
379
     - flat stores
380
     - TextStores for revisions and signatures.
381
    """
382
2241.1.10 by Martin Pool
Remove more references to weaves from the repository.py file
383
    _versionedfile_class = weave.WeaveFile
2241.1.11 by Martin Pool
Get rid of RepositoryFormat*_instance objects. Instead the format
384
    _matchingbzrdir = bzrdir.BzrDirFormat5()
2241.1.10 by Martin Pool
Remove more references to weaves from the repository.py file
385
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
386
    def __init__(self):
387
        super(RepositoryFormat5, self).__init__()
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
388
        self._fetch_order = 'topological'
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
389
        self._fetch_reconcile = True
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
390
391
    def get_format_description(self):
392
        """See RepositoryFormat.get_format_description()."""
393
        return "Weave repository format 5"
394
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
395
    def _get_inventories(self, repo_transport, repo, name='inventory'):
396
        mapper = versionedfile.ConstantMapper(name)
397
        return versionedfile.ThunkedVersionedFiles(repo_transport,
398
            weave.WeaveFile, mapper, repo.is_locked)
399
400
    def _get_revisions(self, repo_transport, repo):
401
        from bzrlib.xml5 import serializer_v5
402
        return RevisionTextStore(repo_transport.clone('revision-store'),
403
            serializer_v5, False, versionedfile.PrefixMapper(),
404
            repo.is_locked, repo.is_write_locked)
405
406
    def _get_signatures(self, repo_transport, repo):
407
        return SignatureTextStore(repo_transport.clone('revision-store'),
408
            False, versionedfile.PrefixMapper(),
409
            repo.is_locked, repo.is_write_locked)
410
411
    def _get_texts(self, repo_transport, repo):
412
        mapper = versionedfile.PrefixMapper()
413
        base_transport = repo_transport.clone('weaves')
414
        return versionedfile.ThunkedVersionedFiles(base_transport,
415
            weave.WeaveFile, mapper, repo.is_locked)
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
416
417
418
class RepositoryFormat6(PreSplitOutRepositoryFormat):
419
    """Bzr control format 6.
420
421
    This repository format has:
422
     - weaves for file texts and inventory
423
     - hash subdirectory based stores.
424
     - TextStores for revisions and signatures.
425
    """
426
2241.1.10 by Martin Pool
Remove more references to weaves from the repository.py file
427
    _versionedfile_class = weave.WeaveFile
2241.1.11 by Martin Pool
Get rid of RepositoryFormat*_instance objects. Instead the format
428
    _matchingbzrdir = bzrdir.BzrDirFormat6()
2241.1.10 by Martin Pool
Remove more references to weaves from the repository.py file
429
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
430
    def __init__(self):
431
        super(RepositoryFormat6, self).__init__()
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
432
        self._fetch_order = 'topological'
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
433
        self._fetch_reconcile = True
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
434
435
    def get_format_description(self):
436
        """See RepositoryFormat.get_format_description()."""
437
        return "Weave repository format 6"
438
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
439
    def _get_inventories(self, repo_transport, repo, name='inventory'):
440
        mapper = versionedfile.ConstantMapper(name)
441
        return versionedfile.ThunkedVersionedFiles(repo_transport,
442
            weave.WeaveFile, mapper, repo.is_locked)
443
444
    def _get_revisions(self, repo_transport, repo):
445
        from bzrlib.xml5 import serializer_v5
446
        return RevisionTextStore(repo_transport.clone('revision-store'),
447
            serializer_v5, False, versionedfile.HashPrefixMapper(),
448
            repo.is_locked, repo.is_write_locked)
449
450
    def _get_signatures(self, repo_transport, repo):
451
        return SignatureTextStore(repo_transport.clone('revision-store'),
452
            False, versionedfile.HashPrefixMapper(),
453
            repo.is_locked, repo.is_write_locked)
454
455
    def _get_texts(self, repo_transport, repo):
456
        mapper = versionedfile.HashPrefixMapper()
457
        base_transport = repo_transport.clone('weaves')
458
        return versionedfile.ThunkedVersionedFiles(base_transport,
459
            weave.WeaveFile, mapper, repo.is_locked)
460
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
461
462
class RepositoryFormat7(MetaDirRepositoryFormat):
463
    """Bzr repository 7.
464
465
    This repository format has:
466
     - weaves for file texts and inventory
467
     - hash subdirectory based stores.
468
     - TextStores for revisions and signatures.
469
     - a format marker of its own
470
     - an optional 'shared-storage' flag
471
     - an optional 'no-working-trees' flag
472
    """
473
2241.1.10 by Martin Pool
Remove more references to weaves from the repository.py file
474
    _versionedfile_class = weave.WeaveFile
2949.1.2 by Robert Collins
* Fetch with pack repositories will no longer read the entire history graph.
475
    supports_ghosts = False
2241.1.10 by Martin Pool
Remove more references to weaves from the repository.py file
476
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
477
    def get_format_string(self):
478
        """See RepositoryFormat.get_format_string()."""
479
        return "Bazaar-NG Repository format 7"
480
481
    def get_format_description(self):
482
        """See RepositoryFormat.get_format_description()."""
483
        return "Weave repository format 7"
484
485
    def check_conversion_target(self, target_format):
486
        pass
487
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
488
    def _get_inventories(self, repo_transport, repo, name='inventory'):
489
        mapper = versionedfile.ConstantMapper(name)
490
        return versionedfile.ThunkedVersionedFiles(repo_transport,
491
            weave.WeaveFile, mapper, repo.is_locked)
492
493
    def _get_revisions(self, repo_transport, repo):
494
        from bzrlib.xml5 import serializer_v5
495
        return RevisionTextStore(repo_transport.clone('revision-store'),
496
            serializer_v5, True, versionedfile.HashPrefixMapper(),
497
            repo.is_locked, repo.is_write_locked)
498
499
    def _get_signatures(self, repo_transport, repo):
500
        return SignatureTextStore(repo_transport.clone('revision-store'),
501
            True, versionedfile.HashPrefixMapper(),
502
            repo.is_locked, repo.is_write_locked)
503
504
    def _get_texts(self, repo_transport, repo):
505
        mapper = versionedfile.HashPrefixMapper()
506
        base_transport = repo_transport.clone('weaves')
507
        return versionedfile.ThunkedVersionedFiles(base_transport,
508
            weave.WeaveFile, mapper, repo.is_locked)
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
509
510
    def initialize(self, a_bzrdir, shared=False):
511
        """Create a weave repository.
512
513
        :param shared: If true the repository will be initialized as a shared
514
                       repository.
515
        """
516
        # Create an empty weave
517
        sio = StringIO()
518
        weavefile.write_weave_v5(weave.Weave(), sio)
519
        empty_weave = sio.getvalue()
520
521
        mutter('creating repository in %s.', a_bzrdir.transport.base)
522
        dirs = ['revision-store', 'weaves']
523
        files = [('inventory.weave', StringIO(empty_weave)), 
524
                 ]
525
        utf8_files = [('format', self.get_format_string())]
526
 
527
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
528
        return self.open(a_bzrdir=a_bzrdir, _found=True)
529
530
    def open(self, a_bzrdir, _found=False, _override_transport=None):
531
        """See RepositoryFormat.open().
532
        
533
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
534
                                    repository at a slightly different url
535
                                    than normal. I.e. during 'upgrade'.
536
        """
537
        if not _found:
538
            format = RepositoryFormat.find_format(a_bzrdir)
539
        if _override_transport is not None:
540
            repo_transport = _override_transport
541
        else:
542
            repo_transport = a_bzrdir.get_repository_transport(None)
543
        control_files = lockable_files.LockableFiles(repo_transport,
544
                                'lock', lockdir.LockDir)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
545
        result = WeaveMetaDirRepository(_format=self, a_bzrdir=a_bzrdir,
546
            control_files=control_files)
547
        result.revisions = self._get_revisions(repo_transport, result)
548
        result.signatures = self._get_signatures(repo_transport, result)
549
        result.inventories = self._get_inventories(repo_transport, result)
550
        result.texts = self._get_texts(repo_transport, result)
551
        result._transport = repo_transport
552
        return result
553
554
555
class TextVersionedFiles(VersionedFiles):
556
    """Just-a-bunch-of-files based VersionedFile stores."""
557
558
    def __init__(self, transport, compressed, mapper, is_locked, can_write):
559
        self._compressed = compressed
560
        self._transport = transport
561
        self._mapper = mapper
562
        if self._compressed:
563
            self._ext = '.gz'
564
        else:
565
            self._ext = ''
566
        self._is_locked = is_locked
567
        self._can_write = can_write
568
569
    def add_lines(self, key, parents, lines):
570
        """Add a revision to the store."""
571
        if not self._is_locked():
572
            raise errors.ObjectNotLocked(self)
573
        if not self._can_write():
574
            raise errors.ReadOnlyError(self)
575
        if '/' in key[-1]:
3350.6.10 by Martin Pool
VersionedFiles review cleanups
576
            raise ValueError('bad idea to put / in %r' % (key,))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
577
        text = ''.join(lines)
578
        if self._compressed:
579
            text = bytes_to_gzip(text)
580
        path = self._map(key)
581
        self._transport.put_bytes_non_atomic(path, text, create_parent_dir=True)
582
583
    def insert_record_stream(self, stream):
584
        adapters = {}
585
        for record in stream:
586
            # Raise an error when a record is missing.
587
            if record.storage_kind == 'absent':
588
                raise errors.RevisionNotPresent([record.key[0]], self)
589
            # adapt to non-tuple interface
590
            if record.storage_kind == 'fulltext':
591
                self.add_lines(record.key, None,
592
                    osutils.split_lines(record.get_bytes_as('fulltext')))
593
            else:
594
                adapter_key = record.storage_kind, 'fulltext'
595
                try:
596
                    adapter = adapters[adapter_key]
597
                except KeyError:
598
                    adapter_factory = adapter_registry.get(adapter_key)
599
                    adapter = adapter_factory(self)
600
                    adapters[adapter_key] = adapter
601
                lines = osutils.split_lines(adapter.get_bytes(
602
                    record, record.get_bytes_as(record.storage_kind)))
603
                try:
604
                    self.add_lines(record.key, None, lines)
605
                except RevisionAlreadyPresent:
606
                    pass
607
608
    def _load_text(self, key):
609
        if not self._is_locked():
610
            raise errors.ObjectNotLocked(self)
611
        path = self._map(key)
612
        try:
613
            text = self._transport.get_bytes(path)
614
            compressed = self._compressed
615
        except errors.NoSuchFile:
616
            if self._compressed:
617
                # try without the .gz
618
                path = path[:-3]
619
                try:
620
                    text = self._transport.get_bytes(path)
621
                    compressed = False
622
                except errors.NoSuchFile:
623
                    return None
624
            else:
625
                return None
626
        if compressed:
627
            text = GzipFile(mode='rb', fileobj=StringIO(text)).read()
628
        return text
629
630
    def _map(self, key):
631
        return self._mapper.map(key) + self._ext
632
633
634
class RevisionTextStore(TextVersionedFiles):
635
    """Legacy thunk for format 4 repositories."""
636
637
    def __init__(self, transport, serializer, compressed, mapper, is_locked,
638
        can_write):
639
        """Create a RevisionTextStore at transport with serializer."""
640
        TextVersionedFiles.__init__(self, transport, compressed, mapper,
641
            is_locked, can_write)
642
        self._serializer = serializer
643
644
    def _load_text_parents(self, key):
645
        text = self._load_text(key)
646
        if text is None:
647
            return None, None
648
        parents = self._serializer.read_revision_from_string(text).parent_ids
649
        return text, tuple((parent,) for parent in parents)
650
651
    def get_parent_map(self, keys):
652
        result = {}
653
        for key in keys:
654
            parents = self._load_text_parents(key)[1]
655
            if parents is None:
656
                continue
657
            result[key] = parents
658
        return result
659
    
660
    def get_record_stream(self, keys, sort_order, include_delta_closure):
661
        for key in keys:
662
            text, parents = self._load_text_parents(key)
663
            if text is None:
664
                yield AbsentContentFactory(key)
665
            else:
666
                yield FulltextContentFactory(key, parents, None, text)
667
668
    def keys(self):
669
        if not self._is_locked():
670
            raise errors.ObjectNotLocked(self)
671
        relpaths = set()
672
        for quoted_relpath in self._transport.iter_files_recursive():
673
            relpath = urllib.unquote(quoted_relpath)
674
            path, ext = os.path.splitext(relpath)
675
            if ext == '.gz':
676
                relpath = path
677
            if '.sig' not in relpath:
678
                relpaths.add(relpath)
679
        paths = list(relpaths)
680
        return set([self._mapper.unmap(path) for path in paths])
681
682
683
class SignatureTextStore(TextVersionedFiles):
684
    """Legacy thunk for format 4-7 repositories."""
685
686
    def __init__(self, transport, compressed, mapper, is_locked, can_write):
687
        TextVersionedFiles.__init__(self, transport, compressed, mapper,
688
            is_locked, can_write)
689
        self._ext = '.sig' + self._ext
690
691
    def get_parent_map(self, keys):
692
        result = {}
693
        for key in keys:
694
            text = self._load_text(key)
695
            if text is None:
696
                continue
697
            result[key] = None
698
        return result
699
    
700
    def get_record_stream(self, keys, sort_order, include_delta_closure):
701
        for key in keys:
702
            text = self._load_text(key)
703
            if text is None:
704
                yield AbsentContentFactory(key)
705
            else:
706
                yield FulltextContentFactory(key, None, None, text)
707
708
    def keys(self):
709
        if not self._is_locked():
710
            raise errors.ObjectNotLocked(self)
711
        relpaths = set()
712
        for quoted_relpath in self._transport.iter_files_recursive():
713
            relpath = urllib.unquote(quoted_relpath)
714
            path, ext = os.path.splitext(relpath)
715
            if ext == '.gz':
716
                relpath = path
717
            if not relpath.endswith('.sig'):
718
                continue
719
            relpaths.add(relpath[:-4])
720
        paths = list(relpaths)
721
        return set([self._mapper.unmap(path) for path in paths])
2803.2.1 by Robert Collins
* CommitBuilder now advertises itself as requiring the root entry to be
722
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
723
_legacy_formats = [RepositoryFormat4(),
724
                   RepositoryFormat5(),
725
                   RepositoryFormat6()]