/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/transport/memory.py

  • Committer: Jelmer Vernooij
  • Date: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
so this is primarily useful for testing.
21
21
"""
22
22
 
23
 
import contextlib
24
 
from io import (
25
 
    BytesIO,
26
 
    )
27
 
import itertools
 
23
from __future__ import absolute_import
 
24
 
28
25
import os
29
26
import errno
30
 
from stat import S_IFREG, S_IFDIR, S_IFLNK, S_ISDIR
 
27
from stat import S_IFREG, S_IFDIR
31
28
 
32
29
from .. import (
33
30
    transport,
38
35
    LockError,
39
36
    InProcessTransport,
40
37
    NoSuchFile,
41
 
    TransportNotPossible,
 
38
    )
 
39
from ..sixish import (
 
40
    BytesIO,
42
41
    )
43
42
from ..transport import (
44
43
    AppendBasedFileStream,
47
46
    )
48
47
 
49
48
 
 
49
 
50
50
class MemoryStat(object):
51
51
 
52
 
    def __init__(self, size, kind, perms=None):
 
52
    def __init__(self, size, is_dir, perms):
53
53
        self.st_size = size
54
 
        if not S_ISDIR(kind):
 
54
        if not is_dir:
55
55
            if perms is None:
56
56
                perms = 0o644
57
 
            self.st_mode = kind | perms
 
57
            self.st_mode = S_IFREG | perms
58
58
        else:
59
59
            if perms is None:
60
60
                perms = 0o755
61
 
            self.st_mode = kind | perms
 
61
            self.st_mode = S_IFDIR | perms
62
62
 
63
63
 
64
64
class MemoryTransport(transport.Transport):
75
75
        self._scheme = url[:split]
76
76
        self._cwd = url[split:]
77
77
        # dictionaries from absolute path to file mode
78
 
        self._dirs = {'/': None}
79
 
        self._symlinks = {}
 
78
        self._dirs = {'/':None}
80
79
        self._files = {}
81
80
        self._locks = {}
82
81
 
88
87
        url = self._scheme + path
89
88
        result = self.__class__(url)
90
89
        result._dirs = self._dirs
91
 
        result._symlinks = self._symlinks
92
90
        result._files = self._files
93
91
        result._locks = self._locks
94
92
        return result
106
104
 
107
105
    def append_file(self, relpath, f, mode=None):
108
106
        """See Transport.append_file()."""
109
 
        _abspath = self._resolve_symlinks(relpath)
 
107
        _abspath = self._abspath(relpath)
110
108
        self._check_parent(_abspath)
111
 
        orig_content, orig_mode = self._files.get(_abspath, (b"", None))
 
109
        orig_content, orig_mode = self._files.get(_abspath, ("", None))
112
110
        if mode is None:
113
111
            mode = orig_mode
114
112
        self._files[_abspath] = (orig_content + f.read(), mode)
117
115
    def _check_parent(self, _abspath):
118
116
        dir = os.path.dirname(_abspath)
119
117
        if dir != '/':
120
 
            if dir not in self._dirs:
 
118
            if not dir in self._dirs:
121
119
                raise NoSuchFile(_abspath)
122
120
 
123
121
    def has(self, relpath):
124
122
        """See Transport.has()."""
125
123
        _abspath = self._abspath(relpath)
126
 
        for container in (self._files, self._dirs, self._symlinks):
127
 
            if _abspath in container.keys():
128
 
                return True
129
 
        return False
 
124
        return (_abspath in self._files) or (_abspath in self._dirs)
130
125
 
131
126
    def delete(self, relpath):
132
127
        """See Transport.delete()."""
133
128
        _abspath = self._abspath(relpath)
134
 
        if _abspath in self._files:
135
 
            del self._files[_abspath]
136
 
        elif _abspath in self._symlinks:
137
 
            del self._symlinks[_abspath]
138
 
        else:
 
129
        if not _abspath in self._files:
139
130
            raise NoSuchFile(relpath)
 
131
        del self._files[_abspath]
140
132
 
141
133
    def external_url(self):
142
134
        """See breezy.transport.Transport.external_url."""
146
138
 
147
139
    def get(self, relpath):
148
140
        """See Transport.get()."""
149
 
        _abspath = self._resolve_symlinks(relpath)
150
 
        if _abspath not in self._files:
 
141
        _abspath = self._abspath(relpath)
 
142
        if not _abspath in self._files:
151
143
            if _abspath in self._dirs:
152
144
                return LateReadError(relpath)
153
145
            else:
156
148
 
157
149
    def put_file(self, relpath, f, mode=None):
158
150
        """See Transport.put_file()."""
159
 
        _abspath = self._resolve_symlinks(relpath)
 
151
        _abspath = self._abspath(relpath)
160
152
        self._check_parent(_abspath)
161
153
        raw_bytes = f.read()
162
154
        self._files[_abspath] = (raw_bytes, mode)
163
155
        return len(raw_bytes)
164
156
 
165
 
    def symlink(self, source, target):
166
 
        _abspath = self._resolve_symlinks(target)
167
 
        self._check_parent(_abspath)
168
 
        self._symlinks[_abspath] = self._abspath(source)
169
 
 
170
157
    def mkdir(self, relpath, mode=None):
171
158
        """See Transport.mkdir()."""
172
 
        _abspath = self._resolve_symlinks(relpath)
 
159
        _abspath = self._abspath(relpath)
173
160
        self._check_parent(_abspath)
174
161
        if _abspath in self._dirs:
175
162
            raise FileExists(relpath)
176
 
        self._dirs[_abspath] = mode
 
163
        self._dirs[_abspath]=mode
177
164
 
178
165
    def open_write_stream(self, relpath, mode=None):
179
166
        """See Transport.open_write_stream."""
180
 
        self.put_bytes(relpath, b"", mode)
 
167
        self.put_bytes(relpath, "", mode)
181
168
        result = AppendBasedFileStream(self, relpath)
182
169
        _file_streams[self.abspath(relpath)] = result
183
170
        return result
187
174
        return True
188
175
 
189
176
    def iter_files_recursive(self):
190
 
        for file in itertools.chain(self._files, self._symlinks):
 
177
        for file in self._files:
191
178
            if file.startswith(self._cwd):
192
179
                yield urlutils.escape(file[len(self._cwd):])
193
180
 
194
181
    def list_dir(self, relpath):
195
182
        """See Transport.list_dir()."""
196
 
        _abspath = self._resolve_symlinks(relpath)
 
183
        _abspath = self._abspath(relpath)
197
184
        if _abspath != '/' and _abspath not in self._dirs:
198
185
            raise NoSuchFile(relpath)
199
186
        result = []
201
188
        if not _abspath.endswith('/'):
202
189
            _abspath += '/'
203
190
 
204
 
        for path_group in self._files, self._dirs, self._symlinks:
 
191
        for path_group in self._files, self._dirs:
205
192
            for path in path_group:
206
193
                if path.startswith(_abspath):
207
194
                    trailing = path[len(_abspath):]
211
198
 
212
199
    def rename(self, rel_from, rel_to):
213
200
        """Rename a file or directory; fail if the destination exists"""
214
 
        abs_from = self._resolve_symlinks(rel_from)
215
 
        abs_to = self._resolve_symlinks(rel_to)
216
 
 
 
201
        abs_from = self._abspath(rel_from)
 
202
        abs_to = self._abspath(rel_to)
217
203
        def replace(x):
218
204
            if x == abs_from:
219
205
                x = abs_to
220
206
            elif x.startswith(abs_from + '/'):
221
207
                x = abs_to + x[len(abs_from):]
222
208
            return x
223
 
 
224
209
        def do_renames(container):
225
 
            renames = []
226
210
            for path in container:
227
211
                new_path = replace(path)
228
212
                if new_path != path:
229
213
                    if new_path in container:
230
214
                        raise FileExists(new_path)
231
 
                    renames.append((path, new_path))
232
 
            for path, new_path in renames:
233
 
                container[new_path] = container[path]
234
 
                del container[path]
235
 
 
236
 
        # If we modify the existing dicts, we're not atomic anymore and may
237
 
        # fail differently depending on dict order. So work on copy, fail on
238
 
        # error on only replace dicts if all goes well.
239
 
        renamed_files = self._files.copy()
240
 
        renamed_symlinks = self._symlinks.copy()
241
 
        renamed_dirs = self._dirs.copy()
242
 
        do_renames(renamed_files)
243
 
        do_renames(renamed_symlinks)
244
 
        do_renames(renamed_dirs)
245
 
        # We may have been cloned so modify in place
246
 
        self._files.clear()
247
 
        self._files.update(renamed_files)
248
 
        self._symlinks.clear()
249
 
        self._symlinks.update(renamed_symlinks)
250
 
        self._dirs.clear()
251
 
        self._dirs.update(renamed_dirs)
 
215
                    container[new_path] = container[path]
 
216
                    del container[path]
 
217
        do_renames(self._files)
 
218
        do_renames(self._dirs)
252
219
 
253
220
    def rmdir(self, relpath):
254
221
        """See Transport.rmdir."""
255
 
        _abspath = self._resolve_symlinks(relpath)
 
222
        _abspath = self._abspath(relpath)
256
223
        if _abspath in self._files:
257
224
            self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
258
 
        for path in itertools.chain(self._files, self._symlinks):
 
225
        for path in self._files:
259
226
            if path.startswith(_abspath + '/'):
260
227
                self._translate_error(IOError(errno.ENOTEMPTY, relpath),
261
228
                                      relpath)
262
229
        for path in self._dirs:
263
230
            if path.startswith(_abspath + '/') and path != _abspath:
264
 
                self._translate_error(
265
 
                    IOError(errno.ENOTEMPTY, relpath), relpath)
266
 
        if _abspath not in self._dirs:
 
231
                self._translate_error(IOError(errno.ENOTEMPTY, relpath), relpath)
 
232
        if not _abspath in self._dirs:
267
233
            raise NoSuchFile(relpath)
268
234
        del self._dirs[_abspath]
269
235
 
270
236
    def stat(self, relpath):
271
237
        """See Transport.stat()."""
272
238
        _abspath = self._abspath(relpath)
273
 
        if _abspath in self._files.keys():
274
 
            return MemoryStat(len(self._files[_abspath][0]), S_IFREG,
 
239
        if _abspath in self._files:
 
240
            return MemoryStat(len(self._files[_abspath][0]), False,
275
241
                              self._files[_abspath][1])
276
 
        elif _abspath in self._dirs.keys():
277
 
            return MemoryStat(0, S_IFDIR, self._dirs[_abspath])
278
 
        elif _abspath in self._symlinks.keys():
279
 
            return MemoryStat(0, S_IFLNK)
 
242
        elif _abspath in self._dirs:
 
243
            return MemoryStat(0, True, self._dirs[_abspath])
280
244
        else:
281
245
            raise NoSuchFile(_abspath)
282
246
 
288
252
        """See Transport.lock_write()."""
289
253
        return _MemoryLock(self._abspath(relpath), self)
290
254
 
291
 
    def _resolve_symlinks(self, relpath):
292
 
        path = self._abspath(relpath)
293
 
        while path in self._symlinks.keys():
294
 
            path = self._symlinks[path]
295
 
        return path
296
 
 
297
255
    def _abspath(self, relpath):
298
256
        """Generate an internal absolute path."""
299
257
        relpath = urlutils.unescape(relpath)
306
264
            if i == '..':
307
265
                if not r:
308
266
                    raise ValueError("illegal relpath %r under %r"
309
 
                                     % (relpath, self._cwd))
 
267
                        % (relpath, self._cwd))
310
268
                r = r[:-1]
311
269
            elif i == '.' or i == '':
312
270
                pass
313
271
            else:
314
272
                r.append(i)
315
 
                r = self._symlinks.get('/'.join(r), r)
316
273
        return '/' + '/'.join(r)
317
274
 
318
 
    def symlink(self, source, link_name):
319
 
        """Create a symlink pointing to source named link_name."""
320
 
        _abspath = self._abspath(link_name)
321
 
        self._check_parent(_abspath)
322
 
        self._symlinks[_abspath] = source.split('/')
323
 
 
324
 
    def readlink(self, link_name):
325
 
        _abspath = self._abspath(link_name)
326
 
        try:
327
 
            return '/'.join(self._symlinks[_abspath])
328
 
        except KeyError:
329
 
            raise NoSuchFile(link_name)
330
 
 
331
275
 
332
276
class _MemoryLock(object):
333
277
    """This makes a lock."""
348
292
    """Server for the MemoryTransport for testing with."""
349
293
 
350
294
    def start_server(self):
351
 
        self._dirs = {'/': None}
 
295
        self._dirs = {'/':None}
352
296
        self._files = {}
353
 
        self._symlinks = {}
354
297
        self._locks = {}
355
298
        self._scheme = "memory+%s:///" % id(self)
356
 
 
357
299
        def memory_factory(url):
358
300
            from . import memory
359
301
            result = memory.MemoryTransport(url)
360
302
            result._dirs = self._dirs
361
303
            result._files = self._files
362
 
            result._symlinks = self._symlinks
363
304
            result._locks = self._locks
364
305
            return result
365
306
        self._memory_factory = memory_factory