Merge lp:~vila/bzr/472161-ftp-utf8 into lp:bzr

Proposed by Vincent Ladeuil
Status: Merged
Approved by: John A Meinel
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~vila/bzr/472161-ftp-utf8
Merge into: lp:bzr
Diff against target: 108 lines (+17/-16)
6 files modified
NEWS (+3/-0)
bzrlib/osutils.py (+5/-3)
bzrlib/tests/ftp_server/medusa_based.py (+2/-0)
bzrlib/tests/ftp_server/pyftpdlib_based.py (+3/-2)
bzrlib/tests/per_transport.py (+4/-0)
bzrlib/transport/ftp/__init__.py (+0/-11)
To merge this branch: bzr merge lp:~vila/bzr/472161-ftp-utf8
Reviewer Review Type Date Requested Status
John A Meinel Approve
Review via email: mp+16967@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

This fix bug #472161 by... simply deleting _remote_path().

It also makes osutils.fancy_rename() more robust against uses with true unicode paths.

I'm not super proud of the trick to disable the unicode tests against medusa,
but I didn't want to make more involved changes for an ftp server that we
don't support with python >= 2.6.

I finally found RFC3640 which clearly states that Unicode paths are to be supported
as utf8-encoded by default.

The RFC mentions the FEAT command to ensure that the server supports UTF8 but I didn't
implement it to avoid the additional roundtrip (we'll find soon enough if UTF8 is not supported).

Feedback and real-world tests welcome !

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Vincent Ladeuil wrote:
> Vincent Ladeuil has proposed merging lp:~vila/bzr/472161-ftp-utf8 into lp:bzr.
>
> Requested reviews:
> bzr-core (bzr-core)
>
>
> This fix bug #472161 by... simply deleting _remote_path().
>
> It also makes osutils.fancy_rename() more robust against uses with true unicode paths.
>
> I'm not super proud of the trick to disable the unicode tests against medusa,
> but I didn't want to make more involved changes for an ftp server that we
> don't support with python >= 2.6.
>
> I finally found RFC3640 which clearly states that Unicode paths are to be supported
> as utf8-encoded by default.
>
> The RFC mentions the FEAT command to ensure that the server supports UTF8 but I didn't
> implement it to avoid the additional roundtrip (we'll find soon enough if UTF8 is not supported).
>
> Feedback and real-world tests welcome !
>

 review: approve
 merge: approve

I did not test this manually, but the code looks good and your
descriptions seem fine.

I think this is something that really just needs real-world testing. FTP
servers are pretty notorious for handling edge cases differently.

+ no_unicode_support = getattr(self._server,
'_no_unicode_support', False)
+ if no_unicode_support:
+ raise TestSkipped("test server cannot handle unicode paths")
+

^- Arguably this would be better seeing something actually fail and
raising knownFailure. At least, I prefer XFAIL because then when we fix
stuff, we know which tests should be updated.

I probably wouldn't make it an '_' attribute. Instead just do
"no_unicode_support".

But what you have is fine if you just want to land it.

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAktGAL0ACgkQJdeBCYSNAAOBXQCgmykxzpdWWyWBGROuIIiVm3p6
EEQAnA+UwN8IcUmrAiPG4v5SC2Lk8KL7
=yNOA
-----END PGP SIGNATURE-----

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2010-01-07 06:34:14 +0000
+++ NEWS 2010-01-07 14:15:28 +0000
@@ -61,6 +61,9 @@
61 returns ``EINTR`` by calling ``PyErr_CheckSignals``. This affected the61 returns ``EINTR`` by calling ``PyErr_CheckSignals``. This affected the
62 optional ``_readdir_pyx`` extension. (Andrew Bennetts, #495023)62 optional ``_readdir_pyx`` extension. (Andrew Bennetts, #495023)
6363
64* FTP transports support Unicode paths by encoding/decoding them as utf8.
65 (Vincent Ladeuil, #472161)
66
64* Give a clearer message if the lockdir disappears after being apparently67* Give a clearer message if the lockdir disappears after being apparently
65 successfully taken. (Martin Pool, #498378)68 successfully taken. (Martin Pool, #498378)
6669
6770
=== modified file 'bzrlib/osutils.py'
--- bzrlib/osutils.py 2009-12-23 00:15:34 +0000
+++ bzrlib/osutils.py 2010-01-07 14:15:27 +0000
@@ -202,13 +202,15 @@
202 :param old: The old path, to rename from202 :param old: The old path, to rename from
203 :param new: The new path, to rename to203 :param new: The new path, to rename to
204 :param rename_func: The potentially non-atomic rename function204 :param rename_func: The potentially non-atomic rename function
205 :param unlink_func: A way to delete the target file if the full rename succeeds205 :param unlink_func: A way to delete the target file if the full rename
206 succeeds
206 """207 """
207208 new = safe_unicode(new)
208 # sftp rename doesn't allow overwriting, so play tricks:209 # sftp rename doesn't allow overwriting, so play tricks:
209 base = os.path.basename(new)210 base = os.path.basename(new)
210 dirname = os.path.dirname(new)211 dirname = os.path.dirname(new)
211 tmp_name = u'tmp.%s.%.9f.%d.%s' % (base, time.time(), os.getpid(), rand_chars(10))212 tmp_name = u'tmp.%s.%.9f.%d.%s' % (base, time.time(),
213 os.getpid(), rand_chars(10))
212 tmp_name = pathjoin(dirname, tmp_name)214 tmp_name = pathjoin(dirname, tmp_name)
213215
214 # Rename the file out of the way, but keep track if it didn't exist216 # Rename the file out of the way, but keep track if it didn't exist
215217
=== modified file 'bzrlib/tests/ftp_server/medusa_based.py'
--- bzrlib/tests/ftp_server/medusa_based.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/ftp_server/medusa_based.py 2010-01-07 14:15:27 +0000
@@ -213,6 +213,8 @@
213class FTPTestServer(transport.Server):213class FTPTestServer(transport.Server):
214 """Common code for FTP server facilities."""214 """Common code for FTP server facilities."""
215215
216 _no_unicode_support = True
217
216 def __init__(self):218 def __init__(self):
217 self._root = None219 self._root = None
218 self._ftp_server = None220 self._ftp_server = None
219221
=== modified file 'bzrlib/tests/ftp_server/pyftpdlib_based.py'
--- bzrlib/tests/ftp_server/pyftpdlib_based.py 2009-10-06 08:24:14 +0000
+++ bzrlib/tests/ftp_server/pyftpdlib_based.py 2010-01-07 14:15:27 +0000
@@ -50,14 +50,15 @@
5050
51 def listdir(self, path):51 def listdir(self, path):
52 """List the content of a directory."""52 """List the content of a directory."""
53 # FIXME: need tests with unicode paths
54 return [osutils.safe_utf8(s) for s in os.listdir(path)]53 return [osutils.safe_utf8(s) for s in os.listdir(path)]
5554
56 def fs2ftp(self, fspath):55 def fs2ftp(self, fspath):
57 p = ftpserver.AbstractedFS.fs2ftp(self, fspath)56 p = ftpserver.AbstractedFS.fs2ftp(self, fspath)
58 # FIXME: need tests with unicode paths
59 return osutils.safe_utf8(p)57 return osutils.safe_utf8(p)
6058
59 def ftp2fs(self, ftppath):
60 p = osutils.safe_unicode(ftppath)
61 return ftpserver.AbstractedFS.ftp2fs(self, p)
6162
62class BzrConformingFTPHandler(ftpserver.FTPHandler):63class BzrConformingFTPHandler(ftpserver.FTPHandler):
6364
6465
=== modified file 'bzrlib/tests/per_transport.py'
--- bzrlib/tests/per_transport.py 2009-10-05 12:50:34 +0000
+++ bzrlib/tests/per_transport.py 2010-01-07 14:15:27 +0000
@@ -1497,6 +1497,10 @@
1497 u'\u65e5', # Kanji person1497 u'\u65e5', # Kanji person
1498 ]1498 ]
14991499
1500 no_unicode_support = getattr(self._server, '_no_unicode_support', False)
1501 if no_unicode_support:
1502 raise TestSkipped("test server cannot handle unicode paths")
1503
1500 try:1504 try:
1501 self.build_tree(files, transport=t, line_endings='binary')1505 self.build_tree(files, transport=t, line_endings='binary')
1502 except UnicodeError:1506 except UnicodeError:
15031507
=== modified file 'bzrlib/transport/ftp/__init__.py'
--- bzrlib/transport/ftp/__init__.py 2009-10-06 08:24:14 +0000
+++ bzrlib/transport/ftp/__init__.py 2010-01-07 14:15:27 +0000
@@ -205,17 +205,6 @@
205 #raise TransportError(msg='Error for path: %s' % (path,), orig_error=e)205 #raise TransportError(msg='Error for path: %s' % (path,), orig_error=e)
206 raise206 raise
207207
208 def _remote_path(self, relpath):
209 # XXX: It seems that ftplib does not handle Unicode paths
210 # at the same time, medusa won't handle utf8 paths So if
211 # we .encode(utf8) here (see ConnectedTransport
212 # implementation), then we get a Server failure. while
213 # if we use str(), we get a UnicodeError, and the test
214 # suite just skips testing UnicodePaths.
215 relative = str(urlutils.unescape(relpath))
216 remote_path = self._combine_paths(self._path, relative)
217 return remote_path
218
219 def has(self, relpath):208 def has(self, relpath):
220 """Does the target location exist?"""209 """Does the target location exist?"""
221 # FIXME jam 20060516 We *do* ask about directories in the test suite210 # FIXME jam 20060516 We *do* ask about directories in the test suite