##// END OF EJS Templates
reverted accidentally removed function in safe_str
marcink -
r2043:ef2f75e9 beta
parent child Browse files
Show More
@@ -1,461 +1,465 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.__init__
3 rhodecode.lib.__init__
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 os
26 import os
27 import re
27 import re
28 from rhodecode.lib.vcs.utils.lazy import LazyProperty
28 from rhodecode.lib.vcs.utils.lazy import LazyProperty
29
29
30
30
31 def __get_lem():
31 def __get_lem():
32 from pygments import lexers
32 from pygments import lexers
33 from string import lower
33 from string import lower
34 from collections import defaultdict
34 from collections import defaultdict
35
35
36 d = defaultdict(lambda: [])
36 d = defaultdict(lambda: [])
37
37
38 def __clean(s):
38 def __clean(s):
39 s = s.lstrip('*')
39 s = s.lstrip('*')
40 s = s.lstrip('.')
40 s = s.lstrip('.')
41
41
42 if s.find('[') != -1:
42 if s.find('[') != -1:
43 exts = []
43 exts = []
44 start, stop = s.find('['), s.find(']')
44 start, stop = s.find('['), s.find(']')
45
45
46 for suffix in s[start + 1:stop]:
46 for suffix in s[start + 1:stop]:
47 exts.append(s[:s.find('[')] + suffix)
47 exts.append(s[:s.find('[')] + suffix)
48 return map(lower, exts)
48 return map(lower, exts)
49 else:
49 else:
50 return map(lower, [s])
50 return map(lower, [s])
51
51
52 for lx, t in sorted(lexers.LEXERS.items()):
52 for lx, t in sorted(lexers.LEXERS.items()):
53 m = map(__clean, t[-2])
53 m = map(__clean, t[-2])
54 if m:
54 if m:
55 m = reduce(lambda x, y: x + y, m)
55 m = reduce(lambda x, y: x + y, m)
56 for ext in m:
56 for ext in m:
57 desc = lx.replace('Lexer', '')
57 desc = lx.replace('Lexer', '')
58 d[ext].append(desc)
58 d[ext].append(desc)
59
59
60 return dict(d)
60 return dict(d)
61
61
62 # language map is also used by whoosh indexer, which for those specified
62 # language map is also used by whoosh indexer, which for those specified
63 # extensions will index it's content
63 # extensions will index it's content
64 LANGUAGES_EXTENSIONS_MAP = __get_lem()
64 LANGUAGES_EXTENSIONS_MAP = __get_lem()
65
65
66 # Additional mappings that are not present in the pygments lexers
66 # Additional mappings that are not present in the pygments lexers
67 # NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
67 # NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
68 ADDITIONAL_MAPPINGS = {'xaml': 'XAML'}
68 ADDITIONAL_MAPPINGS = {'xaml': 'XAML'}
69
69
70 LANGUAGES_EXTENSIONS_MAP.update(ADDITIONAL_MAPPINGS)
70 LANGUAGES_EXTENSIONS_MAP.update(ADDITIONAL_MAPPINGS)
71
71
72 # list of readme files to search in file tree and display in summary
72 # list of readme files to search in file tree and display in summary
73 # attached weights defines the search order lower is first
73 # attached weights defines the search order lower is first
74 ALL_READMES = [
74 ALL_READMES = [
75 ('readme', 0), ('README', 0), ('Readme', 0),
75 ('readme', 0), ('README', 0), ('Readme', 0),
76 ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1),
76 ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1),
77 ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2),
77 ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2),
78 ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2),
78 ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2),
79 ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2),
79 ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2),
80 ]
80 ]
81
81
82 # extension together with weights to search lower is first
82 # extension together with weights to search lower is first
83 RST_EXTS = [
83 RST_EXTS = [
84 ('', 0), ('.rst', 1), ('.rest', 1),
84 ('', 0), ('.rst', 1), ('.rest', 1),
85 ('.RST', 2), ('.REST', 2),
85 ('.RST', 2), ('.REST', 2),
86 ('.txt', 3), ('.TXT', 3)
86 ('.txt', 3), ('.TXT', 3)
87 ]
87 ]
88
88
89 MARKDOWN_EXTS = [
89 MARKDOWN_EXTS = [
90 ('.md', 1), ('.MD', 1),
90 ('.md', 1), ('.MD', 1),
91 ('.mkdn', 2), ('.MKDN', 2),
91 ('.mkdn', 2), ('.MKDN', 2),
92 ('.mdown', 3), ('.MDOWN', 3),
92 ('.mdown', 3), ('.MDOWN', 3),
93 ('.markdown', 4), ('.MARKDOWN', 4)
93 ('.markdown', 4), ('.MARKDOWN', 4)
94 ]
94 ]
95
95
96 PLAIN_EXTS = [('.text', 2), ('.TEXT', 2)]
96 PLAIN_EXTS = [('.text', 2), ('.TEXT', 2)]
97
97
98 ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS
98 ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS
99
99
100
100
101 def str2bool(_str):
101 def str2bool(_str):
102 """
102 """
103 returs True/False value from given string, it tries to translate the
103 returs True/False value from given string, it tries to translate the
104 string into boolean
104 string into boolean
105
105
106 :param _str: string value to translate into boolean
106 :param _str: string value to translate into boolean
107 :rtype: boolean
107 :rtype: boolean
108 :returns: boolean from given string
108 :returns: boolean from given string
109 """
109 """
110 if _str is None:
110 if _str is None:
111 return False
111 return False
112 if _str in (True, False):
112 if _str in (True, False):
113 return _str
113 return _str
114 _str = str(_str).strip().lower()
114 _str = str(_str).strip().lower()
115 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
115 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
116
116
117
117
118 def convert_line_endings(line, mode):
118 def convert_line_endings(line, mode):
119 """
119 """
120 Converts a given line "line end" accordingly to given mode
120 Converts a given line "line end" accordingly to given mode
121
121
122 Available modes are::
122 Available modes are::
123 0 - Unix
123 0 - Unix
124 1 - Mac
124 1 - Mac
125 2 - DOS
125 2 - DOS
126
126
127 :param line: given line to convert
127 :param line: given line to convert
128 :param mode: mode to convert to
128 :param mode: mode to convert to
129 :rtype: str
129 :rtype: str
130 :return: converted line according to mode
130 :return: converted line according to mode
131 """
131 """
132 from string import replace
132 from string import replace
133
133
134 if mode == 0:
134 if mode == 0:
135 line = replace(line, '\r\n', '\n')
135 line = replace(line, '\r\n', '\n')
136 line = replace(line, '\r', '\n')
136 line = replace(line, '\r', '\n')
137 elif mode == 1:
137 elif mode == 1:
138 line = replace(line, '\r\n', '\r')
138 line = replace(line, '\r\n', '\r')
139 line = replace(line, '\n', '\r')
139 line = replace(line, '\n', '\r')
140 elif mode == 2:
140 elif mode == 2:
141 line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
141 line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
142 return line
142 return line
143
143
144
144
145 def detect_mode(line, default):
145 def detect_mode(line, default):
146 """
146 """
147 Detects line break for given line, if line break couldn't be found
147 Detects line break for given line, if line break couldn't be found
148 given default value is returned
148 given default value is returned
149
149
150 :param line: str line
150 :param line: str line
151 :param default: default
151 :param default: default
152 :rtype: int
152 :rtype: int
153 :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
153 :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
154 """
154 """
155 if line.endswith('\r\n'):
155 if line.endswith('\r\n'):
156 return 2
156 return 2
157 elif line.endswith('\n'):
157 elif line.endswith('\n'):
158 return 0
158 return 0
159 elif line.endswith('\r'):
159 elif line.endswith('\r'):
160 return 1
160 return 1
161 else:
161 else:
162 return default
162 return default
163
163
164
164
165 def generate_api_key(username, salt=None):
165 def generate_api_key(username, salt=None):
166 """
166 """
167 Generates unique API key for given username, if salt is not given
167 Generates unique API key for given username, if salt is not given
168 it'll be generated from some random string
168 it'll be generated from some random string
169
169
170 :param username: username as string
170 :param username: username as string
171 :param salt: salt to hash generate KEY
171 :param salt: salt to hash generate KEY
172 :rtype: str
172 :rtype: str
173 :returns: sha1 hash from username+salt
173 :returns: sha1 hash from username+salt
174 """
174 """
175 from tempfile import _RandomNameSequence
175 from tempfile import _RandomNameSequence
176 import hashlib
176 import hashlib
177
177
178 if salt is None:
178 if salt is None:
179 salt = _RandomNameSequence().next()
179 salt = _RandomNameSequence().next()
180
180
181 return hashlib.sha1(username + salt).hexdigest()
181 return hashlib.sha1(username + salt).hexdigest()
182
182
183
183
184 def safe_unicode(str_, from_encoding=None):
184 def safe_unicode(str_, from_encoding=None):
185 """
185 """
186 safe unicode function. Does few trick to turn str_ into unicode
186 safe unicode function. Does few trick to turn str_ into unicode
187
187
188 In case of UnicodeDecode error we try to return it with encoding detected
188 In case of UnicodeDecode error we try to return it with encoding detected
189 by chardet library if it fails fallback to unicode with errors replaced
189 by chardet library if it fails fallback to unicode with errors replaced
190
190
191 :param str_: string to decode
191 :param str_: string to decode
192 :rtype: unicode
192 :rtype: unicode
193 :returns: unicode object
193 :returns: unicode object
194 """
194 """
195 if isinstance(str_, unicode):
195 if isinstance(str_, unicode):
196 return str_
196 return str_
197
197
198 if not from_encoding:
198 if not from_encoding:
199 import rhodecode
199 import rhodecode
200 DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8')
200 DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8')
201 from_encoding = DEFAULT_ENCODING
201 from_encoding = DEFAULT_ENCODING
202
202
203 try:
203 try:
204 return unicode(str_)
204 return unicode(str_)
205 except UnicodeDecodeError:
205 except UnicodeDecodeError:
206 pass
206 pass
207
207
208 try:
208 try:
209 return unicode(str_, from_encoding)
209 return unicode(str_, from_encoding)
210 except UnicodeDecodeError:
210 except UnicodeDecodeError:
211 pass
211 pass
212
212
213 try:
213 try:
214 import chardet
214 import chardet
215 encoding = chardet.detect(str_)['encoding']
215 encoding = chardet.detect(str_)['encoding']
216 if encoding is None:
216 if encoding is None:
217 raise Exception()
217 raise Exception()
218 return str_.decode(encoding)
218 return str_.decode(encoding)
219 except (ImportError, UnicodeDecodeError, Exception):
219 except (ImportError, UnicodeDecodeError, Exception):
220 return unicode(str_, from_encoding, 'replace')
220 return unicode(str_, from_encoding, 'replace')
221
221
222
222
223 def safe_str(unicode_, to_encoding=None):
223 def safe_str(unicode_, to_encoding=None):
224 """
224 """
225 safe str function. Does few trick to turn unicode_ into string
225 safe str function. Does few trick to turn unicode_ into string
226
226
227 In case of UnicodeEncodeError we try to return it with encoding detected
227 In case of UnicodeEncodeError we try to return it with encoding detected
228 by chardet library if it fails fallback to string with errors replaced
228 by chardet library if it fails fallback to string with errors replaced
229
229
230 :param unicode_: unicode to encode
230 :param unicode_: unicode to encode
231 :rtype: str
231 :rtype: str
232 :returns: str object
232 :returns: str object
233 """
233 """
234
234
235 # if it's not basestr cast to str
236 if not isinstance(unicode_, basestring):
237 return str(unicode_)
238
235 if isinstance(unicode_, str):
239 if isinstance(unicode_, str):
236 return unicode_
240 return unicode_
237
241
238 if not to_encoding:
242 if not to_encoding:
239 import rhodecode
243 import rhodecode
240 DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8')
244 DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8')
241 to_encoding = DEFAULT_ENCODING
245 to_encoding = DEFAULT_ENCODING
242
246
243 try:
247 try:
244 return unicode_.encode(to_encoding)
248 return unicode_.encode(to_encoding)
245 except UnicodeEncodeError:
249 except UnicodeEncodeError:
246 pass
250 pass
247
251
248 try:
252 try:
249 import chardet
253 import chardet
250 encoding = chardet.detect(unicode_)['encoding']
254 encoding = chardet.detect(unicode_)['encoding']
251 print encoding
255 print encoding
252 if encoding is None:
256 if encoding is None:
253 raise UnicodeEncodeError()
257 raise UnicodeEncodeError()
254
258
255 return unicode_.encode(encoding)
259 return unicode_.encode(encoding)
256 except (ImportError, UnicodeEncodeError):
260 except (ImportError, UnicodeEncodeError):
257 return unicode_.encode(to_encoding, 'replace')
261 return unicode_.encode(to_encoding, 'replace')
258
262
259 return safe_str
263 return safe_str
260
264
261
265
262 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
266 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
263 """
267 """
264 Custom engine_from_config functions that makes sure we use NullPool for
268 Custom engine_from_config functions that makes sure we use NullPool for
265 file based sqlite databases. This prevents errors on sqlite. This only
269 file based sqlite databases. This prevents errors on sqlite. This only
266 applies to sqlalchemy versions < 0.7.0
270 applies to sqlalchemy versions < 0.7.0
267
271
268 """
272 """
269 import sqlalchemy
273 import sqlalchemy
270 from sqlalchemy import engine_from_config as efc
274 from sqlalchemy import engine_from_config as efc
271 import logging
275 import logging
272
276
273 if int(sqlalchemy.__version__.split('.')[1]) < 7:
277 if int(sqlalchemy.__version__.split('.')[1]) < 7:
274
278
275 # This solution should work for sqlalchemy < 0.7.0, and should use
279 # This solution should work for sqlalchemy < 0.7.0, and should use
276 # proxy=TimerProxy() for execution time profiling
280 # proxy=TimerProxy() for execution time profiling
277
281
278 from sqlalchemy.pool import NullPool
282 from sqlalchemy.pool import NullPool
279 url = configuration[prefix + 'url']
283 url = configuration[prefix + 'url']
280
284
281 if url.startswith('sqlite'):
285 if url.startswith('sqlite'):
282 kwargs.update({'poolclass': NullPool})
286 kwargs.update({'poolclass': NullPool})
283 return efc(configuration, prefix, **kwargs)
287 return efc(configuration, prefix, **kwargs)
284 else:
288 else:
285 import time
289 import time
286 from sqlalchemy import event
290 from sqlalchemy import event
287 from sqlalchemy.engine import Engine
291 from sqlalchemy.engine import Engine
288
292
289 log = logging.getLogger('sqlalchemy.engine')
293 log = logging.getLogger('sqlalchemy.engine')
290 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
294 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
291 engine = efc(configuration, prefix, **kwargs)
295 engine = efc(configuration, prefix, **kwargs)
292
296
293 def color_sql(sql):
297 def color_sql(sql):
294 COLOR_SEQ = "\033[1;%dm"
298 COLOR_SEQ = "\033[1;%dm"
295 COLOR_SQL = YELLOW
299 COLOR_SQL = YELLOW
296 normal = '\x1b[0m'
300 normal = '\x1b[0m'
297 return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
301 return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
298
302
299 if configuration['debug']:
303 if configuration['debug']:
300 #attach events only for debug configuration
304 #attach events only for debug configuration
301
305
302 def before_cursor_execute(conn, cursor, statement,
306 def before_cursor_execute(conn, cursor, statement,
303 parameters, context, executemany):
307 parameters, context, executemany):
304 context._query_start_time = time.time()
308 context._query_start_time = time.time()
305 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
309 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
306
310
307
311
308 def after_cursor_execute(conn, cursor, statement,
312 def after_cursor_execute(conn, cursor, statement,
309 parameters, context, executemany):
313 parameters, context, executemany):
310 total = time.time() - context._query_start_time
314 total = time.time() - context._query_start_time
311 log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
315 log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
312
316
313 event.listen(engine, "before_cursor_execute",
317 event.listen(engine, "before_cursor_execute",
314 before_cursor_execute)
318 before_cursor_execute)
315 event.listen(engine, "after_cursor_execute",
319 event.listen(engine, "after_cursor_execute",
316 after_cursor_execute)
320 after_cursor_execute)
317
321
318 return engine
322 return engine
319
323
320
324
321 def age(curdate):
325 def age(curdate):
322 """
326 """
323 turns a datetime into an age string.
327 turns a datetime into an age string.
324
328
325 :param curdate: datetime object
329 :param curdate: datetime object
326 :rtype: unicode
330 :rtype: unicode
327 :returns: unicode words describing age
331 :returns: unicode words describing age
328 """
332 """
329
333
330 from datetime import datetime
334 from datetime import datetime
331 from webhelpers.date import time_ago_in_words
335 from webhelpers.date import time_ago_in_words
332
336
333 _ = lambda s: s
337 _ = lambda s: s
334
338
335 if not curdate:
339 if not curdate:
336 return ''
340 return ''
337
341
338 agescales = [(_(u"year"), 3600 * 24 * 365),
342 agescales = [(_(u"year"), 3600 * 24 * 365),
339 (_(u"month"), 3600 * 24 * 30),
343 (_(u"month"), 3600 * 24 * 30),
340 (_(u"day"), 3600 * 24),
344 (_(u"day"), 3600 * 24),
341 (_(u"hour"), 3600),
345 (_(u"hour"), 3600),
342 (_(u"minute"), 60),
346 (_(u"minute"), 60),
343 (_(u"second"), 1), ]
347 (_(u"second"), 1), ]
344
348
345 age = datetime.now() - curdate
349 age = datetime.now() - curdate
346 age_seconds = (age.days * agescales[2][1]) + age.seconds
350 age_seconds = (age.days * agescales[2][1]) + age.seconds
347 pos = 1
351 pos = 1
348 for scale in agescales:
352 for scale in agescales:
349 if scale[1] <= age_seconds:
353 if scale[1] <= age_seconds:
350 if pos == 6:
354 if pos == 6:
351 pos = 5
355 pos = 5
352 return '%s %s' % (time_ago_in_words(curdate,
356 return '%s %s' % (time_ago_in_words(curdate,
353 agescales[pos][0]), _('ago'))
357 agescales[pos][0]), _('ago'))
354 pos += 1
358 pos += 1
355
359
356 return _(u'just now')
360 return _(u'just now')
357
361
358
362
359 def uri_filter(uri):
363 def uri_filter(uri):
360 """
364 """
361 Removes user:password from given url string
365 Removes user:password from given url string
362
366
363 :param uri:
367 :param uri:
364 :rtype: unicode
368 :rtype: unicode
365 :returns: filtered list of strings
369 :returns: filtered list of strings
366 """
370 """
367 if not uri:
371 if not uri:
368 return ''
372 return ''
369
373
370 proto = ''
374 proto = ''
371
375
372 for pat in ('https://', 'http://'):
376 for pat in ('https://', 'http://'):
373 if uri.startswith(pat):
377 if uri.startswith(pat):
374 uri = uri[len(pat):]
378 uri = uri[len(pat):]
375 proto = pat
379 proto = pat
376 break
380 break
377
381
378 # remove passwords and username
382 # remove passwords and username
379 uri = uri[uri.find('@') + 1:]
383 uri = uri[uri.find('@') + 1:]
380
384
381 # get the port
385 # get the port
382 cred_pos = uri.find(':')
386 cred_pos = uri.find(':')
383 if cred_pos == -1:
387 if cred_pos == -1:
384 host, port = uri, None
388 host, port = uri, None
385 else:
389 else:
386 host, port = uri[:cred_pos], uri[cred_pos + 1:]
390 host, port = uri[:cred_pos], uri[cred_pos + 1:]
387
391
388 return filter(None, [proto, host, port])
392 return filter(None, [proto, host, port])
389
393
390
394
391 def credentials_filter(uri):
395 def credentials_filter(uri):
392 """
396 """
393 Returns a url with removed credentials
397 Returns a url with removed credentials
394
398
395 :param uri:
399 :param uri:
396 """
400 """
397
401
398 uri = uri_filter(uri)
402 uri = uri_filter(uri)
399 #check if we have port
403 #check if we have port
400 if len(uri) > 2 and uri[2]:
404 if len(uri) > 2 and uri[2]:
401 uri[2] = ':' + uri[2]
405 uri[2] = ':' + uri[2]
402
406
403 return ''.join(uri)
407 return ''.join(uri)
404
408
405
409
406 def get_changeset_safe(repo, rev):
410 def get_changeset_safe(repo, rev):
407 """
411 """
408 Safe version of get_changeset if this changeset doesn't exists for a
412 Safe version of get_changeset if this changeset doesn't exists for a
409 repo it returns a Dummy one instead
413 repo it returns a Dummy one instead
410
414
411 :param repo:
415 :param repo:
412 :param rev:
416 :param rev:
413 """
417 """
414 from rhodecode.lib.vcs.backends.base import BaseRepository
418 from rhodecode.lib.vcs.backends.base import BaseRepository
415 from rhodecode.lib.vcs.exceptions import RepositoryError
419 from rhodecode.lib.vcs.exceptions import RepositoryError
416 if not isinstance(repo, BaseRepository):
420 if not isinstance(repo, BaseRepository):
417 raise Exception('You must pass an Repository '
421 raise Exception('You must pass an Repository '
418 'object as first argument got %s', type(repo))
422 'object as first argument got %s', type(repo))
419
423
420 try:
424 try:
421 cs = repo.get_changeset(rev)
425 cs = repo.get_changeset(rev)
422 except RepositoryError:
426 except RepositoryError:
423 from rhodecode.lib.utils import EmptyChangeset
427 from rhodecode.lib.utils import EmptyChangeset
424 cs = EmptyChangeset(requested_revision=rev)
428 cs = EmptyChangeset(requested_revision=rev)
425 return cs
429 return cs
426
430
427
431
428 def get_current_revision(quiet=False):
432 def get_current_revision(quiet=False):
429 """
433 """
430 Returns tuple of (number, id) from repository containing this package
434 Returns tuple of (number, id) from repository containing this package
431 or None if repository could not be found.
435 or None if repository could not be found.
432
436
433 :param quiet: prints error for fetching revision if True
437 :param quiet: prints error for fetching revision if True
434 """
438 """
435
439
436 try:
440 try:
437 from rhodecode.lib.vcs import get_repo
441 from rhodecode.lib.vcs import get_repo
438 from rhodecode.lib.vcs.utils.helpers import get_scm
442 from rhodecode.lib.vcs.utils.helpers import get_scm
439 repopath = os.path.join(os.path.dirname(__file__), '..', '..')
443 repopath = os.path.join(os.path.dirname(__file__), '..', '..')
440 scm = get_scm(repopath)[0]
444 scm = get_scm(repopath)[0]
441 repo = get_repo(path=repopath, alias=scm)
445 repo = get_repo(path=repopath, alias=scm)
442 tip = repo.get_changeset()
446 tip = repo.get_changeset()
443 return (tip.revision, tip.short_id)
447 return (tip.revision, tip.short_id)
444 except Exception, err:
448 except Exception, err:
445 if not quiet:
449 if not quiet:
446 print ("Cannot retrieve rhodecode's revision. Original error "
450 print ("Cannot retrieve rhodecode's revision. Original error "
447 "was: %s" % err)
451 "was: %s" % err)
448 return None
452 return None
449
453
450
454
451 def extract_mentioned_users(s):
455 def extract_mentioned_users(s):
452 """
456 """
453 Returns unique usernames from given string s that have @mention
457 Returns unique usernames from given string s that have @mention
454
458
455 :param s: string to get mentions
459 :param s: string to get mentions
456 """
460 """
457 usrs = {}
461 usrs = {}
458 for username in re.findall(r'(?:^@|\s@)(\w+)', s):
462 for username in re.findall(r'(?:^@|\s@)(\w+)', s):
459 usrs[username] = username
463 usrs[username] = username
460
464
461 return sorted(usrs.keys())
465 return sorted(usrs.keys())
General Comments 0
You need to be logged in to leave comments. Login now