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
44
43
from duplicity.util import exception_traceback
58
57
_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.
62
83
def import_backends():
165
186
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',
194
'scp', 'ssh', 'sftp',
201
# Do not transform or otherwise parse the URL path component.
202
urlparser.uses_query = []
203
urlparser.uses_fragm = []
205
_urlparser_initialized = True
207
dup_threading.with_lock(_urlparser_initialized_lock, init)
211
191
Parse the given URL as a duplicity backend URL.
220
200
def __init__(self, url_string):
221
201
self.url_string = url_string
222
_ensure_urlparser_initialized()
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.
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)
275
254
self.port = pu.port
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 ) )
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
281
271
# This happens for implicit local paths.
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))
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))
297
287
def geturl(self):
298
288
return self.url_string