##// END OF EJS Templates
catch errors in obfuscate password function
marcink -
r3454:867c4d7f beta
parent child Browse files
Show More
@@ -1,573 +1,577 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Some simple helper functions
6 Some simple helper functions
7
7
8 :created_on: Jan 5, 2011
8 :created_on: Jan 5, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import re
26 import re
27 import time
27 import time
28 import datetime
28 import datetime
29 import webob
29 import webob
30
30
31 from pylons.i18n.translation import _, ungettext
31 from pylons.i18n.translation import _, ungettext
32 from rhodecode.lib.vcs.utils.lazy import LazyProperty
32 from rhodecode.lib.vcs.utils.lazy import LazyProperty
33
33
34
34
35 def __get_lem():
35 def __get_lem():
36 """
36 """
37 Get language extension map based on what's inside pygments lexers
37 Get language extension map based on what's inside pygments lexers
38 """
38 """
39 from pygments import lexers
39 from pygments import lexers
40 from string import lower
40 from string import lower
41 from collections import defaultdict
41 from collections import defaultdict
42
42
43 d = defaultdict(lambda: [])
43 d = defaultdict(lambda: [])
44
44
45 def __clean(s):
45 def __clean(s):
46 s = s.lstrip('*')
46 s = s.lstrip('*')
47 s = s.lstrip('.')
47 s = s.lstrip('.')
48
48
49 if s.find('[') != -1:
49 if s.find('[') != -1:
50 exts = []
50 exts = []
51 start, stop = s.find('['), s.find(']')
51 start, stop = s.find('['), s.find(']')
52
52
53 for suffix in s[start + 1:stop]:
53 for suffix in s[start + 1:stop]:
54 exts.append(s[:s.find('[')] + suffix)
54 exts.append(s[:s.find('[')] + suffix)
55 return map(lower, exts)
55 return map(lower, exts)
56 else:
56 else:
57 return map(lower, [s])
57 return map(lower, [s])
58
58
59 for lx, t in sorted(lexers.LEXERS.items()):
59 for lx, t in sorted(lexers.LEXERS.items()):
60 m = map(__clean, t[-2])
60 m = map(__clean, t[-2])
61 if m:
61 if m:
62 m = reduce(lambda x, y: x + y, m)
62 m = reduce(lambda x, y: x + y, m)
63 for ext in m:
63 for ext in m:
64 desc = lx.replace('Lexer', '')
64 desc = lx.replace('Lexer', '')
65 d[ext].append(desc)
65 d[ext].append(desc)
66
66
67 return dict(d)
67 return dict(d)
68
68
69
69
70 def str2bool(_str):
70 def str2bool(_str):
71 """
71 """
72 returs True/False value from given string, it tries to translate the
72 returs True/False value from given string, it tries to translate the
73 string into boolean
73 string into boolean
74
74
75 :param _str: string value to translate into boolean
75 :param _str: string value to translate into boolean
76 :rtype: boolean
76 :rtype: boolean
77 :returns: boolean from given string
77 :returns: boolean from given string
78 """
78 """
79 if _str is None:
79 if _str is None:
80 return False
80 return False
81 if _str in (True, False):
81 if _str in (True, False):
82 return _str
82 return _str
83 _str = str(_str).strip().lower()
83 _str = str(_str).strip().lower()
84 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
84 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
85
85
86
86
87 def aslist(obj, sep=None, strip=True):
87 def aslist(obj, sep=None, strip=True):
88 """
88 """
89 Returns given string separated by sep as list
89 Returns given string separated by sep as list
90
90
91 :param obj:
91 :param obj:
92 :param sep:
92 :param sep:
93 :param strip:
93 :param strip:
94 """
94 """
95 if isinstance(obj, (basestring)):
95 if isinstance(obj, (basestring)):
96 lst = obj.split(sep)
96 lst = obj.split(sep)
97 if strip:
97 if strip:
98 lst = [v.strip() for v in lst]
98 lst = [v.strip() for v in lst]
99 return lst
99 return lst
100 elif isinstance(obj, (list, tuple)):
100 elif isinstance(obj, (list, tuple)):
101 return obj
101 return obj
102 elif obj is None:
102 elif obj is None:
103 return []
103 return []
104 else:
104 else:
105 return [obj]
105 return [obj]
106
106
107
107
108 def convert_line_endings(line, mode):
108 def convert_line_endings(line, mode):
109 """
109 """
110 Converts a given line "line end" accordingly to given mode
110 Converts a given line "line end" accordingly to given mode
111
111
112 Available modes are::
112 Available modes are::
113 0 - Unix
113 0 - Unix
114 1 - Mac
114 1 - Mac
115 2 - DOS
115 2 - DOS
116
116
117 :param line: given line to convert
117 :param line: given line to convert
118 :param mode: mode to convert to
118 :param mode: mode to convert to
119 :rtype: str
119 :rtype: str
120 :return: converted line according to mode
120 :return: converted line according to mode
121 """
121 """
122 from string import replace
122 from string import replace
123
123
124 if mode == 0:
124 if mode == 0:
125 line = replace(line, '\r\n', '\n')
125 line = replace(line, '\r\n', '\n')
126 line = replace(line, '\r', '\n')
126 line = replace(line, '\r', '\n')
127 elif mode == 1:
127 elif mode == 1:
128 line = replace(line, '\r\n', '\r')
128 line = replace(line, '\r\n', '\r')
129 line = replace(line, '\n', '\r')
129 line = replace(line, '\n', '\r')
130 elif mode == 2:
130 elif mode == 2:
131 line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
131 line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
132 return line
132 return line
133
133
134
134
135 def detect_mode(line, default):
135 def detect_mode(line, default):
136 """
136 """
137 Detects line break for given line, if line break couldn't be found
137 Detects line break for given line, if line break couldn't be found
138 given default value is returned
138 given default value is returned
139
139
140 :param line: str line
140 :param line: str line
141 :param default: default
141 :param default: default
142 :rtype: int
142 :rtype: int
143 :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
143 :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
144 """
144 """
145 if line.endswith('\r\n'):
145 if line.endswith('\r\n'):
146 return 2
146 return 2
147 elif line.endswith('\n'):
147 elif line.endswith('\n'):
148 return 0
148 return 0
149 elif line.endswith('\r'):
149 elif line.endswith('\r'):
150 return 1
150 return 1
151 else:
151 else:
152 return default
152 return default
153
153
154
154
155 def generate_api_key(username, salt=None):
155 def generate_api_key(username, salt=None):
156 """
156 """
157 Generates unique API key for given username, if salt is not given
157 Generates unique API key for given username, if salt is not given
158 it'll be generated from some random string
158 it'll be generated from some random string
159
159
160 :param username: username as string
160 :param username: username as string
161 :param salt: salt to hash generate KEY
161 :param salt: salt to hash generate KEY
162 :rtype: str
162 :rtype: str
163 :returns: sha1 hash from username+salt
163 :returns: sha1 hash from username+salt
164 """
164 """
165 from tempfile import _RandomNameSequence
165 from tempfile import _RandomNameSequence
166 import hashlib
166 import hashlib
167
167
168 if salt is None:
168 if salt is None:
169 salt = _RandomNameSequence().next()
169 salt = _RandomNameSequence().next()
170
170
171 return hashlib.sha1(username + salt).hexdigest()
171 return hashlib.sha1(username + salt).hexdigest()
172
172
173
173
174 def safe_int(val, default=None):
174 def safe_int(val, default=None):
175 """
175 """
176 Returns int() of val if val is not convertable to int use default
176 Returns int() of val if val is not convertable to int use default
177 instead
177 instead
178
178
179 :param val:
179 :param val:
180 :param default:
180 :param default:
181 """
181 """
182
182
183 try:
183 try:
184 val = int(val)
184 val = int(val)
185 except (ValueError, TypeError):
185 except (ValueError, TypeError):
186 val = default
186 val = default
187
187
188 return val
188 return val
189
189
190
190
191 def safe_unicode(str_, from_encoding=None):
191 def safe_unicode(str_, from_encoding=None):
192 """
192 """
193 safe unicode function. Does few trick to turn str_ into unicode
193 safe unicode function. Does few trick to turn str_ into unicode
194
194
195 In case of UnicodeDecode error we try to return it with encoding detected
195 In case of UnicodeDecode error we try to return it with encoding detected
196 by chardet library if it fails fallback to unicode with errors replaced
196 by chardet library if it fails fallback to unicode with errors replaced
197
197
198 :param str_: string to decode
198 :param str_: string to decode
199 :rtype: unicode
199 :rtype: unicode
200 :returns: unicode object
200 :returns: unicode object
201 """
201 """
202 if isinstance(str_, unicode):
202 if isinstance(str_, unicode):
203 return str_
203 return str_
204
204
205 if not from_encoding:
205 if not from_encoding:
206 import rhodecode
206 import rhodecode
207 DEFAULT_ENCODINGS = aslist(rhodecode.CONFIG.get('default_encoding',
207 DEFAULT_ENCODINGS = aslist(rhodecode.CONFIG.get('default_encoding',
208 'utf8'), sep=',')
208 'utf8'), sep=',')
209 from_encoding = DEFAULT_ENCODINGS
209 from_encoding = DEFAULT_ENCODINGS
210
210
211 if not isinstance(from_encoding, (list, tuple)):
211 if not isinstance(from_encoding, (list, tuple)):
212 from_encoding = [from_encoding]
212 from_encoding = [from_encoding]
213
213
214 try:
214 try:
215 return unicode(str_)
215 return unicode(str_)
216 except UnicodeDecodeError:
216 except UnicodeDecodeError:
217 pass
217 pass
218
218
219 for enc in from_encoding:
219 for enc in from_encoding:
220 try:
220 try:
221 return unicode(str_, enc)
221 return unicode(str_, enc)
222 except UnicodeDecodeError:
222 except UnicodeDecodeError:
223 pass
223 pass
224
224
225 try:
225 try:
226 import chardet
226 import chardet
227 encoding = chardet.detect(str_)['encoding']
227 encoding = chardet.detect(str_)['encoding']
228 if encoding is None:
228 if encoding is None:
229 raise Exception()
229 raise Exception()
230 return str_.decode(encoding)
230 return str_.decode(encoding)
231 except (ImportError, UnicodeDecodeError, Exception):
231 except (ImportError, UnicodeDecodeError, Exception):
232 return unicode(str_, from_encoding[0], 'replace')
232 return unicode(str_, from_encoding[0], 'replace')
233
233
234
234
235 def safe_str(unicode_, to_encoding=None):
235 def safe_str(unicode_, to_encoding=None):
236 """
236 """
237 safe str function. Does few trick to turn unicode_ into string
237 safe str function. Does few trick to turn unicode_ into string
238
238
239 In case of UnicodeEncodeError we try to return it with encoding detected
239 In case of UnicodeEncodeError we try to return it with encoding detected
240 by chardet library if it fails fallback to string with errors replaced
240 by chardet library if it fails fallback to string with errors replaced
241
241
242 :param unicode_: unicode to encode
242 :param unicode_: unicode to encode
243 :rtype: str
243 :rtype: str
244 :returns: str object
244 :returns: str object
245 """
245 """
246
246
247 # if it's not basestr cast to str
247 # if it's not basestr cast to str
248 if not isinstance(unicode_, basestring):
248 if not isinstance(unicode_, basestring):
249 return str(unicode_)
249 return str(unicode_)
250
250
251 if isinstance(unicode_, str):
251 if isinstance(unicode_, str):
252 return unicode_
252 return unicode_
253
253
254 if not to_encoding:
254 if not to_encoding:
255 import rhodecode
255 import rhodecode
256 DEFAULT_ENCODINGS = aslist(rhodecode.CONFIG.get('default_encoding',
256 DEFAULT_ENCODINGS = aslist(rhodecode.CONFIG.get('default_encoding',
257 'utf8'), sep=',')
257 'utf8'), sep=',')
258 to_encoding = DEFAULT_ENCODINGS
258 to_encoding = DEFAULT_ENCODINGS
259
259
260 if not isinstance(to_encoding, (list, tuple)):
260 if not isinstance(to_encoding, (list, tuple)):
261 to_encoding = [to_encoding]
261 to_encoding = [to_encoding]
262
262
263 for enc in to_encoding:
263 for enc in to_encoding:
264 try:
264 try:
265 return unicode_.encode(enc)
265 return unicode_.encode(enc)
266 except UnicodeEncodeError:
266 except UnicodeEncodeError:
267 pass
267 pass
268
268
269 try:
269 try:
270 import chardet
270 import chardet
271 encoding = chardet.detect(unicode_)['encoding']
271 encoding = chardet.detect(unicode_)['encoding']
272 if encoding is None:
272 if encoding is None:
273 raise UnicodeEncodeError()
273 raise UnicodeEncodeError()
274
274
275 return unicode_.encode(encoding)
275 return unicode_.encode(encoding)
276 except (ImportError, UnicodeEncodeError):
276 except (ImportError, UnicodeEncodeError):
277 return unicode_.encode(to_encoding[0], 'replace')
277 return unicode_.encode(to_encoding[0], 'replace')
278
278
279 return safe_str
279 return safe_str
280
280
281
281
282 def remove_suffix(s, suffix):
282 def remove_suffix(s, suffix):
283 if s.endswith(suffix):
283 if s.endswith(suffix):
284 s = s[:-1 * len(suffix)]
284 s = s[:-1 * len(suffix)]
285 return s
285 return s
286
286
287
287
288 def remove_prefix(s, prefix):
288 def remove_prefix(s, prefix):
289 if s.startswith(prefix):
289 if s.startswith(prefix):
290 s = s[len(prefix):]
290 s = s[len(prefix):]
291 return s
291 return s
292
292
293
293
294 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
294 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
295 """
295 """
296 Custom engine_from_config functions that makes sure we use NullPool for
296 Custom engine_from_config functions that makes sure we use NullPool for
297 file based sqlite databases. This prevents errors on sqlite. This only
297 file based sqlite databases. This prevents errors on sqlite. This only
298 applies to sqlalchemy versions < 0.7.0
298 applies to sqlalchemy versions < 0.7.0
299
299
300 """
300 """
301 import sqlalchemy
301 import sqlalchemy
302 from sqlalchemy import engine_from_config as efc
302 from sqlalchemy import engine_from_config as efc
303 import logging
303 import logging
304
304
305 if int(sqlalchemy.__version__.split('.')[1]) < 7:
305 if int(sqlalchemy.__version__.split('.')[1]) < 7:
306
306
307 # This solution should work for sqlalchemy < 0.7.0, and should use
307 # This solution should work for sqlalchemy < 0.7.0, and should use
308 # proxy=TimerProxy() for execution time profiling
308 # proxy=TimerProxy() for execution time profiling
309
309
310 from sqlalchemy.pool import NullPool
310 from sqlalchemy.pool import NullPool
311 url = configuration[prefix + 'url']
311 url = configuration[prefix + 'url']
312
312
313 if url.startswith('sqlite'):
313 if url.startswith('sqlite'):
314 kwargs.update({'poolclass': NullPool})
314 kwargs.update({'poolclass': NullPool})
315 return efc(configuration, prefix, **kwargs)
315 return efc(configuration, prefix, **kwargs)
316 else:
316 else:
317 import time
317 import time
318 from sqlalchemy import event
318 from sqlalchemy import event
319 from sqlalchemy.engine import Engine
319 from sqlalchemy.engine import Engine
320
320
321 log = logging.getLogger('sqlalchemy.engine')
321 log = logging.getLogger('sqlalchemy.engine')
322 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
322 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
323 engine = efc(configuration, prefix, **kwargs)
323 engine = efc(configuration, prefix, **kwargs)
324
324
325 def color_sql(sql):
325 def color_sql(sql):
326 COLOR_SEQ = "\033[1;%dm"
326 COLOR_SEQ = "\033[1;%dm"
327 COLOR_SQL = YELLOW
327 COLOR_SQL = YELLOW
328 normal = '\x1b[0m'
328 normal = '\x1b[0m'
329 return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
329 return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
330
330
331 if configuration['debug']:
331 if configuration['debug']:
332 #attach events only for debug configuration
332 #attach events only for debug configuration
333
333
334 def before_cursor_execute(conn, cursor, statement,
334 def before_cursor_execute(conn, cursor, statement,
335 parameters, context, executemany):
335 parameters, context, executemany):
336 context._query_start_time = time.time()
336 context._query_start_time = time.time()
337 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
337 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
338
338
339 def after_cursor_execute(conn, cursor, statement,
339 def after_cursor_execute(conn, cursor, statement,
340 parameters, context, executemany):
340 parameters, context, executemany):
341 total = time.time() - context._query_start_time
341 total = time.time() - context._query_start_time
342 log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
342 log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
343
343
344 event.listen(engine, "before_cursor_execute",
344 event.listen(engine, "before_cursor_execute",
345 before_cursor_execute)
345 before_cursor_execute)
346 event.listen(engine, "after_cursor_execute",
346 event.listen(engine, "after_cursor_execute",
347 after_cursor_execute)
347 after_cursor_execute)
348
348
349 return engine
349 return engine
350
350
351
351
352 def age(prevdate):
352 def age(prevdate):
353 """
353 """
354 turns a datetime into an age string.
354 turns a datetime into an age string.
355
355
356 :param prevdate: datetime object
356 :param prevdate: datetime object
357 :rtype: unicode
357 :rtype: unicode
358 :returns: unicode words describing age
358 :returns: unicode words describing age
359 """
359 """
360 now = datetime.datetime.now()
360 now = datetime.datetime.now()
361 now = now.replace(microsecond=0)
361 now = now.replace(microsecond=0)
362 order = ['year', 'month', 'day', 'hour', 'minute', 'second']
362 order = ['year', 'month', 'day', 'hour', 'minute', 'second']
363 deltas = {}
363 deltas = {}
364 future = False
364 future = False
365
365
366 if prevdate > now:
366 if prevdate > now:
367 now, prevdate = prevdate, now
367 now, prevdate = prevdate, now
368 future = True
368 future = True
369
369
370 # Get date parts deltas
370 # Get date parts deltas
371 for part in order:
371 for part in order:
372 if future:
372 if future:
373 from dateutil import relativedelta
373 from dateutil import relativedelta
374 d = relativedelta.relativedelta(now, prevdate)
374 d = relativedelta.relativedelta(now, prevdate)
375 deltas[part] = getattr(d, part + 's')
375 deltas[part] = getattr(d, part + 's')
376 else:
376 else:
377 deltas[part] = getattr(now, part) - getattr(prevdate, part)
377 deltas[part] = getattr(now, part) - getattr(prevdate, part)
378
378
379 # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00,
379 # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00,
380 # not 1 hour, -59 minutes and -59 seconds)
380 # not 1 hour, -59 minutes and -59 seconds)
381 for num, length in [(5, 60), (4, 60), (3, 24)]: # seconds, minutes, hours
381 for num, length in [(5, 60), (4, 60), (3, 24)]: # seconds, minutes, hours
382 part = order[num]
382 part = order[num]
383 carry_part = order[num - 1]
383 carry_part = order[num - 1]
384
384
385 if deltas[part] < 0:
385 if deltas[part] < 0:
386 deltas[part] += length
386 deltas[part] += length
387 deltas[carry_part] -= 1
387 deltas[carry_part] -= 1
388
388
389 # Same thing for days except that the increment depends on the (variable)
389 # Same thing for days except that the increment depends on the (variable)
390 # number of days in the month
390 # number of days in the month
391 month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
391 month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
392 if deltas['day'] < 0:
392 if deltas['day'] < 0:
393 if prevdate.month == 2 and (prevdate.year % 4 == 0 and
393 if prevdate.month == 2 and (prevdate.year % 4 == 0 and
394 (prevdate.year % 100 != 0 or prevdate.year % 400 == 0)):
394 (prevdate.year % 100 != 0 or prevdate.year % 400 == 0)):
395 deltas['day'] += 29
395 deltas['day'] += 29
396 else:
396 else:
397 deltas['day'] += month_lengths[prevdate.month - 1]
397 deltas['day'] += month_lengths[prevdate.month - 1]
398
398
399 deltas['month'] -= 1
399 deltas['month'] -= 1
400
400
401 if deltas['month'] < 0:
401 if deltas['month'] < 0:
402 deltas['month'] += 12
402 deltas['month'] += 12
403 deltas['year'] -= 1
403 deltas['year'] -= 1
404
404
405 # Format the result
405 # Format the result
406 fmt_funcs = {
406 fmt_funcs = {
407 'year': lambda d: ungettext(u'%d year', '%d years', d) % d,
407 'year': lambda d: ungettext(u'%d year', '%d years', d) % d,
408 'month': lambda d: ungettext(u'%d month', '%d months', d) % d,
408 'month': lambda d: ungettext(u'%d month', '%d months', d) % d,
409 'day': lambda d: ungettext(u'%d day', '%d days', d) % d,
409 'day': lambda d: ungettext(u'%d day', '%d days', d) % d,
410 'hour': lambda d: ungettext(u'%d hour', '%d hours', d) % d,
410 'hour': lambda d: ungettext(u'%d hour', '%d hours', d) % d,
411 'minute': lambda d: ungettext(u'%d minute', '%d minutes', d) % d,
411 'minute': lambda d: ungettext(u'%d minute', '%d minutes', d) % d,
412 'second': lambda d: ungettext(u'%d second', '%d seconds', d) % d,
412 'second': lambda d: ungettext(u'%d second', '%d seconds', d) % d,
413 }
413 }
414
414
415 for i, part in enumerate(order):
415 for i, part in enumerate(order):
416 value = deltas[part]
416 value = deltas[part]
417 if value == 0:
417 if value == 0:
418 continue
418 continue
419
419
420 if i < 5:
420 if i < 5:
421 sub_part = order[i + 1]
421 sub_part = order[i + 1]
422 sub_value = deltas[sub_part]
422 sub_value = deltas[sub_part]
423 else:
423 else:
424 sub_value = 0
424 sub_value = 0
425
425
426 if sub_value == 0:
426 if sub_value == 0:
427 if future:
427 if future:
428 return _(u'in %s') % fmt_funcs[part](value)
428 return _(u'in %s') % fmt_funcs[part](value)
429 else:
429 else:
430 return _(u'%s ago') % fmt_funcs[part](value)
430 return _(u'%s ago') % fmt_funcs[part](value)
431 if future:
431 if future:
432 return _(u'in %s and %s') % (fmt_funcs[part](value),
432 return _(u'in %s and %s') % (fmt_funcs[part](value),
433 fmt_funcs[sub_part](sub_value))
433 fmt_funcs[sub_part](sub_value))
434 else:
434 else:
435 return _(u'%s and %s ago') % (fmt_funcs[part](value),
435 return _(u'%s and %s ago') % (fmt_funcs[part](value),
436 fmt_funcs[sub_part](sub_value))
436 fmt_funcs[sub_part](sub_value))
437
437
438 return _(u'just now')
438 return _(u'just now')
439
439
440
440
441 def uri_filter(uri):
441 def uri_filter(uri):
442 """
442 """
443 Removes user:password from given url string
443 Removes user:password from given url string
444
444
445 :param uri:
445 :param uri:
446 :rtype: unicode
446 :rtype: unicode
447 :returns: filtered list of strings
447 :returns: filtered list of strings
448 """
448 """
449 if not uri:
449 if not uri:
450 return ''
450 return ''
451
451
452 proto = ''
452 proto = ''
453
453
454 for pat in ('https://', 'http://'):
454 for pat in ('https://', 'http://'):
455 if uri.startswith(pat):
455 if uri.startswith(pat):
456 uri = uri[len(pat):]
456 uri = uri[len(pat):]
457 proto = pat
457 proto = pat
458 break
458 break
459
459
460 # remove passwords and username
460 # remove passwords and username
461 uri = uri[uri.find('@') + 1:]
461 uri = uri[uri.find('@') + 1:]
462
462
463 # get the port
463 # get the port
464 cred_pos = uri.find(':')
464 cred_pos = uri.find(':')
465 if cred_pos == -1:
465 if cred_pos == -1:
466 host, port = uri, None
466 host, port = uri, None
467 else:
467 else:
468 host, port = uri[:cred_pos], uri[cred_pos + 1:]
468 host, port = uri[:cred_pos], uri[cred_pos + 1:]
469
469
470 return filter(None, [proto, host, port])
470 return filter(None, [proto, host, port])
471
471
472
472
473 def credentials_filter(uri):
473 def credentials_filter(uri):
474 """
474 """
475 Returns a url with removed credentials
475 Returns a url with removed credentials
476
476
477 :param uri:
477 :param uri:
478 """
478 """
479
479
480 uri = uri_filter(uri)
480 uri = uri_filter(uri)
481 #check if we have port
481 #check if we have port
482 if len(uri) > 2 and uri[2]:
482 if len(uri) > 2 and uri[2]:
483 uri[2] = ':' + uri[2]
483 uri[2] = ':' + uri[2]
484
484
485 return ''.join(uri)
485 return ''.join(uri)
486
486
487
487
488 def get_changeset_safe(repo, rev):
488 def get_changeset_safe(repo, rev):
489 """
489 """
490 Safe version of get_changeset if this changeset doesn't exists for a
490 Safe version of get_changeset if this changeset doesn't exists for a
491 repo it returns a Dummy one instead
491 repo it returns a Dummy one instead
492
492
493 :param repo:
493 :param repo:
494 :param rev:
494 :param rev:
495 """
495 """
496 from rhodecode.lib.vcs.backends.base import BaseRepository
496 from rhodecode.lib.vcs.backends.base import BaseRepository
497 from rhodecode.lib.vcs.exceptions import RepositoryError
497 from rhodecode.lib.vcs.exceptions import RepositoryError
498 from rhodecode.lib.vcs.backends.base import EmptyChangeset
498 from rhodecode.lib.vcs.backends.base import EmptyChangeset
499 if not isinstance(repo, BaseRepository):
499 if not isinstance(repo, BaseRepository):
500 raise Exception('You must pass an Repository '
500 raise Exception('You must pass an Repository '
501 'object as first argument got %s', type(repo))
501 'object as first argument got %s', type(repo))
502
502
503 try:
503 try:
504 cs = repo.get_changeset(rev)
504 cs = repo.get_changeset(rev)
505 except RepositoryError:
505 except RepositoryError:
506 cs = EmptyChangeset(requested_revision=rev)
506 cs = EmptyChangeset(requested_revision=rev)
507 return cs
507 return cs
508
508
509
509
510 def datetime_to_time(dt):
510 def datetime_to_time(dt):
511 if dt:
511 if dt:
512 return time.mktime(dt.timetuple())
512 return time.mktime(dt.timetuple())
513
513
514
514
515 def time_to_datetime(tm):
515 def time_to_datetime(tm):
516 if tm:
516 if tm:
517 if isinstance(tm, basestring):
517 if isinstance(tm, basestring):
518 try:
518 try:
519 tm = float(tm)
519 tm = float(tm)
520 except ValueError:
520 except ValueError:
521 return
521 return
522 return datetime.datetime.fromtimestamp(tm)
522 return datetime.datetime.fromtimestamp(tm)
523
523
524 MENTIONS_REGEX = r'(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)(?:\s{1})'
524 MENTIONS_REGEX = r'(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)(?:\s{1})'
525
525
526
526
527 def extract_mentioned_users(s):
527 def extract_mentioned_users(s):
528 """
528 """
529 Returns unique usernames from given string s that have @mention
529 Returns unique usernames from given string s that have @mention
530
530
531 :param s: string to get mentions
531 :param s: string to get mentions
532 """
532 """
533 usrs = set()
533 usrs = set()
534 for username in re.findall(MENTIONS_REGEX, s):
534 for username in re.findall(MENTIONS_REGEX, s):
535 usrs.add(username)
535 usrs.add(username)
536
536
537 return sorted(list(usrs), key=lambda k: k.lower())
537 return sorted(list(usrs), key=lambda k: k.lower())
538
538
539
539
540 class AttributeDict(dict):
540 class AttributeDict(dict):
541 def __getattr__(self, attr):
541 def __getattr__(self, attr):
542 return self.get(attr, None)
542 return self.get(attr, None)
543 __setattr__ = dict.__setitem__
543 __setattr__ = dict.__setitem__
544 __delattr__ = dict.__delitem__
544 __delattr__ = dict.__delitem__
545
545
546
546
547 def fix_PATH(os_=None):
547 def fix_PATH(os_=None):
548 """
548 """
549 Get current active python path, and append it to PATH variable to fix issues
549 Get current active python path, and append it to PATH variable to fix issues
550 of subprocess calls and different python versions
550 of subprocess calls and different python versions
551 """
551 """
552 import sys
552 import sys
553 if os_ is None:
553 if os_ is None:
554 import os
554 import os
555 else:
555 else:
556 os = os_
556 os = os_
557
557
558 cur_path = os.path.split(sys.executable)[0]
558 cur_path = os.path.split(sys.executable)[0]
559 if not os.environ['PATH'].startswith(cur_path):
559 if not os.environ['PATH'].startswith(cur_path):
560 os.environ['PATH'] = '%s:%s' % (cur_path, os.environ['PATH'])
560 os.environ['PATH'] = '%s:%s' % (cur_path, os.environ['PATH'])
561
561
562
562
563 def obfuscate_url_pw(engine):
563 def obfuscate_url_pw(engine):
564 from sqlalchemy.engine import url
564 _url = engine or ''
565 url = url.make_url(engine)
565 from sqlalchemy.engine import url as sa_url
566 if url.password:
566 try:
567 url.password = 'XXXXX'
567 _url = sa_url.make_url(engine)
568 return str(url)
568 if _url.password:
569 _url.password = 'XXXXX'
570 except:
571 pass
572 return str(_url)
569
573
570
574
571 def get_server_url(environ):
575 def get_server_url(environ):
572 req = webob.Request(environ)
576 req = webob.Request(environ)
573 return req.host_url + req.script_name
577 return req.host_url + req.script_name
General Comments 0
You need to be logged in to leave comments. Login now