~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/memory.py

  • Committer: Robert Collins
  • Date: 2006-02-28 04:31:50 UTC
  • mto: This revision was merged to the branch mainline in revision 1583.
  • Revision ID: robertc@robertcollins.net-20060228043150-fdb9c7f7231b271b
Bugfix aliases to be backwards compatible with plugins providing command.run_argv.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
 
#
 
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
20
so this is primarily useful for testing.
21
21
"""
22
22
 
 
23
from copy import copy
23
24
import os
24
25
import errno
25
26
import re
26
 
from stat import S_IFREG, S_IFDIR
 
27
from stat import *
27
28
from cStringIO import StringIO
28
 
import warnings
29
29
 
 
30
from bzrlib.trace import mutter
30
31
from bzrlib.errors import TransportError, NoSuchFile, FileExists, LockError
31
 
from bzrlib.trace import mutter
32
 
from bzrlib.transport import (Transport, register_transport, Server)
33
 
import bzrlib.urlutils as urlutils
34
 
 
35
 
 
 
32
from bzrlib.transport import Transport, register_transport, Server
36
33
 
37
34
class MemoryStat(object):
38
35
 
39
36
    def __init__(self, size, is_dir, perms):
40
37
        self.st_size = size
 
38
        if perms is None:
 
39
            perms = 0644
41
40
        if not is_dir:
42
 
            if perms is None:
43
 
                perms = 0644
44
41
            self.st_mode = S_IFREG | perms
45
42
        else:
46
 
            if perms is None:
47
 
                perms = 0755
48
43
            self.st_mode = S_IFDIR | perms
49
44
 
50
45
 
54
49
    def __init__(self, url=""):
55
50
        """Set the 'base' path where files will be stored."""
56
51
        if url == "":
57
 
            url = "memory:///"
 
52
            url = "memory:/"
58
53
        if url[-1] != '/':
59
54
            url = url + '/'
60
55
        super(MemoryTransport, self).__init__(url)
61
 
        split = url.find(':') + 3
62
 
        self._scheme = url[:split]
63
 
        self._cwd = url[split:]
 
56
        self._cwd = url[url.find(':') + 1:]
64
57
        # dictionaries from absolute path to file mode
65
 
        self._dirs = {'/':None}
 
58
        self._dirs = {}
66
59
        self._files = {}
67
60
        self._locks = {}
68
61
 
69
62
    def clone(self, offset=None):
70
63
        """See Transport.clone()."""
71
 
        path = self._combine_paths(self._cwd, offset)
72
 
        if len(path) == 0 or path[-1] != '/':
73
 
            path += '/'
74
 
        url = self._scheme + path
 
64
        if offset is None:
 
65
            return copy(self)
 
66
        segments = offset.split('/')
 
67
        cwdsegments = self._cwd.split('/')[:-1]
 
68
        while len(segments):
 
69
            segment = segments.pop(0)
 
70
            if segment == '.':
 
71
                continue
 
72
            if segment == '..':
 
73
                if len(cwdsegments) > 1:
 
74
                    cwdsegments.pop()
 
75
                continue
 
76
            cwdsegments.append(segment)
 
77
        url = self.base[:self.base.find(':') + 1] + '/'.join(cwdsegments) + '/'
75
78
        result = MemoryTransport(url)
76
79
        result._dirs = self._dirs
77
80
        result._files = self._files
80
83
 
81
84
    def abspath(self, relpath):
82
85
        """See Transport.abspath()."""
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)
87
 
        if temp_t.base.count('/') == 3:
88
 
            return temp_t.base
89
 
        else:
90
 
            return temp_t.base[:-1]
 
86
        return self.base[:-1] + self._abspath(relpath)[len(self._cwd) - 1:]
91
87
 
92
 
    def append_file(self, relpath, f, mode=None):
93
 
        """See Transport.append_file()."""
 
88
    def append(self, relpath, f):
 
89
        """See Transport.append()."""
94
90
        _abspath = self._abspath(relpath)
95
91
        self._check_parent(_abspath)
96
92
        orig_content, orig_mode = self._files.get(_abspath, ("", None))
97
 
        if mode is None:
98
 
            mode = orig_mode
99
 
        self._files[_abspath] = (orig_content + f.read(), mode)
100
 
        return len(orig_content)
 
93
        self._files[_abspath] = (orig_content + f.read(), orig_mode)
101
94
 
102
95
    def _check_parent(self, _abspath):
103
96
        dir = os.path.dirname(_abspath)
108
101
    def has(self, relpath):
109
102
        """See Transport.has()."""
110
103
        _abspath = self._abspath(relpath)
111
 
        return (_abspath in self._files) or (_abspath in self._dirs)
 
104
        return _abspath in self._files or _abspath in self._dirs
112
105
 
113
106
    def delete(self, relpath):
114
107
        """See Transport.delete()."""
124
117
            raise NoSuchFile(relpath)
125
118
        return StringIO(self._files[_abspath][0])
126
119
 
127
 
    def put_file(self, relpath, f, mode=None):
128
 
        """See Transport.put_file()."""
 
120
    def put(self, relpath, f, mode=None):
 
121
        """See Transport.put()."""
129
122
        _abspath = self._abspath(relpath)
130
123
        self._check_parent(_abspath)
131
124
        self._files[_abspath] = (f.read(), mode)
145
138
    def iter_files_recursive(self):
146
139
        for file in self._files:
147
140
            if file.startswith(self._cwd):
148
 
                yield urlutils.escape(file[len(self._cwd):])
 
141
                yield file[len(self._cwd):]
149
142
    
150
143
    def list_dir(self, relpath):
151
144
        """See Transport.list_dir()."""
164
157
                len(path) > len(_abspath) and
165
158
                path[len(_abspath)] == '/'):
166
159
                result.append(path[len(_abspath) + 1:])
167
 
        return map(urlutils.escape, result)
 
160
        return result
168
161
 
169
162
    def rename(self, rel_from, rel_to):
170
163
        """Rename a file or directory; fail if the destination exists"""
209
202
        if _abspath in self._files:
210
203
            return MemoryStat(len(self._files[_abspath][0]), False, 
211
204
                              self._files[_abspath][1])
 
205
        elif _abspath == '':
 
206
            return MemoryStat(0, True, None)
212
207
        elif _abspath in self._dirs:
213
208
            return MemoryStat(0, True, self._dirs[_abspath])
214
209
        else:
224
219
 
225
220
    def _abspath(self, relpath):
226
221
        """Generate an internal absolute path."""
227
 
        relpath = urlutils.unescape(relpath)
228
222
        if relpath.find('..') != -1:
229
223
            raise AssertionError('relpath contains ..')
230
 
        if relpath == '':
231
 
            return '/'
232
 
        if relpath[0] == '/':
233
 
            return relpath
234
224
        if relpath == '.':
235
 
            if (self._cwd == '/'):
236
 
                return self._cwd
237
225
            return self._cwd[:-1]
238
226
        if relpath.endswith('/'):
239
227
            relpath = relpath[:-1]
256
244
    def __del__(self):
257
245
        # Should this warn, or actually try to cleanup?
258
246
        if self.transport:
259
 
            warnings.warn("MemoryLock %r not explicitly unlocked" % (self.path,))
 
247
            warn("MemoryLock %r not explicitly unlocked" % (self.path,))
260
248
            self.unlock()
261
249
 
262
250
    def unlock(self):
269
257
 
270
258
    def setUp(self):
271
259
        """See bzrlib.transport.Server.setUp."""
272
 
        self._dirs = {'/':None}
 
260
        self._dirs = {}
273
261
        self._files = {}
274
262
        self._locks = {}
275
 
        self._scheme = "memory+%s:///" % id(self)
 
263
        self._scheme = "memory+%s:" % id(self)
276
264
        def memory_factory(url):
277
265
            result = MemoryTransport(url)
278
266
            result._dirs = self._dirs