Show More
@@ -0,0 +1,58 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | package.rhodecode.config.conf | |||
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
|
5 | ||||
|
6 | Various config settings for RhodeCode | |||
|
7 | ||||
|
8 | :created_on: Mar 7, 2012 | |||
|
9 | :author: marcink | |||
|
10 | :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> | |||
|
11 | :license: <name>, see LICENSE_FILE for more details. | |||
|
12 | """ | |||
|
13 | from rhodecode import EXTENSIONS | |||
|
14 | ||||
|
15 | from rhodecode.lib.utils2 import __get_lem | |||
|
16 | ||||
|
17 | ||||
|
18 | # language map is also used by whoosh indexer, which for those specified | |||
|
19 | # extensions will index it's content | |||
|
20 | LANGUAGES_EXTENSIONS_MAP = __get_lem() | |||
|
21 | ||||
|
22 | #============================================================================== | |||
|
23 | # WHOOSH INDEX EXTENSIONS | |||
|
24 | #============================================================================== | |||
|
25 | # EXTENSIONS WE WANT TO INDEX CONTENT OFF USING WHOOSH | |||
|
26 | INDEX_EXTENSIONS = LANGUAGES_EXTENSIONS_MAP.keys() | |||
|
27 | ||||
|
28 | # list of readme files to search in file tree and display in summary | |||
|
29 | # attached weights defines the search order lower is first | |||
|
30 | ALL_READMES = [ | |||
|
31 | ('readme', 0), ('README', 0), ('Readme', 0), | |||
|
32 | ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1), | |||
|
33 | ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2), | |||
|
34 | ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2), | |||
|
35 | ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2), | |||
|
36 | ] | |||
|
37 | ||||
|
38 | # extension together with weights to search lower is first | |||
|
39 | RST_EXTS = [ | |||
|
40 | ('', 0), ('.rst', 1), ('.rest', 1), | |||
|
41 | ('.RST', 2), ('.REST', 2), | |||
|
42 | ('.txt', 3), ('.TXT', 3) | |||
|
43 | ] | |||
|
44 | ||||
|
45 | MARKDOWN_EXTS = [ | |||
|
46 | ('.md', 1), ('.MD', 1), | |||
|
47 | ('.mkdn', 2), ('.MKDN', 2), | |||
|
48 | ('.mdown', 3), ('.MDOWN', 3), | |||
|
49 | ('.markdown', 4), ('.MARKDOWN', 4) | |||
|
50 | ] | |||
|
51 | ||||
|
52 | PLAIN_EXTS = [('.text', 2), ('.TEXT', 2)] | |||
|
53 | ||||
|
54 | ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS | |||
|
55 | ||||
|
56 | DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" | |||
|
57 | ||||
|
58 | DATE_FORMAT = "%Y-%m-%d" |
@@ -0,0 +1,405 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | rhodecode.lib.utils | |||
|
4 | ~~~~~~~~~~~~~~~~~~~ | |||
|
5 | ||||
|
6 | Some simple helper functions | |||
|
7 | ||||
|
8 | :created_on: Jan 5, 2011 | |||
|
9 | :author: marcink | |||
|
10 | :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com> | |||
|
11 | :license: GPLv3, see COPYING for more details. | |||
|
12 | """ | |||
|
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 | |||
|
15 | # the Free Software Foundation, either version 3 of the License, or | |||
|
16 | # (at your option) any later version. | |||
|
17 | # | |||
|
18 | # This program is distributed in the hope that it will be useful, | |||
|
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
21 | # GNU General Public License for more details. | |||
|
22 | # | |||
|
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/>. | |||
|
25 | ||||
|
26 | import re | |||
|
27 | from rhodecode.lib.vcs.utils.lazy import LazyProperty | |||
|
28 | ||||
|
29 | ||||
|
30 | def __get_lem(): | |||
|
31 | """ | |||
|
32 | Get language extension map based on what's inside pygments lexers | |||
|
33 | """ | |||
|
34 | from pygments import lexers | |||
|
35 | from string import lower | |||
|
36 | from collections import defaultdict | |||
|
37 | ||||
|
38 | d = defaultdict(lambda: []) | |||
|
39 | ||||
|
40 | def __clean(s): | |||
|
41 | s = s.lstrip('*') | |||
|
42 | s = s.lstrip('.') | |||
|
43 | ||||
|
44 | if s.find('[') != -1: | |||
|
45 | exts = [] | |||
|
46 | start, stop = s.find('['), s.find(']') | |||
|
47 | ||||
|
48 | for suffix in s[start + 1:stop]: | |||
|
49 | exts.append(s[:s.find('[')] + suffix) | |||
|
50 | return map(lower, exts) | |||
|
51 | else: | |||
|
52 | return map(lower, [s]) | |||
|
53 | ||||
|
54 | for lx, t in sorted(lexers.LEXERS.items()): | |||
|
55 | m = map(__clean, t[-2]) | |||
|
56 | if m: | |||
|
57 | m = reduce(lambda x, y: x + y, m) | |||
|
58 | for ext in m: | |||
|
59 | desc = lx.replace('Lexer', '') | |||
|
60 | d[ext].append(desc) | |||
|
61 | ||||
|
62 | return dict(d) | |||
|
63 | ||||
|
64 | def str2bool(_str): | |||
|
65 | """ | |||
|
66 | returs True/False value from given string, it tries to translate the | |||
|
67 | string into boolean | |||
|
68 | ||||
|
69 | :param _str: string value to translate into boolean | |||
|
70 | :rtype: boolean | |||
|
71 | :returns: boolean from given string | |||
|
72 | """ | |||
|
73 | if _str is None: | |||
|
74 | return False | |||
|
75 | if _str in (True, False): | |||
|
76 | return _str | |||
|
77 | _str = str(_str).strip().lower() | |||
|
78 | return _str in ('t', 'true', 'y', 'yes', 'on', '1') | |||
|
79 | ||||
|
80 | ||||
|
81 | def convert_line_endings(line, mode): | |||
|
82 | """ | |||
|
83 | Converts a given line "line end" accordingly to given mode | |||
|
84 | ||||
|
85 | Available modes are:: | |||
|
86 | 0 - Unix | |||
|
87 | 1 - Mac | |||
|
88 | 2 - DOS | |||
|
89 | ||||
|
90 | :param line: given line to convert | |||
|
91 | :param mode: mode to convert to | |||
|
92 | :rtype: str | |||
|
93 | :return: converted line according to mode | |||
|
94 | """ | |||
|
95 | from string import replace | |||
|
96 | ||||
|
97 | if mode == 0: | |||
|
98 | line = replace(line, '\r\n', '\n') | |||
|
99 | line = replace(line, '\r', '\n') | |||
|
100 | elif mode == 1: | |||
|
101 | line = replace(line, '\r\n', '\r') | |||
|
102 | line = replace(line, '\n', '\r') | |||
|
103 | elif mode == 2: | |||
|
104 | line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line) | |||
|
105 | return line | |||
|
106 | ||||
|
107 | ||||
|
108 | def detect_mode(line, default): | |||
|
109 | """ | |||
|
110 | Detects line break for given line, if line break couldn't be found | |||
|
111 | given default value is returned | |||
|
112 | ||||
|
113 | :param line: str line | |||
|
114 | :param default: default | |||
|
115 | :rtype: int | |||
|
116 | :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS | |||
|
117 | """ | |||
|
118 | if line.endswith('\r\n'): | |||
|
119 | return 2 | |||
|
120 | elif line.endswith('\n'): | |||
|
121 | return 0 | |||
|
122 | elif line.endswith('\r'): | |||
|
123 | return 1 | |||
|
124 | else: | |||
|
125 | return default | |||
|
126 | ||||
|
127 | ||||
|
128 | def generate_api_key(username, salt=None): | |||
|
129 | """ | |||
|
130 | Generates unique API key for given username, if salt is not given | |||
|
131 | it'll be generated from some random string | |||
|
132 | ||||
|
133 | :param username: username as string | |||
|
134 | :param salt: salt to hash generate KEY | |||
|
135 | :rtype: str | |||
|
136 | :returns: sha1 hash from username+salt | |||
|
137 | """ | |||
|
138 | from tempfile import _RandomNameSequence | |||
|
139 | import hashlib | |||
|
140 | ||||
|
141 | if salt is None: | |||
|
142 | salt = _RandomNameSequence().next() | |||
|
143 | ||||
|
144 | return hashlib.sha1(username + salt).hexdigest() | |||
|
145 | ||||
|
146 | ||||
|
147 | def safe_unicode(str_, from_encoding=None): | |||
|
148 | """ | |||
|
149 | safe unicode function. Does few trick to turn str_ into unicode | |||
|
150 | ||||
|
151 | In case of UnicodeDecode error we try to return it with encoding detected | |||
|
152 | by chardet library if it fails fallback to unicode with errors replaced | |||
|
153 | ||||
|
154 | :param str_: string to decode | |||
|
155 | :rtype: unicode | |||
|
156 | :returns: unicode object | |||
|
157 | """ | |||
|
158 | if isinstance(str_, unicode): | |||
|
159 | return str_ | |||
|
160 | ||||
|
161 | if not from_encoding: | |||
|
162 | import rhodecode | |||
|
163 | DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8') | |||
|
164 | from_encoding = DEFAULT_ENCODING | |||
|
165 | ||||
|
166 | try: | |||
|
167 | return unicode(str_) | |||
|
168 | except UnicodeDecodeError: | |||
|
169 | pass | |||
|
170 | ||||
|
171 | try: | |||
|
172 | return unicode(str_, from_encoding) | |||
|
173 | except UnicodeDecodeError: | |||
|
174 | pass | |||
|
175 | ||||
|
176 | try: | |||
|
177 | import chardet | |||
|
178 | encoding = chardet.detect(str_)['encoding'] | |||
|
179 | if encoding is None: | |||
|
180 | raise Exception() | |||
|
181 | return str_.decode(encoding) | |||
|
182 | except (ImportError, UnicodeDecodeError, Exception): | |||
|
183 | return unicode(str_, from_encoding, 'replace') | |||
|
184 | ||||
|
185 | ||||
|
186 | def safe_str(unicode_, to_encoding=None): | |||
|
187 | """ | |||
|
188 | safe str function. Does few trick to turn unicode_ into string | |||
|
189 | ||||
|
190 | In case of UnicodeEncodeError we try to return it with encoding detected | |||
|
191 | by chardet library if it fails fallback to string with errors replaced | |||
|
192 | ||||
|
193 | :param unicode_: unicode to encode | |||
|
194 | :rtype: str | |||
|
195 | :returns: str object | |||
|
196 | """ | |||
|
197 | ||||
|
198 | # if it's not basestr cast to str | |||
|
199 | if not isinstance(unicode_, basestring): | |||
|
200 | return str(unicode_) | |||
|
201 | ||||
|
202 | if isinstance(unicode_, str): | |||
|
203 | return unicode_ | |||
|
204 | ||||
|
205 | if not to_encoding: | |||
|
206 | import rhodecode | |||
|
207 | DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8') | |||
|
208 | to_encoding = DEFAULT_ENCODING | |||
|
209 | ||||
|
210 | try: | |||
|
211 | return unicode_.encode(to_encoding) | |||
|
212 | except UnicodeEncodeError: | |||
|
213 | pass | |||
|
214 | ||||
|
215 | try: | |||
|
216 | import chardet | |||
|
217 | encoding = chardet.detect(unicode_)['encoding'] | |||
|
218 | print encoding | |||
|
219 | if encoding is None: | |||
|
220 | raise UnicodeEncodeError() | |||
|
221 | ||||
|
222 | return unicode_.encode(encoding) | |||
|
223 | except (ImportError, UnicodeEncodeError): | |||
|
224 | return unicode_.encode(to_encoding, 'replace') | |||
|
225 | ||||
|
226 | return safe_str | |||
|
227 | ||||
|
228 | ||||
|
229 | def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs): | |||
|
230 | """ | |||
|
231 | Custom engine_from_config functions that makes sure we use NullPool for | |||
|
232 | file based sqlite databases. This prevents errors on sqlite. This only | |||
|
233 | applies to sqlalchemy versions < 0.7.0 | |||
|
234 | ||||
|
235 | """ | |||
|
236 | import sqlalchemy | |||
|
237 | from sqlalchemy import engine_from_config as efc | |||
|
238 | import logging | |||
|
239 | ||||
|
240 | if int(sqlalchemy.__version__.split('.')[1]) < 7: | |||
|
241 | ||||
|
242 | # This solution should work for sqlalchemy < 0.7.0, and should use | |||
|
243 | # proxy=TimerProxy() for execution time profiling | |||
|
244 | ||||
|
245 | from sqlalchemy.pool import NullPool | |||
|
246 | url = configuration[prefix + 'url'] | |||
|
247 | ||||
|
248 | if url.startswith('sqlite'): | |||
|
249 | kwargs.update({'poolclass': NullPool}) | |||
|
250 | return efc(configuration, prefix, **kwargs) | |||
|
251 | else: | |||
|
252 | import time | |||
|
253 | from sqlalchemy import event | |||
|
254 | from sqlalchemy.engine import Engine | |||
|
255 | ||||
|
256 | log = logging.getLogger('sqlalchemy.engine') | |||
|
257 | BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38) | |||
|
258 | engine = efc(configuration, prefix, **kwargs) | |||
|
259 | ||||
|
260 | def color_sql(sql): | |||
|
261 | COLOR_SEQ = "\033[1;%dm" | |||
|
262 | COLOR_SQL = YELLOW | |||
|
263 | normal = '\x1b[0m' | |||
|
264 | return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal]) | |||
|
265 | ||||
|
266 | if configuration['debug']: | |||
|
267 | #attach events only for debug configuration | |||
|
268 | ||||
|
269 | def before_cursor_execute(conn, cursor, statement, | |||
|
270 | parameters, context, executemany): | |||
|
271 | context._query_start_time = time.time() | |||
|
272 | log.info(color_sql(">>>>> STARTING QUERY >>>>>")) | |||
|
273 | ||||
|
274 | ||||
|
275 | def after_cursor_execute(conn, cursor, statement, | |||
|
276 | parameters, context, executemany): | |||
|
277 | total = time.time() - context._query_start_time | |||
|
278 | log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total)) | |||
|
279 | ||||
|
280 | event.listen(engine, "before_cursor_execute", | |||
|
281 | before_cursor_execute) | |||
|
282 | event.listen(engine, "after_cursor_execute", | |||
|
283 | after_cursor_execute) | |||
|
284 | ||||
|
285 | return engine | |||
|
286 | ||||
|
287 | ||||
|
288 | def age(curdate): | |||
|
289 | """ | |||
|
290 | turns a datetime into an age string. | |||
|
291 | ||||
|
292 | :param curdate: datetime object | |||
|
293 | :rtype: unicode | |||
|
294 | :returns: unicode words describing age | |||
|
295 | """ | |||
|
296 | ||||
|
297 | from datetime import datetime | |||
|
298 | from webhelpers.date import time_ago_in_words | |||
|
299 | ||||
|
300 | _ = lambda s: s | |||
|
301 | ||||
|
302 | if not curdate: | |||
|
303 | return '' | |||
|
304 | ||||
|
305 | agescales = [(_(u"year"), 3600 * 24 * 365), | |||
|
306 | (_(u"month"), 3600 * 24 * 30), | |||
|
307 | (_(u"day"), 3600 * 24), | |||
|
308 | (_(u"hour"), 3600), | |||
|
309 | (_(u"minute"), 60), | |||
|
310 | (_(u"second"), 1), ] | |||
|
311 | ||||
|
312 | age = datetime.now() - curdate | |||
|
313 | age_seconds = (age.days * agescales[2][1]) + age.seconds | |||
|
314 | pos = 1 | |||
|
315 | for scale in agescales: | |||
|
316 | if scale[1] <= age_seconds: | |||
|
317 | if pos == 6: | |||
|
318 | pos = 5 | |||
|
319 | return '%s %s' % (time_ago_in_words(curdate, | |||
|
320 | agescales[pos][0]), _('ago')) | |||
|
321 | pos += 1 | |||
|
322 | ||||
|
323 | return _(u'just now') | |||
|
324 | ||||
|
325 | ||||
|
326 | def uri_filter(uri): | |||
|
327 | """ | |||
|
328 | Removes user:password from given url string | |||
|
329 | ||||
|
330 | :param uri: | |||
|
331 | :rtype: unicode | |||
|
332 | :returns: filtered list of strings | |||
|
333 | """ | |||
|
334 | if not uri: | |||
|
335 | return '' | |||
|
336 | ||||
|
337 | proto = '' | |||
|
338 | ||||
|
339 | for pat in ('https://', 'http://'): | |||
|
340 | if uri.startswith(pat): | |||
|
341 | uri = uri[len(pat):] | |||
|
342 | proto = pat | |||
|
343 | break | |||
|
344 | ||||
|
345 | # remove passwords and username | |||
|
346 | uri = uri[uri.find('@') + 1:] | |||
|
347 | ||||
|
348 | # get the port | |||
|
349 | cred_pos = uri.find(':') | |||
|
350 | if cred_pos == -1: | |||
|
351 | host, port = uri, None | |||
|
352 | else: | |||
|
353 | host, port = uri[:cred_pos], uri[cred_pos + 1:] | |||
|
354 | ||||
|
355 | return filter(None, [proto, host, port]) | |||
|
356 | ||||
|
357 | ||||
|
358 | def credentials_filter(uri): | |||
|
359 | """ | |||
|
360 | Returns a url with removed credentials | |||
|
361 | ||||
|
362 | :param uri: | |||
|
363 | """ | |||
|
364 | ||||
|
365 | uri = uri_filter(uri) | |||
|
366 | #check if we have port | |||
|
367 | if len(uri) > 2 and uri[2]: | |||
|
368 | uri[2] = ':' + uri[2] | |||
|
369 | ||||
|
370 | return ''.join(uri) | |||
|
371 | ||||
|
372 | ||||
|
373 | def get_changeset_safe(repo, rev): | |||
|
374 | """ | |||
|
375 | Safe version of get_changeset if this changeset doesn't exists for a | |||
|
376 | repo it returns a Dummy one instead | |||
|
377 | ||||
|
378 | :param repo: | |||
|
379 | :param rev: | |||
|
380 | """ | |||
|
381 | from rhodecode.lib.vcs.backends.base import BaseRepository | |||
|
382 | from rhodecode.lib.vcs.exceptions import RepositoryError | |||
|
383 | if not isinstance(repo, BaseRepository): | |||
|
384 | raise Exception('You must pass an Repository ' | |||
|
385 | 'object as first argument got %s', type(repo)) | |||
|
386 | ||||
|
387 | try: | |||
|
388 | cs = repo.get_changeset(rev) | |||
|
389 | except RepositoryError: | |||
|
390 | from rhodecode.lib.utils import EmptyChangeset | |||
|
391 | cs = EmptyChangeset(requested_revision=rev) | |||
|
392 | return cs | |||
|
393 | ||||
|
394 | ||||
|
395 | def extract_mentioned_users(s): | |||
|
396 | """ | |||
|
397 | Returns unique usernames from given string s that have @mention | |||
|
398 | ||||
|
399 | :param s: string to get mentions | |||
|
400 | """ | |||
|
401 | usrs = {} | |||
|
402 | for username in re.findall(r'(?:^@|\s@)(\w+)', s): | |||
|
403 | usrs[username] = username | |||
|
404 | ||||
|
405 | return sorted(usrs.keys()) |
@@ -2,40 +2,45 b'' | |||||
2 |
|
2 | |||
3 | import os |
|
3 | import os | |
4 | import logging |
|
4 | import logging | |
|
5 | import rhodecode | |||
5 |
|
6 | |||
6 | from mako.lookup import TemplateLookup |
|
7 | from mako.lookup import TemplateLookup | |
7 | from pylons.configuration import PylonsConfig |
|
8 | from pylons.configuration import PylonsConfig | |
8 | from pylons.error import handle_mako_error |
|
9 | from pylons.error import handle_mako_error | |
9 |
|
10 | |||
10 | import rhodecode |
|
11 | # don't remove this import it does magic for celery | |
|
12 | from rhodecode.lib import celerypylons | |||
|
13 | ||||
11 | import rhodecode.lib.app_globals as app_globals |
|
14 | import rhodecode.lib.app_globals as app_globals | |
12 | import rhodecode.lib.helpers |
|
|||
13 |
|
15 | |||
14 | from rhodecode.config.routing import make_map |
|
16 | from rhodecode.config.routing import make_map | |
15 | # don't remove this import it does magic for celery |
|
17 | ||
16 |
from rhodecode.lib import |
|
18 | from rhodecode.lib import helpers | |
17 | from rhodecode.lib import engine_from_config |
|
|||
18 | from rhodecode.lib.auth import set_available_permissions |
|
19 | from rhodecode.lib.auth import set_available_permissions | |
19 | from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config |
|
20 | from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config,\ | |
|
21 | load_rcextensions | |||
|
22 | from rhodecode.lib.utils2 import engine_from_config, str2bool | |||
20 | from rhodecode.model import init_model |
|
23 | from rhodecode.model import init_model | |
21 | from rhodecode.model.scm import ScmModel |
|
24 | from rhodecode.model.scm import ScmModel | |
22 | from rhodecode.lib.vcs.utils.fakemod import create_module |
|
|||
23 |
|
25 | |||
24 | log = logging.getLogger(__name__) |
|
26 | log = logging.getLogger(__name__) | |
25 |
|
27 | |||
26 |
|
28 | |||
27 | def load_environment(global_conf, app_conf, initial=False): |
|
29 | def load_environment(global_conf, app_conf, initial=False): | |
28 | """Configure the Pylons environment via the ``pylons.config`` |
|
30 | """ | |
|
31 | Configure the Pylons environment via the ``pylons.config`` | |||
29 | object |
|
32 | object | |
30 | """ |
|
33 | """ | |
31 | config = PylonsConfig() |
|
34 | config = PylonsConfig() | |
32 |
|
35 | |||
33 | # Pylons paths |
|
36 | # Pylons paths | |
34 | root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
|
37 | root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
35 |
paths = dict( |
|
38 | paths = dict( | |
|
39 | root=root, | |||
36 |
|
|
40 | controllers=os.path.join(root, 'controllers'), | |
37 |
|
|
41 | static_files=os.path.join(root, 'public'), | |
38 |
|
|
42 | templates=[os.path.join(root, 'templates')] | |
|
43 | ) | |||
39 |
|
44 | |||
40 | # Initialize config with the basic options |
|
45 | # Initialize config with the basic options | |
41 | config.init_app(global_conf, app_conf, package='rhodecode', paths=paths) |
|
46 | config.init_app(global_conf, app_conf, package='rhodecode', paths=paths) | |
@@ -45,14 +50,11 b' def load_environment(global_conf, app_co' | |||||
45 |
|
50 | |||
46 | config['routes.map'] = make_map(config) |
|
51 | config['routes.map'] = make_map(config) | |
47 | config['pylons.app_globals'] = app_globals.Globals(config) |
|
52 | config['pylons.app_globals'] = app_globals.Globals(config) | |
48 |
config['pylons.h'] = |
|
53 | config['pylons.h'] = helpers | |
49 | rhodecode.CONFIG = config |
|
54 | rhodecode.CONFIG = config | |
50 |
|
55 | |||
51 | path = os.path.join(config['here'], 'rcextensions', '__init__.py') |
|
56 | load_rcextensions(root_path=config['here']) | |
52 | if os.path.isfile(path): |
|
57 | ||
53 | rcext = create_module('rc', path) |
|
|||
54 | rhodecode.EXTENSIONS = rcext |
|
|||
55 | log.debug('Found rcextensions now loading %s...' % rcext) |
|
|||
56 | # Setup cache object as early as possible |
|
58 | # Setup cache object as early as possible | |
57 | import pylons |
|
59 | import pylons | |
58 | pylons.cache._push_object(config['pylons.app_globals'].cache) |
|
60 | pylons.cache._push_object(config['pylons.app_globals'].cache) |
@@ -77,5 +77,3 b' class MakeRcExt(BasePasterCommand):' | |||||
77 |
|
77 | |||
78 | def update_parser(self): |
|
78 | def update_parser(self): | |
79 | pass |
|
79 | pass | |
80 |
|
||||
81 |
|
@@ -32,8 +32,9 b' from pylons import request, session, tmp' | |||||
32 | from pylons.controllers.util import abort, redirect |
|
32 | from pylons.controllers.util import abort, redirect | |
33 | from pylons.i18n.translation import _ |
|
33 | from pylons.i18n.translation import _ | |
34 |
|
34 | |||
|
35 | from rhodecode.lib import helpers as h | |||
35 | from rhodecode.lib.exceptions import UsersGroupsAssignedException |
|
36 | from rhodecode.lib.exceptions import UsersGroupsAssignedException | |
36 |
from rhodecode.lib import |
|
37 | from rhodecode.lib.utils2 import safe_unicode | |
37 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
38 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | |
38 | from rhodecode.lib.base import BaseController, render |
|
39 | from rhodecode.lib.base import BaseController, render | |
39 |
|
40 |
@@ -31,7 +31,7 b' import binascii' | |||||
31 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
31 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
32 | from rhodecode.lib.base import BaseRepoController, render |
|
32 | from rhodecode.lib.base import BaseRepoController, render | |
33 | from rhodecode.lib.compat import OrderedDict |
|
33 | from rhodecode.lib.compat import OrderedDict | |
34 | from rhodecode.lib import safe_unicode |
|
34 | from rhodecode.lib.utils2 import safe_unicode | |
35 | log = logging.getLogger(__name__) |
|
35 | log = logging.getLogger(__name__) | |
36 |
|
36 | |||
37 |
|
37 |
@@ -28,7 +28,7 b' import logging' | |||||
28 | from pylons import url, response, tmpl_context as c |
|
28 | from pylons import url, response, tmpl_context as c | |
29 | from pylons.i18n.translation import _ |
|
29 | from pylons.i18n.translation import _ | |
30 |
|
30 | |||
31 | from rhodecode.lib import safe_unicode |
|
31 | from rhodecode.lib.utils2 import safe_unicode | |
32 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
32 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
33 | from rhodecode.lib.base import BaseRepoController |
|
33 | from rhodecode.lib.base import BaseRepoController | |
34 |
|
34 |
@@ -32,24 +32,26 b' from pylons.i18n.translation import _' | |||||
32 | from pylons.controllers.util import redirect |
|
32 | from pylons.controllers.util import redirect | |
33 | from pylons.decorators import jsonify |
|
33 | from pylons.decorators import jsonify | |
34 |
|
34 | |||
35 |
from rhodecode.lib |
|
35 | from rhodecode.lib import diffs | |
36 | from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \ |
|
36 | from rhodecode.lib import helpers as h | |
37 | EmptyRepositoryError, ImproperArchiveTypeError, VCSError, \ |
|
|||
38 | NodeAlreadyExistsError |
|
|||
39 | from rhodecode.lib.vcs.nodes import FileNode |
|
|||
40 |
|
37 | |||
41 | from rhodecode.lib.compat import OrderedDict |
|
38 | from rhodecode.lib.compat import OrderedDict | |
42 | from rhodecode.lib import convert_line_endings, detect_mode, safe_str |
|
39 | from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str | |
43 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
40 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
44 | from rhodecode.lib.base import BaseRepoController, render |
|
41 | from rhodecode.lib.base import BaseRepoController, render | |
45 | from rhodecode.lib.utils import EmptyChangeset |
|
42 | from rhodecode.lib.utils import EmptyChangeset | |
46 |
from rhodecode.lib import |
|
43 | from rhodecode.lib.vcs.conf import settings | |
47 | import rhodecode.lib.helpers as h |
|
44 | from rhodecode.lib.vcs.exceptions import RepositoryError, \ | |
|
45 | ChangesetDoesNotExistError, EmptyRepositoryError, \ | |||
|
46 | ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError | |||
|
47 | from rhodecode.lib.vcs.nodes import FileNode | |||
|
48 | ||||
48 | from rhodecode.model.repo import RepoModel |
|
49 | from rhodecode.model.repo import RepoModel | |
|
50 | from rhodecode.model.scm import ScmModel | |||
|
51 | ||||
49 | from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\ |
|
52 | from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\ | |
50 | _context_url, get_line_ctx, get_ignore_ws |
|
53 | _context_url, get_line_ctx, get_ignore_ws | |
51 | from rhodecode.lib.diffs import wrapped_diff |
|
54 | ||
52 | from rhodecode.model.scm import ScmModel |
|
|||
53 |
|
55 | |||
54 | log = logging.getLogger(__name__) |
|
56 | log = logging.getLogger(__name__) | |
55 |
|
57 | |||
@@ -447,7 +449,7 b' class FilesController(BaseRepoController' | |||||
447 | ign_whitespace_lcl = get_ignore_ws(fid, request.GET) |
|
449 | ign_whitespace_lcl = get_ignore_ws(fid, request.GET) | |
448 |
|
450 | |||
449 | lim = request.GET.get('fulldiff') or self.cut_off_limit |
|
451 | lim = request.GET.get('fulldiff') or self.cut_off_limit | |
450 | _, cs1, cs2, diff, st = wrapped_diff(filenode_old=node1, |
|
452 | _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1, | |
451 | filenode_new=node2, |
|
453 | filenode_new=node2, | |
452 | cut_off_limit=lim, |
|
454 | cut_off_limit=lim, | |
453 | ignore_whitespace=ign_whitespace_lcl, |
|
455 | ignore_whitespace=ign_whitespace_lcl, |
@@ -40,15 +40,15 b' from pylons.i18n.translation import _' | |||||
40 |
|
40 | |||
41 | from beaker.cache import cache_region, region_invalidate |
|
41 | from beaker.cache import cache_region, region_invalidate | |
42 |
|
42 | |||
|
43 | from rhodecode.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP | |||
43 | from rhodecode.model.db import Statistics, CacheInvalidation |
|
44 | from rhodecode.model.db import Statistics, CacheInvalidation | |
44 |
from rhodecode.lib import |
|
45 | from rhodecode.lib.utils2 import safe_unicode | |
45 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
46 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
46 | from rhodecode.lib.base import BaseRepoController, render |
|
47 | from rhodecode.lib.base import BaseRepoController, render | |
47 | from rhodecode.lib.utils import EmptyChangeset |
|
48 | from rhodecode.lib.utils import EmptyChangeset | |
48 | from rhodecode.lib.markup_renderer import MarkupRenderer |
|
49 | from rhodecode.lib.markup_renderer import MarkupRenderer | |
49 | from rhodecode.lib.celerylib import run_task |
|
50 | from rhodecode.lib.celerylib import run_task | |
50 |
from rhodecode.lib.celerylib.tasks import get_commits_stats |
|
51 | from rhodecode.lib.celerylib.tasks import get_commits_stats | |
51 | LANGUAGES_EXTENSIONS_MAP |
|
|||
52 | from rhodecode.lib.helpers import RepoPage |
|
52 | from rhodecode.lib.helpers import RepoPage | |
53 | from rhodecode.lib.compat import json, OrderedDict |
|
53 | from rhodecode.lib.compat import json, OrderedDict | |
54 |
|
54 |
@@ -1,444 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
|||
2 | """ |
|
|||
3 | rhodecode.lib.__init__ |
|
|||
4 | ~~~~~~~~~~~~~~~~~~~~~~~ |
|
|||
5 |
|
||||
6 | Some simple helper functions |
|
|||
7 |
|
||||
8 | :created_on: Jan 5, 2011 |
|
|||
9 | :author: marcink |
|
|||
10 | :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com> |
|
|||
11 | :license: GPLv3, see COPYING for more details. |
|
|||
12 | """ |
|
|||
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 |
|
|||
15 | # the Free Software Foundation, either version 3 of the License, or |
|
|||
16 | # (at your option) any later version. |
|
|||
17 | # |
|
|||
18 | # This program is distributed in the hope that it will be useful, |
|
|||
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|||
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|||
21 | # GNU General Public License for more details. |
|
|||
22 | # |
|
|||
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/>. |
|
|||
25 |
|
||||
26 |
|
|
1 | import os | |
27 | import re |
|
|||
28 | from rhodecode import EXTENSIONS |
|
|||
29 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
|||
30 |
|
||||
31 |
|
||||
32 | def __get_lem(): |
|
|||
33 | from pygments import lexers |
|
|||
34 | from string import lower |
|
|||
35 | from collections import defaultdict |
|
|||
36 |
|
||||
37 | d = defaultdict(lambda: []) |
|
|||
38 |
|
||||
39 | def __clean(s): |
|
|||
40 | s = s.lstrip('*') |
|
|||
41 | s = s.lstrip('.') |
|
|||
42 |
|
||||
43 | if s.find('[') != -1: |
|
|||
44 | exts = [] |
|
|||
45 | start, stop = s.find('['), s.find(']') |
|
|||
46 |
|
||||
47 | for suffix in s[start + 1:stop]: |
|
|||
48 | exts.append(s[:s.find('[')] + suffix) |
|
|||
49 | return map(lower, exts) |
|
|||
50 | else: |
|
|||
51 | return map(lower, [s]) |
|
|||
52 |
|
||||
53 | for lx, t in sorted(lexers.LEXERS.items()): |
|
|||
54 | m = map(__clean, t[-2]) |
|
|||
55 | if m: |
|
|||
56 | m = reduce(lambda x, y: x + y, m) |
|
|||
57 | for ext in m: |
|
|||
58 | desc = lx.replace('Lexer', '') |
|
|||
59 | d[ext].append(desc) |
|
|||
60 |
|
||||
61 | return dict(d) |
|
|||
62 |
|
||||
63 | # language map is also used by whoosh indexer, which for those specified |
|
|||
64 | # extensions will index it's content |
|
|||
65 | LANGUAGES_EXTENSIONS_MAP = __get_lem() |
|
|||
66 |
|
||||
67 | # Additional mappings that are not present in the pygments lexers |
|
|||
68 | LANGUAGES_EXTENSIONS_MAP.update(getattr(EXTENSIONS, 'EXTRA_MAPPINGS', {})) |
|
|||
69 |
|
||||
70 | #============================================================================== |
|
|||
71 | # WHOOSH INDEX EXTENSIONS |
|
|||
72 | #============================================================================== |
|
|||
73 | # EXTENSIONS WE WANT TO INDEX CONTENT OFF USING WHOOSH |
|
|||
74 | INDEX_EXTENSIONS = LANGUAGES_EXTENSIONS_MAP.keys() |
|
|||
75 |
|
||||
76 | #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present) |
|
|||
77 |
|
||||
78 | if getattr(EXTENSIONS, 'INDEX_EXTENSIONS', []) != []: |
|
|||
79 | INDEX_EXTENSIONS = getattr(EXTENSIONS, 'INDEX_EXTENSIONS', []) |
|
|||
80 |
|
||||
81 | #ADDITIONAL MAPPINGS |
|
|||
82 | INDEX_EXTENSIONS.extend(getattr(EXTENSIONS, 'EXTRA_INDEX_EXTENSIONS', [])) |
|
|||
83 |
|
||||
84 | # list of readme files to search in file tree and display in summary |
|
|||
85 | # attached weights defines the search order lower is first |
|
|||
86 | ALL_READMES = [ |
|
|||
87 | ('readme', 0), ('README', 0), ('Readme', 0), |
|
|||
88 | ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1), |
|
|||
89 | ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2), |
|
|||
90 | ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2), |
|
|||
91 | ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2), |
|
|||
92 | ] |
|
|||
93 |
|
||||
94 | # extension together with weights to search lower is first |
|
|||
95 | RST_EXTS = [ |
|
|||
96 | ('', 0), ('.rst', 1), ('.rest', 1), |
|
|||
97 | ('.RST', 2), ('.REST', 2), |
|
|||
98 | ('.txt', 3), ('.TXT', 3) |
|
|||
99 | ] |
|
|||
100 |
|
||||
101 | MARKDOWN_EXTS = [ |
|
|||
102 | ('.md', 1), ('.MD', 1), |
|
|||
103 | ('.mkdn', 2), ('.MKDN', 2), |
|
|||
104 | ('.mdown', 3), ('.MDOWN', 3), |
|
|||
105 | ('.markdown', 4), ('.MARKDOWN', 4) |
|
|||
106 | ] |
|
|||
107 |
|
||||
108 | PLAIN_EXTS = [('.text', 2), ('.TEXT', 2)] |
|
|||
109 |
|
||||
110 | ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS |
|
|||
111 |
|
||||
112 |
|
||||
113 | def str2bool(_str): |
|
|||
114 | """ |
|
|||
115 | returs True/False value from given string, it tries to translate the |
|
|||
116 | string into boolean |
|
|||
117 |
|
||||
118 | :param _str: string value to translate into boolean |
|
|||
119 | :rtype: boolean |
|
|||
120 | :returns: boolean from given string |
|
|||
121 | """ |
|
|||
122 | if _str is None: |
|
|||
123 | return False |
|
|||
124 | if _str in (True, False): |
|
|||
125 | return _str |
|
|||
126 | _str = str(_str).strip().lower() |
|
|||
127 | return _str in ('t', 'true', 'y', 'yes', 'on', '1') |
|
|||
128 |
|
||||
129 |
|
||||
130 | def convert_line_endings(line, mode): |
|
|||
131 | """ |
|
|||
132 | Converts a given line "line end" accordingly to given mode |
|
|||
133 |
|
||||
134 | Available modes are:: |
|
|||
135 | 0 - Unix |
|
|||
136 | 1 - Mac |
|
|||
137 | 2 - DOS |
|
|||
138 |
|
||||
139 | :param line: given line to convert |
|
|||
140 | :param mode: mode to convert to |
|
|||
141 | :rtype: str |
|
|||
142 | :return: converted line according to mode |
|
|||
143 | """ |
|
|||
144 | from string import replace |
|
|||
145 |
|
||||
146 | if mode == 0: |
|
|||
147 | line = replace(line, '\r\n', '\n') |
|
|||
148 | line = replace(line, '\r', '\n') |
|
|||
149 | elif mode == 1: |
|
|||
150 | line = replace(line, '\r\n', '\r') |
|
|||
151 | line = replace(line, '\n', '\r') |
|
|||
152 | elif mode == 2: |
|
|||
153 | line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line) |
|
|||
154 | return line |
|
|||
155 |
|
||||
156 |
|
||||
157 | def detect_mode(line, default): |
|
|||
158 | """ |
|
|||
159 | Detects line break for given line, if line break couldn't be found |
|
|||
160 | given default value is returned |
|
|||
161 |
|
||||
162 | :param line: str line |
|
|||
163 | :param default: default |
|
|||
164 | :rtype: int |
|
|||
165 | :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS |
|
|||
166 | """ |
|
|||
167 | if line.endswith('\r\n'): |
|
|||
168 | return 2 |
|
|||
169 | elif line.endswith('\n'): |
|
|||
170 | return 0 |
|
|||
171 | elif line.endswith('\r'): |
|
|||
172 | return 1 |
|
|||
173 | else: |
|
|||
174 | return default |
|
|||
175 |
|
||||
176 |
|
||||
177 | def generate_api_key(username, salt=None): |
|
|||
178 | """ |
|
|||
179 | Generates unique API key for given username, if salt is not given |
|
|||
180 | it'll be generated from some random string |
|
|||
181 |
|
||||
182 | :param username: username as string |
|
|||
183 | :param salt: salt to hash generate KEY |
|
|||
184 | :rtype: str |
|
|||
185 | :returns: sha1 hash from username+salt |
|
|||
186 | """ |
|
|||
187 | from tempfile import _RandomNameSequence |
|
|||
188 | import hashlib |
|
|||
189 |
|
||||
190 | if salt is None: |
|
|||
191 | salt = _RandomNameSequence().next() |
|
|||
192 |
|
||||
193 | return hashlib.sha1(username + salt).hexdigest() |
|
|||
194 |
|
||||
195 |
|
||||
196 | def safe_unicode(str_, from_encoding=None): |
|
|||
197 | """ |
|
|||
198 | safe unicode function. Does few trick to turn str_ into unicode |
|
|||
199 |
|
||||
200 | In case of UnicodeDecode error we try to return it with encoding detected |
|
|||
201 | by chardet library if it fails fallback to unicode with errors replaced |
|
|||
202 |
|
||||
203 | :param str_: string to decode |
|
|||
204 | :rtype: unicode |
|
|||
205 | :returns: unicode object |
|
|||
206 | """ |
|
|||
207 | if isinstance(str_, unicode): |
|
|||
208 | return str_ |
|
|||
209 |
|
||||
210 | if not from_encoding: |
|
|||
211 | import rhodecode |
|
|||
212 | DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8') |
|
|||
213 | from_encoding = DEFAULT_ENCODING |
|
|||
214 |
|
||||
215 | try: |
|
|||
216 | return unicode(str_) |
|
|||
217 | except UnicodeDecodeError: |
|
|||
218 | pass |
|
|||
219 |
|
||||
220 | try: |
|
|||
221 | return unicode(str_, from_encoding) |
|
|||
222 | except UnicodeDecodeError: |
|
|||
223 | pass |
|
|||
224 |
|
||||
225 | try: |
|
|||
226 | import chardet |
|
|||
227 | encoding = chardet.detect(str_)['encoding'] |
|
|||
228 | if encoding is None: |
|
|||
229 | raise Exception() |
|
|||
230 | return str_.decode(encoding) |
|
|||
231 | except (ImportError, UnicodeDecodeError, Exception): |
|
|||
232 | return unicode(str_, from_encoding, 'replace') |
|
|||
233 |
|
||||
234 |
|
||||
235 | def safe_str(unicode_, to_encoding=None): |
|
|||
236 | """ |
|
|||
237 | safe str function. Does few trick to turn unicode_ into string |
|
|||
238 |
|
||||
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 |
|
|||
241 |
|
||||
242 | :param unicode_: unicode to encode |
|
|||
243 | :rtype: str |
|
|||
244 | :returns: str object |
|
|||
245 | """ |
|
|||
246 |
|
||||
247 | # if it's not basestr cast to str |
|
|||
248 | if not isinstance(unicode_, basestring): |
|
|||
249 | return str(unicode_) |
|
|||
250 |
|
||||
251 | if isinstance(unicode_, str): |
|
|||
252 | return unicode_ |
|
|||
253 |
|
||||
254 | if not to_encoding: |
|
|||
255 | import rhodecode |
|
|||
256 | DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8') |
|
|||
257 | to_encoding = DEFAULT_ENCODING |
|
|||
258 |
|
||||
259 | try: |
|
|||
260 | return unicode_.encode(to_encoding) |
|
|||
261 | except UnicodeEncodeError: |
|
|||
262 | pass |
|
|||
263 |
|
||||
264 | try: |
|
|||
265 | import chardet |
|
|||
266 | encoding = chardet.detect(unicode_)['encoding'] |
|
|||
267 | print encoding |
|
|||
268 | if encoding is None: |
|
|||
269 | raise UnicodeEncodeError() |
|
|||
270 |
|
||||
271 | return unicode_.encode(encoding) |
|
|||
272 | except (ImportError, UnicodeEncodeError): |
|
|||
273 | return unicode_.encode(to_encoding, 'replace') |
|
|||
274 |
|
||||
275 | return safe_str |
|
|||
276 |
|
||||
277 |
|
||||
278 | def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs): |
|
|||
279 | """ |
|
|||
280 | Custom engine_from_config functions that makes sure we use NullPool for |
|
|||
281 | file based sqlite databases. This prevents errors on sqlite. This only |
|
|||
282 | applies to sqlalchemy versions < 0.7.0 |
|
|||
283 |
|
||||
284 | """ |
|
|||
285 | import sqlalchemy |
|
|||
286 | from sqlalchemy import engine_from_config as efc |
|
|||
287 | import logging |
|
|||
288 |
|
||||
289 | if int(sqlalchemy.__version__.split('.')[1]) < 7: |
|
|||
290 |
|
||||
291 | # This solution should work for sqlalchemy < 0.7.0, and should use |
|
|||
292 | # proxy=TimerProxy() for execution time profiling |
|
|||
293 |
|
||||
294 | from sqlalchemy.pool import NullPool |
|
|||
295 | url = configuration[prefix + 'url'] |
|
|||
296 |
|
||||
297 | if url.startswith('sqlite'): |
|
|||
298 | kwargs.update({'poolclass': NullPool}) |
|
|||
299 | return efc(configuration, prefix, **kwargs) |
|
|||
300 | else: |
|
|||
301 | import time |
|
|||
302 | from sqlalchemy import event |
|
|||
303 | from sqlalchemy.engine import Engine |
|
|||
304 |
|
||||
305 | log = logging.getLogger('sqlalchemy.engine') |
|
|||
306 | BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38) |
|
|||
307 | engine = efc(configuration, prefix, **kwargs) |
|
|||
308 |
|
||||
309 | def color_sql(sql): |
|
|||
310 | COLOR_SEQ = "\033[1;%dm" |
|
|||
311 | COLOR_SQL = YELLOW |
|
|||
312 | normal = '\x1b[0m' |
|
|||
313 | return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal]) |
|
|||
314 |
|
||||
315 | if configuration['debug']: |
|
|||
316 | #attach events only for debug configuration |
|
|||
317 |
|
||||
318 | def before_cursor_execute(conn, cursor, statement, |
|
|||
319 | parameters, context, executemany): |
|
|||
320 | context._query_start_time = time.time() |
|
|||
321 | log.info(color_sql(">>>>> STARTING QUERY >>>>>")) |
|
|||
322 |
|
||||
323 |
|
||||
324 | def after_cursor_execute(conn, cursor, statement, |
|
|||
325 | parameters, context, executemany): |
|
|||
326 | total = time.time() - context._query_start_time |
|
|||
327 | log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total)) |
|
|||
328 |
|
||||
329 | event.listen(engine, "before_cursor_execute", |
|
|||
330 | before_cursor_execute) |
|
|||
331 | event.listen(engine, "after_cursor_execute", |
|
|||
332 | after_cursor_execute) |
|
|||
333 |
|
||||
334 | return engine |
|
|||
335 |
|
||||
336 |
|
||||
337 | def age(curdate): |
|
|||
338 | """ |
|
|||
339 | turns a datetime into an age string. |
|
|||
340 |
|
||||
341 | :param curdate: datetime object |
|
|||
342 | :rtype: unicode |
|
|||
343 | :returns: unicode words describing age |
|
|||
344 | """ |
|
|||
345 |
|
||||
346 | from datetime import datetime |
|
|||
347 | from webhelpers.date import time_ago_in_words |
|
|||
348 |
|
||||
349 | _ = lambda s: s |
|
|||
350 |
|
||||
351 | if not curdate: |
|
|||
352 | return '' |
|
|||
353 |
|
||||
354 | agescales = [(_(u"year"), 3600 * 24 * 365), |
|
|||
355 | (_(u"month"), 3600 * 24 * 30), |
|
|||
356 | (_(u"day"), 3600 * 24), |
|
|||
357 | (_(u"hour"), 3600), |
|
|||
358 | (_(u"minute"), 60), |
|
|||
359 | (_(u"second"), 1), ] |
|
|||
360 |
|
||||
361 | age = datetime.now() - curdate |
|
|||
362 | age_seconds = (age.days * agescales[2][1]) + age.seconds |
|
|||
363 | pos = 1 |
|
|||
364 | for scale in agescales: |
|
|||
365 | if scale[1] <= age_seconds: |
|
|||
366 | if pos == 6: |
|
|||
367 | pos = 5 |
|
|||
368 | return '%s %s' % (time_ago_in_words(curdate, |
|
|||
369 | agescales[pos][0]), _('ago')) |
|
|||
370 | pos += 1 |
|
|||
371 |
|
||||
372 | return _(u'just now') |
|
|||
373 |
|
||||
374 |
|
||||
375 | def uri_filter(uri): |
|
|||
376 | """ |
|
|||
377 | Removes user:password from given url string |
|
|||
378 |
|
||||
379 | :param uri: |
|
|||
380 | :rtype: unicode |
|
|||
381 | :returns: filtered list of strings |
|
|||
382 | """ |
|
|||
383 | if not uri: |
|
|||
384 | return '' |
|
|||
385 |
|
||||
386 | proto = '' |
|
|||
387 |
|
||||
388 | for pat in ('https://', 'http://'): |
|
|||
389 | if uri.startswith(pat): |
|
|||
390 | uri = uri[len(pat):] |
|
|||
391 | proto = pat |
|
|||
392 | break |
|
|||
393 |
|
||||
394 | # remove passwords and username |
|
|||
395 | uri = uri[uri.find('@') + 1:] |
|
|||
396 |
|
||||
397 | # get the port |
|
|||
398 | cred_pos = uri.find(':') |
|
|||
399 | if cred_pos == -1: |
|
|||
400 | host, port = uri, None |
|
|||
401 | else: |
|
|||
402 | host, port = uri[:cred_pos], uri[cred_pos + 1:] |
|
|||
403 |
|
||||
404 | return filter(None, [proto, host, port]) |
|
|||
405 |
|
||||
406 |
|
||||
407 | def credentials_filter(uri): |
|
|||
408 | """ |
|
|||
409 | Returns a url with removed credentials |
|
|||
410 |
|
||||
411 | :param uri: |
|
|||
412 | """ |
|
|||
413 |
|
||||
414 | uri = uri_filter(uri) |
|
|||
415 | #check if we have port |
|
|||
416 | if len(uri) > 2 and uri[2]: |
|
|||
417 | uri[2] = ':' + uri[2] |
|
|||
418 |
|
||||
419 | return ''.join(uri) |
|
|||
420 |
|
||||
421 |
|
||||
422 | def get_changeset_safe(repo, rev): |
|
|||
423 | """ |
|
|||
424 | Safe version of get_changeset if this changeset doesn't exists for a |
|
|||
425 | repo it returns a Dummy one instead |
|
|||
426 |
|
||||
427 | :param repo: |
|
|||
428 | :param rev: |
|
|||
429 | """ |
|
|||
430 | from rhodecode.lib.vcs.backends.base import BaseRepository |
|
|||
431 | from rhodecode.lib.vcs.exceptions import RepositoryError |
|
|||
432 | if not isinstance(repo, BaseRepository): |
|
|||
433 | raise Exception('You must pass an Repository ' |
|
|||
434 | 'object as first argument got %s', type(repo)) |
|
|||
435 |
|
||||
436 | try: |
|
|||
437 | cs = repo.get_changeset(rev) |
|
|||
438 | except RepositoryError: |
|
|||
439 | from rhodecode.lib.utils import EmptyChangeset |
|
|||
440 | cs = EmptyChangeset(requested_revision=rev) |
|
|||
441 | return cs |
|
|||
442 |
|
2 | |||
443 |
|
3 | |||
444 | def get_current_revision(quiet=False): |
|
4 | def get_current_revision(quiet=False): | |
@@ -462,16 +22,3 b' def get_current_revision(quiet=False):' | |||||
462 | print ("Cannot retrieve rhodecode's revision. Original error " |
|
22 | print ("Cannot retrieve rhodecode's revision. Original error " | |
463 | "was: %s" % err) |
|
23 | "was: %s" % err) | |
464 | return None |
|
24 | return None | |
465 |
|
||||
466 |
|
||||
467 | def extract_mentioned_users(s): |
|
|||
468 | """ |
|
|||
469 | Returns unique usernames from given string s that have @mention |
|
|||
470 |
|
||||
471 | :param s: string to get mentions |
|
|||
472 | """ |
|
|||
473 | usrs = {} |
|
|||
474 | for username in re.findall(r'(?:^@|\s@)(\w+)', s): |
|
|||
475 | usrs[username] = username |
|
|||
476 |
|
||||
477 | return sorted(usrs.keys()) |
|
@@ -43,7 +43,7 b' if __platform__ in PLATFORM_WIN:' | |||||
43 | if __platform__ in PLATFORM_OTHERS: |
|
43 | if __platform__ in PLATFORM_OTHERS: | |
44 | import bcrypt |
|
44 | import bcrypt | |
45 |
|
45 | |||
46 | from rhodecode.lib import str2bool, safe_unicode |
|
46 | from rhodecode.lib.utils2 import str2bool, safe_unicode | |
47 | from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError |
|
47 | from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError | |
48 | from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug |
|
48 | from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug | |
49 | from rhodecode.lib.auth_ldap import AuthLdap |
|
49 | from rhodecode.lib.auth_ldap import AuthLdap |
@@ -15,7 +15,7 b' from pylons.templating import render_mak' | |||||
15 |
|
15 | |||
16 | from rhodecode import __version__, BACKENDS |
|
16 | from rhodecode import __version__, BACKENDS | |
17 |
|
17 | |||
18 | from rhodecode.lib import str2bool, safe_unicode |
|
18 | from rhodecode.lib.utils2 import str2bool, safe_unicode | |
19 | from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\ |
|
19 | from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\ | |
20 | HasPermissionAnyMiddleware, CookieStoreWrapper |
|
20 | HasPermissionAnyMiddleware, CookieStoreWrapper | |
21 | from rhodecode.lib.utils import get_repo_slug, invalidate_cache |
|
21 | from rhodecode.lib.utils import get_repo_slug, invalidate_cache |
@@ -24,7 +24,7 b' from beaker.exceptions import BeakerExce' | |||||
24 | from sqlalchemy.orm.interfaces import MapperOption |
|
24 | from sqlalchemy.orm.interfaces import MapperOption | |
25 | from sqlalchemy.orm.query import Query |
|
25 | from sqlalchemy.orm.query import Query | |
26 | from sqlalchemy.sql import visitors |
|
26 | from sqlalchemy.sql import visitors | |
27 | from rhodecode.lib import safe_str |
|
27 | from rhodecode.lib.utils2 import safe_str | |
28 |
|
28 | |||
29 |
|
29 | |||
30 | class CachingQuery(Query): |
|
30 | class CachingQuery(Query): |
@@ -36,7 +36,7 b' from decorator import decorator' | |||||
36 |
|
36 | |||
37 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
37 | from rhodecode.lib.vcs.utils.lazy import LazyProperty | |
38 | from rhodecode import CELERY_ON |
|
38 | from rhodecode import CELERY_ON | |
39 | from rhodecode.lib import str2bool, safe_str |
|
39 | from rhodecode.lib.utils2 import str2bool, safe_str | |
40 | from rhodecode.lib.pidlock import DaemonLock, LockHeld |
|
40 | from rhodecode.lib.pidlock import DaemonLock, LockHeld | |
41 | from rhodecode.model import init_model |
|
41 | from rhodecode.model import init_model | |
42 | from rhodecode.model import meta |
|
42 | from rhodecode.model import meta |
@@ -40,7 +40,7 b' from pylons.i18n.translation import _' | |||||
40 | from rhodecode.lib.vcs import get_backend |
|
40 | from rhodecode.lib.vcs import get_backend | |
41 |
|
41 | |||
42 | from rhodecode import CELERY_ON |
|
42 | from rhodecode import CELERY_ON | |
43 |
from rhodecode.lib import |
|
43 | from rhodecode.lib.utils2 import safe_str | |
44 | from rhodecode.lib.celerylib import run_task, locked_task, dbsession, \ |
|
44 | from rhodecode.lib.celerylib import run_task, locked_task, dbsession, \ | |
45 | str2bool, __get_lockkey, LockHeld, DaemonLock, get_session |
|
45 | str2bool, __get_lockkey, LockHeld, DaemonLock, get_session | |
46 | from rhodecode.lib.helpers import person |
|
46 | from rhodecode.lib.helpers import person | |
@@ -147,6 +147,7 b' def get_commits_stats(repo_name, ts_min_' | |||||
147 | last_rev, last_rev + parse_limit) |
|
147 | last_rev, last_rev + parse_limit) | |
148 | ) |
|
148 | ) | |
149 | for cs in repo[last_rev:last_rev + parse_limit]: |
|
149 | for cs in repo[last_rev:last_rev + parse_limit]: | |
|
150 | log.debug('parsing %s' % cs) | |||
150 | last_cs = cs # remember last parsed changeset |
|
151 | last_cs = cs # remember last parsed changeset | |
151 | k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1], |
|
152 | k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1], | |
152 | cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0]) |
|
153 | cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0]) | |
@@ -395,6 +396,7 b' def create_repo_fork(form_data, cur_user' | |||||
395 | DBS.commit() |
|
396 | DBS.commit() | |
396 |
|
397 | |||
397 | def __get_codes_stats(repo_name): |
|
398 | def __get_codes_stats(repo_name): | |
|
399 | from rhodecode.config.conf import LANGUAGES_EXTENSIONS_MAP | |||
398 | repo = Repository.get_by_repo_name(repo_name).scm_instance |
|
400 | repo = Repository.get_by_repo_name(repo_name).scm_instance | |
399 |
|
401 | |||
400 | tip = repo.get_changeset() |
|
402 | tip = repo.get_changeset() |
@@ -1,9 +1,9 b'' | |||||
1 | import rhodecode |
|
1 | import rhodecode | |
2 | from rhodecode.lib.utils import BasePasterCommand, Command |
|
2 | from rhodecode.lib.utils import BasePasterCommand, Command, load_rcextensions | |
3 | from celery.app import app_or_default |
|
3 | from celery.app import app_or_default | |
4 | from celery.bin import camqadm, celerybeat, celeryd, celeryev |
|
4 | from celery.bin import camqadm, celerybeat, celeryd, celeryev | |
5 |
|
5 | |||
6 | from rhodecode.lib import str2bool |
|
6 | from rhodecode.lib.utils2 import str2bool | |
7 |
|
7 | |||
8 | __all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand', |
|
8 | __all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand', | |
9 | 'CAMQPAdminCommand', 'CeleryEventCommand'] |
|
9 | 'CAMQPAdminCommand', 'CeleryEventCommand'] | |
@@ -39,9 +39,11 b' class CeleryCommand(BasePasterCommand):' | |||||
39 | raise Exception('Please enable celery_on in .ini config ' |
|
39 | raise Exception('Please enable celery_on in .ini config ' | |
40 | 'file before running celeryd') |
|
40 | 'file before running celeryd') | |
41 | rhodecode.CELERY_ON = CELERY_ON |
|
41 | rhodecode.CELERY_ON = CELERY_ON | |
|
42 | load_rcextensions(config['here']) | |||
42 | cmd = self.celery_command(app_or_default()) |
|
43 | cmd = self.celery_command(app_or_default()) | |
43 | return cmd.run(**vars(self.options)) |
|
44 | return cmd.run(**vars(self.options)) | |
44 |
|
45 | |||
|
46 | ||||
45 | class CeleryDaemonCommand(CeleryCommand): |
|
47 | class CeleryDaemonCommand(CeleryCommand): | |
46 | """Start the celery worker |
|
48 | """Start the celery worker | |
47 |
|
49 | |||
@@ -82,6 +84,7 b' class CAMQPAdminCommand(CeleryCommand):' | |||||
82 | parser = Command.standard_parser(quiet=True) |
|
84 | parser = Command.standard_parser(quiet=True) | |
83 | celery_command = camqadm.AMQPAdminCommand |
|
85 | celery_command = camqadm.AMQPAdminCommand | |
84 |
|
86 | |||
|
87 | ||||
85 | class CeleryEventCommand(CeleryCommand): |
|
88 | class CeleryEventCommand(CeleryCommand): | |
86 | """Celery event command. |
|
89 | """Celery event command. | |
87 |
|
90 |
@@ -71,9 +71,6 b' class InvalidScriptError(ScriptError):' | |||||
71 | """Invalid script error.""" |
|
71 | """Invalid script error.""" | |
72 |
|
72 | |||
73 |
|
73 | |||
74 | class InvalidVersionError(Error): |
|
|||
75 | """Invalid version error.""" |
|
|||
76 |
|
||||
77 | # migrate.changeset |
|
74 | # migrate.changeset | |
78 |
|
75 | |||
79 | class NotSupportedError(Error): |
|
76 | class NotSupportedError(Error): |
@@ -39,7 +39,7 b' from rhodecode.lib.vcs.utils.helpers imp' | |||||
39 | from rhodecode.lib.vcs.exceptions import VCSError |
|
39 | from rhodecode.lib.vcs.exceptions import VCSError | |
40 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
40 | from rhodecode.lib.vcs.utils.lazy import LazyProperty | |
41 |
|
41 | |||
42 | from rhodecode.lib import str2bool, safe_str, get_changeset_safe, \ |
|
42 | from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \ | |
43 | generate_api_key, safe_unicode |
|
43 | generate_api_key, safe_unicode | |
44 | from rhodecode.lib.exceptions import UsersGroupsAssignedException |
|
44 | from rhodecode.lib.exceptions import UsersGroupsAssignedException | |
45 | from rhodecode.lib.compat import json |
|
45 | from rhodecode.lib.compat import json | |
@@ -717,7 +717,7 b' class Repository(Base, BaseModel):' | |||||
717 | return repo |
|
717 | return repo | |
718 |
|
718 | |||
719 |
|
719 | |||
720 |
class |
|
720 | class Group(Base, BaseModel): | |
721 | __tablename__ = 'groups' |
|
721 | __tablename__ = 'groups' | |
722 | __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'), |
|
722 | __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'), | |
723 | CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},) |
|
723 | CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},) | |
@@ -728,8 +728,7 b' class RepoGroup(Base, BaseModel):' | |||||
728 | group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) |
|
728 | group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) | |
729 | group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
729 | group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
730 |
|
730 | |||
731 |
parent_group = relationship(' |
|
731 | parent_group = relationship('Group', remote_side=group_id) | |
732 |
|
||||
733 |
|
732 | |||
734 | def __init__(self, group_name='', parent_group=None): |
|
733 | def __init__(self, group_name='', parent_group=None): | |
735 | self.group_name = group_name |
|
734 | self.group_name = group_name |
@@ -39,7 +39,8 b' from webhelpers.html.tags import _set_in' | |||||
39 |
|
39 | |||
40 | from rhodecode.lib.annotate import annotate_highlight |
|
40 | from rhodecode.lib.annotate import annotate_highlight | |
41 | from rhodecode.lib.utils import repo_name_slug |
|
41 | from rhodecode.lib.utils import repo_name_slug | |
42 |
from rhodecode.lib import str2bool, safe_unicode, safe_str, |
|
42 | from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \ | |
|
43 | get_changeset_safe | |||
43 | from rhodecode.lib.markup_renderer import MarkupRenderer |
|
44 | from rhodecode.lib.markup_renderer import MarkupRenderer | |
44 |
|
45 | |||
45 | log = logging.getLogger(__name__) |
|
46 | log = logging.getLogger(__name__) | |
@@ -319,7 +320,7 b' flash = _Flash()' | |||||
319 | # SCM FILTERS available via h. |
|
320 | # SCM FILTERS available via h. | |
320 | #============================================================================== |
|
321 | #============================================================================== | |
321 | from rhodecode.lib.vcs.utils import author_name, author_email |
|
322 | from rhodecode.lib.vcs.utils import author_name, author_email | |
322 | from rhodecode.lib import credentials_filter, age as _age |
|
323 | from rhodecode.lib.utils2 import credentials_filter, age as _age | |
323 | from rhodecode.model.db import User |
|
324 | from rhodecode.model.db import User | |
324 |
|
325 | |||
325 | age = lambda x: _age(x) |
|
326 | age = lambda x: _age(x) |
@@ -47,9 +47,9 b' from rhodecode.model import init_model' | |||||
47 | from rhodecode.model.scm import ScmModel |
|
47 | from rhodecode.model.scm import ScmModel | |
48 | from rhodecode.model.repo import RepoModel |
|
48 | from rhodecode.model.repo import RepoModel | |
49 | from rhodecode.config.environment import load_environment |
|
49 | from rhodecode.config.environment import load_environment | |
50 | from rhodecode.lib import LANGUAGES_EXTENSIONS_MAP, INDEX_EXTENSIONS, \ |
|
50 | from rhodecode.lib.utils2 import LazyProperty | |
51 | LazyProperty |
|
51 | from rhodecode.lib.utils import BasePasterCommand, Command, add_cache,\ | |
52 | from rhodecode.lib.utils import BasePasterCommand, Command, add_cache |
|
52 | load_rcextensions | |
53 |
|
53 | |||
54 | # CUSTOM ANALYZER wordsplit + lowercase filter |
|
54 | # CUSTOM ANALYZER wordsplit + lowercase filter | |
55 | ANALYZER = RegexTokenizer(expression=r"\w+") | LowercaseFilter() |
|
55 | ANALYZER = RegexTokenizer(expression=r"\w+") | LowercaseFilter() | |
@@ -88,13 +88,12 b' class MakeIndex(BasePasterCommand):' | |||||
88 | add_cache(config) |
|
88 | add_cache(config) | |
89 | engine = engine_from_config(config, 'sqlalchemy.db1.') |
|
89 | engine = engine_from_config(config, 'sqlalchemy.db1.') | |
90 | init_model(engine) |
|
90 | init_model(engine) | |
91 |
|
||||
92 | index_location = config['index_dir'] |
|
91 | index_location = config['index_dir'] | |
93 | repo_location = self.options.repo_location \ |
|
92 | repo_location = self.options.repo_location \ | |
94 | if self.options.repo_location else RepoModel().repos_path |
|
93 | if self.options.repo_location else RepoModel().repos_path | |
95 | repo_list = map(strip, self.options.repo_list.split(',')) \ |
|
94 | repo_list = map(strip, self.options.repo_list.split(',')) \ | |
96 | if self.options.repo_list else None |
|
95 | if self.options.repo_list else None | |
97 |
|
96 | load_rcextensions(config['here']) | ||
98 | #====================================================================== |
|
97 | #====================================================================== | |
99 | # WHOOSH DAEMON |
|
98 | # WHOOSH DAEMON | |
100 | #====================================================================== |
|
99 | #====================================================================== | |
@@ -104,7 +103,7 b' class MakeIndex(BasePasterCommand):' | |||||
104 | l = DaemonLock(file_=jn(dn(dn(index_location)), 'make_index.lock')) |
|
103 | l = DaemonLock(file_=jn(dn(dn(index_location)), 'make_index.lock')) | |
105 | WhooshIndexingDaemon(index_location=index_location, |
|
104 | WhooshIndexingDaemon(index_location=index_location, | |
106 | repo_location=repo_location, |
|
105 | repo_location=repo_location, | |
107 | repo_list=repo_list)\ |
|
106 | repo_list=repo_list,)\ | |
108 | .run(full_index=self.options.full_index) |
|
107 | .run(full_index=self.options.full_index) | |
109 | l.release() |
|
108 | l.release() | |
110 | except LockHeld: |
|
109 | except LockHeld: |
@@ -38,10 +38,10 b' from os.path import join as jn' | |||||
38 | project_path = dn(dn(dn(dn(os.path.realpath(__file__))))) |
|
38 | project_path = dn(dn(dn(dn(os.path.realpath(__file__))))) | |
39 | sys.path.append(project_path) |
|
39 | sys.path.append(project_path) | |
40 |
|
40 | |||
41 |
|
41 | from rhodecode.config.conf import INDEX_EXTENSIONS | ||
42 | from rhodecode.model.scm import ScmModel |
|
42 | from rhodecode.model.scm import ScmModel | |
43 | from rhodecode.lib import safe_unicode |
|
43 | from rhodecode.lib.utils2 import safe_unicode | |
44 |
from rhodecode.lib.indexers import |
|
44 | from rhodecode.lib.indexers import SCHEMA, IDX_NAME | |
45 |
|
45 | |||
46 | from rhodecode.lib.vcs.exceptions import ChangesetError, RepositoryError, \ |
|
46 | from rhodecode.lib.vcs.exceptions import ChangesetError, RepositoryError, \ | |
47 | NodeDoesNotExistError |
|
47 | NodeDoesNotExistError | |
@@ -117,10 +117,9 b' class WhooshIndexingDaemon(object):' | |||||
117 | """ |
|
117 | """ | |
118 |
|
118 | |||
119 | node = self.get_node(repo, path) |
|
119 | node = self.get_node(repo, path) | |
120 |
|
120 | indexed = indexed_w_content = 0 | ||
121 | # we just index the content of chosen files, and skip binary files |
|
121 | # we just index the content of chosen files, and skip binary files | |
122 | if node.extension in INDEX_EXTENSIONS and not node.is_binary: |
|
122 | if node.extension in INDEX_EXTENSIONS and not node.is_binary: | |
123 |
|
||||
124 | u_content = node.content |
|
123 | u_content = node.content | |
125 | if not isinstance(u_content, unicode): |
|
124 | if not isinstance(u_content, unicode): | |
126 | log.warning(' >> %s Could not get this content as unicode ' |
|
125 | log.warning(' >> %s Could not get this content as unicode ' | |
@@ -128,11 +127,13 b' class WhooshIndexingDaemon(object):' | |||||
128 | u_content = u'' |
|
127 | u_content = u'' | |
129 | else: |
|
128 | else: | |
130 | log.debug(' >> %s [WITH CONTENT]' % path) |
|
129 | log.debug(' >> %s [WITH CONTENT]' % path) | |
|
130 | indexed_w_content += 1 | |||
131 |
|
131 | |||
132 | else: |
|
132 | else: | |
133 | log.debug(' >> %s' % path) |
|
133 | log.debug(' >> %s' % path) | |
134 | # just index file name without it's content |
|
134 | # just index file name without it's content | |
135 | u_content = u'' |
|
135 | u_content = u'' | |
|
136 | indexed += 1 | |||
136 |
|
137 | |||
137 | writer.add_document( |
|
138 | writer.add_document( | |
138 | owner=unicode(repo.contact), |
|
139 | owner=unicode(repo.contact), | |
@@ -142,6 +143,7 b' class WhooshIndexingDaemon(object):' | |||||
142 | modtime=self.get_node_mtime(node), |
|
143 | modtime=self.get_node_mtime(node), | |
143 | extension=node.extension |
|
144 | extension=node.extension | |
144 | ) |
|
145 | ) | |
|
146 | return indexed, indexed_w_content | |||
145 |
|
147 | |||
146 | def build_index(self): |
|
148 | def build_index(self): | |
147 | if os.path.exists(self.index_location): |
|
149 | if os.path.exists(self.index_location): | |
@@ -153,19 +155,25 b' class WhooshIndexingDaemon(object):' | |||||
153 |
|
155 | |||
154 | idx = create_in(self.index_location, SCHEMA, indexname=IDX_NAME) |
|
156 | idx = create_in(self.index_location, SCHEMA, indexname=IDX_NAME) | |
155 | writer = idx.writer() |
|
157 | writer = idx.writer() | |
156 |
|
158 | log.debug('BUILDIN INDEX FOR EXTENSIONS %s' % INDEX_EXTENSIONS) | ||
157 | for repo_name, repo in self.repo_paths.items(): |
|
159 | for repo_name, repo in self.repo_paths.items(): | |
158 | log.debug('building index @ %s' % repo.path) |
|
160 | log.debug('building index @ %s' % repo.path) | |
159 |
|
161 | i_cnt = iwc_cnt = 0 | ||
160 | for idx_path in self.get_paths(repo): |
|
162 | for idx_path in self.get_paths(repo): | |
161 | self.add_doc(writer, idx_path, repo, repo_name) |
|
163 | i, iwc = self.add_doc(writer, idx_path, repo, repo_name) | |
|
164 | i_cnt += i | |||
|
165 | iwc_cnt += iwc | |||
|
166 | log.debug('added %s files %s with content for repo %s' % ( | |||
|
167 | i_cnt + iwc_cnt, iwc_cnt, repo.path) | |||
|
168 | ) | |||
162 |
|
169 | |||
163 | log.debug('>> COMMITING CHANGES <<') |
|
170 | log.debug('>> COMMITING CHANGES <<') | |
164 | writer.commit(merge=True) |
|
171 | writer.commit(merge=True) | |
165 | log.debug('>>> FINISHED BUILDING INDEX <<<') |
|
172 | log.debug('>>> FINISHED BUILDING INDEX <<<') | |
166 |
|
173 | |||
167 | def update_index(self): |
|
174 | def update_index(self): | |
168 |
log.debug('STARTING INCREMENTAL INDEXING UPDATE' |
|
175 | log.debug('STARTING INCREMENTAL INDEXING UPDATE FOR EXTENSIONS %s' % | |
|
176 | INDEX_EXTENSIONS) | |||
169 |
|
177 | |||
170 | idx = open_dir(self.index_location, indexname=self.indexname) |
|
178 | idx = open_dir(self.index_location, indexname=self.indexname) | |
171 | # The set of all paths in the index |
|
179 | # The set of all paths in the index | |
@@ -204,14 +212,19 b' class WhooshIndexingDaemon(object):' | |||||
204 | # Loop over the files in the filesystem |
|
212 | # Loop over the files in the filesystem | |
205 | # Assume we have a function that gathers the filenames of the |
|
213 | # Assume we have a function that gathers the filenames of the | |
206 | # documents to be indexed |
|
214 | # documents to be indexed | |
|
215 | ri_cnt = riwc_cnt = 0 | |||
207 | for repo_name, repo in self.repo_paths.items(): |
|
216 | for repo_name, repo in self.repo_paths.items(): | |
208 | for path in self.get_paths(repo): |
|
217 | for path in self.get_paths(repo): | |
209 | if path in to_index or path not in indexed_paths: |
|
218 | if path in to_index or path not in indexed_paths: | |
210 | # This is either a file that's changed, or a new file |
|
219 | # This is either a file that's changed, or a new file | |
211 | # that wasn't indexed before. So index it! |
|
220 | # that wasn't indexed before. So index it! | |
212 | self.add_doc(writer, path, repo, repo_name) |
|
221 | i, iwc = self.add_doc(writer, path, repo, repo_name) | |
213 | log.debug('re indexing %s' % path) |
|
222 | log.debug('re indexing %s' % path) | |
214 |
|
223 | ri_cnt += i | ||
|
224 | riwc_cnt += iwc | |||
|
225 | log.debug('added %s files %s with content for repo %s' % ( | |||
|
226 | ri_cnt + riwc_cnt, riwc_cnt, repo.path) | |||
|
227 | ) | |||
215 | log.debug('>> COMMITING CHANGES <<') |
|
228 | log.debug('>> COMMITING CHANGES <<') | |
216 | writer.commit(merge=True) |
|
229 | writer.commit(merge=True) | |
217 | log.debug('>>> FINISHED REBUILDING INDEX <<<') |
|
230 | log.debug('>>> FINISHED REBUILDING INDEX <<<') |
@@ -27,7 +27,7 b'' | |||||
27 | import re |
|
27 | import re | |
28 | import logging |
|
28 | import logging | |
29 |
|
29 | |||
30 | from rhodecode.lib import safe_unicode |
|
30 | from rhodecode.lib.utils2 import safe_unicode | |
31 |
|
31 | |||
32 | log = logging.getLogger(__name__) |
|
32 | log = logging.getLogger(__name__) | |
33 |
|
33 |
@@ -23,7 +23,7 b'' | |||||
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 | from rhodecode.lib import str2bool |
|
26 | from rhodecode.lib.utils2 import str2bool | |
27 |
|
27 | |||
28 |
|
28 | |||
29 | class HttpsFixup(object): |
|
29 | class HttpsFixup(object): |
@@ -69,7 +69,7 b' from dulwich.web import HTTPGitApplicati' | |||||
69 |
|
69 | |||
70 | from paste.httpheaders import REMOTE_USER, AUTH_TYPE |
|
70 | from paste.httpheaders import REMOTE_USER, AUTH_TYPE | |
71 |
|
71 | |||
72 | from rhodecode.lib import safe_str |
|
72 | from rhodecode.lib.utils2 import safe_str | |
73 | from rhodecode.lib.base import BaseVCSController |
|
73 | from rhodecode.lib.base import BaseVCSController | |
74 | from rhodecode.lib.auth import get_container_username |
|
74 | from rhodecode.lib.auth import get_container_username | |
75 | from rhodecode.lib.utils import is_valid_repo |
|
75 | from rhodecode.lib.utils import is_valid_repo |
@@ -34,7 +34,7 b' from mercurial.hgweb import hgweb_mod' | |||||
34 |
|
34 | |||
35 | from paste.httpheaders import REMOTE_USER, AUTH_TYPE |
|
35 | from paste.httpheaders import REMOTE_USER, AUTH_TYPE | |
36 |
|
36 | |||
37 | from rhodecode.lib import safe_str |
|
37 | from rhodecode.lib.utils2 import safe_str | |
38 | from rhodecode.lib.base import BaseVCSController |
|
38 | from rhodecode.lib.base import BaseVCSController | |
39 | from rhodecode.lib.auth import get_container_username |
|
39 | from rhodecode.lib.auth import get_container_username | |
40 | from rhodecode.lib.utils import make_ui, is_valid_repo, ui_sections |
|
40 | from rhodecode.lib.utils import make_ui, is_valid_repo, ui_sections |
@@ -54,7 +54,8 b' from rhodecode.model.db import Repositor' | |||||
54 | UserLog, RepoGroup, RhodeCodeSetting, UserRepoGroupToPerm |
|
54 | UserLog, RepoGroup, RhodeCodeSetting, UserRepoGroupToPerm | |
55 | from rhodecode.model.meta import Session |
|
55 | from rhodecode.model.meta import Session | |
56 | from rhodecode.model.repos_group import ReposGroupModel |
|
56 | from rhodecode.model.repos_group import ReposGroupModel | |
57 | from rhodecode.lib import safe_str, safe_unicode |
|
57 | from rhodecode.lib.utils2 import safe_str, safe_unicode | |
|
58 | from rhodecode.lib.vcs.utils.fakemod import create_module | |||
58 |
|
59 | |||
59 | log = logging.getLogger(__name__) |
|
60 | log = logging.getLogger(__name__) | |
60 |
|
61 | |||
@@ -62,7 +63,8 b" REMOVED_REPO_PAT = re.compile(r'rm__\\d{8" | |||||
62 |
|
63 | |||
63 |
|
64 | |||
64 | def recursive_replace(str_, replace=' '): |
|
65 | def recursive_replace(str_, replace=' '): | |
65 | """Recursive replace of given sign to just one instance |
|
66 | """ | |
|
67 | Recursive replace of given sign to just one instance | |||
66 |
|
68 | |||
67 | :param str_: given string |
|
69 | :param str_: given string | |
68 | :param replace: char to find and replace multiple instances |
|
70 | :param replace: char to find and replace multiple instances | |
@@ -80,7 +82,8 b" def recursive_replace(str_, replace=' ')" | |||||
80 |
|
82 | |||
81 |
|
83 | |||
82 | def repo_name_slug(value): |
|
84 | def repo_name_slug(value): | |
83 | """Return slug of name of repository |
|
85 | """ | |
|
86 | Return slug of name of repository | |||
84 | This function is called on each creation/modification |
|
87 | This function is called on each creation/modification | |
85 | of repository to prevent bad names in repo |
|
88 | of repository to prevent bad names in repo | |
86 | """ |
|
89 | """ | |
@@ -263,7 +266,8 b" ui_sections = ['alias', 'auth'," | |||||
263 |
|
266 | |||
264 |
|
267 | |||
265 | def make_ui(read_from='file', path=None, checkpaths=True): |
|
268 | def make_ui(read_from='file', path=None, checkpaths=True): | |
266 | """A function that will read python rc files or database |
|
269 | """ | |
|
270 | A function that will read python rc files or database | |||
267 | and make an mercurial ui object from read options |
|
271 | and make an mercurial ui object from read options | |
268 |
|
272 | |||
269 | :param path: path to mercurial config file |
|
273 | :param path: path to mercurial config file | |
@@ -489,6 +493,30 b' def add_cache(settings):' | |||||
489 | beaker.cache.cache_regions[region] = region_settings |
|
493 | beaker.cache.cache_regions[region] = region_settings | |
490 |
|
494 | |||
491 |
|
495 | |||
|
496 | def load_rcextensions(root_path): | |||
|
497 | import rhodecode | |||
|
498 | from rhodecode.config import conf | |||
|
499 | ||||
|
500 | path = os.path.join(root_path, 'rcextensions', '__init__.py') | |||
|
501 | if os.path.isfile(path): | |||
|
502 | rcext = create_module('rc', path) | |||
|
503 | EXT = rhodecode.EXTENSIONS = rcext | |||
|
504 | log.debug('Found rcextensions now loading %s...' % rcext) | |||
|
505 | ||||
|
506 | # Additional mappings that are not present in the pygments lexers | |||
|
507 | conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {})) | |||
|
508 | ||||
|
509 | #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present) | |||
|
510 | ||||
|
511 | if getattr(EXT, 'INDEX_EXTENSIONS', []) != []: | |||
|
512 | log.debug('settings custom INDEX_EXTENSIONS') | |||
|
513 | conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', []) | |||
|
514 | ||||
|
515 | #ADDITIONAL MAPPINGS | |||
|
516 | log.debug('adding extra into INDEX_EXTENSIONS') | |||
|
517 | conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', [])) | |||
|
518 | ||||
|
519 | ||||
492 | #============================================================================== |
|
520 | #============================================================================== | |
493 | # TEST FUNCTIONS AND CREATORS |
|
521 | # TEST FUNCTIONS AND CREATORS | |
494 | #============================================================================== |
|
522 | #============================================================================== |
@@ -29,7 +29,7 b' import traceback' | |||||
29 | from pylons.i18n.translation import _ |
|
29 | from pylons.i18n.translation import _ | |
30 | from sqlalchemy.util.compat import defaultdict |
|
30 | from sqlalchemy.util.compat import defaultdict | |
31 |
|
31 | |||
32 | from rhodecode.lib import extract_mentioned_users |
|
32 | from rhodecode.lib.utils2 import extract_mentioned_users | |
33 | from rhodecode.lib import helpers as h |
|
33 | from rhodecode.lib import helpers as h | |
34 | from rhodecode.model import BaseModel |
|
34 | from rhodecode.model import BaseModel | |
35 | from rhodecode.model.db import ChangesetComment, User, Repository, Notification |
|
35 | from rhodecode.model.db import ChangesetComment, User, Repository, Notification |
@@ -39,7 +39,8 b' from rhodecode.lib.vcs.utils.helpers imp' | |||||
39 | from rhodecode.lib.vcs.exceptions import VCSError |
|
39 | from rhodecode.lib.vcs.exceptions import VCSError | |
40 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
40 | from rhodecode.lib.vcs.utils.lazy import LazyProperty | |
41 |
|
41 | |||
42 |
from rhodecode.lib import str2bool, safe_str, get_changeset_safe, |
|
42 | from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \ | |
|
43 | safe_unicode | |||
43 | from rhodecode.lib.compat import json |
|
44 | from rhodecode.lib.compat import json | |
44 | from rhodecode.lib.caching_query import FromCache |
|
45 | from rhodecode.lib.caching_query import FromCache | |
45 |
|
46 |
@@ -32,6 +32,7 b' import datetime' | |||||
32 | from pylons.i18n.translation import _ |
|
32 | from pylons.i18n.translation import _ | |
33 |
|
33 | |||
34 | import rhodecode |
|
34 | import rhodecode | |
|
35 | from rhodecode.config.conf import DATETIME_FORMAT | |||
35 | from rhodecode.lib import helpers as h |
|
36 | from rhodecode.lib import helpers as h | |
36 | from rhodecode.model import BaseModel |
|
37 | from rhodecode.model import BaseModel | |
37 | from rhodecode.model.db import Notification, User, UserNotification |
|
38 | from rhodecode.model.db import Notification, User, UserNotification | |
@@ -176,8 +177,6 b' class NotificationModel(BaseModel):' | |||||
176 | notification.TYPE_REGISTRATION: _('registered in RhodeCode') |
|
177 | notification.TYPE_REGISTRATION: _('registered in RhodeCode') | |
177 | } |
|
178 | } | |
178 |
|
179 | |||
179 | DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" |
|
|||
180 |
|
||||
181 | tmpl = "%(user)s %(action)s %(when)s" |
|
180 | tmpl = "%(user)s %(action)s %(when)s" | |
182 | if show_age: |
|
181 | if show_age: | |
183 | when = h.age(notification.created_on) |
|
182 | when = h.age(notification.created_on) |
@@ -30,8 +30,7 b' from datetime import datetime' | |||||
30 |
|
30 | |||
31 | from rhodecode.lib.vcs.backends import get_backend |
|
31 | from rhodecode.lib.vcs.backends import get_backend | |
32 |
|
32 | |||
33 | from rhodecode.lib import LazyProperty |
|
33 | from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode | |
34 | from rhodecode.lib import safe_str, safe_unicode |
|
|||
35 | from rhodecode.lib.caching_query import FromCache |
|
34 | from rhodecode.lib.caching_query import FromCache | |
36 | from rhodecode.lib.hooks import log_create_repository |
|
35 | from rhodecode.lib.hooks import log_create_repository | |
37 |
|
36 |
@@ -28,7 +28,7 b' import logging' | |||||
28 | import traceback |
|
28 | import traceback | |
29 | import shutil |
|
29 | import shutil | |
30 |
|
30 | |||
31 | from rhodecode.lib import LazyProperty |
|
31 | from rhodecode.lib.utils2 import LazyProperty | |
32 |
|
32 | |||
33 | from rhodecode.model import BaseModel |
|
33 | from rhodecode.model import BaseModel | |
34 | from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \ |
|
34 | from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \ |
@@ -35,7 +35,7 b' from rhodecode.lib.vcs.nodes import File' | |||||
35 |
|
35 | |||
36 | from rhodecode import BACKENDS |
|
36 | from rhodecode import BACKENDS | |
37 | from rhodecode.lib import helpers as h |
|
37 | from rhodecode.lib import helpers as h | |
38 | from rhodecode.lib import safe_str |
|
38 | from rhodecode.lib.utils2 import safe_str | |
39 | from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny |
|
39 | from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny | |
40 | from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \ |
|
40 | from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \ | |
41 | action_logger, EmptyChangeset, REMOVED_REPO_PAT |
|
41 | action_logger, EmptyChangeset, REMOVED_REPO_PAT |
@@ -29,7 +29,7 b' import traceback' | |||||
29 | from pylons import url |
|
29 | from pylons import url | |
30 | from pylons.i18n.translation import _ |
|
30 | from pylons.i18n.translation import _ | |
31 |
|
31 | |||
32 | from rhodecode.lib import safe_unicode |
|
32 | from rhodecode.lib.utils2 import safe_unicode, generate_api_key | |
33 | from rhodecode.lib.caching_query import FromCache |
|
33 | from rhodecode.lib.caching_query import FromCache | |
34 |
|
34 | |||
35 | from rhodecode.model import BaseModel |
|
35 | from rhodecode.model import BaseModel | |
@@ -40,7 +40,7 b' from rhodecode.lib.exceptions import Def' | |||||
40 | UserOwnsReposException |
|
40 | UserOwnsReposException | |
41 |
|
41 | |||
42 | from sqlalchemy.exc import DatabaseError |
|
42 | from sqlalchemy.exc import DatabaseError | |
43 | from rhodecode.lib import generate_api_key |
|
43 | ||
44 | from sqlalchemy.orm import joinedload |
|
44 | from sqlalchemy.orm import joinedload | |
45 |
|
45 | |||
46 | log = logging.getLogger(__name__) |
|
46 | log = logging.getLogger(__name__) |
@@ -3112,7 +3112,12 b' table.code-browser .browser-dir {' | |||||
3112 | top: 5px; |
|
3112 | top: 5px; | |
3113 | width: 16px; |
|
3113 | width: 16px; | |
3114 | } |
|
3114 | } | |
3115 |
|
3115 | div#legend_data{ | ||
|
3116 | padding-left:10px; | |||
|
3117 | } | |||
|
3118 | div#legend_container table{ | |||
|
3119 | border: none !important; | |||
|
3120 | } | |||
3116 | div#legend_container table,div#legend_choices table { |
|
3121 | div#legend_container table,div#legend_choices table { | |
3117 | width: auto !important; |
|
3122 | width: auto !important; | |
3118 | } |
|
3123 | } |
@@ -1,10 +1,11 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | from rhodecode.tests import * |
|
2 | from rhodecode.tests import * | |
3 | from rhodecode.model.db import User, Notification |
|
3 | from rhodecode.model.db import User, Notification | |
4 | from rhodecode.lib import generate_api_key |
|
4 | from rhodecode.lib.utils2 import generate_api_key | |
5 | from rhodecode.lib.auth import check_password |
|
5 | from rhodecode.lib.auth import check_password | |
6 | from rhodecode.model.meta import Session |
|
6 | from rhodecode.model.meta import Session | |
7 |
|
7 | |||
|
8 | ||||
8 | class TestLoginController(TestController): |
|
9 | class TestLoginController(TestController): | |
9 |
|
10 | |||
10 | def tearDown(self): |
|
11 | def tearDown(self): |
@@ -65,22 +65,20 b' TEST_URLS += [' | |||||
65 |
|
65 | |||
66 | class TestLibs(unittest.TestCase): |
|
66 | class TestLibs(unittest.TestCase): | |
67 |
|
67 | |||
68 |
|
||||
69 | def test_uri_filter(self): |
|
68 | def test_uri_filter(self): | |
70 | from rhodecode.lib import uri_filter |
|
69 | from rhodecode.lib.utils2 import uri_filter | |
71 |
|
70 | |||
72 | for url in TEST_URLS: |
|
71 | for url in TEST_URLS: | |
73 | self.assertEqual(uri_filter(url[0]), url[1]) |
|
72 | self.assertEqual(uri_filter(url[0]), url[1]) | |
74 |
|
73 | |||
75 | def test_credentials_filter(self): |
|
74 | def test_credentials_filter(self): | |
76 | from rhodecode.lib import credentials_filter |
|
75 | from rhodecode.lib.utils2 import credentials_filter | |
77 |
|
76 | |||
78 | for url in TEST_URLS: |
|
77 | for url in TEST_URLS: | |
79 | self.assertEqual(credentials_filter(url[0]), url[2]) |
|
78 | self.assertEqual(credentials_filter(url[0]), url[2]) | |
80 |
|
79 | |||
81 |
|
||||
82 | def test_str2bool(self): |
|
80 | def test_str2bool(self): | |
83 | from rhodecode.lib import str2bool |
|
81 | from rhodecode.lib.utils2 import str2bool | |
84 | test_cases = [ |
|
82 | test_cases = [ | |
85 | ('t', True), |
|
83 | ('t', True), | |
86 | ('true', True), |
|
84 | ('true', True), | |
@@ -103,9 +101,8 b' class TestLibs(unittest.TestCase):' | |||||
103 | for case in test_cases: |
|
101 | for case in test_cases: | |
104 | self.assertEqual(str2bool(case[0]), case[1]) |
|
102 | self.assertEqual(str2bool(case[0]), case[1]) | |
105 |
|
103 | |||
106 |
|
||||
107 | def test_mention_extractor(self): |
|
104 | def test_mention_extractor(self): | |
108 | from rhodecode.lib import extract_mentioned_users |
|
105 | from rhodecode.lib.utils2 import extract_mentioned_users | |
109 | sample = ("@first hi there @marcink here's my email marcin@email.com " |
|
106 | sample = ("@first hi there @marcink here's my email marcin@email.com " | |
110 | "@lukaszb check it pls @ ttwelve @D[] @one@two@three " |
|
107 | "@lukaszb check it pls @ ttwelve @D[] @one@two@three " | |
111 | "@MARCIN @maRCiN @2one_more22") |
|
108 | "@MARCIN @maRCiN @2one_more22") |
General Comments 0
You need to be logged in to leave comments.
Login now