changeset 3797:d7488551578e beta

synced vcs with upstream - moved subprocessio module to VCS - many small changes to make embedded vcs as similar to to external lib - use only absolute imports - patch vcs config during load pylons env
author Marcin Kuzminski <marcin@python-works.com>
date Sat, 27 Apr 2013 11:24:25 +0200
parents 2b5f94fc3b7a
children 574825da0d4e
files rhodecode/__init__.py rhodecode/config/environment.py rhodecode/lib/__init__.py rhodecode/lib/compat.py rhodecode/lib/middleware/pygrack.py rhodecode/lib/subprocessio.py rhodecode/lib/utils.py rhodecode/lib/vcs/__init__.py rhodecode/lib/vcs/backends/base.py rhodecode/lib/vcs/backends/git/changeset.py rhodecode/lib/vcs/backends/git/inmemory.py rhodecode/lib/vcs/backends/git/repository.py rhodecode/lib/vcs/backends/hg/changeset.py rhodecode/lib/vcs/backends/hg/repository.py rhodecode/lib/vcs/conf/settings.py rhodecode/lib/vcs/nodes.py rhodecode/lib/vcs/subprocessio.py rhodecode/lib/vcs/utils/__init__.py rhodecode/lib/vcs/utils/annotate.py rhodecode/lib/vcs/utils/compat.py rhodecode/lib/vcs/utils/diffs.py rhodecode/lib/vcs/utils/helpers.py rhodecode/lib/vcs/utils/hgcompat.py rhodecode/lib/vcs/utils/progressbar.py rhodecode/tests/__init__.py rhodecode/tests/functional/test_admin_notifications.py rhodecode/tests/functional/test_admin_repos.py rhodecode/tests/functional/test_admin_settings.py rhodecode/tests/functional/test_admin_users.py rhodecode/tests/functional/test_admin_users_groups.py rhodecode/tests/functional/test_branches.py rhodecode/tests/functional/test_changelog.py rhodecode/tests/functional/test_changeset_comments.py rhodecode/tests/functional/test_compare_local.py rhodecode/tests/functional/test_files.py rhodecode/tests/functional/test_home.py rhodecode/tests/functional/test_journal.py rhodecode/tests/functional/test_login.py rhodecode/tests/functional/test_search.py rhodecode/tests/functional/test_summary.py rhodecode/tests/functional/test_tags.py rhodecode/tests/vcs/__init__.py rhodecode/tests/vcs/base.py rhodecode/tests/vcs/conf.py rhodecode/tests/vcs/test_archives.py rhodecode/tests/vcs/test_branches.py rhodecode/tests/vcs/test_changesets.py rhodecode/tests/vcs/test_filenodes_unicode_path.py rhodecode/tests/vcs/test_getitem.py rhodecode/tests/vcs/test_getslice.py rhodecode/tests/vcs/test_git.py rhodecode/tests/vcs/test_hg.py rhodecode/tests/vcs/test_inmemchangesets.py rhodecode/tests/vcs/test_repository.py rhodecode/tests/vcs/test_tags.py rhodecode/tests/vcs/test_utils.py rhodecode/tests/vcs/test_vcs.py rhodecode/tests/vcs/test_workdirs.py rhodecode/tests/vcs_test_hg.tar.gz test.ini
diffstat 60 files changed, 1343 insertions(+), 967 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/__init__.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/__init__.py	Sat Apr 27 11:24:25 2013 +0200
@@ -27,6 +27,19 @@
 import platform
 
 VERSION = (1, 7, 0, 'dev')
+BACKENDS = {
+    'hg': 'Mercurial repository',
+    'git': 'Git repository',
+}
+
+CELERY_ON = False
+CELERY_EAGER = False
+
+# link to config for pylons
+CONFIG = {}
+
+# Linked module for extensions
+EXTENSIONS = {}
 
 try:
     from rhodecode.lib import get_current_revision
@@ -45,23 +58,5 @@
 __author__ = 'Marcin Kuzminski'
 __url__ = 'http://rhodecode.org'
 
-PLATFORM_WIN = ('Windows')
-PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS') #depracated
-
-is_windows = __platform__ in PLATFORM_WIN
+is_windows = __platform__ in ('Windows')
 is_unix = not is_windows
-
-
-BACKENDS = {
-    'hg': 'Mercurial repository',
-    'git': 'Git repository',
-}
-
-CELERY_ON = False
-CELERY_EAGER = False
-
-# link to config for pylons
-CONFIG = {}
-
-# Linked module for extensions
-EXTENSIONS = {}
--- a/rhodecode/config/environment.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/config/environment.py	Sat Apr 27 11:24:25 2013 +0200
@@ -18,7 +18,7 @@
 from rhodecode.lib import helpers
 from rhodecode.lib.auth import set_available_permissions
 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config,\
-    load_rcextensions, check_git_version
+    load_rcextensions, check_git_version, set_vcs_config
 from rhodecode.lib.utils2 import engine_from_config, str2bool
 from rhodecode.lib.db_manage import DbManage
 from rhodecode.model import init_model
@@ -114,4 +114,6 @@
     # store config reference into our module to skip import magic of
     # pylons
     rhodecode.CONFIG.update(config)
+
+    set_vcs_config(rhodecode.CONFIG)
     return config
--- a/rhodecode/lib/__init__.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/__init__.py	Sat Apr 27 11:24:25 2013 +0200
@@ -12,7 +12,8 @@
     try:
         from rhodecode.lib.vcs import get_repo
         from rhodecode.lib.vcs.utils.helpers import get_scm
-        repopath = os.path.join(os.path.dirname(__file__), '..', '..')
+        repopath = os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                                '..', '..'))
         scm = get_scm(repopath)[0]
         repo = get_repo(path=repopath, alias=scm)
         wk_dir = repo.workdir
--- a/rhodecode/lib/compat.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/compat.py	Sat Apr 27 11:24:25 2013 +0200
@@ -25,13 +25,12 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
-from rhodecode import __platform__, PLATFORM_WIN, __py_version__
+from rhodecode import __py_version__, is_windows
 
 #==============================================================================
 # json
 #==============================================================================
 from rhodecode.lib.ext_json import json
-import array
 
 
 #==============================================================================
@@ -366,7 +365,7 @@
 #==============================================================================
 # kill FUNCTIONS
 #==============================================================================
-if __platform__ in PLATFORM_WIN:
+if is_windows:
     import ctypes
 
     def kill(pid, sig):
@@ -419,6 +418,7 @@
 if __py_version__ >= (2, 6):
     _bytearray = bytearray
 else:
+    import array
     # no idea if this is correct but all integration tests are passing
     # i think we never use bytearray anyway
     _bytearray = array
@@ -548,173 +548,3 @@
             memo[id(self)] = result
             result.__init__(deepcopy(tuple(self), memo))
             return result
-
-
-#==============================================================================
-# threading.Event
-#==============================================================================
-
-if __py_version__ >= (2, 6):
-    from threading import Event, Thread
-else:
-    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 "<Condition(%s, %d)>" % (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)
-
-    class _Event(_Verbose):
-
-        # After Tim Peters' event class (without is_posted())
-
-        def __init__(self, verbose=None):
-            _Verbose.__init__(self, verbose)
-            self.__cond = Condition(Lock())
-            self.__flag = False
-
-        def isSet(self):
-            return self.__flag
-
-        is_set = isSet
-
-        def set(self):
-            self.__cond.acquire()
-            try:
-                self.__flag = True
-                self.__cond.notify_all()
-            finally:
-                self.__cond.release()
-
-        def clear(self):
-            self.__cond.acquire()
-            try:
-                self.__flag = False
-            finally:
-                self.__cond.release()
-
-        def wait(self, timeout=None):
-            self.__cond.acquire()
-            try:
-                if not self.__flag:
-                    self.__cond.wait(timeout)
-            finally:
-                self.__cond.release()
--- a/rhodecode/lib/middleware/pygrack.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/middleware/pygrack.py	Sat Apr 27 11:24:25 2013 +0200
@@ -7,7 +7,7 @@
 from webob import Request, Response, exc
 
 import rhodecode
-from rhodecode.lib import subprocessio
+from rhodecode.lib.vcs import subprocessio
 
 log = logging.getLogger(__name__)
 
--- a/rhodecode/lib/subprocessio.py	Sat Apr 27 11:45:27 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,415 +0,0 @@
-'''
-Module provides a class allowing to wrap communication over subprocess.Popen
-input, output, error streams into a meaningfull, non-blocking, concurrent
-stream processor exposing the output data as an iterator fitting to be a
-return value passed by a WSGI applicaiton to a WSGI server per PEP 3333.
-
-Copyright (c) 2011  Daniel Dotsenko <dotsa@hotmail.com>
-
-This file is part of git_http_backend.py Project.
-
-git_http_backend.py Project is free software: you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public License as
-published by the Free Software Foundation, either version 2.1 of the License,
-or (at your option) any later version.
-
-git_http_backend.py Project is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with git_http_backend.py Project.
-If not, see <http://www.gnu.org/licenses/>.
-'''
-import os
-import subprocess
-from rhodecode.lib.compat import deque, Event, Thread, _bytes, _bytearray
-
-
-class StreamFeeder(Thread):
-    """
-    Normal writing into pipe-like is blocking once the buffer is filled.
-    This thread allows a thread to seep data from a file-like into a pipe
-    without blocking the main thread.
-    We close inpipe once the end of the source stream is reached.
-    """
-    def __init__(self, source):
-        super(StreamFeeder, self).__init__()
-        self.daemon = True
-        filelike = False
-        self.bytes = _bytes()
-        if type(source) in (type(''), _bytes, _bytearray):  # string-like
-            self.bytes = _bytes(source)
-        else:  # can be either file pointer or file-like
-            if type(source) in (int, long):  # file pointer it is
-                ## converting file descriptor (int) stdin into file-like
-                try:
-                    source = os.fdopen(source, 'rb', 16384)
-                except Exception:
-                    pass
-            # let's see if source is file-like by now
-            try:
-                filelike = source.read
-            except Exception:
-                pass
-        if not filelike and not self.bytes:
-            raise TypeError("StreamFeeder's source object must be a readable "
-                            "file-like, a file descriptor, or a string-like.")
-        self.source = source
-        self.readiface, self.writeiface = os.pipe()
-
-    def run(self):
-        t = self.writeiface
-        if self.bytes:
-            os.write(t, self.bytes)
-        else:
-            s = self.source
-            b = s.read(4096)
-            while b:
-                os.write(t, b)
-                b = s.read(4096)
-        os.close(t)
-
-    @property
-    def output(self):
-        return self.readiface
-
-
-class InputStreamChunker(Thread):
-    def __init__(self, source, target, buffer_size, chunk_size):
-
-        super(InputStreamChunker, self).__init__()
-
-        self.daemon = True  # die die die.
-
-        self.source = source
-        self.target = target
-        self.chunk_count_max = int(buffer_size / chunk_size) + 1
-        self.chunk_size = chunk_size
-
-        self.data_added = Event()
-        self.data_added.clear()
-
-        self.keep_reading = Event()
-        self.keep_reading.set()
-
-        self.EOF = Event()
-        self.EOF.clear()
-
-        self.go = Event()
-        self.go.set()
-
-    def stop(self):
-        self.go.clear()
-        self.EOF.set()
-        try:
-            # this is not proper, but is done to force the reader thread let
-            # go of the input because, if successful, .close() will send EOF
-            # down the pipe.
-            self.source.close()
-        except:
-            pass
-
-    def run(self):
-        s = self.source
-        t = self.target
-        cs = self.chunk_size
-        ccm = self.chunk_count_max
-        kr = self.keep_reading
-        da = self.data_added
-        go = self.go
-
-        try:
-            b = s.read(cs)
-        except ValueError:
-            b = ''
-
-        while b and go.is_set():
-            if len(t) > ccm:
-                kr.clear()
-                kr.wait(2)
-#                # this only works on 2.7.x and up
-#                if not kr.wait(10):
-#                    raise Exception("Timed out while waiting for input to be read.")
-                # instead we'll use this
-                if len(t) > ccm + 3:
-                    raise IOError("Timed out while waiting for input from subprocess.")
-            t.append(b)
-            da.set()
-            b = s.read(cs)
-        self.EOF.set()
-        da.set()  # for cases when done but there was no input.
-
-
-class BufferedGenerator():
-    '''
-    Class behaves as a non-blocking, buffered pipe reader.
-    Reads chunks of data (through a thread)
-    from a blocking pipe, and attaches these to an array (Deque) of chunks.
-    Reading is halted in the thread when max chunks is internally buffered.
-    The .next() may operate in blocking or non-blocking fashion by yielding
-    '' if no data is ready
-    to be sent or by not returning until there is some data to send
-    When we get EOF from underlying source pipe we raise the marker to raise
-    StopIteration after the last chunk of data is yielded.
-    '''
-
-    def __init__(self, source, buffer_size=65536, chunk_size=4096,
-                 starting_values=[], bottomless=False):
-
-        if bottomless:
-            maxlen = int(buffer_size / chunk_size)
-        else:
-            maxlen = None
-
-        self.data = deque(starting_values, maxlen)
-
-        self.worker = InputStreamChunker(source, self.data, buffer_size,
-                                         chunk_size)
-        if starting_values:
-            self.worker.data_added.set()
-        self.worker.start()
-
-    ####################
-    # Generator's methods
-    ####################
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        while not len(self.data) and not self.worker.EOF.is_set():
-            self.worker.data_added.clear()
-            self.worker.data_added.wait(0.2)
-        if len(self.data):
-            self.worker.keep_reading.set()
-            return _bytes(self.data.popleft())
-        elif self.worker.EOF.is_set():
-            raise StopIteration
-
-    def throw(self, type, value=None, traceback=None):
-        if not self.worker.EOF.is_set():
-            raise type(value)
-
-    def start(self):
-        self.worker.start()
-
-    def stop(self):
-        self.worker.stop()
-
-    def close(self):
-        try:
-            self.worker.stop()
-            self.throw(GeneratorExit)
-        except (GeneratorExit, StopIteration):
-            pass
-
-    def __del__(self):
-        self.close()
-
-    ####################
-    # Threaded reader's infrastructure.
-    ####################
-    @property
-    def input(self):
-        return self.worker.w
-
-    @property
-    def data_added_event(self):
-        return self.worker.data_added
-
-    @property
-    def data_added(self):
-        return self.worker.data_added.is_set()
-
-    @property
-    def reading_paused(self):
-        return not self.worker.keep_reading.is_set()
-
-    @property
-    def done_reading_event(self):
-        '''
-        Done_reding does not mean that the iterator's buffer is empty.
-        Iterator might have done reading from underlying source, but the read
-        chunks might still be available for serving through .next() method.
-
-        @return An Event class instance.
-        '''
-        return self.worker.EOF
-
-    @property
-    def done_reading(self):
-        '''
-        Done_reding does not mean that the iterator's buffer is empty.
-        Iterator might have done reading from underlying source, but the read
-        chunks might still be available for serving through .next() method.
-
-        @return An Bool value.
-        '''
-        return self.worker.EOF.is_set()
-
-    @property
-    def length(self):
-        '''
-        returns int.
-
-        This is the lenght of the que of chunks, not the length of
-        the combined contents in those chunks.
-
-        __len__() cannot be meaningfully implemented because this
-        reader is just flying throuh a bottomless pit content and
-        can only know the lenght of what it already saw.
-
-        If __len__() on WSGI server per PEP 3333 returns a value,
-        the responce's length will be set to that. In order not to
-        confuse WSGI PEP3333 servers, we will not implement __len__
-        at all.
-        '''
-        return len(self.data)
-
-    def prepend(self, x):
-        self.data.appendleft(x)
-
-    def append(self, x):
-        self.data.append(x)
-
-    def extend(self, o):
-        self.data.extend(o)
-
-    def __getitem__(self, i):
-        return self.data[i]
-
-
-class SubprocessIOChunker(object):
-    '''
-    Processor class wrapping handling of subprocess IO.
-
-    In a way, this is a "communicate()" replacement with a twist.
-
-    - We are multithreaded. Writing in and reading out, err are all sep threads.
-    - We support concurrent (in and out) stream processing.
-    - The output is not a stream. It's a queue of read string (bytes, not unicode)
-      chunks. The object behaves as an iterable. You can "for chunk in obj:" us.
-    - We are non-blocking in more respects than communicate()
-      (reading from subprocess out pauses when internal buffer is full, but
-       does not block the parent calling code. On the flip side, reading from
-       slow-yielding subprocess may block the iteration until data shows up. This
-       does not block the parallel inpipe reading occurring parallel thread.)
-
-    The purpose of the object is to allow us to wrap subprocess interactions into
-    and interable that can be passed to a WSGI server as the application's return
-    value. Because of stream-processing-ability, WSGI does not have to read ALL
-    of the subprocess's output and buffer it, before handing it to WSGI server for
-    HTTP response. Instead, the class initializer reads just a bit of the stream
-    to figure out if error ocurred or likely to occur and if not, just hands the
-    further iteration over subprocess output to the server for completion of HTTP
-    response.
-
-    The real or perceived subprocess error is trapped and raised as one of
-    EnvironmentError family of exceptions
-
-    Example usage:
-    #    try:
-    #        answer = SubprocessIOChunker(
-    #            cmd,
-    #            input,
-    #            buffer_size = 65536,
-    #            chunk_size = 4096
-    #            )
-    #    except (EnvironmentError) as e:
-    #        print str(e)
-    #        raise e
-    #
-    #    return answer
-
-
-    '''
-    def __init__(self, cmd, inputstream=None, buffer_size=65536,
-                 chunk_size=4096, starting_values=[], **kwargs):
-        '''
-        Initializes SubprocessIOChunker
-
-        :param cmd: A Subprocess.Popen style "cmd". Can be string or array of strings
-        :param inputstream: (Default: None) A file-like, string, or file pointer.
-        :param buffer_size: (Default: 65536) A size of total buffer per stream in bytes.
-        :param chunk_size: (Default: 4096) A max size of a chunk. Actual chunk may be smaller.
-        :param starting_values: (Default: []) An array of strings to put in front of output que.
-        '''
-
-        if inputstream:
-            input_streamer = StreamFeeder(inputstream)
-            input_streamer.start()
-            inputstream = input_streamer.output
-
-        if isinstance(cmd, (list, tuple)):
-            cmd = ' '.join(cmd)
-
-        _shell = kwargs.get('shell') or True
-        kwargs['shell'] = _shell
-        _p = subprocess.Popen(cmd,
-            bufsize=-1,
-            stdin=inputstream,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            **kwargs
-            )
-
-        bg_out = BufferedGenerator(_p.stdout, buffer_size, chunk_size, starting_values)
-        bg_err = BufferedGenerator(_p.stderr, 16000, 1, bottomless=True)
-
-        while not bg_out.done_reading and not bg_out.reading_paused and not bg_err.length:
-            # doing this until we reach either end of file, or end of buffer.
-            bg_out.data_added_event.wait(1)
-            bg_out.data_added_event.clear()
-
-        # at this point it's still ambiguous if we are done reading or just full buffer.
-        # Either way, if error (returned by ended process, or implied based on
-        # presence of stuff in stderr output) we error out.
-        # Else, we are happy.
-        _returncode = _p.poll()
-        if _returncode or (_returncode == None and bg_err.length):
-            try:
-                _p.terminate()
-            except:
-                pass
-            bg_out.stop()
-            bg_err.stop()
-            err = '%s' % ''.join(bg_err)
-            if err:
-                raise EnvironmentError("Subprocess exited due to an error:\n" + err)
-            raise EnvironmentError("Subprocess exited with non 0 ret code:%s" % _returncode)
-
-        self.process = _p
-        self.output = bg_out
-        self.error = bg_err
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        if self.process.poll():
-            err = '%s' % ''.join(self.error)
-            raise EnvironmentError("Subprocess exited due to an error:\n" + err)
-        return self.output.next()
-
-    def throw(self, type, value=None, traceback=None):
-        if self.output.length or not self.output.done_reading:
-            raise type(value)
-
-    def close(self):
-        try:
-            self.process.terminate()
-        except:
-            pass
-        try:
-            self.output.close()
-        except:
-            pass
-        try:
-            self.error.close()
-        except:
-            pass
-
-    def __del__(self):
-        self.close()
--- a/rhodecode/lib/utils.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/utils.py	Sat Apr 27 11:24:25 2013 +0200
@@ -374,6 +374,26 @@
         config[k] = v
 
 
+def set_vcs_config(config):
+    """
+    Patch VCS config with some RhodeCode specific stuff
+
+    :param config: rhodecode.CONFIG
+    """
+    import rhodecode
+    from rhodecode.lib.vcs import conf
+    from rhodecode.lib.utils2 import aslist
+    conf.settings.BACKENDS = {
+        'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
+        'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
+    }
+
+    conf.settings.GIT_EXECUTABLE_PATH = config.get('git_path', 'git')
+    conf.settings.GIT_REV_FILTER = config.get('git_rev_filter', '--all').strip()
+    conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding',
+                                                        'utf8'), sep=',')
+
+
 def map_groups(path):
     """
     Given a full path to a repository, create all nested groups that this
@@ -739,6 +759,7 @@
     """
     from rhodecode import BACKENDS
     from rhodecode.lib.vcs.backends.git.repository import GitRepository
+    from rhodecode.lib.vcs.conf import settings
     from distutils.version import StrictVersion
 
     stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
@@ -760,7 +781,8 @@
         to_old_git = True
 
     if 'git' in BACKENDS:
-        log.debug('GIT version detected: %s' % stdout)
+        log.debug('GIT executable: "%s" version detected: %s'
+                  % (settings.GIT_EXECUTABLE_PATH, stdout))
         if stderr:
             log.warning('Unable to detect git version, org error was: %r' % stderr)
         elif to_old_git:
--- a/rhodecode/lib/vcs/__init__.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/__init__.py	Sat Apr 27 11:24:25 2013 +0200
@@ -10,13 +10,14 @@
     :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak.
 """
 
-VERSION = (0, 3, 0, 'dev')
+VERSION = (0, 4, 0, 'dev')
 
 __version__ = '.'.join((str(each) for each in VERSION[:4]))
 
 __all__ = [
     'get_version', 'get_repo', 'get_backend',
-    'VCSError', 'RepositoryError', 'ChangesetError']
+    'VCSError', 'RepositoryError', 'ChangesetError'
+]
 
 import sys
 from rhodecode.lib.vcs.backends import get_repo, get_backend
@@ -29,6 +30,7 @@
     """
     return '.'.join((str(each) for each in VERSION[:3]))
 
+
 def main(argv=None):
     if argv is None:
         argv = sys.argv
--- a/rhodecode/lib/vcs/backends/base.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/backends/base.py	Sat Apr 27 11:24:25 2013 +0200
@@ -10,16 +10,18 @@
 """
 
 import datetime
-from itertools import chain
+import itertools
+
 from rhodecode.lib.vcs.utils import author_name, author_email
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
 from rhodecode.lib.vcs.utils.helpers import get_dict_for_attrs
 from rhodecode.lib.vcs.conf import settings
 
-from rhodecode.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, \
-    NodeAlreadyAddedError, NodeAlreadyChangedError, NodeAlreadyExistsError, \
-    NodeAlreadyRemovedError, NodeDoesNotExistError, NodeNotChangedError, \
-    RepositoryError
+from rhodecode.lib.vcs.exceptions import (
+    ChangesetError, EmptyRepositoryError, NodeAlreadyAddedError,
+    NodeAlreadyChangedError, NodeAlreadyExistsError, NodeAlreadyRemovedError,
+    NodeDoesNotExistError, NodeNotChangedError, RepositoryError
+)
 
 
 class BaseRepository(object):
@@ -851,7 +853,7 @@
         Returns generator of paths from nodes marked as added, changed or
         removed.
         """
-        for node in chain(self.added, self.changed, self.removed):
+        for node in itertools.chain(self.added, self.changed, self.removed):
             yield node.path
 
     def get_paths(self):
--- a/rhodecode/lib/vcs/backends/git/changeset.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/backends/git/changeset.py	Sat Apr 27 11:24:25 2013 +0200
@@ -2,22 +2,21 @@
 from itertools import chain
 from dulwich import objects
 from subprocess import Popen, PIPE
-import rhodecode
+
 from rhodecode.lib.vcs.conf import settings
-from rhodecode.lib.vcs.exceptions import RepositoryError
-from rhodecode.lib.vcs.exceptions import ChangesetError
-from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError
-from rhodecode.lib.vcs.exceptions import VCSError
-from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
-from rhodecode.lib.vcs.exceptions import ImproperArchiveTypeError
 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
-from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, \
-    RemovedFileNode, SubModuleNode, ChangedFileNodesGenerator,\
-    AddedFileNodesGenerator, RemovedFileNodesGenerator
-from rhodecode.lib.vcs.utils import safe_unicode
-from rhodecode.lib.vcs.utils import date_fromtimestamp
+from rhodecode.lib.vcs.exceptions import (
+    RepositoryError, ChangesetError, NodeDoesNotExistError, VCSError,
+    ChangesetDoesNotExistError, ImproperArchiveTypeError
+)
+from rhodecode.lib.vcs.nodes import (
+    FileNode, DirNode, NodeKind, RootNode, RemovedFileNode, SubModuleNode,
+    ChangedFileNodesGenerator, AddedFileNodesGenerator, RemovedFileNodesGenerator
+)
+from rhodecode.lib.vcs.utils import (
+    safe_unicode, safe_str, safe_int, date_fromtimestamp
+)
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
-from rhodecode.lib.utils2 import safe_int, safe_str
 
 
 class GitChangeset(BaseChangeset):
@@ -187,8 +186,7 @@
         """
         Returns list of children changesets.
         """
-        rev_filter = _git_path = rhodecode.CONFIG.get('git_rev_filter',
-                                              '--all').strip()
+        rev_filter = _git_path = settings.GIT_REV_FILTER
         so, se = self.repository.run_git_command(
             "rev-list %s --children | grep '^%s'" % (rev_filter, self.raw_id)
         )
@@ -373,7 +371,7 @@
             frmt = 'zip'
         else:
             frmt = 'tar'
-        _git_path = rhodecode.CONFIG.get('git_path', 'git')
+        _git_path = settings.GIT_EXECUTABLE_PATH
         cmd = '%s archive --format=%s --prefix=%s/ %s' % (_git_path,
                                                 frmt, prefix, self.raw_id)
         if kind == 'tgz':
@@ -472,8 +470,8 @@
         """
         Get's a fast accessible file changes for given changeset
         """
-        a, m, d = self._changes_cache
-        return list(a.union(m).union(d))
+        added, modified, deleted = self._changes_cache
+        return list(added.union(modified).union(deleted))
 
     @LazyProperty
     def _diff_name_status(self):
@@ -516,11 +514,11 @@
 
         :param status: one of: *added*, *modified* or *deleted*
         """
-        a, m, d = self._changes_cache
+        added, modified, deleted = self._changes_cache
         return sorted({
-            'added': list(a),
-            'modified': list(m),
-            'deleted': list(d)}[status]
+            'added': list(added),
+            'modified': list(modified),
+            'deleted': list(deleted)}[status]
         )
 
     @LazyProperty
--- a/rhodecode/lib/vcs/backends/git/inmemory.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/backends/git/inmemory.py	Sat Apr 27 11:24:25 2013 +0200
@@ -150,7 +150,6 @@
 
         ref = 'refs/heads/%s' % branch
         repo.refs[ref] = commit.id
-        repo.refs.set_symbolic_ref('HEAD', ref)
 
         # Update vcs repository object & recreate dulwich repo
         self.repository.revisions.append(commit.id)
--- a/rhodecode/lib/vcs/backends/git/repository.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/backends/git/repository.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 """
-    vcs.backends.git
-    ~~~~~~~~~~~~~~~~
+    vcs.backends.git.repository
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    Git backend implementation.
+    Git repository implementation.
 
     :created_on: Apr 8, 2010
     :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak.
@@ -12,34 +12,36 @@
 import os
 import re
 import time
-import posixpath
-import logging
-import traceback
 import urllib
 import urllib2
-from dulwich.repo import Repo, NotGitRepository
+import logging
+import posixpath
+import string
+
 from dulwich.objects import Tag
-from string import Template
+from dulwich.repo import Repo, NotGitRepository
 
-import rhodecode
+from rhodecode.lib.vcs import subprocessio
 from rhodecode.lib.vcs.backends.base import BaseRepository, CollectionGenerator
-from rhodecode.lib.vcs.exceptions import BranchDoesNotExistError
-from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
-from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
-from rhodecode.lib.vcs.exceptions import RepositoryError
-from rhodecode.lib.vcs.exceptions import TagAlreadyExistError
-from rhodecode.lib.vcs.exceptions import TagDoesNotExistError
+from rhodecode.lib.vcs.conf import settings
+
+from rhodecode.lib.vcs.exceptions import (
+    BranchDoesNotExistError, ChangesetDoesNotExistError, EmptyRepositoryError,
+    RepositoryError, TagAlreadyExistError, TagDoesNotExistError
+)
 from rhodecode.lib.vcs.utils import safe_unicode, makedate, date_fromtimestamp
-from rhodecode.lib.vcs.utils.lazy import LazyProperty, ThreadLocalLazyProperty
+from rhodecode.lib.vcs.utils.lazy import LazyProperty
 from rhodecode.lib.vcs.utils.ordered_dict import OrderedDict
-from rhodecode.lib.vcs.utils.paths import abspath
-from rhodecode.lib.vcs.utils.paths import get_user_home
-from .workdir import GitWorkdir
+from rhodecode.lib.vcs.utils.paths import abspath, get_user_home
+
+from rhodecode.lib.vcs.utils.hgcompat import (
+    hg_url, httpbasicauthhandler, httpdigestauthhandler
+)
+
 from .changeset import GitChangeset
+from .config import ConfigFile
 from .inmemory import GitInMemoryChangeset
-from .config import ConfigFile
-from rhodecode.lib import subprocessio
-
+from .workdir import GitWorkdir
 
 log = logging.getLogger(__name__)
 
@@ -115,7 +117,7 @@
             del gitenv['GIT_DIR']
         gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
 
-        _git_path = rhodecode.CONFIG.get('git_path', 'git')
+        _git_path = settings.GIT_EXECUTABLE_PATH
         cmd = [_git_path] + _copts + cmd
         if _str_cmd:
             cmd = ' '.join(cmd)
@@ -153,11 +155,6 @@
 
         On failures it'll raise urllib2.HTTPError
         """
-        from mercurial.util import url as Url
-
-        # those authnadlers are patched for python 2.6.5 bug an
-        # infinit looping when given invalid resources
-        from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
 
         # check first if it's not an local url
         if os.path.isdir(url) or url.startswith('file:'):
@@ -167,7 +164,7 @@
             url = url[url.find('+') + 1:]
 
         handlers = []
-        test_uri, authinfo = Url(url).authinfo()
+        test_uri, authinfo = hg_url(url).authinfo()
         if not test_uri.endswith('info/refs'):
             test_uri = test_uri.rstrip('/') + '/info/refs'
         if authinfo:
@@ -224,8 +221,8 @@
             self._repo.head()
         except KeyError:
             return []
-        rev_filter = _git_path = rhodecode.CONFIG.get('git_rev_filter',
-                                                      '--all').strip()
+
+        rev_filter = _git_path = settings.GIT_REV_FILTER
         cmd = 'rev-list %s --reverse --date-order' % (rev_filter)
         try:
             so, se = self.run_git_command(cmd)
@@ -502,11 +499,10 @@
             cmd_template += ' $branch_name'
             cmd_params['branch_name'] = branch_name
         else:
-            rev_filter = _git_path = rhodecode.CONFIG.get('git_rev_filter',
-                                                          '--all').strip()
+            rev_filter = _git_path = settings.GIT_REV_FILTER
             cmd_template += ' %s' % (rev_filter)
 
-        cmd = Template(cmd_template).safe_substitute(**cmd_params)
+        cmd = string.Template(cmd_template).safe_substitute(**cmd_params)
         revs = self.run_git_command(cmd)[0].splitlines()
         start_pos = 0
         end_pos = len(revs)
--- a/rhodecode/lib/vcs/backends/hg/changeset.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/backends/hg/changeset.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,14 +1,16 @@
 import os
 import posixpath
 
+from rhodecode.lib.vcs.conf import settings
 from rhodecode.lib.vcs.backends.base import BaseChangeset
-from rhodecode.lib.vcs.conf import settings
-from rhodecode.lib.vcs.exceptions import  ChangesetDoesNotExistError, \
-    ChangesetError, ImproperArchiveTypeError, NodeDoesNotExistError, VCSError
-from rhodecode.lib.vcs.nodes import AddedFileNodesGenerator, \
-    ChangedFileNodesGenerator, DirNode, FileNode, NodeKind, \
-    RemovedFileNodesGenerator, RootNode, SubModuleNode
-
+from rhodecode.lib.vcs.exceptions import (
+    ChangesetDoesNotExistError, ChangesetError, ImproperArchiveTypeError,
+    NodeDoesNotExistError, VCSError
+)
+from rhodecode.lib.vcs.nodes import (
+    AddedFileNodesGenerator, ChangedFileNodesGenerator, DirNode, FileNode,
+    NodeKind, RemovedFileNodesGenerator, RootNode, SubModuleNode
+)
 from rhodecode.lib.vcs.utils import safe_str, safe_unicode, date_fromtimestamp
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
 from rhodecode.lib.vcs.utils.paths import get_dirs_for_path
--- a/rhodecode/lib/vcs/backends/hg/repository.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/backends/hg/repository.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,26 +1,46 @@
+# -*- coding: utf-8 -*-
+"""
+    vcs.backends.hg.repository
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Mercurial repository implementation.
+
+    :created_on: Apr 8, 2010
+    :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak.
+"""
+
 import os
 import time
-import datetime
 import urllib
 import urllib2
+import logging
+import datetime
+
 
 from rhodecode.lib.vcs.backends.base import BaseRepository, CollectionGenerator
-from .workdir import MercurialWorkdir
-from .changeset import MercurialChangeset
-from .inmemory import MercurialInMemoryChangeset
+from rhodecode.lib.vcs.conf import settings
 
-from rhodecode.lib.vcs.exceptions import BranchDoesNotExistError, \
-    ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError, \
-    VCSError, TagAlreadyExistError, TagDoesNotExistError
-from rhodecode.lib.vcs.utils import author_email, author_name, date_fromtimestamp, \
-    makedate, safe_unicode
+from rhodecode.lib.vcs.exceptions import (
+    BranchDoesNotExistError, ChangesetDoesNotExistError, EmptyRepositoryError,
+    RepositoryError, VCSError, TagAlreadyExistError, TagDoesNotExistError
+)
+from rhodecode.lib.vcs.utils import (
+    author_email, author_name, date_fromtimestamp, makedate, safe_unicode
+)
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
 from rhodecode.lib.vcs.utils.ordered_dict import OrderedDict
 from rhodecode.lib.vcs.utils.paths import abspath
+from rhodecode.lib.vcs.utils.hgcompat import (
+    ui, nullid, match, patch, diffopts, clone, get_contact, pull,
+    localrepository, RepoLookupError, Abort, RepoError, hex, scmutil, hg_url,
+    httpbasicauthhandler, httpdigestauthhandler
+)
 
-from rhodecode.lib.vcs.utils.hgcompat import ui, nullid, match, patch, \
-    diffopts, clone, get_contact, pull, localrepository, RepoLookupError, \
-    Abort, RepoError, hex, scmutil
+from .changeset import MercurialChangeset
+from .inmemory import MercurialInMemoryChangeset
+from .workdir import MercurialWorkdir
+
+log = logging.getLogger(__name__)
 
 
 class MercurialRepository(BaseRepository):
@@ -272,12 +292,6 @@
         is valid or True if it's a local path
         """
 
-        from mercurial.util import url as Url
-
-        # those authnadlers are patched for python 2.6.5 bug an
-        # infinit looping when given invalid resources
-        from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
-
         # check first if it's not an local url
         if os.path.isdir(url) or url.startswith('file:'):
             return True
@@ -286,7 +300,7 @@
             url = url[url.find('+') + 1:]
 
         handlers = []
-        test_uri, authinfo = Url(url).authinfo()
+        test_uri, authinfo = hg_url(url).authinfo()
 
         if authinfo:
             #create a password manager
@@ -486,8 +500,10 @@
             revisions = scmutil.revrange(self._repo, filter_)
         else:
             revisions = self.revisions
-        revs = reversed(revisions[start_pos:end_pos]) if reverse else \
-                revisions[start_pos:end_pos]
+
+        revs = revisions[start_pos:end_pos]
+        if reverse:
+            revs = reversed(revs)
 
         return CollectionGenerator(self, revs)
 
--- a/rhodecode/lib/vcs/conf/settings.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/conf/settings.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,5 +1,6 @@
 import os
 import tempfile
+from rhodecode.lib.vcs.utils import aslist
 from rhodecode.lib.vcs.utils.paths import get_user_home
 
 abspath = lambda * p: os.path.abspath(os.path.join(*p))
@@ -15,9 +16,17 @@
 if os.path.isdir(VCSRC_PATH):
     VCSRC_PATH = os.path.join(VCSRC_PATH, '__init__.py')
 
+# list of default encoding used in safe_unicode/safe_str methods
+DEFAULT_ENCODINGS = aslist('utf8')
+
+# path to git executable runned by run_git_command function
+GIT_EXECUTABLE_PATH = 'git'
+# can be also --branches --tags
+GIT_REV_FILTER = '--all'
+
 BACKENDS = {
-    'hg': 'vcs.backends.hg.MercurialRepository',
-    'git': 'vcs.backends.git.GitRepository',
+    'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
+    'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
 }
 
 ARCHIVE_SPECS = {
@@ -26,8 +35,3 @@
     'tgz': ('application/x-gzip', '.tar.gz'),
     'zip': ('application/zip', '.zip'),
 }
-
-BACKENDS = {
-    'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
-    'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
-}
--- a/rhodecode/lib/vcs/nodes.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/nodes.py	Sat Apr 27 11:24:25 2013 +0200
@@ -15,11 +15,10 @@
 
 from pygments import lexers
 
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
+from rhodecode.lib.vcs.exceptions import NodeError, RemovedFileNodeError
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
 from rhodecode.lib.vcs.utils import safe_unicode
-from rhodecode.lib.vcs.exceptions import NodeError
-from rhodecode.lib.vcs.exceptions import RemovedFileNodeError
-from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
 
 class NodeKind:
@@ -353,7 +352,6 @@
 
     @LazyProperty
     def mimetype_main(self):
-        return ['', '']
         return self.mimetype.split('/')[0]
 
     @LazyProperty
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/vcs/subprocessio.py	Sat Apr 27 11:24:25 2013 +0200
@@ -0,0 +1,415 @@
+'''
+Module provides a class allowing to wrap communication over subprocess.Popen
+input, output, error streams into a meaningfull, non-blocking, concurrent
+stream processor exposing the output data as an iterator fitting to be a
+return value passed by a WSGI applicaiton to a WSGI server per PEP 3333.
+
+Copyright (c) 2011  Daniel Dotsenko <dotsa@hotmail.com>
+
+This file is part of git_http_backend.py Project.
+
+git_http_backend.py Project is free software: you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation, either version 2.1 of the License,
+or (at your option) any later version.
+
+git_http_backend.py Project is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with git_http_backend.py Project.
+If not, see <http://www.gnu.org/licenses/>.
+'''
+import os
+import subprocess
+from rhodecode.lib.vcs.utils.compat import deque, Event, Thread, _bytes, _bytearray
+
+
+class StreamFeeder(Thread):
+    """
+    Normal writing into pipe-like is blocking once the buffer is filled.
+    This thread allows a thread to seep data from a file-like into a pipe
+    without blocking the main thread.
+    We close inpipe once the end of the source stream is reached.
+    """
+    def __init__(self, source):
+        super(StreamFeeder, self).__init__()
+        self.daemon = True
+        filelike = False
+        self.bytes = _bytes()
+        if type(source) in (type(''), _bytes, _bytearray):  # string-like
+            self.bytes = _bytes(source)
+        else:  # can be either file pointer or file-like
+            if type(source) in (int, long):  # file pointer it is
+                ## converting file descriptor (int) stdin into file-like
+                try:
+                    source = os.fdopen(source, 'rb', 16384)
+                except Exception:
+                    pass
+            # let's see if source is file-like by now
+            try:
+                filelike = source.read
+            except Exception:
+                pass
+        if not filelike and not self.bytes:
+            raise TypeError("StreamFeeder's source object must be a readable "
+                            "file-like, a file descriptor, or a string-like.")
+        self.source = source
+        self.readiface, self.writeiface = os.pipe()
+
+    def run(self):
+        t = self.writeiface
+        if self.bytes:
+            os.write(t, self.bytes)
+        else:
+            s = self.source
+            b = s.read(4096)
+            while b:
+                os.write(t, b)
+                b = s.read(4096)
+        os.close(t)
+
+    @property
+    def output(self):
+        return self.readiface
+
+
+class InputStreamChunker(Thread):
+    def __init__(self, source, target, buffer_size, chunk_size):
+
+        super(InputStreamChunker, self).__init__()
+
+        self.daemon = True  # die die die.
+
+        self.source = source
+        self.target = target
+        self.chunk_count_max = int(buffer_size / chunk_size) + 1
+        self.chunk_size = chunk_size
+
+        self.data_added = Event()
+        self.data_added.clear()
+
+        self.keep_reading = Event()
+        self.keep_reading.set()
+
+        self.EOF = Event()
+        self.EOF.clear()
+
+        self.go = Event()
+        self.go.set()
+
+    def stop(self):
+        self.go.clear()
+        self.EOF.set()
+        try:
+            # this is not proper, but is done to force the reader thread let
+            # go of the input because, if successful, .close() will send EOF
+            # down the pipe.
+            self.source.close()
+        except:
+            pass
+
+    def run(self):
+        s = self.source
+        t = self.target
+        cs = self.chunk_size
+        ccm = self.chunk_count_max
+        kr = self.keep_reading
+        da = self.data_added
+        go = self.go
+
+        try:
+            b = s.read(cs)
+        except ValueError:
+            b = ''
+
+        while b and go.is_set():
+            if len(t) > ccm:
+                kr.clear()
+                kr.wait(2)
+#                # this only works on 2.7.x and up
+#                if not kr.wait(10):
+#                    raise Exception("Timed out while waiting for input to be read.")
+                # instead we'll use this
+                if len(t) > ccm + 3:
+                    raise IOError("Timed out while waiting for input from subprocess.")
+            t.append(b)
+            da.set()
+            b = s.read(cs)
+        self.EOF.set()
+        da.set()  # for cases when done but there was no input.
+
+
+class BufferedGenerator():
+    '''
+    Class behaves as a non-blocking, buffered pipe reader.
+    Reads chunks of data (through a thread)
+    from a blocking pipe, and attaches these to an array (Deque) of chunks.
+    Reading is halted in the thread when max chunks is internally buffered.
+    The .next() may operate in blocking or non-blocking fashion by yielding
+    '' if no data is ready
+    to be sent or by not returning until there is some data to send
+    When we get EOF from underlying source pipe we raise the marker to raise
+    StopIteration after the last chunk of data is yielded.
+    '''
+
+    def __init__(self, source, buffer_size=65536, chunk_size=4096,
+                 starting_values=[], bottomless=False):
+
+        if bottomless:
+            maxlen = int(buffer_size / chunk_size)
+        else:
+            maxlen = None
+
+        self.data = deque(starting_values, maxlen)
+
+        self.worker = InputStreamChunker(source, self.data, buffer_size,
+                                         chunk_size)
+        if starting_values:
+            self.worker.data_added.set()
+        self.worker.start()
+
+    ####################
+    # Generator's methods
+    ####################
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        while not len(self.data) and not self.worker.EOF.is_set():
+            self.worker.data_added.clear()
+            self.worker.data_added.wait(0.2)
+        if len(self.data):
+            self.worker.keep_reading.set()
+            return _bytes(self.data.popleft())
+        elif self.worker.EOF.is_set():
+            raise StopIteration
+
+    def throw(self, type, value=None, traceback=None):
+        if not self.worker.EOF.is_set():
+            raise type(value)
+
+    def start(self):
+        self.worker.start()
+
+    def stop(self):
+        self.worker.stop()
+
+    def close(self):
+        try:
+            self.worker.stop()
+            self.throw(GeneratorExit)
+        except (GeneratorExit, StopIteration):
+            pass
+
+    def __del__(self):
+        self.close()
+
+    ####################
+    # Threaded reader's infrastructure.
+    ####################
+    @property
+    def input(self):
+        return self.worker.w
+
+    @property
+    def data_added_event(self):
+        return self.worker.data_added
+
+    @property
+    def data_added(self):
+        return self.worker.data_added.is_set()
+
+    @property
+    def reading_paused(self):
+        return not self.worker.keep_reading.is_set()
+
+    @property
+    def done_reading_event(self):
+        '''
+        Done_reding does not mean that the iterator's buffer is empty.
+        Iterator might have done reading from underlying source, but the read
+        chunks might still be available for serving through .next() method.
+
+        @return An Event class instance.
+        '''
+        return self.worker.EOF
+
+    @property
+    def done_reading(self):
+        '''
+        Done_reding does not mean that the iterator's buffer is empty.
+        Iterator might have done reading from underlying source, but the read
+        chunks might still be available for serving through .next() method.
+
+        @return An Bool value.
+        '''
+        return self.worker.EOF.is_set()
+
+    @property
+    def length(self):
+        '''
+        returns int.
+
+        This is the lenght of the que of chunks, not the length of
+        the combined contents in those chunks.
+
+        __len__() cannot be meaningfully implemented because this
+        reader is just flying throuh a bottomless pit content and
+        can only know the lenght of what it already saw.
+
+        If __len__() on WSGI server per PEP 3333 returns a value,
+        the responce's length will be set to that. In order not to
+        confuse WSGI PEP3333 servers, we will not implement __len__
+        at all.
+        '''
+        return len(self.data)
+
+    def prepend(self, x):
+        self.data.appendleft(x)
+
+    def append(self, x):
+        self.data.append(x)
+
+    def extend(self, o):
+        self.data.extend(o)
+
+    def __getitem__(self, i):
+        return self.data[i]
+
+
+class SubprocessIOChunker(object):
+    '''
+    Processor class wrapping handling of subprocess IO.
+
+    In a way, this is a "communicate()" replacement with a twist.
+
+    - We are multithreaded. Writing in and reading out, err are all sep threads.
+    - We support concurrent (in and out) stream processing.
+    - The output is not a stream. It's a queue of read string (bytes, not unicode)
+      chunks. The object behaves as an iterable. You can "for chunk in obj:" us.
+    - We are non-blocking in more respects than communicate()
+      (reading from subprocess out pauses when internal buffer is full, but
+       does not block the parent calling code. On the flip side, reading from
+       slow-yielding subprocess may block the iteration until data shows up. This
+       does not block the parallel inpipe reading occurring parallel thread.)
+
+    The purpose of the object is to allow us to wrap subprocess interactions into
+    and interable that can be passed to a WSGI server as the application's return
+    value. Because of stream-processing-ability, WSGI does not have to read ALL
+    of the subprocess's output and buffer it, before handing it to WSGI server for
+    HTTP response. Instead, the class initializer reads just a bit of the stream
+    to figure out if error ocurred or likely to occur and if not, just hands the
+    further iteration over subprocess output to the server for completion of HTTP
+    response.
+
+    The real or perceived subprocess error is trapped and raised as one of
+    EnvironmentError family of exceptions
+
+    Example usage:
+    #    try:
+    #        answer = SubprocessIOChunker(
+    #            cmd,
+    #            input,
+    #            buffer_size = 65536,
+    #            chunk_size = 4096
+    #            )
+    #    except (EnvironmentError) as e:
+    #        print str(e)
+    #        raise e
+    #
+    #    return answer
+
+
+    '''
+    def __init__(self, cmd, inputstream=None, buffer_size=65536,
+                 chunk_size=4096, starting_values=[], **kwargs):
+        '''
+        Initializes SubprocessIOChunker
+
+        :param cmd: A Subprocess.Popen style "cmd". Can be string or array of strings
+        :param inputstream: (Default: None) A file-like, string, or file pointer.
+        :param buffer_size: (Default: 65536) A size of total buffer per stream in bytes.
+        :param chunk_size: (Default: 4096) A max size of a chunk. Actual chunk may be smaller.
+        :param starting_values: (Default: []) An array of strings to put in front of output que.
+        '''
+
+        if inputstream:
+            input_streamer = StreamFeeder(inputstream)
+            input_streamer.start()
+            inputstream = input_streamer.output
+
+        if isinstance(cmd, (list, tuple)):
+            cmd = ' '.join(cmd)
+
+        _shell = kwargs.get('shell') or True
+        kwargs['shell'] = _shell
+        _p = subprocess.Popen(cmd,
+            bufsize=-1,
+            stdin=inputstream,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            **kwargs
+            )
+
+        bg_out = BufferedGenerator(_p.stdout, buffer_size, chunk_size, starting_values)
+        bg_err = BufferedGenerator(_p.stderr, 16000, 1, bottomless=True)
+
+        while not bg_out.done_reading and not bg_out.reading_paused and not bg_err.length:
+            # doing this until we reach either end of file, or end of buffer.
+            bg_out.data_added_event.wait(1)
+            bg_out.data_added_event.clear()
+
+        # at this point it's still ambiguous if we are done reading or just full buffer.
+        # Either way, if error (returned by ended process, or implied based on
+        # presence of stuff in stderr output) we error out.
+        # Else, we are happy.
+        _returncode = _p.poll()
+        if _returncode or (_returncode == None and bg_err.length):
+            try:
+                _p.terminate()
+            except:
+                pass
+            bg_out.stop()
+            bg_err.stop()
+            err = '%s' % ''.join(bg_err)
+            if err:
+                raise EnvironmentError("Subprocess exited due to an error:\n" + err)
+            raise EnvironmentError("Subprocess exited with non 0 ret code:%s" % _returncode)
+
+        self.process = _p
+        self.output = bg_out
+        self.error = bg_err
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        if self.process.poll():
+            err = '%s' % ''.join(self.error)
+            raise EnvironmentError("Subprocess exited due to an error:\n" + err)
+        return self.output.next()
+
+    def throw(self, type, value=None, traceback=None):
+        if self.output.length or not self.output.done_reading:
+            raise type(value)
+
+    def close(self):
+        try:
+            self.process.terminate()
+        except:
+            pass
+        try:
+            self.output.close()
+        except:
+            pass
+        try:
+            self.error.close()
+        except:
+            pass
+
+    def __del__(self):
+        self.close()
--- a/rhodecode/lib/vcs/utils/__init__.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/utils/__init__.py	Sat Apr 27 11:24:25 2013 +0200
@@ -16,6 +16,27 @@
     return time.mktime(lt), tz
 
 
+def aslist(obj, sep=None, strip=True):
+    """
+    Returns given string separated by sep as list
+
+    :param obj:
+    :param sep:
+    :param strip:
+    """
+    if isinstance(obj, (basestring)):
+        lst = obj.split(sep)
+        if strip:
+            lst = [v.strip() for v in lst]
+        return lst
+    elif isinstance(obj, (list, tuple)):
+        return obj
+    elif obj is None:
+        return []
+    else:
+        return [obj]
+
+
 def date_fromtimestamp(unixts, tzoffset=0):
     """
     Makes a local datetime object out of unix timestamp
@@ -27,6 +48,23 @@
     return datetime.datetime.fromtimestamp(float(unixts))
 
 
+def safe_int(val, default=None):
+    """
+    Returns int() of val if val is not convertable to int use default
+    instead
+
+    :param val:
+    :param default:
+    """
+
+    try:
+        val = int(val)
+    except (ValueError, TypeError):
+        val = default
+
+    return val
+
+
 def safe_unicode(str_, from_encoding=None):
     """
     safe unicode function. Does few trick to turn str_ into unicode
@@ -38,21 +76,26 @@
     :rtype: unicode
     :returns: unicode object
     """
-    from rhodecode.lib.utils2 import safe_unicode
-    return safe_unicode(str_, from_encoding)
-
     if isinstance(str_, unicode):
         return str_
 
+    if not from_encoding:
+        from rhodecode.lib.vcs.conf import settings
+        from_encoding = settings.DEFAULT_ENCODINGS
+
+    if not isinstance(from_encoding, (list, tuple)):
+        from_encoding = [from_encoding]
+
     try:
         return unicode(str_)
     except UnicodeDecodeError:
         pass
 
-    try:
-        return unicode(str_, from_encoding)
-    except UnicodeDecodeError:
-        pass
+    for enc in from_encoding:
+        try:
+            return unicode(str_, enc)
+        except UnicodeDecodeError:
+            pass
 
     try:
         import chardet
@@ -61,7 +104,7 @@
             raise Exception()
         return str_.decode(encoding)
     except (ImportError, UnicodeDecodeError, Exception):
-        return unicode(str_, from_encoding, 'replace')
+        return unicode(str_, from_encoding[0], 'replace')
 
 
 def safe_str(unicode_, to_encoding=None):
@@ -75,16 +118,26 @@
     :rtype: str
     :returns: str object
     """
-    from rhodecode.lib.utils2 import safe_str
-    return safe_str(unicode_, to_encoding)
+
+    # if it's not basestr cast to str
+    if not isinstance(unicode_, basestring):
+        return str(unicode_)
 
     if isinstance(unicode_, str):
         return unicode_
 
-    try:
-        return unicode_.encode(to_encoding)
-    except UnicodeEncodeError:
-        pass
+    if not to_encoding:
+        from rhodecode.lib.vcs.conf import settings
+        to_encoding = settings.DEFAULT_ENCODINGS
+
+    if not isinstance(to_encoding, (list, tuple)):
+        to_encoding = [to_encoding]
+
+    for enc in to_encoding:
+        try:
+            return unicode_.encode(enc)
+        except UnicodeEncodeError:
+            pass
 
     try:
         import chardet
@@ -94,7 +147,7 @@
 
         return unicode_.encode(encoding)
     except (ImportError, UnicodeEncodeError):
-        return unicode_.encode(to_encoding, 'replace')
+        return unicode_.encode(to_encoding[0], 'replace')
 
     return safe_str
 
--- a/rhodecode/lib/vcs/utils/annotate.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/utils/annotate.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,9 +1,10 @@
-from rhodecode.lib.vcs.exceptions import VCSError
-from rhodecode.lib.vcs.nodes import FileNode
+import StringIO
+
 from pygments.formatters import HtmlFormatter
 from pygments import highlight
 
-import StringIO
+from rhodecode.lib.vcs.exceptions import VCSError
+from rhodecode.lib.vcs.nodes import FileNode
 
 
 def annotate_highlight(filenode, annotate_from_changeset_func=None,
--- a/rhodecode/lib/vcs/utils/compat.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/utils/compat.py	Sat Apr 27 11:24:25 2013 +0200
@@ -5,9 +5,314 @@
 versions.
 """
 import sys
-
+import array
 
 if sys.version_info >= (2, 7):
     unittest = __import__('unittest')
 else:
     unittest = __import__('unittest2')
+
+
+if sys.version_info >= (2, 6):
+    _bytes = bytes
+else:
+    # in py2.6 bytes is a synonim for str
+    _bytes = str
+
+if sys.version_info >= (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
+
+if sys.version_info >= (2, 6):
+    from collections import deque
+else:
+    #need to implement our own deque with maxlen
+    class deque(object):
+
+        def __init__(self, iterable=(), maxlen= -1):
+            if not hasattr(self, 'data'):
+                self.left = self.right = 0
+                self.data = {}
+            self.maxlen = maxlen or -1
+            self.extend(iterable)
+
+        def append(self, x):
+            self.data[self.right] = x
+            self.right += 1
+            if self.maxlen != -1 and len(self) > self.maxlen:
+                self.popleft()
+
+        def appendleft(self, x):
+            self.left -= 1
+            self.data[self.left] = x
+            if self.maxlen != -1 and len(self) > self.maxlen:
+                self.pop()
+
+        def pop(self):
+            if self.left == self.right:
+                raise IndexError('cannot pop from empty deque')
+            self.right -= 1
+            elem = self.data[self.right]
+            del self.data[self.right]
+            return elem
+
+        def popleft(self):
+            if self.left == self.right:
+                raise IndexError('cannot pop from empty deque')
+            elem = self.data[self.left]
+            del self.data[self.left]
+            self.left += 1
+            return elem
+
+        def clear(self):
+            self.data.clear()
+            self.left = self.right = 0
+
+        def extend(self, iterable):
+            for elem in iterable:
+                self.append(elem)
+
+        def extendleft(self, iterable):
+            for elem in iterable:
+                self.appendleft(elem)
+
+        def rotate(self, n=1):
+            if self:
+                n %= len(self)
+                for i in xrange(n):
+                    self.appendleft(self.pop())
+
+        def __getitem__(self, i):
+            if i < 0:
+                i += len(self)
+            try:
+                return self.data[i + self.left]
+            except KeyError:
+                raise IndexError
+
+        def __setitem__(self, i, value):
+            if i < 0:
+                i += len(self)
+            try:
+                self.data[i + self.left] = value
+            except KeyError:
+                raise IndexError
+
+        def __delitem__(self, i):
+            size = len(self)
+            if not (-size <= i < size):
+                raise IndexError
+            data = self.data
+            if i < 0:
+                i += size
+            for j in xrange(self.left + i, self.right - 1):
+                data[j] = data[j + 1]
+            self.pop()
+
+        def __len__(self):
+            return self.right - self.left
+
+        def __cmp__(self, other):
+            if type(self) != type(other):
+                return cmp(type(self), type(other))
+            return cmp(list(self), list(other))
+
+        def __repr__(self, _track=[]):
+            if id(self) in _track:
+                return '...'
+            _track.append(id(self))
+            r = 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
+            _track.remove(id(self))
+            return r
+
+        def __getstate__(self):
+            return (tuple(self),)
+
+        def __setstate__(self, s):
+            self.__init__(s[0])
+
+        def __hash__(self):
+            raise TypeError
+
+        def __copy__(self):
+            return self.__class__(self)
+
+        def __deepcopy__(self, memo={}):
+            from copy import deepcopy
+            result = self.__class__()
+            memo[id(self)] = result
+            result.__init__(deepcopy(tuple(self), memo))
+            return result
+
+
+#==============================================================================
+# threading.Event
+#==============================================================================
+
+if sys.version_info >= (2, 6):
+    from threading import Event, Thread
+else:
+    from threading import _Verbose, 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 "<Condition(%s, %d)>" % (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)
+
+    class _Event(_Verbose):
+
+        # After Tim Peters' event class (without is_posted())
+
+        def __init__(self, verbose=None):
+            _Verbose.__init__(self, verbose)
+            self.__cond = Condition(Lock())
+            self.__flag = False
+
+        def isSet(self):
+            return self.__flag
+
+        is_set = isSet
+
+        def set(self):
+            self.__cond.acquire()
+            try:
+                self.__flag = True
+                self.__cond.notify_all()
+            finally:
+                self.__cond.release()
+
+        def clear(self):
+            self.__cond.acquire()
+            try:
+                self.__flag = False
+            finally:
+                self.__cond.release()
+
+        def wait(self, timeout=None):
+            self.__cond.acquire()
+            try:
+                if not self.__flag:
+                    self.__cond.wait(timeout)
+            finally:
+                self.__cond.release()
--- a/rhodecode/lib/vcs/utils/diffs.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/utils/diffs.py	Sat Apr 27 11:24:25 2013 +0200
@@ -5,11 +5,9 @@
 import re
 import difflib
 import logging
+import itertools
 
 from difflib import unified_diff
-from itertools import tee, imap
-
-from mercurial.match import match
 
 from rhodecode.lib.vcs.exceptions import VCSError
 from rhodecode.lib.vcs.nodes import FileNode, NodeError
@@ -65,7 +63,7 @@
     new_raw_id = getattr(filenode_new.changeset, 'raw_id', '0' * 40)
 
     repo = filenode_new.changeset.repository
-    vcs_gitdiff = repo._get_diff(old_raw_id, new_raw_id, filenode_new.path,
+    vcs_gitdiff = repo.get_diff(old_raw_id, new_raw_id, filenode_new.path,
                                  ignore_whitespace)
 
     return vcs_gitdiff
@@ -97,10 +95,11 @@
 
         elif self.__format == 'gitdiff':
             udiff_copy = self.copy_iterator()
-            self.lines = imap(self.escaper, self._parse_gitdiff(udiff_copy))
+            self.lines = itertools.imap(self.escaper,
+                                        self._parse_gitdiff(udiff_copy))
         else:
             udiff_copy = self.copy_iterator()
-            self.lines = imap(self.escaper, udiff_copy)
+            self.lines = itertools.imap(self.escaper, udiff_copy)
 
         # Select a differ.
         if differ == 'difflib':
@@ -117,7 +116,7 @@
         an original as it's needed for repeating operations on
         this instance of DiffProcessor
         """
-        self.__udiff, iterator_copy = tee(self.__udiff)
+        self.__udiff, iterator_copy = itertools.tee(self.__udiff)
         return iterator_copy
 
     def _extract_rev(self, line1, line2):
--- a/rhodecode/lib/vcs/utils/helpers.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/utils/helpers.py	Sat Apr 27 11:24:25 2013 +0200
@@ -4,10 +4,11 @@
 from __future__ import division
 
 import re
+import os
 import time
 import datetime
-import os.path
 from subprocess import Popen, PIPE
+
 from rhodecode.lib.vcs.exceptions import VCSError
 from rhodecode.lib.vcs.exceptions import RepositoryError
 from rhodecode.lib.vcs.utils.paths import abspath
@@ -163,6 +164,7 @@
             return result
     raise ValueError("IDs not recognized")
 
+
 def parse_datetime(text):
     """
     Parses given text and returns ``datetime.datetime`` instance or raises
--- a/rhodecode/lib/vcs/utils/hgcompat.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/utils/hgcompat.py	Sat Apr 27 11:24:25 2013 +0200
@@ -16,3 +16,9 @@
 from mercurial import localrepo
 from mercurial import scmutil
 from mercurial.discovery import findcommonoutgoing
+
+from mercurial.util import url as hg_url
+
+# those authnadlers are patched for python 2.6.5 bug an
+# infinit looping when given invalid resources
+from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
--- a/rhodecode/lib/vcs/utils/progressbar.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/lib/vcs/utils/progressbar.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,7 +1,8 @@
 # encoding: UTF-8
 import sys
 import datetime
-from string import Template
+import string
+
 from rhodecode.lib.vcs.utils.filesize import filesizeformat
 from rhodecode.lib.vcs.utils.helpers import get_total_seconds
 
@@ -63,7 +64,7 @@
     def get_template(self):
         separator = self.get_separator()
         elements = self.get_elements()
-        return Template(separator.join((('$%s' % e) for e in elements)))
+        return string.Template(separator.join((('$%s' % e) for e in elements)))
 
     def get_total_time(self, current_time=None):
         if current_time is None:
--- a/rhodecode/tests/__init__.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/__init__.py	Sat Apr 27 11:24:25 2013 +0200
@@ -30,7 +30,12 @@
 
 from paste.deploy import loadapp
 from paste.script.appinstall import SetupCommand
+
+import pylons
+import pylons.test
 from pylons import config, url
+from pylons.i18n.translation import _get_translator
+
 from routes.util import URLGenerator
 from webtest import TestApp
 from nose.plugins.skip import SkipTest
@@ -39,8 +44,6 @@
 from rhodecode.model.meta import Session
 from rhodecode.model.db import User
 from rhodecode.tests.nose_parametrized import parameterized
-
-import pylons.test
 from rhodecode.lib.utils2 import safe_unicode, safe_str
 
 
@@ -149,7 +152,13 @@
 
         self.app = TestApp(wsgiapp)
         url._push_object(URLGenerator(config['routes.map'], environ))
-        self.Session = Session
+        pylons.app_globals._push_object(config['pylons.app_globals'])
+        pylons.config._push_object(config)
+
+        # Initialize a translator for tests that utilize i18n
+        translator = _get_translator(pylons.config.get('lang'))
+        pylons.translator._push_object(translator)
+
         self.index_location = config['app_conf']['index_dir']
         TestCase.__init__(self, *args, **kwargs)
 
--- a/rhodecode/tests/functional/test_admin_notifications.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_admin_notifications.py	Sat Apr 27 11:24:25 2013 +0200
@@ -3,6 +3,7 @@
 
 from rhodecode.model.user import UserModel
 from rhodecode.model.notification import NotificationModel
+from rhodecode.model.meta import Session
 
 
 class TestNotificationsController(TestController):
@@ -10,8 +11,8 @@
     def tearDown(self):
         for n in Notification.query().all():
             inst = Notification.get(n.notification_id)
-            self.Session().delete(inst)
-        self.Session().commit()
+            Session().delete(inst)
+        Session().commit()
 
     def test_index(self):
         self.log_user()
@@ -29,7 +30,7 @@
         NotificationModel().create(created_by=u1, subject=u'test_notification_1',
                                    body=u'notification_1',
                                    recipients=[cur_user])
-        self.Session().commit()
+        Session().commit()
         response = self.app.get(url('notifications'))
         response.mustcontain(u'test_notification_1')
 
@@ -67,7 +68,7 @@
                                                   subject=u'test',
                                                   body=u'hi there',
                                                   recipients=[cur_user, u1, u2])
-        self.Session().commit()
+        Session().commit()
         u1 = User.get(u1.user_id)
         u2 = User.get(u2.user_id)
 
--- a/rhodecode/tests/functional/test_admin_repos.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_admin_repos.py	Sat Apr 27 11:24:25 2013 +0200
@@ -47,7 +47,7 @@
                                % (repo_name, repo_name))
 
         #test if the repo was created in the database
-        new_repo = self.Session().query(Repository)\
+        new_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name).one()
 
         self.assertEqual(new_repo.repo_name, repo_name)
@@ -80,7 +80,7 @@
                                u'Created repository <a href="/%s">%s</a>'
                                % (urllib.quote(repo_name), repo_name_unicode))
         #test if the repo was created in the database
-        new_repo = self.Session().query(Repository)\
+        new_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name_unicode).one()
 
         self.assertEqual(new_repo.repo_name, repo_name_unicode)
@@ -105,7 +105,7 @@
         gr = ReposGroupModel().create(group_name=group_name,
                                       group_description='test',
                                       owner=TEST_USER_ADMIN_LOGIN)
-        self.Session().commit()
+        Session().commit()
 
         repo_name = 'ingroup'
         repo_name_full = RepoGroup.url_sep().join([group_name, repo_name])
@@ -120,7 +120,7 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name_full, repo_name))
         #test if the repo was created in the database
-        new_repo = self.Session().query(Repository)\
+        new_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name_full).one()
 
         self.assertEqual(new_repo.repo_name, repo_name_full)
@@ -136,12 +136,12 @@
             vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name_full))
         except Exception:
             ReposGroupModel().delete(group_name)
-            self.Session().commit()
+            Session().commit()
             self.fail('no repo %s in filesystem' % repo_name)
 
         RepoModel().delete(repo_name_full)
         ReposGroupModel().delete(group_name)
-        self.Session().commit()
+        Session().commit()
 
     def test_create_git(self):
         self.log_user()
@@ -158,7 +158,7 @@
                                % (repo_name, repo_name))
 
         #test if the repo was created in the database
-        new_repo = self.Session().query(Repository)\
+        new_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name).one()
 
         self.assertEqual(new_repo.repo_name, repo_name)
@@ -194,7 +194,7 @@
                                % (urllib.quote(repo_name), repo_name_unicode))
 
         #test if the repo was created in the database
-        new_repo = self.Session().query(Repository)\
+        new_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name_unicode).one()
 
         self.assertEqual(new_repo.repo_name, repo_name_unicode)
@@ -232,7 +232,7 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name, repo_name))
         #test if the repo was created in the database
-        new_repo = self.Session().query(Repository)\
+        new_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name).one()
 
         self.assertEqual(new_repo.repo_name, repo_name)
@@ -256,7 +256,7 @@
         response.follow()
 
         #check if repo was deleted from db
-        deleted_repo = self.Session().query(Repository)\
+        deleted_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name).scalar()
 
         self.assertEqual(deleted_repo, None)
@@ -279,7 +279,7 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name, repo_name))
         #test if the repo was created in the database
-        new_repo = self.Session().query(Repository)\
+        new_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name).one()
 
         self.assertEqual(new_repo.repo_name, repo_name)
@@ -303,7 +303,7 @@
         response.follow()
 
         #check if repo was deleted from db
-        deleted_repo = self.Session().query(Repository)\
+        deleted_repo = Session().query(Repository)\
             .filter(Repository.repo_name == repo_name).scalar()
 
         self.assertEqual(deleted_repo, None)
--- a/rhodecode/tests/functional/test_admin_settings.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_admin_settings.py	Sat Apr 27 11:24:25 2013 +0200
@@ -6,6 +6,7 @@
 from rhodecode.lib import helpers as h
 from rhodecode.model.user import UserModel
 from rhodecode.model.scm import ScmModel
+from rhodecode.model.meta import Session
 
 
 class TestAdminSettingsController(TestController):
@@ -135,7 +136,7 @@
         uname = 'testme'
         usr = UserModel().create_or_update(username=uname, password='qweqwe',
                                            email='testme@rhodecod.org')
-        self.Session().commit()
+        Session().commit()
         params = usr.get_api_data()
         user_id = usr.user_id
         self.log_user(username=uname, password='qweqwe')
--- a/rhodecode/tests/functional/test_admin_users.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_admin_users.py	Sat Apr 27 11:24:25 2013 +0200
@@ -39,7 +39,7 @@
 
         self.checkSessionFlash(response, '''Created user %s''' % (username))
 
-        new_user = self.Session.query(User).\
+        new_user = Session().query(User).\
             filter(User.username == username).one()
 
         self.assertEqual(new_user.username, username)
@@ -74,7 +74,7 @@
         response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""")
 
         def get_user():
-            self.Session.query(User).filter(User.username == username).one()
+            Session().query(User).filter(User.username == username).one()
 
         self.assertRaises(NoResultFound, get_user), 'found user in database'
 
@@ -100,7 +100,7 @@
         uname = 'testme'
         usr = UserModel().create_or_update(username=uname, password='qweqwe',
                                            email='testme@rhodecod.org')
-        self.Session().commit()
+        Session().commit()
         params = usr.get_api_data()
         params.update({name: expected})
         params.update({'password_confirmation': ''})
@@ -146,7 +146,7 @@
 
         response = response.follow()
 
-        new_user = self.Session.query(User)\
+        new_user = Session().query(User)\
             .filter(User.username == username).one()
         response = self.app.delete(url('user', id=new_user.user_id))
 
--- a/rhodecode/tests/functional/test_admin_users_groups.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_admin_users_groups.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,5 +1,6 @@
 from rhodecode.tests import *
 from rhodecode.model.db import UserGroup, UserGroupToPerm, Permission
+from rhodecode.model.meta import Session
 
 TEST_USER_GROUP = 'admins_test'
 
@@ -48,13 +49,13 @@
         self.checkSessionFlash(response,
                                'Created user group %s' % users_group_name)
 
-        gr = self.Session.query(UserGroup)\
+        gr = Session().query(UserGroup)\
                            .filter(UserGroup.users_group_name ==
                                    users_group_name).one()
 
         response = self.app.delete(url('users_group', id=gr.users_group_id))
 
-        gr = self.Session.query(UserGroup)\
+        gr = Session().query(UserGroup)\
                            .filter(UserGroup.users_group_name ==
                                    users_group_name).scalar()
 
@@ -119,7 +120,7 @@
         ugid = ug.users_group_id
         response = self.app.delete(url('users_group', id=ug.users_group_id))
         response = response.follow()
-        gr = self.Session.query(UserGroup)\
+        gr = Session().query(UserGroup)\
                            .filter(UserGroup.users_group_name ==
                                    users_group_name).scalar()
 
@@ -192,7 +193,7 @@
         ugid = ug.users_group_id
         response = self.app.delete(url('users_group', id=ug.users_group_id))
         response = response.follow()
-        gr = self.Session.query(UserGroup)\
+        gr = Session().query(UserGroup)\
                            .filter(UserGroup.users_group_name ==
                                    users_group_name).scalar()
 
--- a/rhodecode/tests/functional/test_branches.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_branches.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,11 +1,20 @@
 from rhodecode.tests import *
 
+
 class TestBranchesController(TestController):
 
-    def test_index(self):
+    def test_index_hg(self):
         self.log_user()
         response = self.app.get(url(controller='branches',
                                     action='index', repo_name=HG_REPO))
-        response.mustcontain("""<a href="/%s/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/">default</a>""" % HG_REPO)
-        response.mustcontain("""<a href="/%s/files/97e8b885c04894463c51898e14387d80c30ed1ee/">git</a>""" % HG_REPO)
-        response.mustcontain("""<a href="/%s/files/2e6a2bf9356ca56df08807f4ad86d480da72a8f4/">web</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/">default</a>""" % HG_REPO)
+
+        # closed branches
+        response.mustcontain("""<a href="/%s/changeset/95ca6417ec0de6ac3bd19b336d7b608f27b88711">git [closed]</a><""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/changeset/0dd5fd7b37a4eea4dd9b662af63cee743b4ccce2">web [closed]</a>""" % HG_REPO)
+
+    def test_index_git(self):
+        self.log_user()
+        response = self.app.get(url(controller='branches',
+                                    action='index', repo_name=GIT_REPO))
+        response.mustcontain("""<a href="/%s/files/5f2c6ee195929b0be80749243c18121c9864a3b3/">master</a>""" % GIT_REPO)
--- a/rhodecode/tests/functional/test_changelog.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_changelog.py	Sat Apr 27 11:24:25 2013 +0200
@@ -11,23 +11,15 @@
         response.mustcontain('''id="chg_20" class="container tablerow1"''')
         response.mustcontain(
             """<input class="changeset_range" """
-            """id="5e204e7583b9c8e7b93a020bd036564b1e731dae" """
-            """name="5e204e7583b9c8e7b93a020bd036564b1e731dae" """
+            """id="7b22a518347bb9bc19679f6af07cd0a61bfe16e7" """
+            """name="7b22a518347bb9bc19679f6af07cd0a61bfe16e7" """
             """type="checkbox" value="1" />"""
         )
-
+        #rev 640: code garden
         response.mustcontain(
-            """<span class="changeset_hash">r154:5e204e7583b9</span>"""
+            """<span class="changeset_hash">r640:0a4e54a44604</span>"""
         )
-
-        response.mustcontain("""Small update at simplevcs app""")
-
-#        response.mustcontain(
-#            """<div id="changed_total_5e204e7583b9c8e7b93a020bd036564b1e731dae" """
-#            """style="float:right;" class="changed_total tooltip" """
-#            """title="Affected number of files, click to show """
-#            """more details">3</div>"""
-#        )
+        response.mustcontain("""code garden""")
 
     def test_index_pagination_hg(self):
         self.log_user()
@@ -48,29 +40,15 @@
         # Test response after pagination...
         response.mustcontain(
             """<input class="changeset_range" """
-            """id="46ad32a4f974e45472a898c6b0acb600320579b1" """
-            """name="46ad32a4f974e45472a898c6b0acb600320579b1" """
+            """id="22baf968d547386b9516965ce89d189665003a31" """
+            """name="22baf968d547386b9516965ce89d189665003a31" """
             """type="checkbox" value="1" />"""
         )
 
         response.mustcontain(
-            """<span class="changeset_hash">r64:46ad32a4f974</span>"""
+            """<span class="changeset_hash">r539:22baf968d547</span>"""
         )
 
-#        response.mustcontain(
-#            """<div id="changed_total_46ad32a4f974e45472a898c6b0acb600320579b1" """
-#            """style="float:right;" class="changed_total tooltip" """
-#            """title="Affected number of files, click to show """
-#            """more details">21</div>"""
-#        )
-#
-#        response.mustcontain(
-#            """<a href="/%s/changeset/"""
-#            """46ad32a4f974e45472a898c6b0acb600320579b1" """
-#            """title="Merge with 2e6a2bf9356ca56df08807f4ad86d480da72a8f4">"""
-#            """46ad32a4f974</a>""" % HG_REPO
-#        )
-
     def test_index_git(self):
         self.log_user()
         response = self.app.get(url(controller='changelog', action='index',
--- a/rhodecode/tests/functional/test_changeset_comments.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_changeset_comments.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,27 +1,28 @@
 from rhodecode.tests import *
 from rhodecode.model.db import ChangesetComment, Notification, User, \
     UserNotification
+from rhodecode.model.meta import Session
 
 
 class TestChangeSetCommentsController(TestController):
 
     def setUp(self):
         for x in ChangesetComment.query().all():
-            self.Session.delete(x)
-        self.Session.commit()
+            Session().delete(x)
+        Session().commit()
 
         for x in Notification.query().all():
-            self.Session.delete(x)
-        self.Session.commit()
+            Session().delete(x)
+        Session().commit()
 
     def tearDown(self):
         for x in ChangesetComment.query().all():
-            self.Session.delete(x)
-        self.Session.commit()
+            Session().delete(x)
+        Session().commit()
 
         for x in Notification.query().all():
-            self.Session.delete(x)
-        self.Session.commit()
+            Session().delete(x)
+        Session().commit()
 
     def test_create(self):
         self.log_user()
--- a/rhodecode/tests/functional/test_compare_local.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_compare_local.py	Sat Apr 27 11:24:25 2013 +0200
@@ -10,16 +10,17 @@
 
     def test_compare_tag_hg(self):
         self.log_user()
-        tag1 = '0.1.2'
-        tag2 = '0.1.3'
+        tag1 = 'v0.1.2'
+        tag2 = 'v0.1.3'
         response = self.app.get(url(controller='compare', action='index',
                                     repo_name=HG_REPO,
                                     org_ref_type="tag",
                                     org_ref=tag1,
                                     other_ref_type="tag",
                                     other_ref=tag2,
-                                    ))
+                                    ), status=200)
         response.mustcontain('%s@%s -&gt; %s@%s' % (HG_REPO, tag1, HG_REPO, tag2))
+
         ## outgoing changesets between tags
         response.mustcontain('''<a href="/%s/changeset/c5ddebc06eaaba3010c2d66ea6ec9d074eb0f678">r112:c5ddebc06eaa</a>''' % HG_REPO)
         response.mustcontain('''<a href="/%s/changeset/70d4cef8a37657ee4cf5aabb3bd9f68879769816">r115:70d4cef8a376</a>''' % HG_REPO)
@@ -54,7 +55,7 @@
                                     org_ref=tag1,
                                     other_ref_type="tag",
                                     other_ref=tag2,
-                                    ))
+                                    ), status=200)
         response.mustcontain('%s@%s -&gt; %s@%s' % (GIT_REPO, tag1, GIT_REPO, tag2))
 
         ## outgoing changesets between tags
--- a/rhodecode/tests/functional/test_files.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_files.py	Sat Apr 27 11:24:25 2013 +0200
@@ -25,11 +25,19 @@
                                     revision='tip',
                                     f_path='/'))
         # Test response...
-        response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/docs">docs</a>')
-        response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/tests">tests</a>')
-        response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/vcs">vcs</a>')
-        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/.hgignore">.hgignore</a>')
-        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/MANIFEST.in">MANIFEST.in</a>')
+        response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/docs">docs</a>')
+        response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/vcs">vcs</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/.gitignore">.gitignore</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/.hgignore">.hgignore</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/.hgtags">.hgtags</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/.travis.yml">.travis.yml</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/MANIFEST.in">MANIFEST.in</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/README.rst">README.rst</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/run_test_and_report.sh">run_test_and_report.sh</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/setup.cfg">setup.cfg</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/setup.py">setup.py</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/test_and_report.sh">test_and_report.sh</a>')
+        response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/tox.ini">tox.ini</a>')
 
     def test_index_revision(self):
         self.log_user()
@@ -79,7 +87,7 @@
         self.log_user()
         response = self.app.get(url(controller='files', action='index',
                                     repo_name=HG_REPO,
-                                    revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
+                                    revision='8911406ad776fdd3d0b9932a2e89677e57405a48',
                                     f_path='vcs/nodes.py'))
 
         response.mustcontain("""<div class="commit">Partially implemented <a class="issue-tracker-link" href="https://myissueserver.com/vcs_test_hg/issue/16">#16</a>. filecontent/commit message/author/node name are safe_unicode now.
@@ -100,7 +108,41 @@
                                 extra_environ={'HTTP_X_PARTIAL_XHR': '1'},)
         #test or history
         response.mustcontain("""<optgroup label="Changesets">
-<option selected="selected" value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option>
+<option value="dbec37a0d5cab8ff39af4cfc4a4cd3996e4acfc6">r648:dbec37a0d5ca (default)</option>
+<option value="1d20ed9eda9482d46ff0a6af5812550218b3ff15">r639:1d20ed9eda94 (default)</option>
+<option value="0173395e822797f098799ed95c1a81b6a547a9ad">r547:0173395e8227 (default)</option>
+<option value="afbb45ade933a8182f1d8ec5d4d1bb2de2572043">r546:afbb45ade933 (default)</option>
+<option value="6f093e30cac34e6b4b11275a9f22f80c5d7ad1f7">r502:6f093e30cac3 (default)</option>
+<option value="c7e2212dd2ae975d1d06534a3d7e317165c06960">r476:c7e2212dd2ae (default)</option>
+<option value="45477506df79f701bf69419aac3e1f0fed3c5bcf">r472:45477506df79 (default)</option>
+<option value="5fc76cb25d11e07c60de040f78b8cd265ff10d53">r469:5fc76cb25d11 (default)</option>
+<option value="b073433cf8994969ee5cd7cce84cbe587bb880b2">r468:b073433cf899 (default)</option>
+<option value="7a74dbfcacd1dbcb58bb9c860b2f29fbb22c4c96">r467:7a74dbfcacd1 (default)</option>
+<option value="71ee52cc4d629096bdbee036325975dac2af4501">r465:71ee52cc4d62 (default)</option>
+<option value="a5b217d26c5f111e72bae4de672b084ee0fbf75c">r452:a5b217d26c5f (default)</option>
+<option value="47aedd538bf616eedcb0e7d630ea476df0e159c7">r450:47aedd538bf6 (default)</option>
+<option value="8e4915fa32d727dcbf09746f637a5f82e539511e">r432:8e4915fa32d7 (default)</option>
+<option value="25213a5fbb048dff8ba65d21e466a835536e5b70">r356:25213a5fbb04 (default)</option>
+<option value="23debcedddc1c23c14be33e713e7786d4a9de471">r351:23debcedddc1 (default)</option>
+<option value="61e25b2a90a19e7fffd75dea1e4c7e20df526bbe">r342:61e25b2a90a1 (default)</option>
+<option value="fb95b340e0d03fa51f33c56c991c08077c99303e">r318:fb95b340e0d0 (webvcs)</option>
+<option value="bda35e0e564fbbc5cd26fe0a37fb647a254c99fe">r303:bda35e0e564f (default)</option>
+<option value="97ff74896d7dbf3115a337a421d44b55154acc89">r302:97ff74896d7d (default)</option>
+<option value="cec3473c3fdb9599c98067182a075b49bde570f9">r293:cec3473c3fdb (default)</option>
+<option value="0e86c43eef866a013a587666a877c879899599bb">r289:0e86c43eef86 (default)</option>
+<option value="91a27c312808100cf20a602f78befbbff9d89bfd">r288:91a27c312808 (default)</option>
+<option value="400e36a1670a57d11e3edcb5b07bf82c30006d0b">r287:400e36a1670a (default)</option>
+<option value="014fb17dfc95b0995e838c565376bf9a993e230a">r261:014fb17dfc95 (default)</option>
+<option value="cca7aebbc4d6125798446b11e69dc8847834a982">r260:cca7aebbc4d6 (default)</option>
+<option value="14cdb2957c011a5feba36f50d960d9832ba0f0c1">r258:14cdb2957c01 (workdir)</option>
+<option value="34df20118ed74b5987d22a579e8a60e903da5bf8">r245:34df20118ed7 (default)</option>
+<option value="0375d9042a64a1ac1641528f0f0668f9a339e86d">r233:0375d9042a64 (workdir)</option>
+<option value="94aa45fc1806c04d4ba640933edf682c22478453">r222:94aa45fc1806 (workdir)</option>
+<option value="7ed99bc738818879941e3ce20243f8856a7cfc84">r188:7ed99bc73881 (default)</option>
+<option value="1e85975528bcebe853732a9e5fb8dbf4461f6bb2">r184:1e85975528bc (default)</option>
+<option value="ed30beddde7bbddb26042625be19bcd11576c1dd">r183:ed30beddde7b (default)</option>
+<option value="a6664e18181c6fc81b751a8d01474e7e1a3fe7fc">r177:a6664e18181c (default)</option>
+<option value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option>
 <option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35 (default)</option>
 <option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c (default)</option>
 <option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329 (default)</option>
@@ -135,16 +177,23 @@
 <option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3 (default)</option>
 </optgroup>
 <optgroup label="Branches">
-<option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option>
-<option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option>
-<option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option>
+<option value="96507bd11ecc815ebc6270fdf6db110928c09c1e">default</option>
+<option value="4f7e2131323e0749a740c0a56ab68ae9269c562a">stable</option>
 </optgroup>
 <optgroup label="Tags">
-<option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option>
-<option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option>
-<option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option>
-<option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option>
-<option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option>
+<option value="2c96c02def9a7c997f33047761a53943e6254396">v0.2.0</option>
+<option value="8680b1d1cee3aa3c1ab3734b76ee164bbedbc5c9">v0.1.9</option>
+<option value="ecb25ba9c96faf1e65a0bc3fd914918420a2f116">v0.1.8</option>
+<option value="f67633a2894edaf28513706d558205fa93df9209">v0.1.7</option>
+<option value="02b38c0eb6f982174750c0e309ff9faddc0c7e12">v0.1.6</option>
+<option value="a6664e18181c6fc81b751a8d01474e7e1a3fe7fc">v0.1.5</option>
+<option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">v0.1.4</option>
+<option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">v0.1.3</option>
+<option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">v0.1.2</option>
+<option value="fef5bfe1dc17611d5fb59a7f6f95c55c3606f933">v0.1.11</option>
+<option value="92831aebf2f8dd4879e897024b89d09af214df1c">v0.1.10</option>
+<option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">v0.1.1</option>
+<option value="96507bd11ecc815ebc6270fdf6db110928c09c1e">tip</option>
 </optgroup>
 """)
 
@@ -167,8 +216,42 @@
                                     annotate=True),
                                 extra_environ={'HTTP_X_PARTIAL_XHR': '1'})
 
-        response.mustcontain("""<optgroup label="Changesets">
-<option selected="selected" value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option>
+        response.mustcontain("""
+<option value="dbec37a0d5cab8ff39af4cfc4a4cd3996e4acfc6">r648:dbec37a0d5ca (default)</option>
+<option value="1d20ed9eda9482d46ff0a6af5812550218b3ff15">r639:1d20ed9eda94 (default)</option>
+<option value="0173395e822797f098799ed95c1a81b6a547a9ad">r547:0173395e8227 (default)</option>
+<option value="afbb45ade933a8182f1d8ec5d4d1bb2de2572043">r546:afbb45ade933 (default)</option>
+<option value="6f093e30cac34e6b4b11275a9f22f80c5d7ad1f7">r502:6f093e30cac3 (default)</option>
+<option value="c7e2212dd2ae975d1d06534a3d7e317165c06960">r476:c7e2212dd2ae (default)</option>
+<option value="45477506df79f701bf69419aac3e1f0fed3c5bcf">r472:45477506df79 (default)</option>
+<option value="5fc76cb25d11e07c60de040f78b8cd265ff10d53">r469:5fc76cb25d11 (default)</option>
+<option value="b073433cf8994969ee5cd7cce84cbe587bb880b2">r468:b073433cf899 (default)</option>
+<option value="7a74dbfcacd1dbcb58bb9c860b2f29fbb22c4c96">r467:7a74dbfcacd1 (default)</option>
+<option value="71ee52cc4d629096bdbee036325975dac2af4501">r465:71ee52cc4d62 (default)</option>
+<option value="a5b217d26c5f111e72bae4de672b084ee0fbf75c">r452:a5b217d26c5f (default)</option>
+<option value="47aedd538bf616eedcb0e7d630ea476df0e159c7">r450:47aedd538bf6 (default)</option>
+<option value="8e4915fa32d727dcbf09746f637a5f82e539511e">r432:8e4915fa32d7 (default)</option>
+<option value="25213a5fbb048dff8ba65d21e466a835536e5b70">r356:25213a5fbb04 (default)</option>
+<option value="23debcedddc1c23c14be33e713e7786d4a9de471">r351:23debcedddc1 (default)</option>
+<option value="61e25b2a90a19e7fffd75dea1e4c7e20df526bbe">r342:61e25b2a90a1 (default)</option>
+<option value="fb95b340e0d03fa51f33c56c991c08077c99303e">r318:fb95b340e0d0 (webvcs)</option>
+<option value="bda35e0e564fbbc5cd26fe0a37fb647a254c99fe">r303:bda35e0e564f (default)</option>
+<option value="97ff74896d7dbf3115a337a421d44b55154acc89">r302:97ff74896d7d (default)</option>
+<option value="cec3473c3fdb9599c98067182a075b49bde570f9">r293:cec3473c3fdb (default)</option>
+<option value="0e86c43eef866a013a587666a877c879899599bb">r289:0e86c43eef86 (default)</option>
+<option value="91a27c312808100cf20a602f78befbbff9d89bfd">r288:91a27c312808 (default)</option>
+<option value="400e36a1670a57d11e3edcb5b07bf82c30006d0b">r287:400e36a1670a (default)</option>
+<option value="014fb17dfc95b0995e838c565376bf9a993e230a">r261:014fb17dfc95 (default)</option>
+<option value="cca7aebbc4d6125798446b11e69dc8847834a982">r260:cca7aebbc4d6 (default)</option>
+<option value="14cdb2957c011a5feba36f50d960d9832ba0f0c1">r258:14cdb2957c01 (workdir)</option>
+<option value="34df20118ed74b5987d22a579e8a60e903da5bf8">r245:34df20118ed7 (default)</option>
+<option value="0375d9042a64a1ac1641528f0f0668f9a339e86d">r233:0375d9042a64 (workdir)</option>
+<option value="94aa45fc1806c04d4ba640933edf682c22478453">r222:94aa45fc1806 (workdir)</option>
+<option value="7ed99bc738818879941e3ce20243f8856a7cfc84">r188:7ed99bc73881 (default)</option>
+<option value="1e85975528bcebe853732a9e5fb8dbf4461f6bb2">r184:1e85975528bc (default)</option>
+<option value="ed30beddde7bbddb26042625be19bcd11576c1dd">r183:ed30beddde7b (default)</option>
+<option value="a6664e18181c6fc81b751a8d01474e7e1a3fe7fc">r177:a6664e18181c (default)</option>
+<option value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option>
 <option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35 (default)</option>
 <option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c (default)</option>
 <option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329 (default)</option>
@@ -203,16 +286,23 @@
 <option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3 (default)</option>
 </optgroup>
 <optgroup label="Branches">
-<option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option>
-<option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option>
-<option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option>
+<option value="96507bd11ecc815ebc6270fdf6db110928c09c1e">default</option>
+<option value="4f7e2131323e0749a740c0a56ab68ae9269c562a">stable</option>
 </optgroup>
 <optgroup label="Tags">
-<option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option>
-<option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option>
-<option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option>
-<option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option>
-<option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option>
+<option value="2c96c02def9a7c997f33047761a53943e6254396">v0.2.0</option>
+<option value="8680b1d1cee3aa3c1ab3734b76ee164bbedbc5c9">v0.1.9</option>
+<option value="ecb25ba9c96faf1e65a0bc3fd914918420a2f116">v0.1.8</option>
+<option value="f67633a2894edaf28513706d558205fa93df9209">v0.1.7</option>
+<option value="02b38c0eb6f982174750c0e309ff9faddc0c7e12">v0.1.6</option>
+<option value="a6664e18181c6fc81b751a8d01474e7e1a3fe7fc">v0.1.5</option>
+<option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">v0.1.4</option>
+<option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">v0.1.3</option>
+<option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">v0.1.2</option>
+<option value="fef5bfe1dc17611d5fb59a7f6f95c55c3606f933">v0.1.11</option>
+<option value="92831aebf2f8dd4879e897024b89d09af214df1c">v0.1.10</option>
+<option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">v0.1.1</option>
+<option value="96507bd11ecc815ebc6270fdf6db110928c09c1e">tip</option>
 </optgroup>""")
 
     def test_file_annotation_git(self):
--- a/rhodecode/tests/functional/test_home.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_home.py	Sat Apr 27 11:24:25 2013 +0200
@@ -29,11 +29,11 @@
                         r"""alt=\"Public repository\" src=\"/images/icons/lock_"""
                         r"""open.png\"/>""")
 
-        response.mustcontain(
-r"""<a title=\"Marcin Kuzminski &amp;lt;marcin@python-works.com&amp;gt;:\n\n"""
-r"""merge\" class=\"tooltip\" href=\"/vcs_test_hg/changeset/27cd5cce30c96924232"""
-r"""dffcd24178a07ffeb5dfc\">r173:27cd5cce30c9</a>"""
-)
+        response.mustcontain("""fixes issue with having custom format for git-log""")
+        response.mustcontain("""/%s/changeset/5f2c6ee195929b0be80749243c18121c9864a3b3""" % GIT_REPO)
+
+        response.mustcontain("""disable security checks on hg clone for travis""")
+        response.mustcontain("""/%s/changeset/96507bd11ecc815ebc6270fdf6db110928c09c1e""" % HG_REPO)
 
     def test_repo_summary_with_anonymous_access_disabled(self):
         anon = User.get_default_user()
--- a/rhodecode/tests/functional/test_journal.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_journal.py	Sat Apr 27 11:24:25 2013 +0200
@@ -14,10 +14,10 @@
 
     def test_stop_following_repository(self):
         session = self.log_user()
-#        usr = self.Session.query(User).filter(User.username == 'test_admin').one()
-#        repo = self.Session.query(Repository).filter(Repository.repo_name == HG_REPO).one()
+#        usr = Session().query(User).filter(User.username == 'test_admin').one()
+#        repo = Session().query(Repository).filter(Repository.repo_name == HG_REPO).one()
 #
-#        followings = self.Session.query(UserFollowing)\
+#        followings = Session().query(UserFollowing)\
 #            .filter(UserFollowing.user == usr)\
 #            .filter(UserFollowing.follows_repository == repo).all()
 #
--- a/rhodecode/tests/functional/test_login.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_login.py	Sat Apr 27 11:24:25 2013 +0200
@@ -5,15 +5,16 @@
 from rhodecode.lib.auth import check_password
 from rhodecode.lib import helpers as h
 from rhodecode.model import validators
+from rhodecode.model.meta import Session
 
 
 class TestLoginController(TestController):
 
     def tearDown(self):
         for n in Notification.query().all():
-            self.Session().delete(n)
+            Session().delete(n)
 
-        self.Session().commit()
+        Session().commit()
         self.assertEqual(Notification.query().all(), [])
 
     def test_index(self):
@@ -216,7 +217,7 @@
         self.assertEqual(response.status, '302 Found')
         self.checkSessionFlash(response, 'You have successfully registered into RhodeCode')
 
-        ret = self.Session().query(User).filter(User.username == 'test_regular4').one()
+        ret = Session().query(User).filter(User.username == 'test_regular4').one()
         self.assertEqual(ret.username, username)
         self.assertEqual(check_password(password, ret.password), True)
         self.assertEqual(ret.email, email)
@@ -254,8 +255,8 @@
         new.name = name
         new.lastname = lastname
         new.api_key = generate_api_key(username)
-        self.Session().add(new)
-        self.Session().commit()
+        Session().add(new)
+        Session().commit()
 
         response = self.app.post(url(controller='login',
                                      action='password_reset'),
--- a/rhodecode/tests/functional/test_search.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_search.py	Sat Apr 27 11:24:25 2013 +0200
@@ -25,14 +25,14 @@
         self.log_user()
         response = self.app.get(url(controller='search', action='index'),
                                 {'q': 'def repo'})
-        response.mustcontain('39 results')
+        response.mustcontain('58 results')
 
     def test_repo_search(self):
         self.log_user()
         response = self.app.get(url(controller='search', action='index'),
                                 {'q': 'repository:%s def test' % HG_REPO})
 
-        response.mustcontain('4 results')
+        response.mustcontain('18 results')
 
     def test_search_last(self):
         self.log_user()
@@ -67,7 +67,7 @@
                                 {'q': 'changed:tests/utils.py',
                                  'type': 'commit'})
 
-        response.mustcontain('20 results')
+        response.mustcontain('29 results')
 
     def test_search_commit_changed_files_get_commit(self):
         self.log_user()
@@ -75,7 +75,7 @@
                                 {'q': 'changed:vcs/utils/lazy.py',
                                  'type': 'commit'})
 
-        response.mustcontain('7 results')
+        response.mustcontain('11 results')
         response.mustcontain('36e0fc9d2808c5022a24f49d6658330383ed8666')
         response.mustcontain('af182745859d779f17336241a0815d15166ae1ee')
         response.mustcontain('17438a11f72b93f56d0e08e7d1fa79a378578a82')
--- a/rhodecode/tests/functional/test_summary.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_summary.py	Sat Apr 27 11:24:25 2013 +0200
@@ -36,13 +36,16 @@
         response = self.app.get(url(controller='summary', action='index',
                                     repo_name=HG_REPO))
         response.mustcontain(
-            """var data = [["py", {"count": 42, "desc": ["Python"]}], """
-            """["rst", {"count": 11, "desc": ["Rst"]}], """
+            """var data = [["py", {"count": 68, "desc": ["Python"]}], """
+            """["rst", {"count": 16, "desc": ["Rst"]}], """
+            """["css", {"count": 2, "desc": ["Css"]}], """
             """["sh", {"count": 2, "desc": ["Bash"]}], """
-            """["makefile", {"count": 1, "desc": ["Makefile", "Makefile"]}],"""
-            """ ["cfg", {"count": 1, "desc": ["Ini"]}], """
-            """["css", {"count": 1, "desc": ["Css"]}], """
-            """["bat", {"count": 1, "desc": ["Batch"]}]];"""
+            """["yml", {"count": 1, "desc": ["Yaml"]}], """
+            """["makefile", {"count": 1, "desc": ["Makefile", "Makefile"]}], """
+            """["js", {"count": 1, "desc": ["Javascript"]}], """
+            """["cfg", {"count": 1, "desc": ["Ini"]}], """
+            """["ini", {"count": 1, "desc": ["Ini"]}], """
+            """["html", {"count": 1, "desc": ["EvoqueHtml", "Html"]}]];"""
         )
 
         # clone url...
@@ -118,5 +121,5 @@
     def _enable_stats(self):
         r = Repository.get_by_repo_name(HG_REPO)
         r.enable_statistics = True
-        self.Session.add(r)
-        self.Session.commit()
+        Session().add(r)
+        Session().commit()
--- a/rhodecode/tests/functional/test_tags.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/functional/test_tags.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,12 +1,40 @@
 from rhodecode.tests import *
 
+
 class TestTagsController(TestController):
 
-    def test_index(self):
+    def test_index_hg(self):
         self.log_user()
         response = self.app.get(url(controller='tags', action='index', repo_name=HG_REPO))
-        response.mustcontain("""<a href="/%s/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/">tip</a>""" % HG_REPO)
-        response.mustcontain("""<a href="/%s/files/fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200/">0.1.4</a>""" % HG_REPO)
-        response.mustcontain("""<a href="/%s/files/17544fbfcd33ffb439e2b728b5d526b1ef30bfcf/">0.1.3</a>""" % HG_REPO)
-        response.mustcontain("""<a href="/%s/files/a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720/">0.1.2</a>""" % HG_REPO)
-        response.mustcontain("""<a href="/%s/files/eb3a60fc964309c1a318b8dfe26aa2d1586c85ae/">0.1.1</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/">tip</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/2c96c02def9a7c997f33047761a53943e6254396/">v0.2.0</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/fef5bfe1dc17611d5fb59a7f6f95c55c3606f933/">v0.1.11</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/92831aebf2f8dd4879e897024b89d09af214df1c/">v0.1.10</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/8680b1d1cee3aa3c1ab3734b76ee164bbedbc5c9/">v0.1.9</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/ecb25ba9c96faf1e65a0bc3fd914918420a2f116/">v0.1.8</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/f67633a2894edaf28513706d558205fa93df9209/">v0.1.7</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/02b38c0eb6f982174750c0e309ff9faddc0c7e12/">v0.1.6</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/a6664e18181c6fc81b751a8d01474e7e1a3fe7fc/">v0.1.5</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200/">v0.1.4</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/17544fbfcd33ffb439e2b728b5d526b1ef30bfcf/">v0.1.3</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720/">v0.1.2</a>""" % HG_REPO)
+        response.mustcontain("""<a href="/%s/files/eb3a60fc964309c1a318b8dfe26aa2d1586c85ae/">v0.1.1</a>""" % HG_REPO)
+
+    def test_index_git(self):
+        self.log_user()
+        response = self.app.get(url(controller='tags', action='index', repo_name=GIT_REPO))
+
+        response.mustcontain("""<a href="/%s/files/137fea89f304a42321d40488091ee2ed419a3686/">v0.2.2</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/5051d0fa344d4408a2659d9a0348eb2d41868ecf/">v0.2.1</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/599ba911aa24d2981225f3966eb659dfae9e9f30/">v0.2.0</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/c60f01b77c42dce653d6b1d3b04689862c261929/">v0.1.11</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/10cddef6b794696066fb346434014f0a56810218/">v0.1.10</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/341d28f0eec5ddf0b6b77871e13c2bbd6bec685c/">v0.1.9</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/74ebce002c088b8a5ecf40073db09375515ecd68/">v0.1.8</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/4d78bf73b5c22c82b68f902f138f7881b4fffa2c/">v0.1.7</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/0205cb3f44223fb3099d12a77a69c81b798772d9/">v0.1.6</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/6c0ce52b229aa978889e91b38777f800e85f330b/">v0.1.5</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/7d735150934cd7645ac3051903add952390324a5/">v0.1.4</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/5a3a8fb005554692b16e21dee62bf02667d8dc3e/">v0.1.3</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/0ba5f8a4660034ff25c0cac2a5baabf5d2791d63/">v0.1.2</a>""" % GIT_REPO)
+        response.mustcontain("""<a href="/%s/files/e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0/">v0.1.1</a>""" % GIT_REPO)
--- a/rhodecode/tests/vcs/__init__.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/__init__.py	Sat Apr 27 11:24:25 2013 +0200
@@ -19,10 +19,10 @@
 .. _unittest: http://pypi.python.org/pypi/unittest
 
 """
-import os
-from rhodecode.lib import vcs
 from rhodecode.lib.vcs.utils.compat import unittest
-from utils import VCSTestError, SCMFetcher
+from rhodecode.tests.vcs.conf import *
+from rhodecode.tests.vcs.utils import VCSTestError, SCMFetcher
+
 from rhodecode.tests import *
 
 
@@ -36,7 +36,7 @@
             'alias': 'hg',
             'test_repo_path': TEST_HG_REPO,
             'remote_repo': HG_REMOTE_REPO,
-            'clone_cmd': 'hg clone',
+            'clone_cmd': 'hg clone --insecure',
         },
         'git': {
             'alias': 'git',
@@ -52,5 +52,16 @@
     except VCSTestError, err:
         raise RuntimeError(str(err))
 
-#start_dir = os.path.abspath(os.path.dirname(__file__))
-#unittest.defaultTestLoader.discover(start_dir)
+
+def collector():
+    setup_package()
+    start_dir = os.path.abspath(os.path.dirname(__file__))
+    return unittest.defaultTestLoader.discover(start_dir)
+
+
+def main():
+    collector()
+    unittest.main()
+
+#if __name__ == '__main__':
+#    main()
--- a/rhodecode/tests/vcs/base.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/base.py	Sat Apr 27 11:24:25 2013 +0200
@@ -3,14 +3,13 @@
 InMemoryChangeset class is working properly at backend class.
 """
 import os
-from rhodecode.lib import vcs
 import time
 import shutil
 import datetime
-from rhodecode.lib.vcs.utils.compat import unittest
+from rhodecode.tests.vcs.conf import SCM_TESTS, get_new_dir
 
-from conf import SCM_TESTS, get_new_dir
-
+from rhodecode.lib import vcs
+from rhodecode.lib.vcs.utils.compat import unittest
 from rhodecode.lib.vcs.nodes import FileNode
 
 
@@ -68,6 +67,7 @@
         cls.repo_path = get_new_dir(str(time.time()))
         cls.repo = Backend(cls.repo_path, create=True)
         cls.imc = cls.repo.in_memory_changeset
+        cls.default_branch = cls.repo.DEFAULT_BRANCH_NAME
 
         for commit in cls._get_commits():
             for node in commit.get('added', []):
--- a/rhodecode/tests/vcs/conf.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/conf.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,64 +1,65 @@
 """
 Unit tests configuration module for vcs.
 """
-
 import os
 import time
 import hashlib
 import tempfile
 import datetime
 import shutil
-from rhodecode.tests import *
 from utils import get_normalized_path
 from os.path import join as jn
 
-TEST_TMP_PATH = TESTS_TMP_PATH
-#__all__ = (
-#    'TEST_HG_REPO', 'TEST_GIT_REPO', 'HG_REMOTE_REPO', 'GIT_REMOTE_REPO',
-#    'SCM_TESTS',
-#)
-#
-#SCM_TESTS = ['hg', 'git']
-#uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
-#
+__all__ = (
+    'TEST_HG_REPO', 'TEST_GIT_REPO', 'HG_REMOTE_REPO', 'GIT_REMOTE_REPO',
+    'SCM_TESTS',
+)
+
+SCM_TESTS = ['hg', 'git']
+uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
+
 THIS = os.path.abspath(os.path.dirname(__file__))
-#
-#GIT_REMOTE_REPO = 'git://github.com/codeinn/vcs.git'
-#
-#TEST_TMP_PATH = os.environ.get('VCS_TEST_ROOT', '/tmp')
-#TEST_GIT_REPO = os.environ.get('VCS_TEST_GIT_REPO',
-#                              jn(TEST_TMP_PATH, 'vcs-git'))
-#TEST_GIT_REPO_CLONE = os.environ.get('VCS_TEST_GIT_REPO_CLONE',
-#                            jn(TEST_TMP_PATH, 'vcsgitclone%s' % uniq_suffix))
-#TEST_GIT_REPO_PULL = os.environ.get('VCS_TEST_GIT_REPO_PULL',
-#                            jn(TEST_TMP_PATH, 'vcsgitpull%s' % uniq_suffix))
-#
-#HG_REMOTE_REPO = 'http://bitbucket.org/marcinkuzminski/vcs'
-#TEST_HG_REPO = os.environ.get('VCS_TEST_HG_REPO',
-#                              jn(TEST_TMP_PATH, 'vcs-hg'))
-#TEST_HG_REPO_CLONE = os.environ.get('VCS_TEST_HG_REPO_CLONE',
-#                              jn(TEST_TMP_PATH, 'vcshgclone%s' % uniq_suffix))
-#TEST_HG_REPO_PULL = os.environ.get('VCS_TEST_HG_REPO_PULL',
-#                              jn(TEST_TMP_PATH, 'vcshgpull%s' % uniq_suffix))
-#
-#TEST_DIR = os.environ.get('VCS_TEST_ROOT', tempfile.gettempdir())
-#TEST_REPO_PREFIX = 'vcs-test'
-#
-#
-#def get_new_dir(title):
-#    """
-#    Returns always new directory path.
-#    """
-#    name = TEST_REPO_PREFIX
-#    if title:
-#        name = '-'.join((name, title))
-#    hex = hashlib.sha1(str(time.time())).hexdigest()
-#    name = '-'.join((name, hex))
-#    path = os.path.join(TEST_DIR, name)
-#    return get_normalized_path(path)
+
+GIT_REMOTE_REPO = 'git://github.com/codeinn/vcs.git'
+
+TEST_TMP_PATH = os.environ.get('VCS_TEST_ROOT', '/tmp')
+TEST_GIT_REPO = os.environ.get('VCS_TEST_GIT_REPO',
+                              jn(TEST_TMP_PATH, 'vcs-git'))
+TEST_GIT_REPO_CLONE = os.environ.get('VCS_TEST_GIT_REPO_CLONE',
+                            jn(TEST_TMP_PATH, 'vcsgitclone%s' % uniq_suffix))
+TEST_GIT_REPO_PULL = os.environ.get('VCS_TEST_GIT_REPO_PULL',
+                            jn(TEST_TMP_PATH, 'vcsgitpull%s' % uniq_suffix))
+
+HG_REMOTE_REPO = 'http://bitbucket.org/marcinkuzminski/vcs'
+TEST_HG_REPO = os.environ.get('VCS_TEST_HG_REPO',
+                              jn(TEST_TMP_PATH, 'vcs-hg'))
+TEST_HG_REPO_CLONE = os.environ.get('VCS_TEST_HG_REPO_CLONE',
+                              jn(TEST_TMP_PATH, 'vcshgclone%s' % uniq_suffix))
+TEST_HG_REPO_PULL = os.environ.get('VCS_TEST_HG_REPO_PULL',
+                              jn(TEST_TMP_PATH, 'vcshgpull%s' % uniq_suffix))
+
+TEST_DIR = os.environ.get('VCS_TEST_ROOT', tempfile.gettempdir())
+TEST_REPO_PREFIX = 'vcs-test'
+
+
+def get_new_dir(title):
+    """
+    Returns always new directory path.
+    """
+    name = TEST_REPO_PREFIX
+    if title:
+        name = '-'.join((name, title))
+    hex = hashlib.sha1(str(time.time())).hexdigest()
+    name = '-'.join((name, hex))
+    path = os.path.join(TEST_DIR, name)
+    return get_normalized_path(path)
+
 
 PACKAGE_DIR = os.path.abspath(os.path.join(
     os.path.dirname(__file__), '..'))
-_dest = jn(TESTS_TMP_PATH,'aconfig')
+_dest = jn(TEST_TMP_PATH, 'aconfig')
 shutil.copy(jn(THIS, 'aconfig'), _dest)
 TEST_USER_CONFIG_FILE = _dest
+
+#overide default configurations with rhodecode ones
+from rhodecode.tests import *
--- a/rhodecode/tests/vcs/test_archives.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_archives.py	Sat Apr 27 11:24:25 2013 +0200
@@ -6,8 +6,8 @@
 import datetime
 import tempfile
 import StringIO
-from base import BackendTestMixin
-from conf import SCM_TESTS
+from rhodecode.tests.vcs.base import BackendTestMixin
+from rhodecode.tests.vcs.conf import SCM_TESTS
 from rhodecode.lib.vcs.exceptions import VCSError
 from rhodecode.lib.vcs.nodes import FileNode
 from rhodecode.lib.vcs.utils.compat import unittest
--- a/rhodecode/tests/vcs/test_branches.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_branches.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,13 +1,12 @@
 from __future__ import with_statement
 
+import datetime
 from rhodecode.lib import vcs
-import datetime
 from rhodecode.lib.vcs.utils.compat import unittest
+from rhodecode.lib.vcs.nodes import FileNode
 
-from base import BackendTestMixin
-from conf import SCM_TESTS
-
-from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.tests.vcs.base import BackendTestMixin
+from rhodecode.tests.vcs.conf import SCM_TESTS
 
 
 class BranchesTestCaseMixin(BackendTestMixin):
--- a/rhodecode/tests/vcs/test_changesets.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_changesets.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,15 +1,19 @@
 from __future__ import with_statement
 
+import datetime
 from rhodecode.lib import vcs
-import datetime
-from base import BackendTestMixin
-from conf import SCM_TESTS
+from rhodecode.tests.vcs.base import BackendTestMixin
+from rhodecode.tests.vcs.conf import SCM_TESTS
+
 from rhodecode.lib.vcs.backends.base import BaseChangeset
-from rhodecode.lib.vcs.nodes import FileNode, AddedFileNodesGenerator,\
+from rhodecode.lib.vcs.nodes import (
+    FileNode, AddedFileNodesGenerator,
     ChangedFileNodesGenerator, RemovedFileNodesGenerator
-from rhodecode.lib.vcs.exceptions import BranchDoesNotExistError
-from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
-from rhodecode.lib.vcs.exceptions import RepositoryError
+)
+from rhodecode.lib.vcs.exceptions import (
+    BranchDoesNotExistError, ChangesetDoesNotExistError,
+    RepositoryError
+)
 from rhodecode.lib.vcs.utils.compat import unittest
 
 
--- a/rhodecode/tests/vcs/test_filenodes_unicode_path.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_filenodes_unicode_path.py	Sat Apr 27 11:24:25 2013 +0200
@@ -5,8 +5,8 @@
 import datetime
 from rhodecode.lib.vcs.nodes import FileNode
 from rhodecode.lib.vcs.utils.compat import unittest
-from test_inmemchangesets import BackendBaseTestCase
-from conf import SCM_TESTS
+from rhodecode.tests.vcs.test_inmemchangesets import BackendBaseTestCase
+from rhodecode.tests.vcs.conf import SCM_TESTS
 
 
 class FileNodeUnicodePathTestsMixin(object):
--- a/rhodecode/tests/vcs/test_getitem.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_getitem.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,8 +1,8 @@
 from __future__ import with_statement
 
 import datetime
-from base import BackendTestMixin
-from conf import SCM_TESTS
+from rhodecode.tests.vcs.base import BackendTestMixin
+from rhodecode.tests.vcs.conf import SCM_TESTS
 from rhodecode.lib.vcs.nodes import FileNode
 from rhodecode.lib.vcs.utils.compat import unittest
 
--- a/rhodecode/tests/vcs/test_getslice.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_getslice.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,8 +1,8 @@
 from __future__ import with_statement
 
 import datetime
-from base import BackendTestMixin
-from conf import SCM_TESTS
+from rhodecode.tests.vcs.base import BackendTestMixin
+from rhodecode.tests.vcs.conf import SCM_TESTS
 from rhodecode.lib.vcs.nodes import FileNode
 from rhodecode.lib.vcs.utils.compat import unittest
 
--- a/rhodecode/tests/vcs/test_git.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_git.py	Sat Apr 27 11:24:25 2013 +0200
@@ -8,7 +8,7 @@
 from rhodecode.lib.vcs.nodes import NodeKind, FileNode, DirNode, NodeState
 from rhodecode.lib.vcs.utils.compat import unittest
 from rhodecode.tests.vcs.base import BackendTestMixin
-from conf import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, get_new_dir
+from rhodecode.tests.vcs.conf import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, get_new_dir
 
 
 class GitRepositoryTest(unittest.TestCase):
--- a/rhodecode/tests/vcs/test_hg.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_hg.py	Sat Apr 27 11:24:25 2013 +0200
@@ -4,7 +4,7 @@
 from rhodecode.lib.vcs.backends.hg import MercurialRepository, MercurialChangeset
 from rhodecode.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
 from rhodecode.lib.vcs.nodes import NodeKind, NodeState
-from conf import PACKAGE_DIR, TEST_HG_REPO, TEST_HG_REPO_CLONE, \
+from rhodecode.tests.vcs.conf import PACKAGE_DIR, TEST_HG_REPO, TEST_HG_REPO_CLONE, \
     TEST_HG_REPO_PULL
 from rhodecode.lib.vcs.utils.compat import unittest
 
@@ -156,9 +156,10 @@
 
         #active branches
         self.assertTrue('default' in self.repo.branches)
-        self.assertTrue('git' in self.repo.branches)
+        self.assertTrue('stable' in self.repo.branches)
 
         # closed
+        self.assertTrue('git' in self.repo._get_branches(closed=True))
         self.assertTrue('web' in self.repo._get_branches(closed=True))
 
         for name, id in self.repo.branches.items():
--- a/rhodecode/tests/vcs/test_inmemchangesets.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_inmemchangesets.py	Sat Apr 27 11:24:25 2013 +0200
@@ -3,10 +3,11 @@
 """
 from __future__ import with_statement
 
-from rhodecode.lib import vcs
 import time
 import datetime
-from conf import SCM_TESTS, get_new_dir
+
+from rhodecode.lib import vcs
+from rhodecode.tests.vcs.conf import SCM_TESTS, get_new_dir
 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
 from rhodecode.lib.vcs.exceptions import NodeAlreadyAddedError
 from rhodecode.lib.vcs.exceptions import NodeAlreadyExistsError
--- a/rhodecode/tests/vcs/test_repository.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_repository.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,8 +1,8 @@
 from __future__ import with_statement
 import datetime
-from base import BackendTestMixin
-from conf import SCM_TESTS
-from conf import TEST_USER_CONFIG_FILE
+from rhodecode.tests.vcs.base import BackendTestMixin
+from rhodecode.tests.vcs.conf import SCM_TESTS
+from rhodecode.tests.vcs.conf import TEST_USER_CONFIG_FILE
 from rhodecode.lib.vcs.nodes import FileNode
 from rhodecode.lib.vcs.utils.compat import unittest
 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
--- a/rhodecode/tests/vcs/test_tags.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_tags.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,7 +1,7 @@
 from __future__ import with_statement
 
-from base import BackendTestMixin
-from conf import SCM_TESTS
+from rhodecode.tests.vcs.base import BackendTestMixin
+from rhodecode.tests.vcs.conf import SCM_TESTS
 from rhodecode.lib.vcs.exceptions import TagAlreadyExistError
 from rhodecode.lib.vcs.exceptions import TagDoesNotExistError
 from rhodecode.lib.vcs.utils.compat import unittest
--- a/rhodecode/tests/vcs/test_utils.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_utils.py	Sat Apr 27 11:24:25 2013 +0200
@@ -18,7 +18,7 @@
 from rhodecode.lib.vcs.utils.paths import get_user_home
 from rhodecode.lib.vcs.exceptions import VCSError
 
-from conf import TEST_HG_REPO, TEST_GIT_REPO, TEST_TMP_PATH
+from rhodecode.tests.vcs.conf import TEST_HG_REPO, TEST_GIT_REPO, TEST_TMP_PATH
 
 
 class PathsTest(unittest.TestCase):
--- a/rhodecode/tests/vcs/test_vcs.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_vcs.py	Sat Apr 27 11:24:25 2013 +0200
@@ -1,11 +1,13 @@
 from __future__ import with_statement
 
+import os
+import shutil
+
 from rhodecode.lib.vcs import VCSError, get_repo, get_backend
 from rhodecode.lib.vcs.backends.hg import MercurialRepository
 from rhodecode.lib.vcs.utils.compat import unittest
-from conf import TEST_HG_REPO, TEST_GIT_REPO, TEST_TMP_PATH
-import os
-import shutil
+from rhodecode.tests.vcs.conf import TEST_HG_REPO, TEST_GIT_REPO, TEST_TMP_PATH
+
 
 
 class VCSTest(unittest.TestCase):
--- a/rhodecode/tests/vcs/test_workdirs.py	Sat Apr 27 11:45:27 2013 +0200
+++ b/rhodecode/tests/vcs/test_workdirs.py	Sat Apr 27 11:24:25 2013 +0200
@@ -3,8 +3,8 @@
 import datetime
 from rhodecode.lib.vcs.nodes import FileNode
 from rhodecode.lib.vcs.utils.compat import unittest
-from base import BackendTestMixin
-from conf import SCM_TESTS
+from rhodecode.tests.vcs.base import BackendTestMixin
+from rhodecode.tests.vcs.conf import SCM_TESTS
 
 
 class WorkdirTestCaseMixin(BackendTestMixin):
Binary file rhodecode/tests/vcs_test_hg.tar.gz has changed
--- a/test.ini	Sat Apr 27 11:45:27 2013 +0200
+++ b/test.ini	Sat Apr 27 11:24:25 2013 +0200
@@ -47,7 +47,7 @@
 max_request_body_size = 107374182400
 use = egg:waitress#main
 
-host = 127.0.0.1
+host = 0.0.0.0
 port = 5000
 
 ## prefix middleware for rc