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