Show More
@@ -20,6 +20,9 b' fixes' | |||||
20 | - fixes for issues #137 and #116 |
|
20 | - fixes for issues #137 and #116 | |
21 | - fixes crashes on gravatar, when passed in email as unicode |
|
21 | - fixes crashes on gravatar, when passed in email as unicode | |
22 | - fixed tooltip flickering problems |
|
22 | - fixed tooltip flickering problems | |
|
23 | - fixed came_from redirection on windows | |||
|
24 | - fixed logging modules,and sql formatters | |||
|
25 | - windows fixes for os.kill and path spliting, issues #148 and #133 | |||
23 |
|
26 | |||
24 | 1.1.7 (**2011-03-23**) |
|
27 | 1.1.7 (**2011-03-23**) | |
25 | ====================== |
|
28 | ====================== |
@@ -31,8 +31,8 b' VERSION = (1, 1, 8)' | |||||
31 | __platform__ = platform.system() |
|
31 | __platform__ = platform.system() | |
32 | __license__ = 'GPLv3' |
|
32 | __license__ = 'GPLv3' | |
33 |
|
33 | |||
34 |
PLATFORM_WIN = ('Windows' |
|
34 | PLATFORM_WIN = ('Windows') | |
35 | PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD',) |
|
35 | PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD') | |
36 |
|
36 | |||
37 | try: |
|
37 | try: | |
38 | from rhodecode.lib.utils import get_current_revision |
|
38 | from rhodecode.lib.utils import get_current_revision | |
@@ -52,5 +52,5 b' def get_version():' | |||||
52 |
|
52 | |||
53 | BACKENDS = { |
|
53 | BACKENDS = { | |
54 | 'hg': 'Mercurial repository', |
|
54 | 'hg': 'Mercurial repository', | |
55 | #'git': 'Git repository', |
|
55 | #'git': 'Git repository', | |
56 | } |
|
56 | } |
@@ -23,20 +23,33 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 | def str2bool(s): |
|
26 | ||
27 | if s is None: |
|
27 | def str2bool(_str): | |
|
28 | """ | |||
|
29 | returs True/False value from given string, it tries to translate the | |||
|
30 | string into boolean | |||
|
31 | ||||
|
32 | :param _str: string value to translate into boolean | |||
|
33 | :rtype: boolean | |||
|
34 | :returns: boolean from given string | |||
|
35 | """ | |||
|
36 | if _str is None: | |||
28 | return False |
|
37 | return False | |
29 | if s in (True, False): |
|
38 | if _str in (True, False): | |
30 | return s |
|
39 | return _str | |
31 | s = str(s).strip().lower() |
|
40 | _str = str(_str).strip().lower() | |
32 | return s in ('t', 'true', 'y', 'yes', 'on', '1') |
|
41 | return _str in ('t', 'true', 'y', 'yes', 'on', '1') | |
|
42 | ||||
33 |
|
43 | |||
34 | def generate_api_key(username, salt=None): |
|
44 | def generate_api_key(username, salt=None): | |
35 | """ |
|
45 | """ | |
36 | Generates uniq API key for given username |
|
46 | Generates unique API key for given username,if salt is not given | |
|
47 | it'll be generated from some random string | |||
37 |
|
48 | |||
38 | :param username: username as string |
|
49 | :param username: username as string | |
39 | :param salt: salt to hash generate KEY |
|
50 | :param salt: salt to hash generate KEY | |
|
51 | :rtype: str | |||
|
52 | :returns: sha1 hash from username+salt | |||
40 | """ |
|
53 | """ | |
41 | from tempfile import _RandomNameSequence |
|
54 | from tempfile import _RandomNameSequence | |
42 | import hashlib |
|
55 | import hashlib | |
@@ -46,23 +59,23 b' def generate_api_key(username, salt=None' | |||||
46 |
|
59 | |||
47 | return hashlib.sha1(username + salt).hexdigest() |
|
60 | return hashlib.sha1(username + salt).hexdigest() | |
48 |
|
61 | |||
49 | def safe_unicode(_str): |
|
62 | ||
|
63 | def safe_unicode(_str, from_encoding='utf8'): | |||
50 | """ |
|
64 | """ | |
51 | safe unicode function. In case of UnicodeDecode error we try to return |
|
65 | safe unicode function. In case of UnicodeDecode error we try to return | |
52 |
unicode with errors replace |
|
66 | unicode with errors replace | |
53 | string_escape decoding |
|
67 | ||
|
68 | :param _str: string to decode | |||
|
69 | :rtype: unicode | |||
|
70 | :returns: unicode object | |||
54 | """ |
|
71 | """ | |
55 |
|
72 | |||
56 | if isinstance(_str, unicode): |
|
73 | if isinstance(_str, unicode): | |
57 | return _str |
|
74 | return _str | |
58 |
|
75 | |||
59 | try: |
|
76 | try: | |
60 | u_str = unicode(_str) |
|
77 | u_str = unicode(_str, from_encoding) | |
61 | except UnicodeDecodeError: |
|
78 | except UnicodeDecodeError: | |
62 | try: |
|
79 | u_str = unicode(_str, from_encoding, 'replace') | |
63 | u_str = _str.decode('utf-8', 'replace') |
|
|||
64 | except UnicodeDecodeError: |
|
|||
65 | #incase we have a decode error just represent as byte string |
|
|||
66 | u_str = unicode(_str.encode('string_escape')) |
|
|||
67 |
|
80 | |||
68 | return u_str No newline at end of file |
|
81 | return u_str |
@@ -354,14 +354,7 b' class LoginRequired(object):' | |||||
354 | return func(*fargs, **fkwargs) |
|
354 | return func(*fargs, **fkwargs) | |
355 | else: |
|
355 | else: | |
356 | log.warn('user %s not authenticated', user.username) |
|
356 | log.warn('user %s not authenticated', user.username) | |
357 |
|
357 | p = url.current() | ||
358 | p = '' |
|
|||
359 | if request.environ.get('SCRIPT_NAME') != '/': |
|
|||
360 | p += request.environ.get('SCRIPT_NAME') |
|
|||
361 |
|
||||
362 | p += request.environ.get('PATH_INFO') |
|
|||
363 | if request.environ.get('QUERY_STRING'): |
|
|||
364 | p += '?' + request.environ.get('QUERY_STRING') |
|
|||
365 |
|
358 | |||
366 | log.debug('redirecting to login page with %s', p) |
|
359 | log.debug('redirecting to login page with %s', p) | |
367 | return redirect(url('login_home', came_from=p)) |
|
360 | return redirect(url('login_home', came_from=p)) |
@@ -3,7 +3,7 b' import logging' | |||||
3 |
|
3 | |||
4 | BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38) |
|
4 | BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38) | |
5 |
|
5 | |||
6 |
# Sequences |
|
6 | # Sequences | |
7 | RESET_SEQ = "\033[0m" |
|
7 | RESET_SEQ = "\033[0m" | |
8 | COLOR_SEQ = "\033[1;%dm" |
|
8 | COLOR_SEQ = "\033[1;%dm" | |
9 | BOLD_SEQ = "\033[1m" |
|
9 | BOLD_SEQ = "\033[1m" | |
@@ -14,8 +14,35 b' COLORS = {' | |||||
14 | 'WARNING': CYAN, # level 30 |
|
14 | 'WARNING': CYAN, # level 30 | |
15 | 'INFO': GREEN, # level 20 |
|
15 | 'INFO': GREEN, # level 20 | |
16 | 'DEBUG': BLUE, # level 10 |
|
16 | 'DEBUG': BLUE, # level 10 | |
|
17 | 'SQL' : YELLOW | |||
17 | } |
|
18 | } | |
18 |
|
19 | |||
|
20 | def one_space_trim(s): | |||
|
21 | if s.find(" ") == -1: | |||
|
22 | return s | |||
|
23 | else: | |||
|
24 | s = s.replace(' ', ' ') | |||
|
25 | return one_space_trim(s) | |||
|
26 | ||||
|
27 | def format_sql(sql): | |||
|
28 | sql = sql.replace('\n', '') | |||
|
29 | sql = one_space_trim(sql) | |||
|
30 | sql = sql\ | |||
|
31 | .replace(',', ',\n\t')\ | |||
|
32 | .replace('SELECT', '\n\tSELECT \n\t')\ | |||
|
33 | .replace('UPDATE', '\n\tUPDATE \n\t')\ | |||
|
34 | .replace('DELETE', '\n\tDELETE \n\t')\ | |||
|
35 | .replace('FROM', '\n\tFROM')\ | |||
|
36 | .replace('ORDER BY', '\n\tORDER BY')\ | |||
|
37 | .replace('LIMIT', '\n\tLIMIT')\ | |||
|
38 | .replace('WHERE', '\n\tWHERE')\ | |||
|
39 | .replace('AND', '\n\tAND')\ | |||
|
40 | .replace('LEFT', '\n\tLEFT')\ | |||
|
41 | .replace('INNER', '\n\tINNER')\ | |||
|
42 | .replace('INSERT', '\n\tINSERT')\ | |||
|
43 | .replace('DELETE', '\n\tDELETE') | |||
|
44 | return sql | |||
|
45 | ||||
19 | class ColorFormatter(logging.Formatter): |
|
46 | class ColorFormatter(logging.Formatter): | |
20 |
|
47 | |||
21 | def __init__(self, *args, **kwargs): |
|
48 | def __init__(self, *args, **kwargs): | |
@@ -26,13 +53,30 b' class ColorFormatter(logging.Formatter):' | |||||
26 | """ |
|
53 | """ | |
27 | Changes record's levelname to use with COLORS enum |
|
54 | Changes record's levelname to use with COLORS enum | |
28 | """ |
|
55 | """ | |
29 |
|
56 | |||
30 | levelname = record.levelname |
|
57 | levelname = record.levelname | |
31 | start = COLOR_SEQ % (COLORS[levelname]) |
|
58 | start = COLOR_SEQ % (COLORS[levelname]) | |
32 | def_record = logging.Formatter.format(self, record) |
|
59 | def_record = logging.Formatter.format(self, record) | |
33 | end = RESET_SEQ |
|
60 | end = RESET_SEQ | |
34 |
|
61 | |||
35 | colored_record = start + def_record + end |
|
62 | colored_record = start + def_record + end | |
36 | return colored_record |
|
63 | return colored_record | |
37 |
|
64 | |||
38 | logging.ColorFormatter = ColorFormatter |
|
65 | ||
|
66 | class ColorFormatterSql(logging.Formatter): | |||
|
67 | ||||
|
68 | def __init__(self, *args, **kwargs): | |||
|
69 | # can't do super(...) here because Formatter is an old school class | |||
|
70 | logging.Formatter.__init__(self, *args, **kwargs) | |||
|
71 | ||||
|
72 | def format(self, record): | |||
|
73 | """ | |||
|
74 | Changes record's levelname to use with COLORS enum | |||
|
75 | """ | |||
|
76 | ||||
|
77 | start = COLOR_SEQ % (COLORS['SQL']) | |||
|
78 | def_record = format_sql(logging.Formatter.format(self, record)) | |||
|
79 | end = RESET_SEQ | |||
|
80 | ||||
|
81 | colored_record = start + def_record + end | |||
|
82 | return colored_record |
@@ -1,8 +1,15 b'' | |||||
1 | #!/usr/bin/env python |
|
1 | # -*- coding: utf-8 -*- | |
2 | # encoding: utf-8 |
|
2 | """ | |
3 | # Custom Exceptions modules |
|
3 | rhodecode.lib.exceptions | |
4 | # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> |
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~ | |
5 | # |
|
5 | ||
|
6 | Custom Exceptions modules | |||
|
7 | ||||
|
8 | :created_on: Apr 10, 2010 | |||
|
9 | :author: marcink | |||
|
10 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |||
|
11 | :license: GPLv3, see COPYING for more details. | |||
|
12 | """ | |||
6 | # This program is free software: you can redistribute it and/or modify |
|
13 | # This program is free software: you can redistribute it and/or modify | |
7 | # it under the terms of the GNU General Public License as published by |
|
14 | # it under the terms of the GNU General Public License as published by | |
8 | # the Free Software Foundation, either version 3 of the License, or |
|
15 | # the Free Software Foundation, either version 3 of the License, or | |
@@ -15,16 +22,27 b'' | |||||
15 | # |
|
22 | # | |
16 | # 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 | |
17 | # 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/>. | |
18 | """ |
|
25 | ||
19 | Created on Nov 17, 2010 |
|
26 | ||
20 | Custom Exceptions modules |
|
27 | class LdapUsernameError(Exception): | |
21 | @author: marcink |
|
28 | pass | |
22 | """ |
|
29 | ||
|
30 | ||||
|
31 | class LdapPasswordError(Exception): | |||
|
32 | pass | |||
|
33 | ||||
23 |
|
34 | |||
24 |
class Ldap |
|
35 | class LdapConnectionError(Exception): | |
25 | class LdapPasswordError(Exception):pass |
|
36 | pass | |
26 | class LdapConnectionError(Exception):pass |
|
37 | ||
27 | class LdapImportError(Exception):pass |
|
38 | ||
|
39 | class LdapImportError(Exception): | |||
|
40 | pass | |||
28 |
|
41 | |||
29 | class DefaultUserException(Exception):pass |
|
42 | ||
30 |
class User |
|
43 | class DefaultUserException(Exception): | |
|
44 | pass | |||
|
45 | ||||
|
46 | ||||
|
47 | class UserOwnsReposException(Exception): | |||
|
48 | pass |
@@ -4,6 +4,19 b' from warnings import warn' | |||||
4 | from multiprocessing.util import Finalize |
|
4 | from multiprocessing.util import Finalize | |
5 | import errno |
|
5 | import errno | |
6 |
|
6 | |||
|
7 | from rhodecode import __platform__, PLATFORM_WIN | |||
|
8 | ||||
|
9 | if __platform__ in PLATFORM_WIN: | |||
|
10 | import ctypes | |||
|
11 | def kill(pid): | |||
|
12 | """kill function for Win32""" | |||
|
13 | kernel32 = ctypes.windll.kernel32 | |||
|
14 | handle = kernel32.OpenProcess(1, 0, pid) | |||
|
15 | return (0 != kernel32.TerminateProcess(handle, 0)) | |||
|
16 | ||||
|
17 | else: | |||
|
18 | kill = os.kill | |||
|
19 | ||||
7 | class LockHeld(Exception):pass |
|
20 | class LockHeld(Exception):pass | |
8 |
|
21 | |||
9 |
|
22 | |||
@@ -58,9 +71,9 b' class DaemonLock(object):' | |||||
58 | pidfile = open(self.pidfile, "r") |
|
71 | pidfile = open(self.pidfile, "r") | |
59 | pidfile.seek(0) |
|
72 | pidfile.seek(0) | |
60 | running_pid = int(pidfile.readline()) |
|
73 | running_pid = int(pidfile.readline()) | |
61 |
|
74 | |||
62 | pidfile.close() |
|
75 | pidfile.close() | |
63 |
|
76 | |||
64 | if self.debug: |
|
77 | if self.debug: | |
65 | print 'lock file present running_pid: %s, checking for execution'\ |
|
78 | print 'lock file present running_pid: %s, checking for execution'\ | |
66 | % running_pid |
|
79 | % running_pid | |
@@ -68,19 +81,19 b' class DaemonLock(object):' | |||||
68 | # process PID |
|
81 | # process PID | |
69 | if running_pid: |
|
82 | if running_pid: | |
70 | try: |
|
83 | try: | |
71 |
|
|
84 | kill(running_pid, 0) | |
72 | except OSError, exc: |
|
85 | except OSError, exc: | |
73 | if exc.errno in (errno.ESRCH, errno.EPERM): |
|
86 | if exc.errno in (errno.ESRCH, errno.EPERM): | |
74 | print "Lock File is there but the program is not running" |
|
87 | print "Lock File is there but the program is not running" | |
75 |
print "Removing lock file for the: %s" % running_pid |
|
88 | print "Removing lock file for the: %s" % running_pid | |
76 | self.release() |
|
89 | self.release() | |
77 | else: |
|
90 | else: | |
78 | raise |
|
91 | raise | |
79 | else: |
|
92 | else: | |
80 | print "You already have an instance of the program running" |
|
93 | print "You already have an instance of the program running" | |
81 |
print "It is running as process %s" % running_pid |
|
94 | print "It is running as process %s" % running_pid | |
82 | raise LockHeld() |
|
95 | raise LockHeld() | |
83 |
|
96 | |||
84 | except IOError, e: |
|
97 | except IOError, e: | |
85 | if e.errno != 2: |
|
98 | if e.errno != 2: | |
86 | raise |
|
99 | raise | |
@@ -90,7 +103,7 b' class DaemonLock(object):' | |||||
90 | """ |
|
103 | """ | |
91 | if self.debug: |
|
104 | if self.debug: | |
92 | print 'trying to release the pidlock' |
|
105 | print 'trying to release the pidlock' | |
93 |
|
106 | |||
94 | if self.callbackfn: |
|
107 | if self.callbackfn: | |
95 | #execute callback function on release |
|
108 | #execute callback function on release | |
96 | if self.debug: |
|
109 | if self.debug: |
@@ -1,59 +1,28 b'' | |||||
1 | from sqlalchemy.interfaces import ConnectionProxy |
|
1 | from sqlalchemy.interfaces import ConnectionProxy | |
2 | import time |
|
2 | import time | |
3 | from sqlalchemy import log |
|
3 | import logging | |
|
4 | log = logging.getLogger('timerproxy') | |||
|
5 | ||||
4 | BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38) |
|
6 | BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38) | |
5 |
|
7 | |||
6 | def color_sql(sql): |
|
8 | def color_sql(sql): | |
7 | COLOR_SEQ = "\033[1;%dm" |
|
9 | COLOR_SEQ = "\033[1;%dm" | |
8 | COLOR_SQL = YELLOW |
|
10 | COLOR_SQL = YELLOW | |
9 | normal = '\x1b[0m' |
|
11 | normal = '\x1b[0m' | |
10 |
return COLOR_SEQ % COLOR_SQL + sql + normal |
|
12 | return COLOR_SEQ % COLOR_SQL + sql + normal | |
11 |
|
||||
12 | def one_space_trim(s): |
|
|||
13 | if s.find(" ") == -1: |
|
|||
14 | return s |
|
|||
15 | else: |
|
|||
16 | s = s.replace(' ', ' ') |
|
|||
17 | return one_space_trim(s) |
|
|||
18 |
|
||||
19 | def format_sql(sql): |
|
|||
20 | sql = color_sql(sql) |
|
|||
21 | sql = sql.replace('\n', '') |
|
|||
22 | sql = one_space_trim(sql) |
|
|||
23 | sql = sql\ |
|
|||
24 | .replace(',', ',\n\t')\ |
|
|||
25 | .replace('SELECT', '\n\tSELECT \n\t')\ |
|
|||
26 | .replace('UPDATE', '\n\tUPDATE \n\t')\ |
|
|||
27 | .replace('DELETE', '\n\tDELETE \n\t')\ |
|
|||
28 | .replace('FROM', '\n\tFROM')\ |
|
|||
29 | .replace('ORDER BY', '\n\tORDER BY')\ |
|
|||
30 | .replace('LIMIT', '\n\tLIMIT')\ |
|
|||
31 | .replace('WHERE', '\n\tWHERE')\ |
|
|||
32 | .replace('AND', '\n\tAND')\ |
|
|||
33 | .replace('LEFT', '\n\tLEFT')\ |
|
|||
34 | .replace('INNER', '\n\tINNER')\ |
|
|||
35 | .replace('INSERT', '\n\tINSERT')\ |
|
|||
36 | .replace('DELETE', '\n\tDELETE') |
|
|||
37 | return sql |
|
|||
38 |
|
||||
39 |
|
13 | |||
40 | class TimerProxy(ConnectionProxy): |
|
14 | class TimerProxy(ConnectionProxy): | |
41 |
|
15 | |||
42 | def __init__(self): |
|
16 | def __init__(self): | |
43 | super(TimerProxy, self).__init__() |
|
17 | super(TimerProxy, self).__init__() | |
44 | self.logging_name = 'timerProxy' |
|
18 | ||
45 | self.log = log.instance_logger(self, True) |
|
19 | def cursor_execute(self, execute, cursor, statement, parameters, | |
46 |
|
20 | context, executemany): | ||
47 | def cursor_execute(self, execute, cursor, statement, parameters, context, executemany): |
|
21 | ||
48 |
|
||||
49 | now = time.time() |
|
22 | now = time.time() | |
50 | try: |
|
23 | try: | |
51 |
|
|
24 | log.info(color_sql(">>>>> STARTING QUERY >>>>>")) | |
52 | return execute(cursor, statement, parameters, context) |
|
25 | return execute(cursor, statement, parameters, context) | |
53 | finally: |
|
26 | finally: | |
54 | total = time.time() - now |
|
27 | total = time.time() - now | |
55 | try: |
|
28 | log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total)) | |
56 | self.log.info(format_sql("Query: %s" % statement % parameters)) |
|
|||
57 | except TypeError: |
|
|||
58 | self.log.info(format_sql("Query: %s %s" % (statement, parameters))) |
|
|||
59 | self.log.info("<<<<< TOTAL TIME: %f <<<<<" % total) |
|
General Comments 0
You need to be logged in to leave comments.
Login now