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 | 3 | import os |
|
4 | 4 | import logging |
|
5 | import rhodecode | |
|
5 | 6 | |
|
6 | 7 | from mako.lookup import TemplateLookup |
|
7 | 8 | from pylons.configuration import PylonsConfig |
|
8 | 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 | 14 | import rhodecode.lib.app_globals as app_globals |
|
12 | import rhodecode.lib.helpers | |
|
13 | 15 | |
|
14 | 16 | from rhodecode.config.routing import make_map |
|
15 | # don't remove this import it does magic for celery | |
|
16 |
from rhodecode.lib import |
|
|
17 | from rhodecode.lib import engine_from_config | |
|
17 | ||
|
18 | from rhodecode.lib import helpers | |
|
18 | 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 | 23 | from rhodecode.model import init_model |
|
21 | 24 | from rhodecode.model.scm import ScmModel |
|
22 | from rhodecode.lib.vcs.utils.fakemod import create_module | |
|
23 | 25 | |
|
24 | 26 | log = logging.getLogger(__name__) |
|
25 | 27 | |
|
26 | 28 | |
|
27 | 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 | 32 | object |
|
30 | 33 | """ |
|
31 | 34 | config = PylonsConfig() |
|
32 | 35 | |
|
33 | 36 | # Pylons paths |
|
34 | 37 | root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
|
35 |
paths = dict( |
|
|
38 | paths = dict( | |
|
39 | root=root, | |
|
36 | 40 |
|
|
37 | 41 |
|
|
38 |
|
|
|
42 | templates=[os.path.join(root, 'templates')] | |
|
43 | ) | |
|
39 | 44 | |
|
40 | 45 | # Initialize config with the basic options |
|
41 | 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 | 51 | config['routes.map'] = make_map(config) |
|
47 | 52 | config['pylons.app_globals'] = app_globals.Globals(config) |
|
48 |
config['pylons.h'] = |
|
|
53 | config['pylons.h'] = helpers | |
|
49 | 54 | rhodecode.CONFIG = config |
|
50 | 55 | |
|
51 | path = os.path.join(config['here'], 'rcextensions', '__init__.py') | |
|
52 | if os.path.isfile(path): | |
|
53 | rcext = create_module('rc', path) | |
|
54 | rhodecode.EXTENSIONS = rcext | |
|
55 | log.debug('Found rcextensions now loading %s...' % rcext) | |
|
56 | load_rcextensions(root_path=config['here']) | |
|
57 | ||
|
56 | 58 | # Setup cache object as early as possible |
|
57 | 59 | import pylons |
|
58 | 60 | pylons.cache._push_object(config['pylons.app_globals'].cache) |
@@ -77,5 +77,3 b' class MakeRcExt(BasePasterCommand):' | |||
|
77 | 77 | |
|
78 | 78 | def update_parser(self): |
|
79 | 79 | pass |
|
80 | ||
|
81 |
@@ -32,8 +32,9 b' from pylons import request, session, tmp' | |||
|
32 | 32 | from pylons.controllers.util import abort, redirect |
|
33 | 33 | from pylons.i18n.translation import _ |
|
34 | 34 | |
|
35 | from rhodecode.lib import helpers as h | |
|
35 | 36 | from rhodecode.lib.exceptions import UsersGroupsAssignedException |
|
36 |
from rhodecode.lib import |
|
|
37 | from rhodecode.lib.utils2 import safe_unicode | |
|
37 | 38 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
38 | 39 | from rhodecode.lib.base import BaseController, render |
|
39 | 40 |
@@ -31,7 +31,7 b' import binascii' | |||
|
31 | 31 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
32 | 32 | from rhodecode.lib.base import BaseRepoController, render |
|
33 | 33 | from rhodecode.lib.compat import OrderedDict |
|
34 | from rhodecode.lib import safe_unicode | |
|
34 | from rhodecode.lib.utils2 import safe_unicode | |
|
35 | 35 | log = logging.getLogger(__name__) |
|
36 | 36 | |
|
37 | 37 |
@@ -28,7 +28,7 b' import logging' | |||
|
28 | 28 | from pylons import url, response, tmpl_context as c |
|
29 | 29 | from pylons.i18n.translation import _ |
|
30 | 30 | |
|
31 | from rhodecode.lib import safe_unicode | |
|
31 | from rhodecode.lib.utils2 import safe_unicode | |
|
32 | 32 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
33 | 33 | from rhodecode.lib.base import BaseRepoController |
|
34 | 34 |
@@ -32,24 +32,26 b' from pylons.i18n.translation import _' | |||
|
32 | 32 | from pylons.controllers.util import redirect |
|
33 | 33 | from pylons.decorators import jsonify |
|
34 | 34 | |
|
35 |
from rhodecode.lib |
|
|
36 | from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \ | |
|
37 | EmptyRepositoryError, ImproperArchiveTypeError, VCSError, \ | |
|
38 | NodeAlreadyExistsError | |
|
39 | from rhodecode.lib.vcs.nodes import FileNode | |
|
35 | from rhodecode.lib import diffs | |
|
36 | from rhodecode.lib import helpers as h | |
|
40 | 37 | |
|
41 | 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 | 40 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
44 | 41 | from rhodecode.lib.base import BaseRepoController, render |
|
45 | 42 | from rhodecode.lib.utils import EmptyChangeset |
|
46 |
from rhodecode.lib import |
|
|
47 | import rhodecode.lib.helpers as h | |
|
43 | from rhodecode.lib.vcs.conf import settings | |
|
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 | 49 | from rhodecode.model.repo import RepoModel |
|
50 | from rhodecode.model.scm import ScmModel | |
|
51 | ||
|
49 | 52 | from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\ |
|
50 | 53 | _context_url, get_line_ctx, get_ignore_ws |
|
51 | from rhodecode.lib.diffs import wrapped_diff | |
|
52 | from rhodecode.model.scm import ScmModel | |
|
54 | ||
|
53 | 55 | |
|
54 | 56 | log = logging.getLogger(__name__) |
|
55 | 57 | |
@@ -447,7 +449,7 b' class FilesController(BaseRepoController' | |||
|
447 | 449 | ign_whitespace_lcl = get_ignore_ws(fid, request.GET) |
|
448 | 450 | |
|
449 | 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 | 453 | filenode_new=node2, |
|
452 | 454 | cut_off_limit=lim, |
|
453 | 455 | ignore_whitespace=ign_whitespace_lcl, |
@@ -40,15 +40,15 b' from pylons.i18n.translation import _' | |||
|
40 | 40 | |
|
41 | 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 | 44 | from rhodecode.model.db import Statistics, CacheInvalidation |
|
44 |
from rhodecode.lib import |
|
|
45 | from rhodecode.lib.utils2 import safe_unicode | |
|
45 | 46 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
46 | 47 | from rhodecode.lib.base import BaseRepoController, render |
|
47 | 48 | from rhodecode.lib.utils import EmptyChangeset |
|
48 | 49 | from rhodecode.lib.markup_renderer import MarkupRenderer |
|
49 | 50 | from rhodecode.lib.celerylib import run_task |
|
50 |
from rhodecode.lib.celerylib.tasks import get_commits_stats |
|
|
51 | LANGUAGES_EXTENSIONS_MAP | |
|
51 | from rhodecode.lib.celerylib.tasks import get_commits_stats | |
|
52 | 52 | from rhodecode.lib.helpers import RepoPage |
|
53 | 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 |
|
|
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 | 4 | def get_current_revision(quiet=False): |
@@ -462,16 +22,3 b' def get_current_revision(quiet=False):' | |||
|
462 | 22 | print ("Cannot retrieve rhodecode's revision. Original error " |
|
463 | 23 | "was: %s" % err) |
|
464 | 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 | 43 | if __platform__ in PLATFORM_OTHERS: |
|
44 | 44 | import bcrypt |
|
45 | 45 | |
|
46 | from rhodecode.lib import str2bool, safe_unicode | |
|
46 | from rhodecode.lib.utils2 import str2bool, safe_unicode | |
|
47 | 47 | from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError |
|
48 | 48 | from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug |
|
49 | 49 | from rhodecode.lib.auth_ldap import AuthLdap |
@@ -15,7 +15,7 b' from pylons.templating import render_mak' | |||
|
15 | 15 | |
|
16 | 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 | 19 | from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\ |
|
20 | 20 | HasPermissionAnyMiddleware, CookieStoreWrapper |
|
21 | 21 | from rhodecode.lib.utils import get_repo_slug, invalidate_cache |
@@ -24,7 +24,7 b' from beaker.exceptions import BeakerExce' | |||
|
24 | 24 | from sqlalchemy.orm.interfaces import MapperOption |
|
25 | 25 | from sqlalchemy.orm.query import Query |
|
26 | 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 | 30 | class CachingQuery(Query): |
@@ -36,7 +36,7 b' from decorator import decorator' | |||
|
36 | 36 | |
|
37 | 37 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
38 | 38 | from rhodecode import CELERY_ON |
|
39 | from rhodecode.lib import str2bool, safe_str | |
|
39 | from rhodecode.lib.utils2 import str2bool, safe_str | |
|
40 | 40 | from rhodecode.lib.pidlock import DaemonLock, LockHeld |
|
41 | 41 | from rhodecode.model import init_model |
|
42 | 42 | from rhodecode.model import meta |
@@ -40,7 +40,7 b' from pylons.i18n.translation import _' | |||
|
40 | 40 | from rhodecode.lib.vcs import get_backend |
|
41 | 41 | |
|
42 | 42 | from rhodecode import CELERY_ON |
|
43 |
from rhodecode.lib import |
|
|
43 | from rhodecode.lib.utils2 import safe_str | |
|
44 | 44 | from rhodecode.lib.celerylib import run_task, locked_task, dbsession, \ |
|
45 | 45 | str2bool, __get_lockkey, LockHeld, DaemonLock, get_session |
|
46 | 46 | from rhodecode.lib.helpers import person |
@@ -147,6 +147,7 b' def get_commits_stats(repo_name, ts_min_' | |||
|
147 | 147 | last_rev, last_rev + parse_limit) |
|
148 | 148 | ) |
|
149 | 149 | for cs in repo[last_rev:last_rev + parse_limit]: |
|
150 | log.debug('parsing %s' % cs) | |
|
150 | 151 | last_cs = cs # remember last parsed changeset |
|
151 | 152 | k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1], |
|
152 | 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 | 396 | DBS.commit() |
|
396 | 397 | |
|
397 | 398 | def __get_codes_stats(repo_name): |
|
399 | from rhodecode.config.conf import LANGUAGES_EXTENSIONS_MAP | |
|
398 | 400 | repo = Repository.get_by_repo_name(repo_name).scm_instance |
|
399 | 401 | |
|
400 | 402 | tip = repo.get_changeset() |
@@ -1,9 +1,9 b'' | |||
|
1 | 1 | import rhodecode |
|
2 | from rhodecode.lib.utils import BasePasterCommand, Command | |
|
2 | from rhodecode.lib.utils import BasePasterCommand, Command, load_rcextensions | |
|
3 | 3 | from celery.app import app_or_default |
|
4 | 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 | 8 | __all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand', |
|
9 | 9 | 'CAMQPAdminCommand', 'CeleryEventCommand'] |
@@ -39,9 +39,11 b' class CeleryCommand(BasePasterCommand):' | |||
|
39 | 39 | raise Exception('Please enable celery_on in .ini config ' |
|
40 | 40 | 'file before running celeryd') |
|
41 | 41 | rhodecode.CELERY_ON = CELERY_ON |
|
42 | load_rcextensions(config['here']) | |
|
42 | 43 | cmd = self.celery_command(app_or_default()) |
|
43 | 44 | return cmd.run(**vars(self.options)) |
|
44 | 45 | |
|
46 | ||
|
45 | 47 | class CeleryDaemonCommand(CeleryCommand): |
|
46 | 48 | """Start the celery worker |
|
47 | 49 | |
@@ -82,6 +84,7 b' class CAMQPAdminCommand(CeleryCommand):' | |||
|
82 | 84 | parser = Command.standard_parser(quiet=True) |
|
83 | 85 | celery_command = camqadm.AMQPAdminCommand |
|
84 | 86 | |
|
87 | ||
|
85 | 88 | class CeleryEventCommand(CeleryCommand): |
|
86 | 89 | """Celery event command. |
|
87 | 90 |
@@ -71,9 +71,6 b' class InvalidScriptError(ScriptError):' | |||
|
71 | 71 | """Invalid script error.""" |
|
72 | 72 | |
|
73 | 73 | |
|
74 | class InvalidVersionError(Error): | |
|
75 | """Invalid version error.""" | |
|
76 | ||
|
77 | 74 | # migrate.changeset |
|
78 | 75 | |
|
79 | 76 | class NotSupportedError(Error): |
@@ -39,7 +39,7 b' from rhodecode.lib.vcs.utils.helpers imp' | |||
|
39 | 39 | from rhodecode.lib.vcs.exceptions import VCSError |
|
40 | 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 | 43 | generate_api_key, safe_unicode |
|
44 | 44 | from rhodecode.lib.exceptions import UsersGroupsAssignedException |
|
45 | 45 | from rhodecode.lib.compat import json |
@@ -717,7 +717,7 b' class Repository(Base, BaseModel):' | |||
|
717 | 717 | return repo |
|
718 | 718 | |
|
719 | 719 | |
|
720 |
class |
|
|
720 | class Group(Base, BaseModel): | |
|
721 | 721 | __tablename__ = 'groups' |
|
722 | 722 | __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'), |
|
723 | 723 | CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},) |
@@ -728,8 +728,7 b' class RepoGroup(Base, BaseModel):' | |||
|
728 | 728 | group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) |
|
729 | 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(' |
|
|
732 | ||
|
731 | parent_group = relationship('Group', remote_side=group_id) | |
|
733 | 732 | |
|
734 | 733 | def __init__(self, group_name='', parent_group=None): |
|
735 | 734 | self.group_name = group_name |
@@ -39,7 +39,8 b' from webhelpers.html.tags import _set_in' | |||
|
39 | 39 | |
|
40 | 40 | from rhodecode.lib.annotate import annotate_highlight |
|
41 | 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 | 44 | from rhodecode.lib.markup_renderer import MarkupRenderer |
|
44 | 45 | |
|
45 | 46 | log = logging.getLogger(__name__) |
@@ -319,7 +320,7 b' flash = _Flash()' | |||
|
319 | 320 | # SCM FILTERS available via h. |
|
320 | 321 | #============================================================================== |
|
321 | 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 | 324 | from rhodecode.model.db import User |
|
324 | 325 | |
|
325 | 326 | age = lambda x: _age(x) |
@@ -47,9 +47,9 b' from rhodecode.model import init_model' | |||
|
47 | 47 | from rhodecode.model.scm import ScmModel |
|
48 | 48 | from rhodecode.model.repo import RepoModel |
|
49 | 49 | from rhodecode.config.environment import load_environment |
|
50 | from rhodecode.lib import LANGUAGES_EXTENSIONS_MAP, INDEX_EXTENSIONS, \ | |
|
51 | LazyProperty | |
|
52 | from rhodecode.lib.utils import BasePasterCommand, Command, add_cache | |
|
50 | from rhodecode.lib.utils2 import LazyProperty | |
|
51 | from rhodecode.lib.utils import BasePasterCommand, Command, add_cache,\ | |
|
52 | load_rcextensions | |
|
53 | 53 | |
|
54 | 54 | # CUSTOM ANALYZER wordsplit + lowercase filter |
|
55 | 55 | ANALYZER = RegexTokenizer(expression=r"\w+") | LowercaseFilter() |
@@ -88,13 +88,12 b' class MakeIndex(BasePasterCommand):' | |||
|
88 | 88 | add_cache(config) |
|
89 | 89 | engine = engine_from_config(config, 'sqlalchemy.db1.') |
|
90 | 90 | init_model(engine) |
|
91 | ||
|
92 | 91 | index_location = config['index_dir'] |
|
93 | 92 | repo_location = self.options.repo_location \ |
|
94 | 93 | if self.options.repo_location else RepoModel().repos_path |
|
95 | 94 | repo_list = map(strip, self.options.repo_list.split(',')) \ |
|
96 | 95 | if self.options.repo_list else None |
|
97 | ||
|
96 | load_rcextensions(config['here']) | |
|
98 | 97 | #====================================================================== |
|
99 | 98 | # WHOOSH DAEMON |
|
100 | 99 | #====================================================================== |
@@ -104,7 +103,7 b' class MakeIndex(BasePasterCommand):' | |||
|
104 | 103 | l = DaemonLock(file_=jn(dn(dn(index_location)), 'make_index.lock')) |
|
105 | 104 | WhooshIndexingDaemon(index_location=index_location, |
|
106 | 105 | repo_location=repo_location, |
|
107 | repo_list=repo_list)\ | |
|
106 | repo_list=repo_list,)\ | |
|
108 | 107 | .run(full_index=self.options.full_index) |
|
109 | 108 | l.release() |
|
110 | 109 | except LockHeld: |
@@ -38,10 +38,10 b' from os.path import join as jn' | |||
|
38 | 38 | project_path = dn(dn(dn(dn(os.path.realpath(__file__))))) |
|
39 | 39 | sys.path.append(project_path) |
|
40 | 40 | |
|
41 | ||
|
41 | from rhodecode.config.conf import INDEX_EXTENSIONS | |
|
42 | 42 | from rhodecode.model.scm import ScmModel |
|
43 | from rhodecode.lib import safe_unicode | |
|
44 |
from rhodecode.lib.indexers import |
|
|
43 | from rhodecode.lib.utils2 import safe_unicode | |
|
44 | from rhodecode.lib.indexers import SCHEMA, IDX_NAME | |
|
45 | 45 | |
|
46 | 46 | from rhodecode.lib.vcs.exceptions import ChangesetError, RepositoryError, \ |
|
47 | 47 | NodeDoesNotExistError |
@@ -117,10 +117,9 b' class WhooshIndexingDaemon(object):' | |||
|
117 | 117 | """ |
|
118 | 118 | |
|
119 | 119 | node = self.get_node(repo, path) |
|
120 | ||
|
120 | indexed = indexed_w_content = 0 | |
|
121 | 121 | # we just index the content of chosen files, and skip binary files |
|
122 | 122 | if node.extension in INDEX_EXTENSIONS and not node.is_binary: |
|
123 | ||
|
124 | 123 | u_content = node.content |
|
125 | 124 | if not isinstance(u_content, unicode): |
|
126 | 125 | log.warning(' >> %s Could not get this content as unicode ' |
@@ -128,11 +127,13 b' class WhooshIndexingDaemon(object):' | |||
|
128 | 127 | u_content = u'' |
|
129 | 128 | else: |
|
130 | 129 | log.debug(' >> %s [WITH CONTENT]' % path) |
|
130 | indexed_w_content += 1 | |
|
131 | 131 | |
|
132 | 132 | else: |
|
133 | 133 | log.debug(' >> %s' % path) |
|
134 | 134 | # just index file name without it's content |
|
135 | 135 | u_content = u'' |
|
136 | indexed += 1 | |
|
136 | 137 | |
|
137 | 138 | writer.add_document( |
|
138 | 139 | owner=unicode(repo.contact), |
@@ -142,6 +143,7 b' class WhooshIndexingDaemon(object):' | |||
|
142 | 143 | modtime=self.get_node_mtime(node), |
|
143 | 144 | extension=node.extension |
|
144 | 145 | ) |
|
146 | return indexed, indexed_w_content | |
|
145 | 147 | |
|
146 | 148 | def build_index(self): |
|
147 | 149 | if os.path.exists(self.index_location): |
@@ -153,19 +155,25 b' class WhooshIndexingDaemon(object):' | |||
|
153 | 155 | |
|
154 | 156 | idx = create_in(self.index_location, SCHEMA, indexname=IDX_NAME) |
|
155 | 157 | writer = idx.writer() |
|
156 | ||
|
158 | log.debug('BUILDIN INDEX FOR EXTENSIONS %s' % INDEX_EXTENSIONS) | |
|
157 | 159 | for repo_name, repo in self.repo_paths.items(): |
|
158 | 160 | log.debug('building index @ %s' % repo.path) |
|
159 | ||
|
161 | i_cnt = iwc_cnt = 0 | |
|
160 | 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 | 170 | log.debug('>> COMMITING CHANGES <<') |
|
164 | 171 | writer.commit(merge=True) |
|
165 | 172 | log.debug('>>> FINISHED BUILDING INDEX <<<') |
|
166 | 173 | |
|
167 | 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 | 178 | idx = open_dir(self.index_location, indexname=self.indexname) |
|
171 | 179 | # The set of all paths in the index |
@@ -204,14 +212,19 b' class WhooshIndexingDaemon(object):' | |||
|
204 | 212 | # Loop over the files in the filesystem |
|
205 | 213 | # Assume we have a function that gathers the filenames of the |
|
206 | 214 | # documents to be indexed |
|
215 | ri_cnt = riwc_cnt = 0 | |
|
207 | 216 | for repo_name, repo in self.repo_paths.items(): |
|
208 | 217 | for path in self.get_paths(repo): |
|
209 | 218 | if path in to_index or path not in indexed_paths: |
|
210 | 219 | # This is either a file that's changed, or a new file |
|
211 | 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 | 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 | 228 | log.debug('>> COMMITING CHANGES <<') |
|
216 | 229 | writer.commit(merge=True) |
|
217 | 230 | log.debug('>>> FINISHED REBUILDING INDEX <<<') |
@@ -27,7 +27,7 b'' | |||
|
27 | 27 | import re |
|
28 | 28 | import logging |
|
29 | 29 | |
|
30 | from rhodecode.lib import safe_unicode | |
|
30 | from rhodecode.lib.utils2 import safe_unicode | |
|
31 | 31 | |
|
32 | 32 | log = logging.getLogger(__name__) |
|
33 | 33 |
@@ -23,7 +23,7 b'' | |||
|
23 | 23 | # You should have received a copy of the GNU General Public License |
|
24 | 24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
25 | 25 | |
|
26 | from rhodecode.lib import str2bool | |
|
26 | from rhodecode.lib.utils2 import str2bool | |
|
27 | 27 | |
|
28 | 28 | |
|
29 | 29 | class HttpsFixup(object): |
@@ -69,7 +69,7 b' from dulwich.web import HTTPGitApplicati' | |||
|
69 | 69 | |
|
70 | 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 | 73 | from rhodecode.lib.base import BaseVCSController |
|
74 | 74 | from rhodecode.lib.auth import get_container_username |
|
75 | 75 | from rhodecode.lib.utils import is_valid_repo |
@@ -34,7 +34,7 b' from mercurial.hgweb import hgweb_mod' | |||
|
34 | 34 | |
|
35 | 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 | 38 | from rhodecode.lib.base import BaseVCSController |
|
39 | 39 | from rhodecode.lib.auth import get_container_username |
|
40 | 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 | 54 | UserLog, RepoGroup, RhodeCodeSetting, UserRepoGroupToPerm |
|
55 | 55 | from rhodecode.model.meta import Session |
|
56 | 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 | 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 | 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 | 69 | :param str_: given string |
|
68 | 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 | 84 | def repo_name_slug(value): |
|
83 | """Return slug of name of repository | |
|
85 | """ | |
|
86 | Return slug of name of repository | |
|
84 | 87 | This function is called on each creation/modification |
|
85 | 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 | 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 | 271 | and make an mercurial ui object from read options |
|
268 | 272 | |
|
269 | 273 | :param path: path to mercurial config file |
@@ -489,6 +493,30 b' def add_cache(settings):' | |||
|
489 | 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 | 521 | # TEST FUNCTIONS AND CREATORS |
|
494 | 522 | #============================================================================== |
@@ -29,7 +29,7 b' import traceback' | |||
|
29 | 29 | from pylons.i18n.translation import _ |
|
30 | 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 | 33 | from rhodecode.lib import helpers as h |
|
34 | 34 | from rhodecode.model import BaseModel |
|
35 | 35 | from rhodecode.model.db import ChangesetComment, User, Repository, Notification |
@@ -39,7 +39,8 b' from rhodecode.lib.vcs.utils.helpers imp' | |||
|
39 | 39 | from rhodecode.lib.vcs.exceptions import VCSError |
|
40 | 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 | 44 | from rhodecode.lib.compat import json |
|
44 | 45 | from rhodecode.lib.caching_query import FromCache |
|
45 | 46 |
@@ -32,6 +32,7 b' import datetime' | |||
|
32 | 32 | from pylons.i18n.translation import _ |
|
33 | 33 | |
|
34 | 34 | import rhodecode |
|
35 | from rhodecode.config.conf import DATETIME_FORMAT | |
|
35 | 36 | from rhodecode.lib import helpers as h |
|
36 | 37 | from rhodecode.model import BaseModel |
|
37 | 38 | from rhodecode.model.db import Notification, User, UserNotification |
@@ -176,8 +177,6 b' class NotificationModel(BaseModel):' | |||
|
176 | 177 | notification.TYPE_REGISTRATION: _('registered in RhodeCode') |
|
177 | 178 | } |
|
178 | 179 | |
|
179 | DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" | |
|
180 | ||
|
181 | 180 | tmpl = "%(user)s %(action)s %(when)s" |
|
182 | 181 | if show_age: |
|
183 | 182 | when = h.age(notification.created_on) |
@@ -30,8 +30,7 b' from datetime import datetime' | |||
|
30 | 30 | |
|
31 | 31 | from rhodecode.lib.vcs.backends import get_backend |
|
32 | 32 | |
|
33 | from rhodecode.lib import LazyProperty | |
|
34 | from rhodecode.lib import safe_str, safe_unicode | |
|
33 | from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode | |
|
35 | 34 | from rhodecode.lib.caching_query import FromCache |
|
36 | 35 | from rhodecode.lib.hooks import log_create_repository |
|
37 | 36 |
@@ -28,7 +28,7 b' import logging' | |||
|
28 | 28 | import traceback |
|
29 | 29 | import shutil |
|
30 | 30 | |
|
31 | from rhodecode.lib import LazyProperty | |
|
31 | from rhodecode.lib.utils2 import LazyProperty | |
|
32 | 32 | |
|
33 | 33 | from rhodecode.model import BaseModel |
|
34 | 34 | from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \ |
@@ -35,7 +35,7 b' from rhodecode.lib.vcs.nodes import File' | |||
|
35 | 35 | |
|
36 | 36 | from rhodecode import BACKENDS |
|
37 | 37 | from rhodecode.lib import helpers as h |
|
38 | from rhodecode.lib import safe_str | |
|
38 | from rhodecode.lib.utils2 import safe_str | |
|
39 | 39 | from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny |
|
40 | 40 | from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \ |
|
41 | 41 | action_logger, EmptyChangeset, REMOVED_REPO_PAT |
@@ -29,7 +29,7 b' import traceback' | |||
|
29 | 29 | from pylons import url |
|
30 | 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 | 33 | from rhodecode.lib.caching_query import FromCache |
|
34 | 34 | |
|
35 | 35 | from rhodecode.model import BaseModel |
@@ -40,7 +40,7 b' from rhodecode.lib.exceptions import Def' | |||
|
40 | 40 | UserOwnsReposException |
|
41 | 41 | |
|
42 | 42 | from sqlalchemy.exc import DatabaseError |
|
43 | from rhodecode.lib import generate_api_key | |
|
43 | ||
|
44 | 44 | from sqlalchemy.orm import joinedload |
|
45 | 45 | |
|
46 | 46 | log = logging.getLogger(__name__) |
@@ -3112,7 +3112,12 b' table.code-browser .browser-dir {' | |||
|
3112 | 3112 | top: 5px; |
|
3113 | 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 | 3121 | div#legend_container table,div#legend_choices table { |
|
3117 | 3122 | width: auto !important; |
|
3118 | 3123 | } |
@@ -1,10 +1,11 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | from rhodecode.tests import * |
|
3 | 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 | 5 | from rhodecode.lib.auth import check_password |
|
6 | 6 | from rhodecode.model.meta import Session |
|
7 | 7 | |
|
8 | ||
|
8 | 9 | class TestLoginController(TestController): |
|
9 | 10 | |
|
10 | 11 | def tearDown(self): |
@@ -65,22 +65,20 b' TEST_URLS += [' | |||
|
65 | 65 | |
|
66 | 66 | class TestLibs(unittest.TestCase): |
|
67 | 67 | |
|
68 | ||
|
69 | 68 | def test_uri_filter(self): |
|
70 | from rhodecode.lib import uri_filter | |
|
69 | from rhodecode.lib.utils2 import uri_filter | |
|
71 | 70 | |
|
72 | 71 | for url in TEST_URLS: |
|
73 | 72 | self.assertEqual(uri_filter(url[0]), url[1]) |
|
74 | 73 | |
|
75 | 74 | def test_credentials_filter(self): |
|
76 | from rhodecode.lib import credentials_filter | |
|
75 | from rhodecode.lib.utils2 import credentials_filter | |
|
77 | 76 | |
|
78 | 77 | for url in TEST_URLS: |
|
79 | 78 | self.assertEqual(credentials_filter(url[0]), url[2]) |
|
80 | 79 | |
|
81 | ||
|
82 | 80 | def test_str2bool(self): |
|
83 | from rhodecode.lib import str2bool | |
|
81 | from rhodecode.lib.utils2 import str2bool | |
|
84 | 82 | test_cases = [ |
|
85 | 83 | ('t', True), |
|
86 | 84 | ('true', True), |
@@ -103,9 +101,8 b' class TestLibs(unittest.TestCase):' | |||
|
103 | 101 | for case in test_cases: |
|
104 | 102 | self.assertEqual(str2bool(case[0]), case[1]) |
|
105 | 103 | |
|
106 | ||
|
107 | 104 | def test_mention_extractor(self): |
|
108 | from rhodecode.lib import extract_mentioned_users | |
|
105 | from rhodecode.lib.utils2 import extract_mentioned_users | |
|
109 | 106 | sample = ("@first hi there @marcink here's my email marcin@email.com " |
|
110 | 107 | "@lukaszb check it pls @ ttwelve @D[] @one@two@three " |
|
111 | 108 | "@MARCIN @maRCiN @2one_more22") |
General Comments 0
You need to be logged in to leave comments.
Login now