/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
1185.85.80 by John Arbash Meinel
[merge] jam-integration 1527, including branch-formats, help text, misc bug fixes.
30
from bzrlib.errors import TransportError, NoSuchFile, FileExists, LockError
1442.1.44 by Robert Collins
Many transport related tweaks:
31
from bzrlib.trace import mutter
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
32
from bzrlib.transport import (Transport, register_transport, Server)
33
import bzrlib.urlutils as urlutils
1442.1.44 by Robert Collins
Many transport related tweaks:
34
35
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
36
1442.1.44 by Robert Collins
Many transport related tweaks:
37
class MemoryStat(object):
38
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
39
    def __init__(self, size, is_dir, perms):
1442.1.44 by Robert Collins
Many transport related tweaks:
40
        self.st_size = size
1530.1.3 by Robert Collins
transport implementations now tested consistently.
41
        if not is_dir:
1553.5.65 by Martin Pool
MemoryTransport: Set better permissions on fake directory inodes
42
            if perms is None:
43
                perms = 0644
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
44
            self.st_mode = S_IFREG | perms
1530.1.3 by Robert Collins
transport implementations now tested consistently.
45
        else:
1553.5.65 by Martin Pool
MemoryTransport: Set better permissions on fake directory inodes
46
            if perms is None:
47
                perms = 0755
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
48
            self.st_mode = S_IFDIR | perms
1442.1.44 by Robert Collins
Many transport related tweaks:
49
50
51
class MemoryTransport(Transport):
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
52
    """This is an in memory file system for transient data storage."""
1442.1.44 by Robert Collins
Many transport related tweaks:
53
1530.1.3 by Robert Collins
transport implementations now tested consistently.
54
    def __init__(self, url=""):
1442.1.44 by Robert Collins
Many transport related tweaks:
55
        """Set the 'base' path where files will be stored."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
56
        if url == "":
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
57
            url = "memory:///"
1530.1.3 by Robert Collins
transport implementations now tested consistently.
58
        if url[-1] != '/':
59
            url = url + '/'
60
        super(MemoryTransport, self).__init__(url)
1910.16.2 by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport.
61
        split = url.find(':') + 3
62
        self._scheme = url[:split]
63
        self._cwd = url[split:]
1553.5.16 by Martin Pool
MemoryTransport.rename() must raise exceptions on collision
64
        # dictionaries from absolute path to file mode
1685.1.44 by John Arbash Meinel
Now all MemoryTransports start with a valid root.
65
        self._dirs = {'/':None}
1442.1.44 by Robert Collins
Many transport related tweaks:
66
        self._files = {}
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
67
        self._locks = {}
1442.1.44 by Robert Collins
Many transport related tweaks:
68
69
    def clone(self, offset=None):
70
        """See Transport.clone()."""
1910.16.2 by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport.
71
        path = self._combine_paths(self._cwd, offset)
72
        if len(path) == 0 or path[-1] != '/':
73
            path += '/'
74
        url = self._scheme + path
1530.1.3 by Robert Collins
transport implementations now tested consistently.
75
        result = MemoryTransport(url)
76
        result._dirs = self._dirs
77
        result._files = self._files
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
78
        result._locks = self._locks
1530.1.3 by Robert Collins
transport implementations now tested consistently.
79
        return result
1442.1.44 by Robert Collins
Many transport related tweaks:
80
81
    def abspath(self, relpath):
82
        """See Transport.abspath()."""
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
83
        # while a little slow, this is sufficiently fast to not matter in our
84
        # current environment - XXX RBC 20060404 move the clone '..' handling
85
        # into here and call abspath from clone
86
        temp_t = self.clone(relpath)
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
87
        if temp_t.base.count('/') == 3:
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
88
            return temp_t.base
89
        else:
90
            return temp_t.base[:-1]
1442.1.44 by Robert Collins
Many transport related tweaks:
91
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
92
    def append_file(self, relpath, f, mode=None):
1955.3.16 by John Arbash Meinel
Switch over to Transport.append_bytes or append_files
93
        """See Transport.append_file()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
94
        _abspath = self._abspath(relpath)
95
        self._check_parent(_abspath)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
96
        orig_content, orig_mode = self._files.get(_abspath, ("", None))
1666.1.6 by Robert Collins
Make knit the default format.
97
        if mode is None:
98
            mode = orig_mode
99
        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.
100
        return len(orig_content)
1442.1.44 by Robert Collins
Many transport related tweaks:
101
1530.1.3 by Robert Collins
transport implementations now tested consistently.
102
    def _check_parent(self, _abspath):
103
        dir = os.path.dirname(_abspath)
104
        if dir != '/':
1442.1.44 by Robert Collins
Many transport related tweaks:
105
            if not dir in self._dirs:
1530.1.3 by Robert Collins
transport implementations now tested consistently.
106
                raise NoSuchFile(_abspath)
1442.1.44 by Robert Collins
Many transport related tweaks:
107
108
    def has(self, relpath):
109
        """See Transport.has()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
110
        _abspath = self._abspath(relpath)
1711.9.11 by John Arbash Meinel
change return foo in bar to return (foo in bar)
111
        return (_abspath in self._files) or (_abspath in self._dirs)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
112
113
    def delete(self, relpath):
114
        """See Transport.delete()."""
115
        _abspath = self._abspath(relpath)
116
        if not _abspath in self._files:
117
            raise NoSuchFile(relpath)
118
        del self._files[_abspath]
1442.1.44 by Robert Collins
Many transport related tweaks:
119
120
    def get(self, relpath):
121
        """See Transport.get()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
122
        _abspath = self._abspath(relpath)
123
        if not _abspath in self._files:
1442.1.44 by Robert Collins
Many transport related tweaks:
124
            raise NoSuchFile(relpath)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
125
        return StringIO(self._files[_abspath][0])
1442.1.44 by Robert Collins
Many transport related tweaks:
126
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
127
    def put_file(self, relpath, f, mode=None):
128
        """See Transport.put_file()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
129
        _abspath = self._abspath(relpath)
130
        self._check_parent(_abspath)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
131
        self._files[_abspath] = (f.read(), mode)
1442.1.44 by Robert Collins
Many transport related tweaks:
132
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
133
    def mkdir(self, relpath, mode=None):
1442.1.44 by Robert Collins
Many transport related tweaks:
134
        """See Transport.mkdir()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
135
        _abspath = self._abspath(relpath)
136
        self._check_parent(_abspath)
137
        if _abspath in self._dirs:
1442.1.44 by Robert Collins
Many transport related tweaks:
138
            raise FileExists(relpath)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
139
        self._dirs[_abspath]=mode
1442.1.44 by Robert Collins
Many transport related tweaks:
140
141
    def listable(self):
142
        """See Transport.listable."""
143
        return True
144
145
    def iter_files_recursive(self):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
146
        for file in self._files:
147
            if file.startswith(self._cwd):
1959.2.4 by John Arbash Meinel
MemoryTransport.iter_files_recursive() was not returning escaped paths
148
                yield urlutils.escape(file[len(self._cwd):])
1442.1.44 by Robert Collins
Many transport related tweaks:
149
    
1530.1.3 by Robert Collins
transport implementations now tested consistently.
150
    def list_dir(self, relpath):
151
        """See Transport.list_dir()."""
152
        _abspath = self._abspath(relpath)
153
        if _abspath != '/' and _abspath not in self._dirs:
154
            raise NoSuchFile(relpath)
155
        result = []
156
        for path in self._files:
157
            if (path.startswith(_abspath) and 
158
                path[len(_abspath) + 1:].find('/') == -1 and
159
                len(path) > len(_abspath)):
160
                result.append(path[len(_abspath) + 1:])
161
        for path in self._dirs:
162
            if (path.startswith(_abspath) and 
163
                path[len(_abspath) + 1:].find('/') == -1 and
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
164
                len(path) > len(_abspath) and
165
                path[len(_abspath)] == '/'):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
166
                result.append(path[len(_abspath) + 1:])
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
167
        return map(urlutils.escape, result)
1553.5.16 by Martin Pool
MemoryTransport.rename() must raise exceptions on collision
168
169
    def rename(self, rel_from, rel_to):
170
        """Rename a file or directory; fail if the destination exists"""
171
        abs_from = self._abspath(rel_from)
172
        abs_to = self._abspath(rel_to)
173
        def replace(x):
174
            if x == abs_from:
175
                x = abs_to
176
            elif x.startswith(abs_from + '/'):
177
                x = abs_to + x[len(abs_from):]
178
            return x
179
        def do_renames(container):
180
            for path in container:
181
                new_path = replace(path)
182
                if new_path != path:
183
                    if new_path in container:
184
                        raise FileExists(new_path)
185
                    container[new_path] = container[path]
186
                    del container[path]
187
        do_renames(self._files)
188
        do_renames(self._dirs)
1442.1.44 by Robert Collins
Many transport related tweaks:
189
    
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
190
    def rmdir(self, relpath):
191
        """See Transport.rmdir."""
192
        _abspath = self._abspath(relpath)
193
        if _abspath in self._files:
194
            self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
195
        for path in self._files:
196
            if path.startswith(_abspath):
1553.5.15 by Martin Pool
MemoryTransport should indicate ENOTEMPTY on rmdir of nonempty, same as unix
197
                self._translate_error(IOError(errno.ENOTEMPTY, relpath),
198
                                      relpath)
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
199
        for path in self._dirs:
200
            if path.startswith(_abspath) and path != _abspath:
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
201
                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.
202
        if not _abspath in self._dirs:
203
            raise NoSuchFile(relpath)
204
        del self._dirs[_abspath]
205
1442.1.44 by Robert Collins
Many transport related tweaks:
206
    def stat(self, relpath):
207
        """See Transport.stat()."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
208
        _abspath = self._abspath(relpath)
209
        if _abspath in self._files:
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
210
            return MemoryStat(len(self._files[_abspath][0]), False, 
211
                              self._files[_abspath][1])
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
212
        elif _abspath in self._dirs:
213
            return MemoryStat(0, True, self._dirs[_abspath])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
214
        else:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
215
            raise NoSuchFile(_abspath)
216
217
    def lock_read(self, relpath):
218
        """See Transport.lock_read()."""
219
        return _MemoryLock(self._abspath(relpath), self)
220
221
    def lock_write(self, relpath):
222
        """See Transport.lock_write()."""
223
        return _MemoryLock(self._abspath(relpath), self)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
224
225
    def _abspath(self, relpath):
226
        """Generate an internal absolute path."""
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
227
        relpath = urlutils.unescape(relpath)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
228
        if relpath.find('..') != -1:
229
            raise AssertionError('relpath contains ..')
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
230
        if relpath == '':
231
            return '/'
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
232
        if relpath[0] == '/':
233
            return relpath
1530.1.3 by Robert Collins
transport implementations now tested consistently.
234
        if relpath == '.':
1685.1.44 by John Arbash Meinel
Now all MemoryTransports start with a valid root.
235
            if (self._cwd == '/'):
236
                return self._cwd
1530.1.3 by Robert Collins
transport implementations now tested consistently.
237
            return self._cwd[:-1]
238
        if relpath.endswith('/'):
239
            relpath = relpath[:-1]
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
240
        if relpath.startswith('./'):
241
            relpath = relpath[2:]
1530.1.3 by Robert Collins
transport implementations now tested consistently.
242
        return self._cwd + relpath
243
244
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
245
class _MemoryLock(object):
246
    """This makes a lock."""
247
248
    def __init__(self, path, transport):
249
        assert isinstance(transport, MemoryTransport)
250
        self.path = path
251
        self.transport = transport
252
        if self.path in self.transport._locks:
253
            raise LockError('File %r already locked' % (self.path,))
254
        self.transport._locks[self.path] = self
255
256
    def __del__(self):
257
        # Should this warn, or actually try to cleanup?
258
        if self.transport:
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
259
            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.
260
            self.unlock()
261
262
    def unlock(self):
263
        del self.transport._locks[self.path]
264
        self.transport = None
265
266
1530.1.3 by Robert Collins
transport implementations now tested consistently.
267
class MemoryServer(Server):
268
    """Server for the MemoryTransport for testing with."""
269
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
270
    def setUp(self):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
271
        """See bzrlib.transport.Server.setUp."""
1685.1.44 by John Arbash Meinel
Now all MemoryTransports start with a valid root.
272
        self._dirs = {'/':None}
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
273
        self._files = {}
274
        self._locks = {}
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
275
        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.
276
        def memory_factory(url):
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
277
            result = MemoryTransport(url)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
278
            result._dirs = self._dirs
279
            result._files = self._files
280
            result._locks = self._locks
281
            return result
282
        register_transport(self._scheme, memory_factory)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
283
284
    def tearDown(self):
285
        """See bzrlib.transport.Server.tearDown."""
286
        # unregister this server
287
288
    def get_url(self):
289
        """See bzrlib.transport.Server.get_url."""
290
        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.
291
292
293
def get_test_permutations():
294
    """Return the permutations to be used in testing."""
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
295
    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.
296
            ]