duplicity-team team mailing list archive
-
duplicity-team team
-
Mailing list archive
-
Message #01407
[Merge] lp:~mterry/duplicity/unicode-decode into lp:duplicity
Kenneth Loafman has proposed merging lp:~mterry/duplicity/unicode-decode into lp:duplicity.
Requested reviews:
duplicity-team (duplicity-team)
Related bugs:
Bug #989496 in Duplicity: "UnicodeDecodeError during backup due to non-utf8 translation"
https://bugs.launchpad.net/duplicity/+bug/989496
For more details, see:
https://code.launchpad.net/~mterry/duplicity/unicode-decode/+merge/133812
always load po files as utf8
--
https://code.launchpad.net/~mterry/duplicity/unicode-decode/+merge/133812
Your team duplicity-team is requested to review the proposed merge of lp:~mterry/duplicity/unicode-decode into lp:duplicity.
=== modified file 'bin/duplicity'
=== modified file 'duplicity/backends/u1backend.py'
--- duplicity/backends/u1backend.py 2012-11-03 22:12:45 +0000
+++ duplicity/backends/u1backend.py 2012-11-11 01:45:26 +0000
@@ -19,6 +19,7 @@
# You should have received a copy of the GNU General Public License
# along with duplicity. If not, see <http://www.gnu.org/licenses/>.
+import gettext
import duplicity.backend
from duplicity.errors import BackendException
from duplicity import log
@@ -144,6 +145,7 @@
self.volume_uri = "%s/volumes/~/%s" % (self.api_base, path)
self.meta_base = "%s/~/%s/" % (self.api_base, path)
+<<<<<<< TREE
self.client=OAuthHttpClient();
@@ -172,12 +174,129 @@
resp, content = self.client.request(self.volume_uri,ignore=[404])
if resp['status']=='404':
resp, content = self.client.request(self.volume_uri,"PUT")
+=======
+ # This next line *should* work, but isn't set up correctly server-side yet
+ #self.content_base = self.api_base
+ self.content_base = "https://files.%s" % self.parsed_url.hostname
+
+ ensure_dbus()
+
+ if not self.login():
+ from duplicity import log
+ log.FatalError(_("Could not obtain Ubuntu One credentials"),
+ log.ErrorCode.backend_error)
+
+ # Create volume in case it doesn't exist yet
+ self.create_volume()
+
+ def login(self):
+ from gobject import MainLoop
+ from dbus.mainloop.glib import DBusGMainLoop
+ from ubuntuone.platform.credentials import CredentialsManagementTool
+ gettext.install('duplicity', codeset='utf8') # workaround LP: #1050061
+
+ self.login_success = False
+
+ DBusGMainLoop(set_as_default=True)
+ loop = MainLoop()
+
+ def quit(result):
+ loop.quit()
+ if result:
+ self.login_success = True
+
+ cd = CredentialsManagementTool()
+ d = cd.login()
+ d.addCallbacks(quit)
+ loop.run()
+ return self.login_success
+>>>>>>> MERGE-SOURCE
def quote(self, url):
+<<<<<<< TREE
return urllib.quote(url, safe="/~").replace(" ","%20")
def put(self, source_path, remote_filename = None):
+=======
+ import urllib
+ return urllib.quote(url, safe="/~")
+
+ def parse_error(self, headers, ignore=None):
+ from duplicity import log
+
+ status = int(headers[0].get('status'))
+ if status >= 200 and status < 300:
+ return None
+
+ if ignore and status in ignore:
+ return None
+
+ if status == 400:
+ code = log.ErrorCode.backend_permission_denied
+ elif status == 404:
+ code = log.ErrorCode.backend_not_found
+ elif status == 507:
+ code = log.ErrorCode.backend_no_space
+ else:
+ code = log.ErrorCode.backend_error
+ return code
+
+ def handle_error(self, raise_error, op, headers, file1=None, file2=None, ignore=None):
+ from duplicity import log
+ from duplicity import util
+ import json
+
+ code = self.parse_error(headers, ignore)
+ if code is None:
+ return
+
+ status = int(headers[0].get('status'))
+
+ if file1:
+ file1 = file1.encode("utf8")
+ else:
+ file1 = None
+ if file2:
+ file2 = file2.encode("utf8")
+ else:
+ file2 = None
+ extra = ' '.join([util.escape(x) for x in [file1, file2] if x])
+ extra = ' '.join([op, extra])
+ msg = _("Got status code %s") % status
+ if headers[0].get('x-oops-id') is not None:
+ msg += '\nOops-ID: %s' % headers[0].get('x-oops-id')
+ if headers[0].get('content-type') == 'application/json':
+ node = json.loads(headers[1])
+ if node.get('error'):
+ msg = node.get('error')
+
+ if raise_error:
+ if status == 503:
+ raise TemporaryLoadException(msg)
+ else:
+ raise BackendException(msg)
+ else:
+ log.FatalError(msg, code, extra)
+
+ @retry
+ def create_volume(self, raise_errors=False):
+ import ubuntuone.couch.auth as auth
+ gettext.install('duplicity', codeset='utf8') # workaround LP: #1050061
+
+ answer = auth.request(self.volume_uri, http_method="PUT")
+ self.handle_error(raise_errors, 'put', answer, self.volume_uri)
+
+ @retry
+ def put(self, source_path, remote_filename = None, raise_errors=False):
+>>>>>>> MERGE-SOURCE
"""Copy file to remote"""
+<<<<<<< TREE
+=======
+ import json
+ import mimetypes
+ import ubuntuone.couch.auth as auth
+ gettext.install('duplicity', codeset='utf8') # workaround LP: #1050061
+>>>>>>> MERGE-SOURCE
if not remote_filename:
remote_filename = source_path.get_filename()
remote_full = self.meta_base + self.quote(remote_filename)
@@ -211,8 +330,14 @@
def get(self, filename, local_path):
"""Get file and put in local_path (Path object)"""
+<<<<<<< TREE
# get with path returns content_path
+=======
+ import json
+ import ubuntuone.couch.auth as auth
+ gettext.install('duplicity', codeset='utf8') # workaround LP: #1050061
+>>>>>>> MERGE-SOURCE
remote_full = self.meta_base + self.quote(filename)
resp, content = self.client.request(remote_full)
@@ -229,6 +354,13 @@
def list(self):
"""List files in that directory"""
+<<<<<<< TREE
+=======
+ import json
+ import urllib
+ import ubuntuone.couch.auth as auth
+ gettext.install('duplicity', codeset='utf8') # workaround LP: #1050061
+>>>>>>> MERGE-SOURCE
remote_full = self.meta_base + "?include_children=true"
resp, content = self.client.request(remote_full)
@@ -242,6 +374,11 @@
def delete(self, filename_list):
"""Delete all files in filename list"""
import types
+<<<<<<< TREE
+=======
+ import ubuntuone.couch.auth as auth
+ gettext.install('duplicity', codeset='utf8') # workaround LP: #1050061
+>>>>>>> MERGE-SOURCE
assert type(filename_list) is not types.StringType
for filename in filename_list:
@@ -250,6 +387,13 @@
def _query_file_info(self, filename):
"""Query attributes on filename"""
+<<<<<<< TREE
+=======
+ import json
+ from duplicity import log
+ import ubuntuone.couch.auth as auth
+ gettext.install('duplicity', codeset='utf8') # workaround LP: #1050061
+>>>>>>> MERGE-SOURCE
remote_full = self.meta_base + self.quote(filename)
resp, content = self.client.request(remote_full)
=== added file 'testing/tests/unicode.py'
--- testing/tests/unicode.py 1970-01-01 00:00:00 +0000
+++ testing/tests/unicode.py 2012-11-11 01:45:26 +0000
@@ -0,0 +1,66 @@
+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
+#
+# Copyright 2012 Canonical Ltd
+#
+# This file is part of duplicity.
+#
+# Duplicity is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# Duplicity is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with duplicity; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import unittest
+from mock import patch
+
+
+class U1UnicodeTest(unittest.TestCase):
+ """Test Unicode support when using U1"""
+
+ # Patch out some bits that would cause us to actually talk to U1 or try
+ # to log in to U1 credentials
+ @patch('duplicity.backends.u1backend.U1Backend.create_volume')
+ @patch('gobject.MainLoop')
+ def test_gettext(self, vol_mock, loop_mock):
+ """Verify workaround of ubuntuone's gettext.install (LP: #1050061)"""
+ self.assertEqual(_, _.im_self.gettext)
+ import duplicity.backend
+ import duplicity.backends.u1backend
+ try:
+ # Patch here because if we patched as a decorator, we'd
+ # accidentally import before we got to the first assertEqual, which
+ # is too early.
+ tool = 'ubuntuone.platform.credentials.CredentialsManagementTool'
+ url = duplicity.backend.ParsedUrl('u1+http://bucket/volume')
+ with patch(tool) as tool_mock:
+ # fake immediate success when adding a callback
+ tool_mock().login().addCallbacks = lambda f: f(True)
+ duplicity.backends.u1backend.U1Backend(url)
+ except ImportError:
+ self.skipTest("ubuntuone not installed")
+ self.assertEqual(_, _.im_self.gettext)
+
+
+class UTF8Test(unittest.TestCase):
+
+ def setUp(self):
+ import sys
+ if 'duplicity' in sys.modules:
+ del(sys.modules["duplicity"])
+
+ @patch('gettext.install')
+ def test_module_install(self, inst_mock):
+ """Make sure we convert po files to utf8"""
+ import duplicity
+ inst_mock.assert_called_once_with('duplicity', codeset='utf8')
+
+if __name__ == "__main__":
+ unittest.main()
=== renamed file 'testing/tests/unicode.py' => 'testing/tests/unicode.py.moved'
Follow ups