Merge lp:~jelmer/brz/memorytransport-links into lp:brz

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/memorytransport-links
Merge into: lp:brz
Diff against target: 174 lines (+55/-9)
4 files modified
breezy/tests/per_transport.py (+10/-0)
breezy/tests/stub_sftp.py (+9/-1)
breezy/transport/local.py (+4/-1)
breezy/transport/memory.py (+32/-7)
To merge this branch: bzr merge lp:~jelmer/brz/memorytransport-links
Reviewer Review Type Date Requested Status
Martin Packman Approve
Review via email: mp+355006@code.launchpad.net

Commit message

Support symlinks in MemoryTransport, and add tests for Transport.readlink.

Description of the change

Support symlinks in MemoryTransport, and add tests for Transport.readlink.

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

All looks sensible to me, see one inline note about assertion.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'breezy/tests/per_transport.py'
--- breezy/tests/per_transport.py 2018-08-04 18:44:34 +0000
+++ breezy/tests/per_transport.py 2018-09-21 22:47:54 +0000
@@ -1021,6 +1021,16 @@
1021 raise TestSkipped("Transport %s does not support symlinks." %1021 raise TestSkipped("Transport %s does not support symlinks." %
1022 self._server.__class__)1022 self._server.__class__)
10231023
1024 self.assertEqual(source_name, t.readlink(link_name))
1025
1026 def test_readlink_nonexistent(self):
1027 t = self.get_transport()
1028 try:
1029 self.assertRaises(NoSuchFile, t.readlink, 'nonexistent')
1030 except TransportNotPossible:
1031 raise TestSkipped("Transport %s does not support symlinks." %
1032 self._server.__class__)
1033
1024 def test_list_dir(self):1034 def test_list_dir(self):
1025 # TODO: Test list_dir, just try once, and if it throws, stop testing1035 # TODO: Test list_dir, just try once, and if it throws, stop testing
1026 t = self.get_transport()1036 t = self.get_transport()
10271037
=== modified file 'breezy/tests/stub_sftp.py'
--- breezy/tests/stub_sftp.py 2018-08-04 18:44:34 +0000
+++ breezy/tests/stub_sftp.py 2018-09-21 22:47:54 +0000
@@ -224,6 +224,14 @@
224 return paramiko.SFTPServer.convert_errno(e.errno)224 return paramiko.SFTPServer.convert_errno(e.errno)
225 return paramiko.SFTP_OK225 return paramiko.SFTP_OK
226226
227 def readlink(self, path):
228 path = self._realpath(path)
229 try:
230 target_path = os.readlink(path)
231 except OSError as e:
232 return paramiko.SFTPServer.convert_errno(e.errno)
233 return target_path
234
227 def mkdir(self, path, attr):235 def mkdir(self, path, attr):
228 path = self._realpath(path)236 path = self._realpath(path)
229 try:237 try:
@@ -248,7 +256,7 @@
248 return paramiko.SFTPServer.convert_errno(e.errno)256 return paramiko.SFTPServer.convert_errno(e.errno)
249 return paramiko.SFTP_OK257 return paramiko.SFTP_OK
250258
251 # removed: chattr, symlink, readlink259 # removed: chattr
252 # (nothing in bzr's sftp transport uses those)260 # (nothing in bzr's sftp transport uses those)
253261
254262
255263
=== modified file 'breezy/transport/local.py'
--- breezy/transport/local.py 2017-11-19 18:55:26 +0000
+++ breezy/transport/local.py 2018-09-21 22:47:54 +0000
@@ -519,7 +519,10 @@
519 if osutils.host_os_dereferences_symlinks():519 if osutils.host_os_dereferences_symlinks():
520 def readlink(self, relpath):520 def readlink(self, relpath):
521 """See Transport.readlink."""521 """See Transport.readlink."""
522 return osutils.readlink(self._abspath(relpath))522 try:
523 return osutils.readlink(self._abspath(relpath))
524 except (IOError, OSError) as e:
525 self._translate_error(e, relpath)
523526
524 if osutils.hardlinks_good():527 if osutils.hardlinks_good():
525 def hardlink(self, source, link_name):528 def hardlink(self, source, link_name):
526529
=== modified file 'breezy/transport/memory.py'
--- breezy/transport/memory.py 2018-06-30 17:27:13 +0000
+++ breezy/transport/memory.py 2018-09-21 22:47:54 +0000
@@ -28,7 +28,7 @@
28 )28 )
29import os29import os
30import errno30import errno
31from stat import S_IFREG, S_IFDIR31from stat import S_IFREG, S_IFDIR, S_IFLNK
3232
33from .. import (33from .. import (
34 transport,34 transport,
@@ -39,6 +39,7 @@
39 LockError,39 LockError,
40 InProcessTransport,40 InProcessTransport,
41 NoSuchFile,41 NoSuchFile,
42 TransportNotPossible,
42 )43 )
43from ..transport import (44from ..transport import (
44 AppendBasedFileStream,45 AppendBasedFileStream,
@@ -50,16 +51,20 @@
5051
51class MemoryStat(object):52class MemoryStat(object):
5253
53 def __init__(self, size, is_dir, perms):54 def __init__(self, size, kind, perms):
54 self.st_size = size55 self.st_size = size
55 if not is_dir:56 if kind == 'file':
56 if perms is None:57 if perms is None:
57 perms = 0o64458 perms = 0o644
58 self.st_mode = S_IFREG | perms59 self.st_mode = S_IFREG | perms
59 else:60 elif kind == 'directory':
60 if perms is None:61 if perms is None:
61 perms = 0o75562 perms = 0o755
62 self.st_mode = S_IFDIR | perms63 self.st_mode = S_IFDIR | perms
64 elif kind == 'symlink':
65 self.st_mode = S_IFLNK | 0o644
66 else:
67 raise AssertionError('unknown kind %r' % kind)
6368
6469
65class MemoryTransport(transport.Transport):70class MemoryTransport(transport.Transport):
@@ -77,6 +82,7 @@
77 self._cwd = url[split:]82 self._cwd = url[split:]
78 # dictionaries from absolute path to file mode83 # dictionaries from absolute path to file mode
79 self._dirs = {'/':None}84 self._dirs = {'/':None}
85 self._symlinks = {}
80 self._files = {}86 self._files = {}
81 self._locks = {}87 self._locks = {}
8288
@@ -88,6 +94,7 @@
88 url = self._scheme + path94 url = self._scheme + path
89 result = self.__class__(url)95 result = self.__class__(url)
90 result._dirs = self._dirs96 result._dirs = self._dirs
97 result._symlinks = self._symlinks
91 result._files = self._files98 result._files = self._files
92 result._locks = self._locks99 result._locks = self._locks
93 return result100 return result
@@ -122,7 +129,9 @@
122 def has(self, relpath):129 def has(self, relpath):
123 """See Transport.has()."""130 """See Transport.has()."""
124 _abspath = self._abspath(relpath)131 _abspath = self._abspath(relpath)
125 return (_abspath in self._files) or (_abspath in self._dirs)132 return ((_abspath in self._files) or
133 (_abspath in self._dirs) or
134 (_abspath in self._symlinks))
126135
127 def delete(self, relpath):136 def delete(self, relpath):
128 """See Transport.delete()."""137 """See Transport.delete()."""
@@ -254,10 +263,12 @@
254 """See Transport.stat()."""263 """See Transport.stat()."""
255 _abspath = self._abspath(relpath)264 _abspath = self._abspath(relpath)
256 if _abspath in self._files:265 if _abspath in self._files:
257 return MemoryStat(len(self._files[_abspath][0]), False,266 return MemoryStat(len(self._files[_abspath][0]), 'file',
258 self._files[_abspath][1])267 self._files[_abspath][1])
259 elif _abspath in self._dirs:268 elif _abspath in self._dirs:
260 return MemoryStat(0, True, self._dirs[_abspath])269 return MemoryStat(0, 'directory', self._dirs[_abspath])
270 elif _abspath in self._symlinks:
271 return MemoryStat(0, 'symlink', 0)
261 else:272 else:
262 raise NoSuchFile(_abspath)273 raise NoSuchFile(_abspath)
263274
@@ -287,8 +298,22 @@
287 pass298 pass
288 else:299 else:
289 r.append(i)300 r.append(i)
301 r = self._symlinks.get('/'.join(r), r)
290 return '/' + '/'.join(r)302 return '/' + '/'.join(r)
291303
304 def symlink(self, source, link_name):
305 """Create a symlink pointing to source named link_name."""
306 _abspath = self._abspath(link_name)
307 self._check_parent(_abspath)
308 self._symlinks[_abspath] = source.split('/')
309
310 def readlink(self, link_name):
311 _abspath = self._abspath(link_name)
312 try:
313 return '/'.join(self._symlinks[_abspath])
314 except KeyError:
315 raise NoSuchFile(link_name)
316
292317
293class _MemoryLock(object):318class _MemoryLock(object):
294 """This makes a lock."""319 """This makes a lock."""

Subscribers

People subscribed via source and target branches