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
43
44
from duplicity.util import exception_traceback
57
58
_forced_backend = None
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.
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.
83
62
def import_backends():
186
165
raise BackendException(_("Could not initialize backend: %s") % str(sys.exc_info()[1]))
168
_urlparser_initialized = False
169
_urlparser_initialized_lock = dup_threading.threading_module().Lock()
171
def _ensure_urlparser_initialized():
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.
178
global _urlparser_initialized
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.
187
# todo: eliminate the need for backend specific hacking here completely.
188
urlparser.uses_netloc = ['ftp',
193
'scp', 'ssh', 'sftp',
200
# Do not transform or otherwise parse the URL path component.
201
urlparser.uses_query = []
202
urlparser.uses_fragm = []
204
_urlparser_initialized = True
206
dup_threading.with_lock(_urlparser_initialized_lock, init)
191
210
Parse the given URL as a duplicity backend URL.
200
219
def __init__(self, url_string):
201
220
self.url_string = url_string
221
_ensure_urlparser_initialized()
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.
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)
254
274
self.port = pu.port
255
except Exception: # not raised in python2.7+, just returns None
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 ) )
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:
265
self.path = '//' + self.netloc + self.path
268
elif self.path.startswith('/'):
269
self.path = '//' + self.path
271
280
# This happens for implicit local paths.
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))
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))
287
296
def geturl(self):
288
297
return self.url_string