##// END OF EJS Templates
indexers: get default filenames for indexing from lexer definitions
Takumi IINO -
r5558:130f8e17 default
parent child Browse files
Show More
@@ -1,73 +1,73 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.config.conf
16 16 ~~~~~~~~~~~~~~~~~~~~~
17 17
18 18 Various config settings for Kallithea
19 19
20 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Mar 7, 2012
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 from kallithea.lib.utils2 import __get_lem
28 from kallithea.lib.utils2 import __get_lem, __get_index_filenames
29 29
30 30
31 31 # language map is also used by whoosh indexer, which for those specified
32 32 # extensions will index it's content
33 33 LANGUAGES_EXTENSIONS_MAP = __get_lem()
34 34
35 35 # Whoosh index targets
36 36
37 37 # Extensions we want to index content of using whoosh
38 38 INDEX_EXTENSIONS = LANGUAGES_EXTENSIONS_MAP.keys()
39 39
40 40 # Filenames we want to index content of using whoosh
41 INDEX_FILENAMES = []
41 INDEX_FILENAMES = __get_index_filenames()
42 42
43 43 # list of readme files to search in file tree and display in summary
44 44 # attached weights defines the search order lower is first
45 45 ALL_READMES = [
46 46 ('readme', 0), ('README', 0), ('Readme', 0),
47 47 ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1),
48 48 ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2),
49 49 ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2),
50 50 ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2),
51 51 ]
52 52
53 53 # extension together with weights to search lower is first
54 54 RST_EXTS = [
55 55 ('', 0), ('.rst', 1), ('.rest', 1),
56 56 ('.RST', 2), ('.REST', 2),
57 57 ('.txt', 3), ('.TXT', 3)
58 58 ]
59 59
60 60 MARKDOWN_EXTS = [
61 61 ('.md', 1), ('.MD', 1),
62 62 ('.mkdn', 2), ('.MKDN', 2),
63 63 ('.mdown', 3), ('.MDOWN', 3),
64 64 ('.markdown', 4), ('.MARKDOWN', 4)
65 65 ]
66 66
67 67 PLAIN_EXTS = [('.text', 2), ('.TEXT', 2)]
68 68
69 69 ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS
70 70
71 71 DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
72 72
73 73 DATE_FORMAT = "%Y-%m-%d"
@@ -1,760 +1,779 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.lib.utils2
16 16 ~~~~~~~~~~~~~~~~~~~~
17 17
18 18 Some simple helper functions
19 19
20 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Jan 5, 2011
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 28
29 29 import os
30 30 import re
31 31 import sys
32 32 import time
33 33 import uuid
34 34 import datetime
35 35 import urllib
36 36 import binascii
37 37
38 38 import webob
39 39 import urlobject
40 40
41 41 from pylons.i18n.translation import _, ungettext
42 42 from kallithea.lib.vcs.utils.lazy import LazyProperty
43 43 from kallithea.lib.compat import json
44 44
45 45
46 46 def __get_lem():
47 47 """
48 48 Get language extension map based on what's inside pygments lexers
49 49 """
50 50 from pygments import lexers
51 51 from string import lower
52 52 from collections import defaultdict
53 53
54 54 d = defaultdict(lambda: [])
55 55
56 56 def __clean(s):
57 57 s = s.lstrip('*')
58 58 s = s.lstrip('.')
59 59
60 60 if s.find('[') != -1:
61 61 exts = []
62 62 start, stop = s.find('['), s.find(']')
63 63
64 64 for suffix in s[start + 1:stop]:
65 65 exts.append(s[:s.find('[')] + suffix)
66 66 return map(lower, exts)
67 67 else:
68 68 return map(lower, [s])
69 69
70 70 for lx, t in sorted(lexers.LEXERS.items()):
71 71 m = map(__clean, t[-2])
72 72 if m:
73 73 m = reduce(lambda x, y: x + y, m)
74 74 for ext in m:
75 75 desc = lx.replace('Lexer', '')
76 76 d[ext].append(desc)
77 77
78 78 return dict(d)
79 79
80 80
81 def __get_index_filenames():
82 """
83 Get list of known indexable filenames from pygment lexer internals
84 """
85 from pygments import lexers
86 from itertools import ifilter
87
88 filenames = []
89
90 def likely_filename(s):
91 return s.find('*') == -1 and s.find('[') == -1
92
93 for lx, t in sorted(lexers.LEXERS.items()):
94 for f in ifilter(likely_filename, t[-2]):
95 filenames.append(f)
96
97 return filenames
98
99
81 100 def str2bool(_str):
82 101 """
83 102 returs True/False value from given string, it tries to translate the
84 103 string into boolean
85 104
86 105 :param _str: string value to translate into boolean
87 106 :rtype: boolean
88 107 :returns: boolean from given string
89 108 """
90 109 if _str is None:
91 110 return False
92 111 if _str in (True, False):
93 112 return _str
94 113 _str = str(_str).strip().lower()
95 114 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
96 115
97 116
98 117 def aslist(obj, sep=None, strip=True):
99 118 """
100 119 Returns given string separated by sep as list
101 120
102 121 :param obj:
103 122 :param sep:
104 123 :param strip:
105 124 """
106 125 if isinstance(obj, (basestring)):
107 126 lst = obj.split(sep)
108 127 if strip:
109 128 lst = [v.strip() for v in lst]
110 129 return lst
111 130 elif isinstance(obj, (list, tuple)):
112 131 return obj
113 132 elif obj is None:
114 133 return []
115 134 else:
116 135 return [obj]
117 136
118 137
119 138 def convert_line_endings(line, mode):
120 139 """
121 140 Converts a given line "line end" according to given mode
122 141
123 142 Available modes are::
124 143 0 - Unix
125 144 1 - Mac
126 145 2 - DOS
127 146
128 147 :param line: given line to convert
129 148 :param mode: mode to convert to
130 149 :rtype: str
131 150 :return: converted line according to mode
132 151 """
133 152 from string import replace
134 153
135 154 if mode == 0:
136 155 line = replace(line, '\r\n', '\n')
137 156 line = replace(line, '\r', '\n')
138 157 elif mode == 1:
139 158 line = replace(line, '\r\n', '\r')
140 159 line = replace(line, '\n', '\r')
141 160 elif mode == 2:
142 161 line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
143 162 return line
144 163
145 164
146 165 def detect_mode(line, default):
147 166 """
148 167 Detects line break for given line, if line break couldn't be found
149 168 given default value is returned
150 169
151 170 :param line: str line
152 171 :param default: default
153 172 :rtype: int
154 173 :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
155 174 """
156 175 if line.endswith('\r\n'):
157 176 return 2
158 177 elif line.endswith('\n'):
159 178 return 0
160 179 elif line.endswith('\r'):
161 180 return 1
162 181 else:
163 182 return default
164 183
165 184
166 185 def generate_api_key():
167 186 """
168 187 Generates a random (presumably unique) API key.
169 188 """
170 189 return binascii.hexlify(os.urandom(20))
171 190
172 191
173 192 def safe_int(val, default=None):
174 193 """
175 194 Returns int() of val if val is not convertable to int use default
176 195 instead
177 196
178 197 :param val:
179 198 :param default:
180 199 """
181 200
182 201 try:
183 202 val = int(val)
184 203 except (ValueError, TypeError):
185 204 val = default
186 205
187 206 return val
188 207
189 208
190 209 def safe_unicode(str_, from_encoding=None):
191 210 """
192 211 safe unicode function. Does few trick to turn str_ into unicode
193 212
194 213 In case of UnicodeDecode error we try to return it with encoding detected
195 214 by chardet library if it fails fallback to unicode with errors replaced
196 215
197 216 :param str_: string to decode
198 217 :rtype: unicode
199 218 :returns: unicode object
200 219 """
201 220 if isinstance(str_, unicode):
202 221 return str_
203 222
204 223 if not from_encoding:
205 224 import kallithea
206 225 DEFAULT_ENCODINGS = aslist(kallithea.CONFIG.get('default_encoding',
207 226 'utf8'), sep=',')
208 227 from_encoding = DEFAULT_ENCODINGS
209 228
210 229 if not isinstance(from_encoding, (list, tuple)):
211 230 from_encoding = [from_encoding]
212 231
213 232 try:
214 233 return unicode(str_)
215 234 except UnicodeDecodeError:
216 235 pass
217 236
218 237 for enc in from_encoding:
219 238 try:
220 239 return unicode(str_, enc)
221 240 except UnicodeDecodeError:
222 241 pass
223 242
224 243 try:
225 244 import chardet
226 245 encoding = chardet.detect(str_)['encoding']
227 246 if encoding is None:
228 247 raise Exception()
229 248 return str_.decode(encoding)
230 249 except (ImportError, UnicodeDecodeError, Exception):
231 250 return unicode(str_, from_encoding[0], 'replace')
232 251
233 252
234 253 def safe_str(unicode_, to_encoding=None):
235 254 """
236 255 safe str function. Does few trick to turn unicode_ into string
237 256
238 257 In case of UnicodeEncodeError we try to return it with encoding detected
239 258 by chardet library if it fails fallback to string with errors replaced
240 259
241 260 :param unicode_: unicode to encode
242 261 :rtype: str
243 262 :returns: str object
244 263 """
245 264
246 265 # if it's not basestr cast to str
247 266 if not isinstance(unicode_, basestring):
248 267 return str(unicode_)
249 268
250 269 if isinstance(unicode_, str):
251 270 return unicode_
252 271
253 272 if not to_encoding:
254 273 import kallithea
255 274 DEFAULT_ENCODINGS = aslist(kallithea.CONFIG.get('default_encoding',
256 275 'utf8'), sep=',')
257 276 to_encoding = DEFAULT_ENCODINGS
258 277
259 278 if not isinstance(to_encoding, (list, tuple)):
260 279 to_encoding = [to_encoding]
261 280
262 281 for enc in to_encoding:
263 282 try:
264 283 return unicode_.encode(enc)
265 284 except UnicodeEncodeError:
266 285 pass
267 286
268 287 try:
269 288 import chardet
270 289 encoding = chardet.detect(unicode_)['encoding']
271 290 if encoding is None:
272 291 raise UnicodeEncodeError()
273 292
274 293 return unicode_.encode(encoding)
275 294 except (ImportError, UnicodeEncodeError):
276 295 return unicode_.encode(to_encoding[0], 'replace')
277 296
278 297
279 298 def remove_suffix(s, suffix):
280 299 if s.endswith(suffix):
281 300 s = s[:-1 * len(suffix)]
282 301 return s
283 302
284 303
285 304 def remove_prefix(s, prefix):
286 305 if s.startswith(prefix):
287 306 s = s[len(prefix):]
288 307 return s
289 308
290 309
291 310 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
292 311 """
293 312 Custom engine_from_config functions that makes sure we use NullPool for
294 313 file based sqlite databases. This prevents errors on sqlite. This only
295 314 applies to sqlalchemy versions < 0.7.0
296 315
297 316 """
298 317 import sqlalchemy
299 318 from sqlalchemy import engine_from_config as efc
300 319 import logging
301 320
302 321 if int(sqlalchemy.__version__.split('.')[1]) < 7:
303 322
304 323 # This solution should work for sqlalchemy < 0.7.0, and should use
305 324 # proxy=TimerProxy() for execution time profiling
306 325
307 326 from sqlalchemy.pool import NullPool
308 327 url = configuration[prefix + 'url']
309 328
310 329 if url.startswith('sqlite'):
311 330 kwargs.update({'poolclass': NullPool})
312 331 return efc(configuration, prefix, **kwargs)
313 332 else:
314 333 import time
315 334 from sqlalchemy import event
316 335
317 336 log = logging.getLogger('sqlalchemy.engine')
318 337 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
319 338 engine = efc(configuration, prefix, **kwargs)
320 339
321 340 def color_sql(sql):
322 341 COLOR_SEQ = "\033[1;%dm"
323 342 COLOR_SQL = YELLOW
324 343 normal = '\x1b[0m'
325 344 return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
326 345
327 346 if configuration['debug']:
328 347 #attach events only for debug configuration
329 348
330 349 def before_cursor_execute(conn, cursor, statement,
331 350 parameters, context, executemany):
332 351 context._query_start_time = time.time()
333 352 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
334 353
335 354 def after_cursor_execute(conn, cursor, statement,
336 355 parameters, context, executemany):
337 356 total = time.time() - context._query_start_time
338 357 log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
339 358
340 359 event.listen(engine, "before_cursor_execute",
341 360 before_cursor_execute)
342 361 event.listen(engine, "after_cursor_execute",
343 362 after_cursor_execute)
344 363
345 364 return engine
346 365
347 366
348 367 def age(prevdate, show_short_version=False, now=None):
349 368 """
350 369 turns a datetime into an age string.
351 370 If show_short_version is True, then it will generate a not so accurate but shorter string,
352 371 example: 2days ago, instead of 2 days and 23 hours ago.
353 372
354 373 :param prevdate: datetime object
355 374 :param show_short_version: if it should aproximate the date and return a shorter string
356 375 :rtype: unicode
357 376 :returns: unicode words describing age
358 377 """
359 378 now = now or datetime.datetime.now()
360 379 order = ['year', 'month', 'day', 'hour', 'minute', 'second']
361 380 deltas = {}
362 381 future = False
363 382
364 383 if prevdate > now:
365 384 now, prevdate = prevdate, now
366 385 future = True
367 386 if future:
368 387 prevdate = prevdate.replace(microsecond=0)
369 388 # Get date parts deltas
370 389 from dateutil import relativedelta
371 390 for part in order:
372 391 d = relativedelta.relativedelta(now, prevdate)
373 392 deltas[part] = getattr(d, part + 's')
374 393
375 394 # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00,
376 395 # not 1 hour, -59 minutes and -59 seconds)
377 396 for num, length in [(5, 60), (4, 60), (3, 24)]: # seconds, minutes, hours
378 397 part = order[num]
379 398 carry_part = order[num - 1]
380 399
381 400 if deltas[part] < 0:
382 401 deltas[part] += length
383 402 deltas[carry_part] -= 1
384 403
385 404 # Same thing for days except that the increment depends on the (variable)
386 405 # number of days in the month
387 406 month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
388 407 if deltas['day'] < 0:
389 408 if prevdate.month == 2 and (prevdate.year % 4 == 0 and
390 409 (prevdate.year % 100 != 0 or prevdate.year % 400 == 0)):
391 410 deltas['day'] += 29
392 411 else:
393 412 deltas['day'] += month_lengths[prevdate.month - 1]
394 413
395 414 deltas['month'] -= 1
396 415
397 416 if deltas['month'] < 0:
398 417 deltas['month'] += 12
399 418 deltas['year'] -= 1
400 419
401 420 # In short version, we want nicer handling of ages of more than a year
402 421 if show_short_version:
403 422 if deltas['year'] == 1:
404 423 # ages between 1 and 2 years: show as months
405 424 deltas['month'] += 12
406 425 deltas['year'] = 0
407 426 if deltas['year'] >= 2:
408 427 # ages 2+ years: round
409 428 if deltas['month'] > 6:
410 429 deltas['year'] += 1
411 430 deltas['month'] = 0
412 431
413 432 # Format the result
414 433 fmt_funcs = {
415 434 'year': lambda d: ungettext(u'%d year', '%d years', d) % d,
416 435 'month': lambda d: ungettext(u'%d month', '%d months', d) % d,
417 436 'day': lambda d: ungettext(u'%d day', '%d days', d) % d,
418 437 'hour': lambda d: ungettext(u'%d hour', '%d hours', d) % d,
419 438 'minute': lambda d: ungettext(u'%d minute', '%d minutes', d) % d,
420 439 'second': lambda d: ungettext(u'%d second', '%d seconds', d) % d,
421 440 }
422 441
423 442 for i, part in enumerate(order):
424 443 value = deltas[part]
425 444 if value == 0:
426 445 continue
427 446
428 447 if i < 5:
429 448 sub_part = order[i + 1]
430 449 sub_value = deltas[sub_part]
431 450 else:
432 451 sub_value = 0
433 452
434 453 if sub_value == 0 or show_short_version:
435 454 if future:
436 455 return _('in %s') % fmt_funcs[part](value)
437 456 else:
438 457 return _('%s ago') % fmt_funcs[part](value)
439 458 if future:
440 459 return _('in %s and %s') % (fmt_funcs[part](value),
441 460 fmt_funcs[sub_part](sub_value))
442 461 else:
443 462 return _('%s and %s ago') % (fmt_funcs[part](value),
444 463 fmt_funcs[sub_part](sub_value))
445 464
446 465 return _('just now')
447 466
448 467
449 468 def uri_filter(uri):
450 469 """
451 470 Removes user:password from given url string
452 471
453 472 :param uri:
454 473 :rtype: unicode
455 474 :returns: filtered list of strings
456 475 """
457 476 if not uri:
458 477 return ''
459 478
460 479 proto = ''
461 480
462 481 for pat in ('https://', 'http://', 'git://'):
463 482 if uri.startswith(pat):
464 483 uri = uri[len(pat):]
465 484 proto = pat
466 485 break
467 486
468 487 # remove passwords and username
469 488 uri = uri[uri.find('@') + 1:]
470 489
471 490 # get the port
472 491 cred_pos = uri.find(':')
473 492 if cred_pos == -1:
474 493 host, port = uri, None
475 494 else:
476 495 host, port = uri[:cred_pos], uri[cred_pos + 1:]
477 496
478 497 return filter(None, [proto, host, port])
479 498
480 499
481 500 def credentials_filter(uri):
482 501 """
483 502 Returns a url with removed credentials
484 503
485 504 :param uri:
486 505 """
487 506
488 507 uri = uri_filter(uri)
489 508 #check if we have port
490 509 if len(uri) > 2 and uri[2]:
491 510 uri[2] = ':' + uri[2]
492 511
493 512 return ''.join(uri)
494 513
495 514
496 515 def get_clone_url(uri_tmpl, qualified_home_url, repo_name, repo_id, **override):
497 516 parsed_url = urlobject.URLObject(qualified_home_url)
498 517 decoded_path = safe_unicode(urllib.unquote(parsed_url.path.rstrip('/')))
499 518 args = {
500 519 'scheme': parsed_url.scheme,
501 520 'user': '',
502 521 'netloc': parsed_url.netloc+decoded_path, # path if we use proxy-prefix
503 522 'prefix': decoded_path,
504 523 'repo': repo_name,
505 524 'repoid': str(repo_id)
506 525 }
507 526 args.update(override)
508 527 args['user'] = urllib.quote(safe_str(args['user']))
509 528
510 529 for k, v in args.items():
511 530 uri_tmpl = uri_tmpl.replace('{%s}' % k, v)
512 531
513 532 # remove leading @ sign if it's present. Case of empty user
514 533 url_obj = urlobject.URLObject(uri_tmpl)
515 534 url = url_obj.with_netloc(url_obj.netloc.lstrip('@'))
516 535
517 536 return safe_unicode(url)
518 537
519 538
520 539 def get_changeset_safe(repo, rev):
521 540 """
522 541 Safe version of get_changeset if this changeset doesn't exists for a
523 542 repo it returns a Dummy one instead
524 543
525 544 :param repo:
526 545 :param rev:
527 546 """
528 547 from kallithea.lib.vcs.backends.base import BaseRepository
529 548 from kallithea.lib.vcs.exceptions import RepositoryError
530 549 from kallithea.lib.vcs.backends.base import EmptyChangeset
531 550 if not isinstance(repo, BaseRepository):
532 551 raise Exception('You must pass an Repository '
533 552 'object as first argument got %s', type(repo))
534 553
535 554 try:
536 555 cs = repo.get_changeset(rev)
537 556 except (RepositoryError, LookupError):
538 557 cs = EmptyChangeset(requested_revision=rev)
539 558 return cs
540 559
541 560
542 561 def datetime_to_time(dt):
543 562 if dt:
544 563 return time.mktime(dt.timetuple())
545 564
546 565
547 566 def time_to_datetime(tm):
548 567 if tm:
549 568 if isinstance(tm, basestring):
550 569 try:
551 570 tm = float(tm)
552 571 except ValueError:
553 572 return
554 573 return datetime.datetime.fromtimestamp(tm)
555 574
556 575 # Must match regexp in kallithea/public/js/base.js MentionsAutoComplete()
557 576 # Check char before @ - it must not look like we are in an email addresses.
558 577 # Matching is gready so we don't have to look beyond the end.
559 578 MENTIONS_REGEX = re.compile(r'(?:^|(?<=[^a-zA-Z0-9]))@([a-zA-Z0-9][-_.a-zA-Z0-9]*[a-zA-Z0-9])')
560 579
561 580 def extract_mentioned_users(s):
562 581 r"""
563 582 Returns unique usernames from given string s that have @mention
564 583
565 584 :param s: string to get mentions
566 585
567 586 >>> extract_mentioned_users('@1-2.a_X,@1234 not@not @ddd@not @n @ee @ff @gg, @gg;@hh @n\n@zz,')
568 587 ['1-2.a_X', '1234', 'ddd', 'ee', 'ff', 'gg', 'hh', 'zz']
569 588 """
570 589 usrs = set()
571 590 for username in MENTIONS_REGEX.findall(s):
572 591 usrs.add(username)
573 592
574 593 return sorted(list(usrs), key=lambda k: k.lower())
575 594
576 595
577 596 class AttributeDict(dict):
578 597 def __getattr__(self, attr):
579 598 return self.get(attr, None)
580 599 __setattr__ = dict.__setitem__
581 600 __delattr__ = dict.__delitem__
582 601
583 602
584 603 def fix_PATH(os_=None):
585 604 """
586 605 Get current active python path, and append it to PATH variable to fix issues
587 606 of subprocess calls and different python versions
588 607 """
589 608 if os_ is None:
590 609 import os
591 610 else:
592 611 os = os_
593 612
594 613 cur_path = os.path.split(sys.executable)[0]
595 614 if not os.environ['PATH'].startswith(cur_path):
596 615 os.environ['PATH'] = '%s:%s' % (cur_path, os.environ['PATH'])
597 616
598 617
599 618 def obfuscate_url_pw(engine):
600 619 from sqlalchemy.engine import url as sa_url
601 620 from sqlalchemy.exc import ArgumentError
602 621 try:
603 622 _url = sa_url.make_url(engine or '')
604 623 except ArgumentError:
605 624 return engine
606 625 if _url.password:
607 626 _url.password = 'XXXXX'
608 627 return str(_url)
609 628
610 629
611 630 def get_server_url(environ):
612 631 req = webob.Request(environ)
613 632 return req.host_url + req.script_name
614 633
615 634
616 635 def _extract_extras(env=None):
617 636 """
618 637 Extracts the Kallithea extras data from os.environ, and wraps it into named
619 638 AttributeDict object
620 639 """
621 640 if not env:
622 641 env = os.environ
623 642
624 643 try:
625 644 extras = json.loads(env['KALLITHEA_EXTRAS'])
626 645 except KeyError:
627 646 extras = {}
628 647
629 648 try:
630 649 for k in ['username', 'repository', 'locked_by', 'scm', 'make_lock',
631 650 'action', 'ip']:
632 651 extras[k]
633 652 except KeyError as e:
634 653 raise Exception('Missing key %s in os.environ %s' % (e, extras))
635 654
636 655 return AttributeDict(extras)
637 656
638 657
639 658 def _set_extras(extras):
640 659 # RC_SCM_DATA can probably be removed in the future, but for compatibilty now...
641 660 os.environ['KALLITHEA_EXTRAS'] = os.environ['RC_SCM_DATA'] = json.dumps(extras)
642 661
643 662
644 663 def unique_id(hexlen=32):
645 664 alphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjklmnpqrstuvwxyz"
646 665 return suuid(truncate_to=hexlen, alphabet=alphabet)
647 666
648 667
649 668 def suuid(url=None, truncate_to=22, alphabet=None):
650 669 """
651 670 Generate and return a short URL safe UUID.
652 671
653 672 If the url parameter is provided, set the namespace to the provided
654 673 URL and generate a UUID.
655 674
656 675 :param url to get the uuid for
657 676 :truncate_to: truncate the basic 22 UUID to shorter version
658 677
659 678 The IDs won't be universally unique any longer, but the probability of
660 679 a collision will still be very low.
661 680 """
662 681 # Define our alphabet.
663 682 _ALPHABET = alphabet or "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
664 683
665 684 # If no URL is given, generate a random UUID.
666 685 if url is None:
667 686 unique_id = uuid.uuid4().int
668 687 else:
669 688 unique_id = uuid.uuid3(uuid.NAMESPACE_URL, url).int
670 689
671 690 alphabet_length = len(_ALPHABET)
672 691 output = []
673 692 while unique_id > 0:
674 693 digit = unique_id % alphabet_length
675 694 output.append(_ALPHABET[digit])
676 695 unique_id = int(unique_id / alphabet_length)
677 696 return "".join(output)[:truncate_to]
678 697
679 698
680 699 def get_current_authuser():
681 700 """
682 701 Gets kallithea user from threadlocal tmpl_context variable if it's
683 702 defined, else returns None.
684 703 """
685 704 from pylons import tmpl_context
686 705 if hasattr(tmpl_context, 'authuser'):
687 706 return tmpl_context.authuser
688 707
689 708 return None
690 709
691 710
692 711 class OptionalAttr(object):
693 712 """
694 713 Special Optional Option that defines other attribute. Example::
695 714
696 715 def test(apiuser, userid=Optional(OAttr('apiuser')):
697 716 user = Optional.extract(userid)
698 717 # calls
699 718
700 719 """
701 720
702 721 def __init__(self, attr_name):
703 722 self.attr_name = attr_name
704 723
705 724 def __repr__(self):
706 725 return '<OptionalAttr:%s>' % self.attr_name
707 726
708 727 def __call__(self):
709 728 return self
710 729
711 730 #alias
712 731 OAttr = OptionalAttr
713 732
714 733
715 734 class Optional(object):
716 735 """
717 736 Defines an optional parameter::
718 737
719 738 param = param.getval() if isinstance(param, Optional) else param
720 739 param = param() if isinstance(param, Optional) else param
721 740
722 741 is equivalent of::
723 742
724 743 param = Optional.extract(param)
725 744
726 745 """
727 746
728 747 def __init__(self, type_):
729 748 self.type_ = type_
730 749
731 750 def __repr__(self):
732 751 return '<Optional:%s>' % self.type_.__repr__()
733 752
734 753 def __call__(self):
735 754 return self.getval()
736 755
737 756 def getval(self):
738 757 """
739 758 returns value from this Optional instance
740 759 """
741 760 if isinstance(self.type_, OAttr):
742 761 # use params name
743 762 return self.type_.attr_name
744 763 return self.type_
745 764
746 765 @classmethod
747 766 def extract(cls, val):
748 767 """
749 768 Extracts value from Optional() instance
750 769
751 770 :param val:
752 771 :return: original value if it's not Optional instance else
753 772 value of instance
754 773 """
755 774 if isinstance(val, cls):
756 775 return val.getval()
757 776 return val
758 777
759 778 def urlreadable(s, _cleanstringsub=re.compile('[^-a-zA-Z0-9./]+').sub):
760 779 return _cleanstringsub('_', safe_str(s)).rstrip('_')
General Comments 0
You need to be logged in to leave comments. Login now