blob: 4f4585970507ce9fd7809bc5a3fc3450c52f09c3 [file] [log] [blame]
Max Rasskazovb07aacb2015-05-29 19:54:52 +03001#-*- coding: utf-8 -*-
2
3import logging
4import re
5
6logging.basicConfig(level='INFO')
7logger = logging.getLogger('RsyncUrl')
8
9
10class RsyncUrl(object):
11
12 def __init__(self, remote_url):
13
Max Rasskazov64f77bf2015-06-02 15:22:48 +030014 self._url = remote_url
Max Rasskazovb07aacb2015-05-29 19:54:52 +030015 self._url_type = False
16
17 self.regexps = {
18 # ssh: [USER@]HOST:SRC
19 'ssh': re.compile(
20 r'^'
21 r'(?P<user>[-\w]+@)?'
22 r'(?P<host>[-\.\w]+){1}'
23 r':'
Max Rasskazov95e001b2015-05-30 23:53:22 +030024 r'(?P<path>(~{0,1}[\w/-]*)){1}'
Max Rasskazovb07aacb2015-05-29 19:54:52 +030025 r'$'
26 ),
27 # rsync: [USER@]HOST::SRC
28 'rsync1': re.compile(
29 r'^'
30 r'(?P<user>[-\w]+@)?'
31 r'(?P<host>[-\.\w]+){1}'
32 r'::'
Max Rasskazov64f77bf2015-06-02 15:22:48 +030033 r'(?P<module>[\w-]+){1}'
34 r'(?P<path>[\w/-]*)?'
Max Rasskazovb07aacb2015-05-29 19:54:52 +030035 r'$'
36 ),
37 # rsync://[USER@]HOST[:PORT]/SRC
38 'rsync2': re.compile(
39 r'^rsync://'
40 r'(?P<user>[-\w]+@)?'
41 r'(?P<host>[-\.\w]+){1}'
42 r'(?P<port>:[\d]+)?'
Max Rasskazov64f77bf2015-06-02 15:22:48 +030043 r'(?P<module>/[\w-]*)?'
44 r'(?P<path>[\w/-]*)?'
Max Rasskazovb07aacb2015-05-29 19:54:52 +030045 r'$'
46 ),
47 # local/path/to/directory
48 'path': re.compile(
49 r'^'
Max Rasskazov95e001b2015-05-30 23:53:22 +030050 r'(?P<path>(~{0,1}[\w/-]+)){1}'
Max Rasskazovb07aacb2015-05-29 19:54:52 +030051 r'$'
52 ),
53 }
54
Max Rasskazov64f77bf2015-06-02 15:22:48 +030055 self._match = self._get_matching_regexp()
Max Rasskazovb07aacb2015-05-29 19:54:52 +030056 if self.match is None:
Max Rasskazov64f77bf2015-06-02 15:22:48 +030057 self.user, self.host, self.module, self.port, self.path = \
58 None, None, None, None, None
Max Rasskazovb07aacb2015-05-29 19:54:52 +030059 else:
60 self._parse_rsync_url(self.match)
61
62 def _get_matching_regexp(self):
63 regexps = self._get_all_matching_regexps()
64 regexps_len = len(regexps)
65 #if regexps_len > 1:
66 # raise Exception('Rsync location {} matches with {} regexps {}'
67 # ''.format(self.url, len(regexps), str(regexps)))
68 # TODO: Possible may be better remove this raise and keep
69 # only warning with request to fail bug. rsync will parse this
70 # remote later
71 if regexps_len != 1:
72 logger.warn('Rsync location "{}" matches with {} regexps: {}.'
73 'Please fail a bug on {} if it is wrong.'
74 ''.format(self.url, len(regexps), str(regexps), '...'))
75 if regexps_len == 0:
76 self._url_type = None
77 return None
78 else:
79 return regexps[0]
80
81 def _get_all_matching_regexps(self):
82 regexps = list()
83 for url_type, regexp in self.regexps.items():
84 match = regexp.match(self.url)
85 if match is not None:
86 if self.url_type is False:
87 self._url_type = url_type
88 regexps.append(regexp)
Max Rasskazovb07aacb2015-05-29 19:54:52 +030089 return regexps
90
91 def _parse_rsync_url(self, regexp):
92 # parse remote url
93
Max Rasskazov64f77bf2015-06-02 15:22:48 +030094 for match in re.finditer(regexp, self._url):
Max Rasskazovb07aacb2015-05-29 19:54:52 +030095
96 self.path = match.group('path')
Max Rasskazov64f77bf2015-06-02 15:22:48 +030097 if self.path is None:
98 self.path = ''
Max Rasskazovb07aacb2015-05-29 19:54:52 +030099
100 try:
101 self.host = match.group('host')
102 except IndexError:
103 self.host = None
104
105 try:
106 self.user = match.group('user')
107 except IndexError:
108 self.user = None
109 else:
110 if self.user is not None:
111 self.user = self.user.strip('@')
112
113 try:
114 self.port = match.group('port')
115 except IndexError:
116 self.port = None
117 else:
118 if self.port is not None:
119 self.port = int(self.port.strip(':'))
120
Max Rasskazov64f77bf2015-06-02 15:22:48 +0300121 try:
122 self.module = match.group('module')
123 except IndexError:
124 self.module = None
125 else:
126 if self.module is not None:
127 self.module = self.module.strip('/')
128 if not self.module:
129 self.module = None
130
131 @property
132 def match(self):
133 return self._match
134
Max Rasskazovb07aacb2015-05-29 19:54:52 +0300135 @property
136 def url_type(self):
137 return self._url_type
Max Rasskazov64f77bf2015-06-02 15:22:48 +0300138
139 @property
140 def is_valid(self):
141 if self.match is None:
142 return False
143 if self.path in (None, False):
144 return False
145 if self.url_type != 'path':
146 if self.host in ('', None, False):
147 return False
148 if self.url_type.startswith('rsync'):
149 if self.module is None:
150 return False
151 return True
152
153 @property
154 def url(self):
155 return self._url