/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1553.5.16 by Martin Pool
MemoryTransport.rename() must raise exceptions on collision
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
#
1442.1.44 by Robert Collins
Many transport related tweaks:
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
#
1442.1.44 by Robert Collins
Many transport related tweaks:
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
#
1442.1.44 by Robert Collins
Many transport related tweaks:
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
1553.5.14 by Martin Pool
doc
16
17
"""Implementation of Transport that uses memory for its storage.
18
19
The contents of the transport will be lost when the object is discarded,
20
so this is primarily useful for testing.
21
"""
1442.1.44 by Robert Collins
Many transport related tweaks:
22
23
import os
24
import errno
1553.5.16 by Martin Pool
MemoryTransport.rename() must raise exceptions on collision
25
import re
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
26
from stat import S_IFREG, S_IFDIR
1442.1.44 by Robert Collins
Many transport related tweaks:
27
from cStringIO import StringIO
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
28
import warnings
1442.1.44 by Robert Collins
Many transport related tweaks:
29
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
30
from bzrlib.errors import (
31
    FileExists,
32
    LockError,
33
    InProcessTransport,
34
    NoSuchFile,
35
    TransportError,
36
    )
1442.1.44 by Robert Collins
Many transport related tweaks:
37
from bzrlib.trace import mutter
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
38
from bzrlib.transport import (
2671.3.6 by Robert Collins
Review feedback.
39
    AppendBasedFileStream,
2671.3.2 by Robert Collins
Start open_file_stream logic.
40
    _file_streams,
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
41
    LateReadError,
42
    register_transport,
43
    Server,
44
    Transport,
45
    )
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
46
import bzrlib.urlutils as urlutils
1442.1.44 by Robert Collins
Many transport related tweaks:
47
48
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
49
1442.1.44 by Robert Collins
Many transport related tweaks:
50
class MemoryStat(object):
51
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
52
    def __init__(self, size, is_dir, perms):
1442.1.44 by Robert Collins
Many transport related tweaks:
53
        self.st_size = size
1530.1.3 by Robert Collins
transport implementations now tested consistently.
54
        if not is_dir:
1553.5.65 by Martin Pool
MemoryTransport: Set better permissions on fake directory inodes
55
            if perms is None:
56
                perms = 0644
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
57
            self.st_mode = S_IFREG | perms
1530.1.3 by Robert Collins
transport implementations now tested consistently.
58
        else:
1553.5.65 by Martin Pool
MemoryTransport: Set better permissions on fake directory inodes
59
            if perms is None:
60
                perms = 0755
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
61
            self.st_mode = S_IFDIR | perms
1442.1.44 by Robert Collins
Many transport related tweaks:
62
63
64
class MemoryTransport(Transport):
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
65
    """This is an in memory file system for transient data storage."""
1442.1.44 by Robert Collins
Many transport related tweaks:
66
1530.1.3 by Robert Collins
transport implementations now tested consistently.
67
    def __init__(self, url=""):
1442.1.44 by Robert Collins
Many transport related tweaks:
68
        """Set the 'base' path where files will be stored."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
69
        if url == "":
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
70
            url = "memory:///"
1530.1.3 by Robert Collins
transport implementations now tested consistently.
71
        if url[-1] != '/':
72
            url = url + '/'
73
        super(MemoryTransport, self).__init__(url)
1910.16.2 by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport.
74
        split = url.find(':') + 3
75
        self._scheme = url[:split]
76
        self._cwd = url[split:]
1553.5.16 by Martin Pool
MemoryTransport.rename() must raise exceptions on collision
77
        # dictionaries from absolute path to file mode
1685.1.44 by John Arbash Meinel
Now all MemoryTransports start with a valid root.
78
        self._dirs = {'/':None}
1442.1.44 by Robert Collins
Many transport related tweaks:
79
        self._files = {}
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
80
        self._locks = {}
1442.1.44 by Robert Collins
Many transport related tweaks:
81
82
    def clone(self, offset=None):
83
        """See Transport.clone()."""
1910.16.2 by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport.
84
        path = self._combine_paths(self._cwd, offset)
85
        if len(path) == 0 or path[-1] != '/':
86
            path += '/'
87
        url = self._scheme + path
1530.1.3 by Robert Collins
transport implementations now tested consistently.
88
        result = MemoryTransport(url)
89
        result._dirs = self._dirs
90
        result._files = self._files
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
91
        result._locks = self._locks
1530.1.3 by Robert Collins
transport implementations now tested consistently.
92
        return result
1442.1.44 by Robert Collins
Many transport related tweaks:
93
94
    def abspath(self, relpath):
95
        """See Transport.abspath()."""
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
96
        # while a little slow, this is sufficiently fast to not matter in our
97
        # current environment - XXX RBC 20060404 move the clone '..' handling
98
        # into here and call abspath from clone
99
        temp_t = self.clone(relpath)
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
100
        if temp_t.base.count('/') == 3:
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
101
            return temp_t.base
102
        else:
103
            return temp_t.base[:-1]
1442.1.44 by Robert Collins
Many transport related tweaks:
104
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
105
    def append_file(self, relpath, f, mode=None):
1955.3.16 by John Arbash Meinel
Switch over to Transport.append_bytes or append_files
106
        """See Transport.append_file()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
107
        _abspath = self._abspath(relpath)
108
        self._check_parent(_abspath)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
109
        orig_content, orig_mode = self._files.get(_abspath, ("", None))
1666.1.6 by Robert Collins
Make knit the default format.
110
        if mode is None:
111
            mode = orig_mode
112
        self._files[_abspath] = (orig_content + f.read(), mode)
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
113
        return len(orig_content)
1442.1.44 by Robert Collins
Many transport related tweaks:
114
1530.1.3 by Robert Collins
transport implementations now tested consistently.
115
    def _check_parent(self, _abspath):
116
        dir = os.path.dirname(_abspath)
117
        if dir != '/':
1442.1.44 by Robert Collins
Many transport related tweaks:
118
            if not dir in self._dirs:
1530.1.3 by Robert Collins
transport implementations now tested consistently.
119
                raise NoSuchFile(_abspath)
1442.1.44 by Robert Collins
Many transport related tweaks:
120
121
    def has(self, relpath):
122
        """See Transport.has()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
123
        _abspath = self._abspath(relpath)
1711.9.11 by John Arbash Meinel
change return foo in bar to return (foo in bar)
124
        return (_abspath in self._files) or (_abspath in self._dirs)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
125
126
    def delete(self, relpath):
127
        """See Transport.delete()."""
128
        _abspath = self._abspath(relpath)
129
        if not _abspath in self._files:
130
            raise NoSuchFile(relpath)
131
        del self._files[_abspath]
1442.1.44 by Robert Collins
Many transport related tweaks:
132
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
133
    def external_url(self):
134
        """See bzrlib.transport.Transport.external_url."""
135
        # MemoryTransport's are only accessible in-process
136
        # so we raise here
137
        raise InProcessTransport(self)
138
2164.2.15 by Vincent Ladeuil
Http redirections are not followed by default. Do not use hints
139
    def get(self, relpath):
1442.1.44 by Robert Collins
Many transport related tweaks:
140
        """See Transport.get()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
141
        _abspath = self._abspath(relpath)
142
        if not _abspath in self._files:
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
143
            if _abspath in self._dirs:
144
                return LateReadError(relpath)
145
            else:
146
                raise NoSuchFile(relpath)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
147
        return StringIO(self._files[_abspath][0])
1442.1.44 by Robert Collins
Many transport related tweaks:
148
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
149
    def put_file(self, relpath, f, mode=None):
150
        """See Transport.put_file()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
151
        _abspath = self._abspath(relpath)
152
        self._check_parent(_abspath)
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
153
        bytes = f.read()
154
        if type(bytes) is not str:
155
            # Although not strictly correct, we raise UnicodeEncodeError to be
156
            # compatible with other transports.
157
            raise UnicodeEncodeError(
158
                'undefined', bytes, 0, 1,
159
                'put_file must be given a file of bytes, not unicode.')
160
        self._files[_abspath] = (bytes, mode)
1442.1.44 by Robert Collins
Many transport related tweaks:
161
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
162
    def mkdir(self, relpath, mode=None):
1442.1.44 by Robert Collins
Many transport related tweaks:
163
        """See Transport.mkdir()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
164
        _abspath = self._abspath(relpath)
165
        self._check_parent(_abspath)
166
        if _abspath in self._dirs:
1442.1.44 by Robert Collins
Many transport related tweaks:
167
            raise FileExists(relpath)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
168
        self._dirs[_abspath]=mode
1442.1.44 by Robert Collins
Many transport related tweaks:
169
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
170
    def open_write_stream(self, relpath, mode=None):
171
        """See Transport.open_write_stream."""
2671.3.6 by Robert Collins
Review feedback.
172
        self.put_bytes(relpath, "", mode)
173
        result = AppendBasedFileStream(self, relpath)
174
        _file_streams[self.abspath(relpath)] = result
175
        return result
2671.3.2 by Robert Collins
Start open_file_stream logic.
176
1442.1.44 by Robert Collins
Many transport related tweaks:
177
    def listable(self):
178
        """See Transport.listable."""
179
        return True
180
181
    def iter_files_recursive(self):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
182
        for file in self._files:
183
            if file.startswith(self._cwd):
1959.2.4 by John Arbash Meinel
MemoryTransport.iter_files_recursive() was not returning escaped paths
184
                yield urlutils.escape(file[len(self._cwd):])
1442.1.44 by Robert Collins
Many transport related tweaks:
185
    
1530.1.3 by Robert Collins
transport implementations now tested consistently.
186
    def list_dir(self, relpath):
187
        """See Transport.list_dir()."""
188
        _abspath = self._abspath(relpath)
189
        if _abspath != '/' and _abspath not in self._dirs:
190
            raise NoSuchFile(relpath)
191
        result = []
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
192
193
        if not _abspath.endswith('/'):
194
            _abspath += '/'
195
196
        for path_group in self._files, self._dirs:
197
            for path in path_group:
198
                if path.startswith(_abspath):
199
                    trailing = path[len(_abspath):]
200
                    if trailing and '/' not in trailing:
201
                        result.append(trailing)
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
202
        return map(urlutils.escape, result)
1553.5.16 by Martin Pool
MemoryTransport.rename() must raise exceptions on collision
203
204
    def rename(self, rel_from, rel_to):
205
        """Rename a file or directory; fail if the destination exists"""
206
        abs_from = self._abspath(rel_from)
207
        abs_to = self._abspath(rel_to)
208
        def replace(x):
209
            if x == abs_from:
210
                x = abs_to
211
            elif x.startswith(abs_from + '/'):
212
                x = abs_to + x[len(abs_from):]
213
            return x
214
        def do_renames(container):
215
            for path in container:
216
                new_path = replace(path)
217
                if new_path != path:
218
                    if new_path in container:
219
                        raise FileExists(new_path)
220
                    container[new_path] = container[path]
221
                    del container[path]
222
        do_renames(self._files)
223
        do_renames(self._dirs)
1442.1.44 by Robert Collins
Many transport related tweaks:
224
    
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
225
    def rmdir(self, relpath):
226
        """See Transport.rmdir."""
227
        _abspath = self._abspath(relpath)
228
        if _abspath in self._files:
229
            self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
230
        for path in self._files:
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
231
            if path.startswith(_abspath + '/'):
1553.5.15 by Martin Pool
MemoryTransport should indicate ENOTEMPTY on rmdir of nonempty, same as unix
232
                self._translate_error(IOError(errno.ENOTEMPTY, relpath),
233
                                      relpath)
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
234
        for path in self._dirs:
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
235
            if path.startswith(_abspath + '/') and path != _abspath:
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
236
                self._translate_error(IOError(errno.ENOTEMPTY, relpath), relpath)
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
237
        if not _abspath in self._dirs:
238
            raise NoSuchFile(relpath)
239
        del self._dirs[_abspath]
240
1442.1.44 by Robert Collins
Many transport related tweaks:
241
    def stat(self, relpath):
242
        """See Transport.stat()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
243
        _abspath = self._abspath(relpath)
244
        if _abspath in self._files:
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
245
            return MemoryStat(len(self._files[_abspath][0]), False, 
246
                              self._files[_abspath][1])
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
247
        elif _abspath in self._dirs:
248
            return MemoryStat(0, True, self._dirs[_abspath])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
249
        else:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
250
            raise NoSuchFile(_abspath)
251
252
    def lock_read(self, relpath):
253
        """See Transport.lock_read()."""
254
        return _MemoryLock(self._abspath(relpath), self)
255
256
    def lock_write(self, relpath):
257
        """See Transport.lock_write()."""
258
        return _MemoryLock(self._abspath(relpath), self)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
259
260
    def _abspath(self, relpath):
261
        """Generate an internal absolute path."""
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
262
        relpath = urlutils.unescape(relpath)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
263
        if relpath.find('..') != -1:
264
            raise AssertionError('relpath contains ..')
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
265
        if relpath == '':
266
            return '/'
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
267
        if relpath[0] == '/':
268
            return relpath
1530.1.3 by Robert Collins
transport implementations now tested consistently.
269
        if relpath == '.':
1685.1.44 by John Arbash Meinel
Now all MemoryTransports start with a valid root.
270
            if (self._cwd == '/'):
271
                return self._cwd
1530.1.3 by Robert Collins
transport implementations now tested consistently.
272
            return self._cwd[:-1]
273
        if relpath.endswith('/'):
274
            relpath = relpath[:-1]
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
275
        if relpath.startswith('./'):
276
            relpath = relpath[2:]
1530.1.3 by Robert Collins
transport implementations now tested consistently.
277
        return self._cwd + relpath
278
279
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
280
class _MemoryLock(object):
281
    """This makes a lock."""
282
283
    def __init__(self, path, transport):
284
        assert isinstance(transport, MemoryTransport)
285
        self.path = path
286
        self.transport = transport
287
        if self.path in self.transport._locks:
288
            raise LockError('File %r already locked' % (self.path,))
289
        self.transport._locks[self.path] = self
290
291
    def __del__(self):
292
        # Should this warn, or actually try to cleanup?
293
        if self.transport:
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
294
            warnings.warn("MemoryLock %r not explicitly unlocked" % (self.path,))
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
295
            self.unlock()
296
297
    def unlock(self):
298
        del self.transport._locks[self.path]
299
        self.transport = None
300
301
1530.1.3 by Robert Collins
transport implementations now tested consistently.
302
class MemoryServer(Server):
303
    """Server for the MemoryTransport for testing with."""
304
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
305
    def setUp(self):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
306
        """See bzrlib.transport.Server.setUp."""
1685.1.44 by John Arbash Meinel
Now all MemoryTransports start with a valid root.
307
        self._dirs = {'/':None}
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
308
        self._files = {}
309
        self._locks = {}
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
310
        self._scheme = "memory+%s:///" % id(self)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
311
        def memory_factory(url):
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
312
            result = MemoryTransport(url)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
313
            result._dirs = self._dirs
314
            result._files = self._files
315
            result._locks = self._locks
316
            return result
317
        register_transport(self._scheme, memory_factory)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
318
319
    def tearDown(self):
320
        """See bzrlib.transport.Server.tearDown."""
321
        # unregister this server
322
323
    def get_url(self):
324
        """See bzrlib.transport.Server.get_url."""
325
        return self._scheme
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
326
327
328
def get_test_permutations():
329
    """Return the permutations to be used in testing."""
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
330
    return [(MemoryTransport, MemoryServer),
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
331
            ]