diff --git a/rhodecode/lib/compat.py b/rhodecode/lib/compat.py --- a/rhodecode/lib/compat.py +++ b/rhodecode/lib/compat.py @@ -31,6 +31,7 @@ from rhodecode import __platform__, PLAT # json #============================================================================== from rhodecode.lib.ext_json import json +import array #============================================================================== @@ -415,6 +416,14 @@ else: # in py2.6 bytes is a synonim for str _bytes = str +if __py_version__ >= (2, 6): + _bytearray = bytearray +else: + # no idea if this is correct but all integration tests are passing + # i think we never use bytearray anyway + _bytearray = array + + #============================================================================== # deque #============================================================================== @@ -548,7 +557,127 @@ else: if __py_version__ >= (2, 6): from threading import Event, Thread else: - from threading import _Verbose, Condition, Lock, Thread + from threading import _Verbose, Condition, Lock, Thread, _time, \ + _allocate_lock, RLock, _sleep + + def Condition(*args, **kwargs): + return _Condition(*args, **kwargs) + + class _Condition(_Verbose): + + def __init__(self, lock=None, verbose=None): + _Verbose.__init__(self, verbose) + if lock is None: + lock = RLock() + self.__lock = lock + # Export the lock's acquire() and release() methods + self.acquire = lock.acquire + self.release = lock.release + # If the lock defines _release_save() and/or _acquire_restore(), + # these override the default implementations (which just call + # release() and acquire() on the lock). Ditto for _is_owned(). + try: + self._release_save = lock._release_save + except AttributeError: + pass + try: + self._acquire_restore = lock._acquire_restore + except AttributeError: + pass + try: + self._is_owned = lock._is_owned + except AttributeError: + pass + self.__waiters = [] + + def __enter__(self): + return self.__lock.__enter__() + + def __exit__(self, *args): + return self.__lock.__exit__(*args) + + def __repr__(self): + return "" % (self.__lock, len(self.__waiters)) + + def _release_save(self): + self.__lock.release() # No state to save + + def _acquire_restore(self, x): + self.__lock.acquire() # Ignore saved state + + def _is_owned(self): + # Return True if lock is owned by current_thread. + # This method is called only if __lock doesn't have _is_owned(). + if self.__lock.acquire(0): + self.__lock.release() + return False + else: + return True + + def wait(self, timeout=None): + if not self._is_owned(): + raise RuntimeError("cannot wait on un-acquired lock") + waiter = _allocate_lock() + waiter.acquire() + self.__waiters.append(waiter) + saved_state = self._release_save() + try: # restore state no matter what (e.g., KeyboardInterrupt) + if timeout is None: + waiter.acquire() + if __debug__: + self._note("%s.wait(): got it", self) + else: + # Balancing act: We can't afford a pure busy loop, so we + # have to sleep; but if we sleep the whole timeout time, + # we'll be unresponsive. The scheme here sleeps very + # little at first, longer as time goes on, but never longer + # than 20 times per second (or the timeout time remaining). + endtime = _time() + timeout + delay = 0.0005 # 500 us -> initial delay of 1 ms + while True: + gotit = waiter.acquire(0) + if gotit: + break + remaining = endtime - _time() + if remaining <= 0: + break + delay = min(delay * 2, remaining, .05) + _sleep(delay) + if not gotit: + if __debug__: + self._note("%s.wait(%s): timed out", self, timeout) + try: + self.__waiters.remove(waiter) + except ValueError: + pass + else: + if __debug__: + self._note("%s.wait(%s): got it", self, timeout) + finally: + self._acquire_restore(saved_state) + + def notify(self, n=1): + if not self._is_owned(): + raise RuntimeError("cannot notify on un-acquired lock") + __waiters = self.__waiters + waiters = __waiters[:n] + if not waiters: + if __debug__: + self._note("%s.notify(): no waiters", self) + return + self._note("%s.notify(): notifying %d waiter%s", self, n, + n != 1 and "s" or "") + for waiter in waiters: + waiter.release() + try: + __waiters.remove(waiter) + except ValueError: + pass + + def notifyAll(self): + self.notify(len(self.__waiters)) + + notify_all = notifyAll def Event(*args, **kwargs): return _Event(*args, **kwargs) diff --git a/rhodecode/lib/db_manage.py b/rhodecode/lib/db_manage.py --- a/rhodecode/lib/db_manage.py +++ b/rhodecode/lib/db_manage.py @@ -30,7 +30,7 @@ import uuid import logging from os.path import dirname as dn, join as jn -from rhodecode import __dbversion__ +from rhodecode import __dbversion__, __py_version__ from rhodecode.model.user import UserModel from rhodecode.lib.utils import ask_ok @@ -659,3 +659,12 @@ class DbManage(object): reg_perm.user = default_user reg_perm.permission = perm self.sa.add(reg_perm) + + def finish(self): + """ + Function executed at the end of setup + """ + if not __py_version__ >= (2, 6): + notify('Python2.5 detected, please switch ' + 'egg:waitress#main -> egg:Paste#http ' + 'in your .ini file') \ No newline at end of file diff --git a/rhodecode/lib/subprocessio.py b/rhodecode/lib/subprocessio.py --- a/rhodecode/lib/subprocessio.py +++ b/rhodecode/lib/subprocessio.py @@ -24,7 +24,7 @@ If not, see