~bzr-pqm/bzr/bzr.dev

1608.2.1 by Martin Pool
[merge] Storage filename escaping
1
# Copyright (C) 2005, 2006 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
16
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
17
# XXX: Some consideration of the problems that might occur if there are
18
# files whose id differs only in case.  That should probably be forbidden.
19
20
1471 by Robert Collins
Bugfix to previous url escaping patch - include weave stores
21
import errno
22
import os
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
23
from cStringIO import StringIO
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
24
from warnings import warn
1223 by Martin Pool
- store inventories in weave
25
2294.1.10 by John Arbash Meinel
Switch all apis over to utf8 file ids. All tests pass
26
from bzrlib import (
27
    errors,
28
    osutils,
29
    )
1223 by Martin Pool
- store inventories in weave
30
from bzrlib.weavefile import read_weave, write_weave_v5
1608.2.1 by Martin Pool
[merge] Storage filename escaping
31
from bzrlib.weave import WeaveFile, Weave
1185.80.6 by John Arbash Meinel
Adding tests to make sure weave stores can retrieve the files they add.
32
from bzrlib.store import TransportStore
1223 by Martin Pool
- store inventories in weave
33
from bzrlib.atomicfile import AtomicFile
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
34
from bzrlib.symbol_versioning import (deprecated_method,
2696.1.1 by Martin Pool
Remove things deprecated in 0.11 and earlier
35
        )
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
36
from bzrlib.trace import mutter
1185.80.10 by John Arbash Meinel
Adding progress indicators and improved get order for 'bzr branch'
37
import bzrlib.ui
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
38
39
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
40
class VersionedFileStore(TransportStore):
41
    """Collection of many versioned files in a transport."""
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
42
1651.1.1 by Martin Pool
[merge][wip] Storage escaping
43
    # TODO: Rather than passing versionedfile_kwargs, perhaps pass in a
44
    # transport factory callable?
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
45
    def __init__(self, transport, prefixed=False, precious=False,
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
46
                 dir_mode=None, file_mode=None,
1608.2.1 by Martin Pool
[merge] Storage filename escaping
47
                 versionedfile_class=WeaveFile,
1651.1.1 by Martin Pool
[merge][wip] Storage escaping
48
                 versionedfile_kwargs={},
1608.2.1 by Martin Pool
[merge] Storage filename escaping
49
                 escaped=False):
50
        super(VersionedFileStore, self).__init__(transport,
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
51
                dir_mode=dir_mode, file_mode=file_mode,
1185.80.1 by John Arbash Meinel
Text store and weave store both allow escaping fileid paths.
52
                prefixed=prefixed, compressed=False, escaped=escaped)
1417.1.10 by Robert Collins
add a cache bound to Transactions, and a precious facility, so that we keep inventory.weave in memory, but can discard weaves for other such files.
53
        self._precious = precious
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
54
        self._versionedfile_class = versionedfile_class
1628.1.4 by Robert Collins
Change knit format to use non-delta, non-annotated revisions and signatures.
55
        self._versionedfile_kwargs = versionedfile_kwargs
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
56
        # Used for passing get_scope to versioned file constructors;
57
        self.get_scope = None
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
58
1223 by Martin Pool
- store inventories in weave
59
    def filename(self, file_id):
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
60
        """Return the path relative to the transport root."""
1608.2.1 by Martin Pool
[merge] Storage filename escaping
61
        return self._relpath(file_id)
1429 by Robert Collins
merge in niemeyers prefixed-store patch
62
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
63
    def __iter__(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
64
        suffixes = self._versionedfile_class.get_suffixes()
1563.2.15 by Robert Collins
remove the weavestore assumptions about the number and nature of files it manages.
65
        ids = set()
1479 by Robert Collins
More quoting at the transport layer bugfixes.
66
        for relpath in self._iter_files_recursive():
1563.2.15 by Robert Collins
remove the weavestore assumptions about the number and nature of files it manages.
67
            for suffix in suffixes:
68
                if relpath.endswith(suffix):
1608.2.1 by Martin Pool
[merge] Storage filename escaping
69
                    # TODO: use standard remove_suffix function
70
                    escaped_id = os.path.basename(relpath[:-len(suffix)])
3350.6.1 by Robert Collins
* New ``versionedfile.KeyMapper`` interface to abstract out the access to
71
                    file_id = self._mapper.unmap(escaped_id)[0]
1608.2.1 by Martin Pool
[merge] Storage filename escaping
72
                    if file_id not in ids:
73
                        ids.add(file_id)
74
                        yield file_id
75
                    break # only one suffix can match
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
76
2294.1.10 by John Arbash Meinel
Switch all apis over to utf8 file ids. All tests pass
77
    def has_id(self, file_id):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
78
        suffixes = self._versionedfile_class.get_suffixes()
2294.1.10 by John Arbash Meinel
Switch all apis over to utf8 file ids. All tests pass
79
        filename = self.filename(file_id)
1563.2.15 by Robert Collins
remove the weavestore assumptions about the number and nature of files it manages.
80
        for suffix in suffixes:
81
            if not self._transport.has(filename + suffix):
82
                return False
83
        return True
1223 by Martin Pool
- store inventories in weave
84
1563.2.25 by Robert Collins
Merge in upstream.
85
    def get_empty(self, file_id, transaction):
86
        """Get an empty weave, which implies deleting the existing one first."""
87
        if self.has_id(file_id):
88
            self.delete(file_id, transaction)
89
        return self.get_weave_or_empty(file_id, transaction)
90
91
    def delete(self, file_id, transaction):
92
        """Remove file_id from the store."""
93
        suffixes = self._versionedfile_class.get_suffixes()
94
        filename = self.filename(file_id)
95
        for suffix in suffixes:
96
            self._transport.delete(filename + suffix)
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
97
98
    def _get(self, file_id):
99
        return self._transport.get(self.filename(file_id))
100
101
    def _put(self, file_id, f):
1185.80.6 by John Arbash Meinel
Adding tests to make sure weave stores can retrieve the files they add.
102
        fn = self.filename(file_id)
103
        try:
1955.3.9 by John Arbash Meinel
Find more occurrances of put() and replace with put_file or put_bytes
104
            return self._transport.put_file(fn, f, mode=self._file_mode)
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
105
        except errors.NoSuchFile:
1185.80.6 by John Arbash Meinel
Adding tests to make sure weave stores can retrieve the files they add.
106
            if not self._prefixed:
107
                raise
108
            self._transport.mkdir(os.path.dirname(fn), mode=self._dir_mode)
1955.3.9 by John Arbash Meinel
Find more occurrances of put() and replace with put_file or put_bytes
109
            return self._transport.put_file(fn, f, mode=self._file_mode)
1223 by Martin Pool
- store inventories in weave
110
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
111
    def get_weave(self, file_id, transaction, _filename=None):
112
        """Return the VersionedFile for file_id.
113
114
        :param _filename: filename that would be returned from self.filename for
115
        file_id. This is used to reduce duplicate filename calculations when
116
        using 'get_weave_or_empty'. FOR INTERNAL USE ONLY.
117
        """
118
        if _filename is None:
119
            _filename = self.filename(file_id)
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
120
        if transaction.writeable():
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
121
            w = self._versionedfile_class(_filename, self._transport, self._file_mode,
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
122
                get_scope=self.get_scope, **self._versionedfile_kwargs)
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
123
        else:
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
124
            w = self._versionedfile_class(_filename,
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
125
                                          self._transport,
126
                                          self._file_mode,
127
                                          create=False,
1628.1.4 by Robert Collins
Change knit format to use non-delta, non-annotated revisions and signatures.
128
                                          access_mode='r',
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
129
                                          get_scope=self.get_scope,
1628.1.4 by Robert Collins
Change knit format to use non-delta, non-annotated revisions and signatures.
130
                                          **self._versionedfile_kwargs)
1363 by Martin Pool
- add quick-and-dirty cache for weaves to speed check command
131
        return w
1262 by Martin Pool
- fetch should also copy ancestry records
132
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
133
    def _make_new_versionedfile(self, file_id, transaction,
134
        known_missing=False, _filename=None):
135
        """Make a new versioned file.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
136
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
137
        :param _filename: filename that would be returned from self.filename for
138
        file_id. This is used to reduce duplicate filename calculations when
139
        using 'get_weave_or_empty'. FOR INTERNAL USE ONLY.
140
        """
141
        if not known_missing and self.has_id(file_id):
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
142
            self.delete(file_id, transaction)
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
143
        if _filename is None:
144
            _filename = self.filename(file_id)
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
145
        try:
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
146
            # we try without making the directory first because thats optimising
147
            # for the common case.
148
            weave = self._versionedfile_class(_filename, self._transport, self._file_mode, create=True,
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
149
                get_scope=self.get_scope, **self._versionedfile_kwargs)
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
150
        except errors.NoSuchFile:
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
151
            if not self._prefixed:
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
152
                # unexpected error - NoSuchFile is expected to be raised on a
153
                # missing dir only and that only occurs when we are prefixed.
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
154
                raise
3350.6.1 by Robert Collins
* New ``versionedfile.KeyMapper`` interface to abstract out the access to
155
            dirname = osutils.dirname(_filename)
156
            self._transport.mkdir(dirname, mode=self._dir_mode)
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
157
            weave = self._versionedfile_class(_filename, self._transport,
1651.1.1 by Martin Pool
[merge][wip] Storage escaping
158
                                              self._file_mode, create=True,
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
159
                                              get_scope=self.get_scope,
1628.1.4 by Robert Collins
Change knit format to use non-delta, non-annotated revisions and signatures.
160
                                              **self._versionedfile_kwargs)
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
161
        return weave
162
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
163
    def get_weave_or_empty(self, file_id, transaction):
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
164
        """Return a weave, or an empty one if it doesn't exist."""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
165
        # This is typically used from 'commit' and 'fetch/push/pull' where
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
166
        # we scan across many versioned files once. As such the small overhead
167
        # of calculating the filename before doing a cache lookup is more than
168
        # compensated for by not calculating the filename when making new
169
        # versioned files.
170
        _filename = self.filename(file_id)
1224 by Martin Pool
- new method WeaveStore.get_weave_or_empty
171
        try:
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
172
            return self.get_weave(file_id, transaction, _filename=_filename)
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
173
        except errors.NoSuchFile:
1725.2.2 by Robert Collins
reduce file path escaping calls during commit.
174
            weave = self._make_new_versionedfile(file_id, transaction,
175
                known_missing=True, _filename=_filename)
176
            return weave
1224 by Martin Pool
- new method WeaveStore.get_weave_or_empty
177
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
178
    def _put_weave(self, file_id, weave, transaction):
179
        """Preserved here for upgrades-to-weaves to use."""
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
180
        myweave = self._make_new_versionedfile(file_id, transaction)
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.
181
        myweave.insert_record_stream(weave.get_record_stream(
182
            [(version,) for version in weave.versions()],
3350.3.20 by Robert Collins
Remove more uses of versionedfile.join() and fix a bug with weave's insert_record_stream.
183
            'topological', False))
1223 by Martin Pool
- store inventories in weave
184
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
185
    def copy_all_ids(self, store_from, pb=None, from_transaction=None,
186
                     to_transaction=None):
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
187
        """Copy all the file ids from store_from into self."""
188
        if from_transaction is None:
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
189
            warn("Please pass from_transaction into "
190
                 "versioned_store.copy_all_ids.", stacklevel=2)
191
        if to_transaction is None:
192
            warn("Please pass to_transaction into "
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
193
                 "versioned_store.copy_all_ids.", stacklevel=2)
194
        if not store_from.listable():
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
195
            raise errors.UnlistableStore(store_from)
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
196
        ids = []
197
        for count, file_id in enumerate(store_from):
198
            if pb:
199
                pb.update('listing files', count, count)
200
            ids.append(file_id)
201
        if pb:
202
            pb.clear()
203
        mutter('copy_all ids: %r', ids)
204
        self.copy_multi(store_from, ids, pb=pb,
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
205
                        from_transaction=from_transaction,
206
                        to_transaction=to_transaction)
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
207
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
208
    def copy_multi(self, from_store, file_ids, pb=None, from_transaction=None,
209
                   to_transaction=None):
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
210
        """Copy all the versions for multiple file_ids from from_store.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
211
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
212
        :param from_transaction: required current transaction in from_store.
213
        """
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
214
        from bzrlib.transactions import PassThroughTransaction
1563.2.14 by Robert Collins
Prepare weave store to delegate copy details to the versioned file.
215
        if from_transaction is None:
216
            warn("WeaveStore.copy_multi without a from_transaction parameter "
217
                 "is deprecated. Please provide a from_transaction.",
218
                 DeprecationWarning,
219
                 stacklevel=2)
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
220
            # we are reading one object - caching is irrelevant.
221
            from_transaction = PassThroughTransaction()
222
        if to_transaction is None:
223
            warn("WeaveStore.copy_multi without a to_transaction parameter "
224
                 "is deprecated. Please provide a to_transaction.",
225
                 DeprecationWarning,
226
                 stacklevel=2)
227
            # we are copying single objects, and there may be open tranasactions
228
            # so again with the passthrough
229
            to_transaction = PassThroughTransaction()
1608.2.1 by Martin Pool
[merge] Storage filename escaping
230
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
2127.1.1 by John Arbash Meinel
use try/finally to clean up a nested progress bar during weave fetching
231
        try:
232
            for count, f in enumerate(file_ids):
233
                mutter("copy weave {%s} into %s", f, self)
234
                pb.update('copy', count, len(file_ids))
235
                # if we have it in cache, its faster.
236
                # joining is fast with knits, and bearable for weaves -
237
                # indeed the new case can be optimised if needed.
238
                target = self._make_new_versionedfile(f, to_transaction)
3350.3.20 by Robert Collins
Remove more uses of versionedfile.join() and fix a bug with weave's insert_record_stream.
239
                source = from_store.get_weave(f, from_transaction)
240
                target.insert_record_stream(source.get_record_stream(
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.
241
                    [(version,) for version in source.versions()],
242
                    'topological', False))
2127.1.1 by John Arbash Meinel
use try/finally to clean up a nested progress bar during weave fetching
243
        finally:
244
            pb.finished()
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
245
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
246
    def total_size(self):
247
        count, bytes =  super(VersionedFileStore, self).total_size()
248
        return (count / len(self._versionedfile_class.get_suffixes())), bytes
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
249
250
WeaveStore = VersionedFileStore