~mterry/duplicity/2.6isms

« back to all changes in this revision

Viewing changes to duplicity/backend.py

  • Committer: Kenneth Loafman
  • Date: 2014-04-17 17:58:17 UTC
  • mfrom: (967.3.1 drop-u1)
  • Revision ID: kenneth@loafman.com-20140417175817-g74li39tg0cikn5v
* Merged in lp:~mterry/duplicity/drop-u1
  - Ubuntu One is closing shop. So no need to support a u1 backend anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
import getpass
33
33
import gettext
34
34
import urllib
35
 
import urlparse
36
35
 
37
36
from duplicity import dup_temp
 
37
from duplicity import dup_threading
38
38
from duplicity import file_naming
39
39
from duplicity import globals
40
40
from duplicity import log
 
41
from duplicity import urlparse_2_5 as urlparser
41
42
from duplicity import progress
42
43
 
43
44
from duplicity.util import exception_traceback
57
58
_forced_backend = None
58
59
_backends = {}
59
60
 
60
 
# These URL schemes have a backend with a notion of an RFC "network location".
61
 
# The 'file' and 's3+http' schemes should not be in this list.
62
 
# 'http' and 'https' are not actually used for duplicity backend urls, but are needed
63
 
# in order to properly support urls returned from some webdav servers. adding them here
64
 
# is a hack. we should instead not stomp on the url parsing module to begin with.
65
 
#
66
 
# This looks similar to urlparse's 'uses_netloc' list, but urlparse doesn't use
67
 
# that list for parsing, only creating urls.  And doesn't include our custom
68
 
# schemes anyway.  So we keep our own here for our own use.
69
 
uses_netloc = ['ftp',
70
 
               'ftps',
71
 
               'hsi',
72
 
               'rsync',
73
 
               's3',
74
 
               'u1',
75
 
               'scp', 'ssh', 'sftp',
76
 
               'webdav', 'webdavs',
77
 
               'gdocs',
78
 
               'http', 'https',
79
 
               'imap', 'imaps',
80
 
               'mega']
81
 
 
82
61
 
83
62
def import_backends():
84
63
    """
186
165
            raise BackendException(_("Could not initialize backend: %s") % str(sys.exc_info()[1]))
187
166
 
188
167
 
 
168
_urlparser_initialized = False
 
169
_urlparser_initialized_lock = dup_threading.threading_module().Lock()
 
170
 
 
171
def _ensure_urlparser_initialized():
 
172
    """
 
173
    Ensure that the appropriate clobbering of variables in the
 
174
    urlparser module has been done. In the future, the need for this
 
175
    clobbering to begin with should preferably be eliminated.
 
176
    """
 
177
    def init():
 
178
        global _urlparser_initialized
 
179
 
 
180
        if not _urlparser_initialized:
 
181
            # These URL schemes have a backend with a notion of an RFC "network location".
 
182
            # The 'file' and 's3+http' schemes should not be in this list.
 
183
            # 'http' and 'https' are not actually used for duplicity backend urls, but are needed
 
184
            # in order to properly support urls returned from some webdav servers. adding them here
 
185
            # is a hack. we should instead not stomp on the url parsing module to begin with.
 
186
            #
 
187
            # todo: eliminate the need for backend specific hacking here completely.
 
188
            urlparser.uses_netloc = ['ftp',
 
189
                                     'ftps',
 
190
                                     'hsi',
 
191
                                     'rsync',
 
192
                                     's3',
 
193
                                     'scp', 'ssh', 'sftp',
 
194
                                     'webdav', 'webdavs',
 
195
                                     'gdocs',
 
196
                                     'http', 'https',
 
197
                                     'imap', 'imaps',
 
198
                                     'mega']
 
199
 
 
200
            # Do not transform or otherwise parse the URL path component.
 
201
            urlparser.uses_query = []
 
202
            urlparser.uses_fragm = []
 
203
 
 
204
            _urlparser_initialized = True
 
205
 
 
206
    dup_threading.with_lock(_urlparser_initialized_lock, init)
 
207
 
189
208
class ParsedUrl:
190
209
    """
191
210
    Parse the given URL as a duplicity backend URL.
199
218
    """
200
219
    def __init__(self, url_string):
201
220
        self.url_string = url_string
 
221
        _ensure_urlparser_initialized()
202
222
 
203
223
        # While useful in some cases, the fact is that the urlparser makes
204
224
        # all the properties in the URL deferred or lazy.  This means that
206
226
        # problems here, so they will be caught early.
207
227
 
208
228
        try:
209
 
            pu = urlparse.urlparse(url_string)
 
229
            pu = urlparser.urlparse(url_string)
210
230
        except Exception:
211
231
            raise InvalidBackendURL("Syntax error in: %s" % url_string)
212
232
 
252
272
        self.port = None
253
273
        try:
254
274
            self.port = pu.port
255
 
        except Exception: # not raised in python2.7+, just returns None
 
275
        except Exception:
256
276
            # old style rsync://host::[/]dest, are still valid, though they contain no port
257
277
            if not ( self.scheme in ['rsync'] and re.search('::[^:]*$', self.url_string)):
258
278
                raise InvalidBackendURL("Syntax error (port) in: %s A%s B%s C%s" % (url_string, (self.scheme in ['rsync']), re.search('::[^:]+$', self.netloc), self.netloc ) )
259
279
 
260
 
        # Our URL system uses two slashes more than urlparse's does when using
261
 
        # non-netloc URLs.  And we want to make sure that if urlparse assuming
262
 
        # a netloc where we don't want one, that we correct it.
263
 
        if self.scheme not in uses_netloc:
264
 
            if self.netloc:
265
 
                self.path = '//' + self.netloc + self.path
266
 
                self.netloc = ''
267
 
                self.hostname = None
268
 
            elif self.path.startswith('/'):
269
 
                self.path = '//' + self.path
270
 
 
271
280
        # This happens for implicit local paths.
272
 
        if not self.scheme:
 
281
        if not pu.scheme:
273
282
            return
274
283
 
275
284
        # Our backends do not handle implicit hosts.
276
 
        if self.scheme in uses_netloc and not self.hostname:
 
285
        if pu.scheme in urlparser.uses_netloc and not pu.hostname:
277
286
            raise InvalidBackendURL("Missing hostname in a backend URL which "
278
287
                                    "requires an explicit hostname: %s"
279
288
                                    "" % (url_string))
280
289
 
281
290
        # Our backends do not handle implicit relative paths.
282
 
        if self.scheme not in uses_netloc and not self.path.startswith('//'):
 
291
        if pu.scheme not in urlparser.uses_netloc and not pu.path.startswith('//'):
283
292
            raise InvalidBackendURL("missing // - relative paths not supported "
284
293
                                    "for scheme %s: %s"
285
 
                                    "" % (self.scheme, url_string))
 
294
                                    "" % (pu.scheme, url_string))
286
295
 
287
296
    def geturl(self):
288
297
        return self.url_string