~mterry/duplicity/require-2.6

« back to all changes in this revision

Viewing changes to duplicity/backend.py

  • Committer: Michael Terry
  • Date: 2014-04-16 20:45:09 UTC
  • Revision ID: michael.terry@canonical.com-20140416204509-s9mz4mp6szn089f4
Drop support for Python 2.4 and 2.5

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
35
36
 
36
37
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
42
41
from duplicity import progress
43
42
 
44
43
from duplicity.util import exception_traceback
58
57
_forced_backend = None
59
58
_backends = {}
60
59
 
 
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
 
61
82
 
62
83
def import_backends():
63
84
    """
165
186
            raise BackendException(_("Could not initialize backend: %s") % str(sys.exc_info()[1]))
166
187
 
167
188
 
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
 
                                     'u1',
194
 
                                     'scp', 'ssh', 'sftp',
195
 
                                     'webdav', 'webdavs',
196
 
                                     'gdocs',
197
 
                                     'http', 'https',
198
 
                                     'imap', 'imaps',
199
 
                                     'mega']
200
 
 
201
 
            # Do not transform or otherwise parse the URL path component.
202
 
            urlparser.uses_query = []
203
 
            urlparser.uses_fragm = []
204
 
 
205
 
            _urlparser_initialized = True
206
 
 
207
 
    dup_threading.with_lock(_urlparser_initialized_lock, init)
208
 
 
209
189
class ParsedUrl:
210
190
    """
211
191
    Parse the given URL as a duplicity backend URL.
219
199
    """
220
200
    def __init__(self, url_string):
221
201
        self.url_string = url_string
222
 
        _ensure_urlparser_initialized()
223
202
 
224
203
        # While useful in some cases, the fact is that the urlparser makes
225
204
        # all the properties in the URL deferred or lazy.  This means that
227
206
        # problems here, so they will be caught early.
228
207
 
229
208
        try:
230
 
            pu = urlparser.urlparse(url_string)
 
209
            pu = urlparse.urlparse(url_string)
231
210
        except Exception:
232
211
            raise InvalidBackendURL("Syntax error in: %s" % url_string)
233
212
 
273
252
        self.port = None
274
253
        try:
275
254
            self.port = pu.port
276
 
        except Exception:
 
255
        except Exception: # not raised in python2.7+, just returns None
277
256
            # old style rsync://host::[/]dest, are still valid, though they contain no port
278
257
            if not ( self.scheme in ['rsync'] and re.search('::[^:]*$', self.url_string)):
279
258
                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 ) )
280
259
 
 
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
 
281
271
        # This happens for implicit local paths.
282
 
        if not pu.scheme:
 
272
        if not self.scheme:
283
273
            return
284
274
 
285
275
        # Our backends do not handle implicit hosts.
286
 
        if pu.scheme in urlparser.uses_netloc and not pu.hostname:
 
276
        if self.scheme in uses_netloc and not self.hostname:
287
277
            raise InvalidBackendURL("Missing hostname in a backend URL which "
288
278
                                    "requires an explicit hostname: %s"
289
279
                                    "" % (url_string))
290
280
 
291
281
        # Our backends do not handle implicit relative paths.
292
 
        if pu.scheme not in urlparser.uses_netloc and not pu.path.startswith('//'):
 
282
        if self.scheme not in uses_netloc and not self.path.startswith('//'):
293
283
            raise InvalidBackendURL("missing // - relative paths not supported "
294
284
                                    "for scheme %s: %s"
295
 
                                    "" % (pu.scheme, url_string))
 
285
                                    "" % (self.scheme, url_string))
296
286
 
297
287
    def geturl(self):
298
288
        return self.url_string