##// 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 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 now = datetime.datetime.now()
361 361 now = now.replace(microsecond=0)
362 362 order = ['year', 'month', 'day', 'hour', 'minute', 'second']
363 363 deltas = {}
364 364 future = False
365 365
366 366 if prevdate > now:
367 367 now, prevdate = prevdate, now
368 368 future = True
369 369
370 370 # Get date parts deltas
371 371 for part in order:
372 372 if future:
373 373 from dateutil import relativedelta
374 374 d = relativedelta.relativedelta(now, prevdate)
375 375 deltas[part] = getattr(d, part + 's')
376 376 else:
377 377 deltas[part] = getattr(now, part) - getattr(prevdate, part)
378 378
379 379 # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00,
380 380 # not 1 hour, -59 minutes and -59 seconds)
381 381 for num, length in [(5, 60), (4, 60), (3, 24)]: # seconds, minutes, hours
382 382 part = order[num]
383 383 carry_part = order[num - 1]
384 384
385 385 if deltas[part] < 0:
386 386 deltas[part] += length
387 387 deltas[carry_part] -= 1
388 388
389 389 # Same thing for days except that the increment depends on the (variable)
390 390 # number of days in the month
391 391 month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
392 392 if deltas['day'] < 0:
393 393 if prevdate.month == 2 and (prevdate.year % 4 == 0 and
394 394 (prevdate.year % 100 != 0 or prevdate.year % 400 == 0)):
395 395 deltas['day'] += 29
396 396 else:
397 397 deltas['day'] += month_lengths[prevdate.month - 1]
398 398
399 399 deltas['month'] -= 1
400 400
401 401 if deltas['month'] < 0:
402 402 deltas['month'] += 12
403 403 deltas['year'] -= 1
404 404
405 405 # Format the result
406 406 fmt_funcs = {
407 407 'year': lambda d: ungettext(u'%d year', '%d years', d) % d,
408 408 'month': lambda d: ungettext(u'%d month', '%d months', d) % d,
409 409 'day': lambda d: ungettext(u'%d day', '%d days', d) % d,
410 410 'hour': lambda d: ungettext(u'%d hour', '%d hours', d) % d,
411 411 'minute': lambda d: ungettext(u'%d minute', '%d minutes', d) % d,
412 412 'second': lambda d: ungettext(u'%d second', '%d seconds', d) % d,
413 413 }
414 414
415 415 for i, part in enumerate(order):
416 416 value = deltas[part]
417 417 if value == 0:
418 418 continue
419 419
420 420 if i < 5:
421 421 sub_part = order[i + 1]
422 422 sub_value = deltas[sub_part]
423 423 else:
424 424 sub_value = 0
425 425
426 426 if sub_value == 0:
427 427 if future:
428 428 return _(u'in %s') % fmt_funcs[part](value)
429 429 else:
430 430 return _(u'%s ago') % fmt_funcs[part](value)
431 431 if future:
432 432 return _(u'in %s and %s') % (fmt_funcs[part](value),
433 433 fmt_funcs[sub_part](sub_value))
434 434 else:
435 435 return _(u'%s and %s ago') % (fmt_funcs[part](value),
436 436 fmt_funcs[sub_part](sub_value))
437 437
438 438 return _(u'just now')
439 439
440 440
441 441 def uri_filter(uri):
442 442 """
443 443 Removes user:password from given url string
444 444
445 445 :param uri:
446 446 :rtype: unicode
447 447 :returns: filtered list of strings
448 448 """
449 449 if not uri:
450 450 return ''
451 451
452 452 proto = ''
453 453
454 454 for pat in ('https://', 'http://'):
455 455 if uri.startswith(pat):
456 456 uri = uri[len(pat):]
457 457 proto = pat
458 458 break
459 459
460 460 # remove passwords and username
461 461 uri = uri[uri.find('@') + 1:]
462 462
463 463 # get the port
464 464 cred_pos = uri.find(':')
465 465 if cred_pos == -1:
466 466 host, port = uri, None
467 467 else:
468 468 host, port = uri[:cred_pos], uri[cred_pos + 1:]
469 469
470 470 return filter(None, [proto, host, port])
471 471
472 472
473 473 def credentials_filter(uri):
474 474 """
475 475 Returns a url with removed credentials
476 476
477 477 :param uri:
478 478 """
479 479
480 480 uri = uri_filter(uri)
481 481 #check if we have port
482 482 if len(uri) > 2 and uri[2]:
483 483 uri[2] = ':' + uri[2]
484 484
485 485 return ''.join(uri)
486 486
487 487
488 488 def get_changeset_safe(repo, rev):
489 489 """
490 490 Safe version of get_changeset if this changeset doesn't exists for a
491 491 repo it returns a Dummy one instead
492 492
493 493 :param repo:
494 494 :param rev:
495 495 """
496 496 from rhodecode.lib.vcs.backends.base import BaseRepository
497 497 from rhodecode.lib.vcs.exceptions import RepositoryError
498 498 from rhodecode.lib.vcs.backends.base import EmptyChangeset
499 499 if not isinstance(repo, BaseRepository):
500 500 raise Exception('You must pass an Repository '
501 501 'object as first argument got %s', type(repo))
502 502
503 503 try:
504 504 cs = repo.get_changeset(rev)
505 505 except RepositoryError:
506 506 cs = EmptyChangeset(requested_revision=rev)
507 507 return cs
508 508
509 509
510 510 def datetime_to_time(dt):
511 511 if dt:
512 512 return time.mktime(dt.timetuple())
513 513
514 514
515 515 def time_to_datetime(tm):
516 516 if tm:
517 517 if isinstance(tm, basestring):
518 518 try:
519 519 tm = float(tm)
520 520 except ValueError:
521 521 return
522 522 return datetime.datetime.fromtimestamp(tm)
523 523
524 524 MENTIONS_REGEX = r'(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)(?:\s{1})'
525 525
526 526
527 527 def extract_mentioned_users(s):
528 528 """
529 529 Returns unique usernames from given string s that have @mention
530 530
531 531 :param s: string to get mentions
532 532 """
533 533 usrs = set()
534 534 for username in re.findall(MENTIONS_REGEX, s):
535 535 usrs.add(username)
536 536
537 537 return sorted(list(usrs), key=lambda k: k.lower())
538 538
539 539
540 540 class AttributeDict(dict):
541 541 def __getattr__(self, attr):
542 542 return self.get(attr, None)
543 543 __setattr__ = dict.__setitem__
544 544 __delattr__ = dict.__delitem__
545 545
546 546
547 547 def fix_PATH(os_=None):
548 548 """
549 549 Get current active python path, and append it to PATH variable to fix issues
550 550 of subprocess calls and different python versions
551 551 """
552 552 import sys
553 553 if os_ is None:
554 554 import os
555 555 else:
556 556 os = os_
557 557
558 558 cur_path = os.path.split(sys.executable)[0]
559 559 if not os.environ['PATH'].startswith(cur_path):
560 560 os.environ['PATH'] = '%s:%s' % (cur_path, os.environ['PATH'])
561 561
562 562
563 563 def obfuscate_url_pw(engine):
564 from sqlalchemy.engine import url
565 url = url.make_url(engine)
566 if url.password:
567 url.password = 'XXXXX'
568 return str(url)
564 _url = engine or ''
565 from sqlalchemy.engine import url as sa_url
566 try:
567 _url = sa_url.make_url(engine)
568 if _url.password:
569 _url.password = 'XXXXX'
570 except:
571 pass
572 return str(_url)
569 573
570 574
571 575 def get_server_url(environ):
572 576 req = webob.Request(environ)
573 577 return req.host_url + req.script_name
General Comments 0
You need to be logged in to leave comments. Login now