From f300051fe412d2945f66316285e9a879ed3dad9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Borgstr=C3=B6m?= Date: Wed, 17 Nov 2010 21:28:13 +0100 Subject: [PATCH] Added support for ssh://user@host/path and file:///file locations --- darc/archiver.py | 2 +- darc/helpers.py | 78 ++++++++++++++++++++++++++++++++++-------------- darc/remote.py | 2 +- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/darc/archiver.py b/darc/archiver.py index c98c08768..3a4cf4d30 100644 --- a/darc/archiver.py +++ b/darc/archiver.py @@ -18,7 +18,7 @@ class Archiver(object): self.exit_code = 0 def open_store(self, location, create=False): - if location.host: + if location.proto == 'ssh': return RemoteStore(location, create=create) else: return Store(location.path, create=create) diff --git a/darc/helpers.py b/darc/helpers.py index c4bb499b3..055071e19 100644 --- a/darc/helpers.py +++ b/darc/helpers.py @@ -171,36 +171,70 @@ def group2gid(group): class Location(object): + """Object representing a store / archive location - loc_re = re.compile(r'^((?:(?P[^@]+)@)?(?P[^:]+):)?' - r'(?P[^:]*)(?:::(?P[^:]+))?$') + >>> Location('ssh://user@host:1234/some/path::archive') + Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive='archive') + >>> Location('file:///some/path::archive') + Location(proto='file', user=None, host=None, port=None, path='/some/path', archive='archive') + >>> Location('user@host:/some/path::archive') + Location(proto='ssh', user='user', host='host', port=22, path='/some/path', archive='archive') + >>> Location('/some/path::archive') + Location(proto='file', user=None, host=None, port=None, path='/some/path', archive='archive') + """ + proto = user = host = port = path = archive = None + ssh_re = re.compile(r'(?Pssh)://(?:(?P[^@]+)@)?' + r'(?P[^:/#]+)(?::(?P\d+))?' + r'(?P[^:]*)(?:::(?P.+))?') + file_re = re.compile(r'(?Pfile)://' + r'(?P[^:]*)(?:::(?P.+))?') + scp_re = re.compile(r'((?:(?P[^@]+)@)?(?P[^:/]+):)?' + r'(?P[^:]*)(?:::(?P.+))?') def __init__(self, text): - loc = self.loc_re.match(text) - loc = loc and loc.groupdict() - if not loc: + if not self.parse(text): raise ValueError - self.user = loc['user'] - self.host = loc['host'] - self.path = loc['path'] - if not self.host and not self.path: - raise ValueError - self.archive = loc['archive'] + + def parse(self, text): + m = self.ssh_re.match(text) + if m: + self.proto = m.group('proto') + self.user = m.group('user') + self.host = m.group('host') + self.port = m.group('port') and int(m.group('port')) or 22 + self.path = m.group('path') + self.archive = m.group('archive') + return True + m = self.file_re.match(text) + if m: + self.proto = m.group('proto') + self.path = m.group('path') + self.archive = m.group('archive') + return True + m = self.scp_re.match(text) + if m: + self.user = m.group('user') + self.host = m.group('host') + self.path = m.group('path') + self.archive = m.group('archive') + self.proto = self.host and 'ssh' or 'file' + if self.proto == 'ssh': + self.port = 22 + return True + return False def __str__(self): - text = '' - if self.user: - text += '%s@' % self.user - if self.host: - text += '%s::' % self.host - if self.path: - text += self.path - if self.archive: - text += ':%s' % self.archive - return text + items = [] + items.append('proto=%r' % self.proto) + items.append('user=%r' % self.user) + items.append('host=%r' % self.host) + items.append('port=%r' % self.port) + items.append('path=%r'% self.path) + items.append('archive=%r' % self.archive) + return ', '.join(items) def __repr__(self): - return "Location('%s')" % self + return "Location(%s)" % self def location_validator(archive=None): diff --git a/darc/remote.py b/darc/remote.py index 5a7911b76..e397b489d 100644 --- a/darc/remote.py +++ b/darc/remote.py @@ -63,7 +63,7 @@ class RemoteStore(object): self.client = paramiko.SSHClient() self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) params = {'username': location.user or getpass.getuser(), - 'hostname': location.host} + 'hostname': location.host, 'port': location.port} while True: try: self.client.connect(**params)