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