1. slurdge
  2. RhodeCode

Commits

Marcin Kuzminski  committed a045579 Merge

merge default into demo branch

  • Participants
  • Parent commits 6ee253b, b0b86e4
  • Branches demo

Comments (0)

Files changed (87)

File .hgignore

View file
 *.egg
 
 syntax: regexp
+^rcextensions
 ^build
 ^docs/build/
 ^docs/_build/

File .hgtags

View file
 79a95f338fd0115b2cdb77118f39e17d22ff505c v1.3.1
 9ab21c5ddb84935bea5c743b4e147ed5a398b30c v1.3.2
 934906f028b582a254e0028ba25e5d20dd32b9cd v1.3.3
+af21362474e3ab5aa0e2fbb1c872356f2c16c4f3 v1.3.4

File README.rst

View file
 however RhodeCode can be run as standalone hosted application on your own server.
 It is open source and donation ware and focuses more on providing a customized, 
 self administered interface for Mercurial_ and GIT_  repositories. 
-RhodeCode is powered by a vcs_ library that Lukasz Balcerzak and I created to 
-handle multiple different version control systems.
+RhodeCode works on *nix systems and Windows it is powered by a vcs_ library 
+that Lukasz Balcerzak and Marcin Kuzminski created to handle multiple 
+different version control systems.
 
-RhodeCode uses `Semantic Versioning <http://semver.org/>`_
+RhodeCode uses `PEP386 versioning <http://www.python.org/dev/peps/pep-0386/>`_
 
 Installation
 ------------
 - Intelligent cache with invalidation after push or project change, provides 
   high performance and always up to date data.
 - Rss / atom feeds, gravatar support, download sources as zip/tar/gz
-- Async tasks for speed and performance using celery_ (works without them too)  
+- Optional async tasks for speed and performance using celery_  
 - Backup scripts can do backup of whole app and send it over scp to desired 
   location 
 - Based on pylons / sqlalchemy / sqlite / whoosh / vcs

File development.ini

View file
 ## all running rhodecode instances. Leave empty if you don't use it
 instance_id = 
 
+## alternative return HTTP header for failed authentication. Default HTTP
+## response is 401 HTTPUnauthorized. Currently HG clients have troubles with 
+## handling that. Set this variable to 403 to return HTTPForbidden
+auth_ret_code =
+
 ####################################
 ###        CELERY CONFIG        ####
 ####################################
 
 beaker.session.type = file
 beaker.session.key = rhodecode
+# secure cookie requires AES python libraries
 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
 #beaker.session.validate_key = 9712sds2212c--zxc123
 beaker.session.timeout = 36000
 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
 sqlalchemy.db1.echo = false
 sqlalchemy.db1.pool_recycle = 3600
-sqlalchemy.convert_unicode = true
+sqlalchemy.db1.convert_unicode = true
 
 ################################
 ### LOGGING CONFIGURATION   ####
 ################################
 [loggers]
-keys = root, routes, rhodecode, sqlalchemy, beaker, templates
+keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
 
 [handlers]
 keys = console, console_sql
 qualname = sqlalchemy.engine
 propagate = 0
 
+[logger_whoosh_indexer]
+level = DEBUG
+handlers = 
+qualname = whoosh_indexer
+propagate = 1
+
 ##############
 ## HANDLERS ##
 ##############

File docs/api/api.rst

View file
 All clients are required to send JSON-RPC spec JSON data::
 
     {   
-        "id:<id>,
+        "id:"<id>",
         "api_key":"<api_key>",
         "method":"<method_name>",
         "args":{"<arg_key>":"<arg_val>"}
 RhodeCode API will return always a JSON-RPC response::
 
     {   
-        "id":<id>,
-        "result": "<result>",
-        "error": null
+        "id":<id>, # matching id sent by request
+        "result": "<result>"|null, # JSON formatted result, null if any errors
+        "error": "null"|<error_message> # JSON formatted error (if any)
     }
 
 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "pull"
     args :    {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "get_user"
     args :    { 
                 "email" :    "<email>",
                 "active" :   "<bool>",
                 "admin" :    "<bool>",
-                "ldap_dn" :  "<ldap_dn>"
+                "ldap_dn" :  "<ldap_dn>",
+                "last_login": "<last_login>",
+                "permissions": {
+                    "global": ["hg.create.repository",
+                               "repository.read",
+                               "hg.register.manual_activate"],
+                    "repositories": {"repo1": "repository.none"},
+                    "repositories_groups": {"Group1": "group.read"}
+                 },
             }
 
     error:  null
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "get_users"
     args :    { }
                 "email" :    "<email>",
                 "active" :   "<bool>",
                 "admin" :    "<bool>",
-                "ldap_dn" :  "<ldap_dn>"
+                "ldap_dn" :  "<ldap_dn>",
+                "last_login": "<last_login>",
               },
             ]
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "create_user"
     args :    {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "update_user"
     args :    {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "get_users_group"
     args :    {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "get_users_groups"
     args :    { }
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "create_users_group"
     args:     {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "add_user_users_group"
     args:     {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "remove_user_from_users_group"
     args:     {
 get_repo
 --------
 
-Gets an existing repository by it's name or repository_id. This command can 
+Gets an existing repository by it's name or repository_id. Members will return
+either users_group or user associated to that repository. This command can 
 be executed only using api_key belonging to user with admin rights.
 
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "get_repo"
     args:     {
                 "type" :        "<type>",
                 "description" : "<description>",
                 "members" :     [
-                                  { "id" :         "<userid>",
+                                  { 
+                                    "type": "user",
+                                    "id" :         "<userid>",
                                     "username" :   "<username>",
                                     "firstname":   "<firstname>",
                                     "lastname" :   "<lastname>",
                                     "permission" : "repository.(read|write|admin)"
                                   },
-                                  {
+                                  { 
+                                    "type": "users_group",
                                     "id" :       "<usersgroupid>",
                                     "name" :     "<usersgroupname>",
                                     "active":    "<bool>",
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "get_repos"
     args:     { }
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "get_repo_nodes"
     args:     {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "create_repo"
     args:     {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "delete_repo"
     args:     {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "grant_user_permission"
     args:     {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method  : "revoke_user_permission"
     args:     {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method :  "grant_users_group_permission"
     args:     {
 
 INPUT::
 
+    id : <id_for_response>
     api_key : "<api_key>"
     method  : "revoke_users_group_permission"
     args:     {

File docs/changelog.rst

View file
 =========
 
 
+1.3.4 (**2012-03-28**)
+----------------------
 
+news
+++++
+
+- Whoosh logging is now controlled by the .ini files logging setup
+- added clone-url into edit form on /settings page
+- added help text into repo add/edit forms
+- created rcextensions module with additional mappings (ref #322) and
+  post push/pull/create repo hooks callbacks
+- implemented #377 Users view for his own permissions on account page
+- #399 added inheritance of permissions for users group on repos groups
+- #401 repository group is automatically pre-selected when adding repos 
+  inside a repository group
+- added alternative HTTP 403 response when client failed to authenticate. Helps 
+  solving issues with Mercurial and LDAP
+- #402 removed group prefix from repository name when listing repositories 
+  inside a group
+- added gravatars into permission view and permissions autocomplete
+- #347 when running multiple RhodeCode instances, properly invalidates cache 
+  for all registered servers
+
+fixes
++++++
+
+- fixed #390 cache invalidation problems on repos inside group
+- fixed #385 clone by ID url was loosing proxy prefix in URL
+- fixed some unicode problems with waitress
+- fixed issue with escaping < and > in changeset commits
+- fixed error occurring during recursive group creation in API 
+  create_repo function
+- fixed #393 py2.5 fixes for routes url generator
+- fixed #397 Private repository groups shows up before login
+- fixed #396 fixed problems with revoking users in nested groups
+- fixed mysql unicode issues + specified InnoDB as default engine with 
+  utf8 charset
+- #406 trim long branch/tag names in changelog to not break UI
+  
 1.3.3 (**2012-03-02**)
 ----------------------
 

File docs/index.rst

View file
    usage/git_support
    usage/statistics
    usage/backup
-   
+   usage/debugging
+
 **Develop**
 
 .. toctree::

File docs/setup.rst

View file
 
 
 Next, you need to create the databases used by RhodeCode. I recommend that you
-use sqlite (default) or postgresql. If you choose a database other than the
+use postgresql or sqlite (default). If you choose a database other than the
 default ensure you properly adjust the db url in your production.ini
-configuration file to use this other database. Create the databases by running
+configuration file to use this other database. RhodeCode currently supports
+postgresql, sqlite and mysql databases. Create the database by running
 the following command::
 
     paster setup-app production.ini
 - In the admin panel you can toggle ldap, anonymous, permissions settings. As
   well as edit more advanced options on users and repositories
 
-Try copying your own mercurial repository into the "root" directory you are
-using, then from within the RhodeCode web application choose Admin >
-repositories. Then choose Add New Repository. Add the repository you copied 
-into the root. Test that you can browse your repository from within RhodeCode 
-and then try cloning your repository from RhodeCode with::
+Optionally users can create `rcextensions` package that extends RhodeCode
+functionality. To do this simply execute::
 
-    hg clone http://127.0.0.1:5000/<repository name>
+    paster make-rcext production.ini
 
-where *repository name* is replaced by the name of your repository.
+This will create `rcextensions` package in the same place that your `ini` file
+lives. With `rcextensions` it's possible to add additional mapping for whoosh, 
+stats and add additional code into the push/pull/create repo hooks. For example
+for sending signals to build-bots such as jenkins.
+Please see the `__init__.py` file inside `rcextensions` package 
+for more details.
+
 
 Using RhodeCode with SSH
 ------------------------

File docs/upgrade.rst

View file
 and will always recheck the settings of the application, if there are no new 
 options that need to be set.
 
+.. note::
+   If you're using Celery, make sure you restart all instances of it after
+   upgrade.
 
 .. _virtualenv: http://pypi.python.org/pypi/virtualenv  
 .. _python: http://www.python.org/

File docs/usage/debugging.rst

View file
+.. _debugging:
+
+===================
+Debugging RhodeCode
+===================
+
+If you encountered problems with RhodeCode here are some instructions how to
+possibly debug them.
+
+** First make sure you're using the latest version available.**
+
+enable detailed debug
+---------------------
+
+RhodeCode uses standard python logging modules to log it's output.
+By default only loggers with INFO level are displayed. To enable full output
+change `level = DEBUG` for all logging handlers in currently used .ini file. 
+This change will allow to see much more detailed output in the logfile or
+console. This generally helps a lot to track issues.
+
+
+enable interactive debug mode
+-----------------------------
+
+To enable interactive debug mode simply comment out `set debug = false` in
+.ini file, this will trigger and interactive debugger each time there an
+error in browser, or send a http link if error occured in the backend. This
+is a great tool for fast debugging as you get a handy python console right
+in the web view. ** NEVER ENABLE THIS ON PRODUCTION ** the interactive console
+can be a serious security threat to you system.

File docs/usage/general.rst

View file
 on errors the mails will have a detailed traceback of error.
 
 
+Mails are also sent for code comments. If someone comments on a changeset
+mail is sent to all participants, the person who commited the changeset 
+(if present in RhodeCode), and to all people mentioned with @mention system.
+
+
 Trending source files
 ---------------------
 

File init.d/rhodecode-daemon4

View file
+#!/bin/bash
+###########################################
+#### THIS IS AN ARCH LINUX RC.D SCRIPT ####
+###########################################
+
+. /etc/rc.conf
+. /etc/rc.d/functions
+
+DAEMON=rhodecode
+APP_HOMEDIR="/srv"
+APP_PATH="$APP_HOMEDIR/$DAEMON"
+CONF_NAME="production.ini"
+LOG_FILE="/var/log/$DAEMON.log"
+PID_FILE="/run/daemons/$DAEMON"
+APPL=/usr/bin/paster
+RUN_AS="*****"
+
+ARGS="serve --daemon \
+--user=$RUN_AS \
+--group=$RUN_AS \
+--pid-file=$PID_FILE \
+--log-file=$LOG_FILE \
+$APP_PATH/$CONF_NAME"
+
+[ -r /etc/conf.d/$DAEMON ] && . /etc/conf.d/$DAEMON
+
+if [[ -r $PID_FILE ]]; then
+    read -r PID < "$PID_FILE"
+    if [[ $PID && ! -d /proc/$PID ]]; then
+        unset PID
+        rm_daemon $DAEMON
+    fi
+fi
+
+case "$1" in
+start)
+    stat_busy "Starting $DAEMON"
+    export HOME=$APP_PATH
+    [ -z "$PID" ] && $APPL $ARGS &>/dev/null
+    if [ $? = 0 ]; then
+        add_daemon $DAEMON
+        stat_done
+    else
+        stat_fail
+        exit 1
+    fi
+    ;;
+stop)
+    stat_busy "Stopping $DAEMON"
+    [ -n "$PID" ] && kill $PID &>/dev/null 
+    if [ $? = 0 ]; then
+        rm_daemon $DAEMON
+        stat_done
+    else
+        stat_fail
+        exit 1
+    fi
+    ;;
+restart)
+    $0 stop
+    sleep 1
+    $0 start
+    ;;
+status)
+    stat_busy "Checking $name status";
+    ck_status $name
+    ;;
+*)
+    echo "usage: $0 {start|stop|restart|status}"
+esac

File production.ini

View file
 ## all running rhodecode instances. Leave empty if you don't use it
 instance_id = 
 
+## alternative return HTTP header for failed authentication. Default HTTP
+## response is 401 HTTPUnauthorized. Currently HG clients have troubles with 
+## handling that. Set this variable to 403 to return HTTPForbidden
+auth_ret_code =
+
 errormator = true
 errormator.server_url = https://api.errormator.com
 errormator.api_key = AewWgTYtmlcijfJlARVJYJUwFcekxyCi
 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
 sqlalchemy.db1.echo = false
 sqlalchemy.db1.pool_recycle = 3600
-sqlalchemy.convert_unicode = true
+sqlalchemy.db1.convert_unicode = true
 
 ################################
 ### LOGGING CONFIGURATION   ####
 ################################
 [loggers]
-keys = root, routes, rhodecode, sqlalchemy, beaker, templates
+keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
 
 [handlers]
 keys = console, console_sql
 qualname = sqlalchemy.engine
 propagate = 0
 
+[logger_whoosh_indexer]
+level = DEBUG
+handlers = 
+qualname = whoosh_indexer
+propagate = 1
+
 ##############
 ## HANDLERS ##
 ##############

File requires.txt

View file
 Pylons==1.0.0
 Beaker==1.6.3
-WebHelpers>=1.2
+WebHelpers==1.3
 formencode==1.2.4
-SQLAlchemy==0.7.4
-Mako==0.5.0
+SQLAlchemy==0.7.6
+Mako==0.6.2
 pygments>=1.4
 whoosh>=2.3.0,<2.4
 celery>=2.2.5,<2.3
 babel
 python-dateutil>=1.5.0,<2.0.0
-dulwich>=0.8.0,<0.9.0
+dulwich>=0.8.4,<0.9.0
 webob==1.0.8
 markdown==2.1.1
 docutils==0.8.1
+simplejson
+pysqlite
 py-bcrypt
 mercurial>=2.1,<2.2

File rhodecode/__init__.py

View file
     ~~~~~~~~~~~~~~~~~~
 
     RhodeCode, a web based repository management based on pylons
-    versioning implementation: http://semver.org/
+    versioning implementation: http://www.python.org/dev/peps/pep-0386/
 
     :created_on: Apr 9, 2010
     :author: marcink
 import sys
 import platform
 
-VERSION = (1, 3, 3)
-__version__ = '.'.join((str(each) for each in VERSION[:4]))
+VERSION = (1, 3, 4)
+
+try:
+    from rhodecode.lib import get_current_revision
+    _rev = get_current_revision()
+    if _rev:
+        VERSION += ('dev%s' % _rev[0],)
+except ImportError:
+    pass
+
+__version__ = ('.'.join((str(each) for each in VERSION[:3])) +
+               '.'.join(VERSION[3:]))
 __dbversion__ = 5  # defines current db version for migrations
 __platform__ = platform.system()
 __license__ = 'GPLv3'
 requirements = [
     "Pylons==1.0.0",
     "Beaker==1.6.3",
-    "WebHelpers>=1.2",
+    "WebHelpers==1.3",
     "formencode==1.2.4",
-    "SQLAlchemy==0.7.4",
-    "Mako==0.5.0",
+    "SQLAlchemy==0.7.6",
+    "Mako==0.6.2",
     "pygments>=1.4",
     "whoosh>=2.3.0,<2.4",
     "celery>=2.2.5,<2.3",
     "babel",
     "python-dateutil>=1.5.0,<2.0.0",
-    "dulwich>=0.8.0,<0.9.0",
+    "dulwich>=0.8.4,<0.9.0",
     "webob==1.0.8",
     "markdown==2.1.1",
     "docutils==0.8.1",
     requirements.append("mercurial>=2.1,<2.2")
 
 
-try:
-    from rhodecode.lib import get_current_revision
-    _rev = get_current_revision(quiet=True)
-except ImportError:
-    # this is needed when doing some setup.py operations
-    _rev = False
-
-if len(VERSION) > 3 and _rev:
-    __version__ += ' [rev:%s]' % _rev[0]
-
-
 def get_version():
     """Returns shorter version (digit parts only) as string."""
 
 
 # link to config for pylons
 CONFIG = {}
+
+# Linked module for extensions
+EXTENSIONS = {}

File rhodecode/config/conf.py

View file
+# -*- coding: utf-8 -*-
+"""
+    package.rhodecode.config.conf
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Various config settings for RhodeCode
+
+    :created_on: Mar 7, 2012
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+    :license: <name>, see LICENSE_FILE for more details.
+"""
+from rhodecode import EXTENSIONS
+
+from rhodecode.lib.utils2 import __get_lem
+
+
+# language map is also used by whoosh indexer, which for those specified
+# extensions will index it's content
+LANGUAGES_EXTENSIONS_MAP = __get_lem()
+
+#==============================================================================
+# WHOOSH INDEX EXTENSIONS
+#==============================================================================
+# EXTENSIONS WE WANT TO INDEX CONTENT OFF USING WHOOSH
+INDEX_EXTENSIONS = LANGUAGES_EXTENSIONS_MAP.keys()
+
+# list of readme files to search in file tree and display in summary
+# attached weights defines the search  order lower is first
+ALL_READMES = [
+    ('readme', 0), ('README', 0), ('Readme', 0),
+    ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1),
+    ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2),
+    ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2),
+    ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2),
+]
+
+# extension together with weights to search lower is first
+RST_EXTS = [
+    ('', 0), ('.rst', 1), ('.rest', 1),
+    ('.RST', 2), ('.REST', 2),
+    ('.txt', 3), ('.TXT', 3)
+]
+
+MARKDOWN_EXTS = [
+    ('.md', 1), ('.MD', 1),
+    ('.mkdn', 2), ('.MKDN', 2),
+    ('.mdown', 3), ('.MDOWN', 3),
+    ('.markdown', 4), ('.MARKDOWN', 4)
+]
+
+PLAIN_EXTS = [('.text', 2), ('.TEXT', 2)]
+
+ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS
+
+DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
+
+DATE_FORMAT = "%Y-%m-%d"

File rhodecode/config/deployment.ini_tmpl

View file
 ## all running rhodecode instances. Leave empty if you don't use it
 instance_id = 
 
+## alternative return HTTP header for failed authentication. Default HTTP
+## response is 401 HTTPUnauthorized. Currently HG clients have troubles with 
+## handling that. Set this variable to 403 to return HTTPForbidden
+auth_ret_code =
+
 ####################################
 ###        CELERY CONFIG        ####
 ####################################
 
 sqlalchemy.db1.echo = false
 sqlalchemy.db1.pool_recycle = 3600
-sqlalchemy.convert_unicode = true
+sqlalchemy.db1.convert_unicode = true
 
 ################################
 ### LOGGING CONFIGURATION   ####
 ################################
 [loggers]
-keys = root, routes, rhodecode, sqlalchemy, beaker, templates
+keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
 
 [handlers]
 keys = console, console_sql
 qualname = sqlalchemy.engine
 propagate = 0
 
+[logger_whoosh_indexer]
+level = DEBUG
+handlers = 
+qualname = whoosh_indexer
+propagate = 1
+
 ##############
 ## HANDLERS ##
 ##############

File rhodecode/config/environment.py

View file
 
 import os
 import logging
+import rhodecode
 
 from mako.lookup import TemplateLookup
 from pylons.configuration import PylonsConfig
 from pylons.error import handle_mako_error
 
-import rhodecode
+# don't remove this import it does magic for celery
+from rhodecode.lib import celerypylons
+
 import rhodecode.lib.app_globals as app_globals
-import rhodecode.lib.helpers
 
 from rhodecode.config.routing import make_map
-# don't remove this import it does magic for celery
-from rhodecode.lib import celerypylons, str2bool
-from rhodecode.lib import engine_from_config
+
+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
+from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config,\
+    load_rcextensions
+from rhodecode.lib.utils2 import engine_from_config, str2bool
 from rhodecode.model import init_model
 from rhodecode.model.scm import ScmModel
 
 
 
 def load_environment(global_conf, app_conf, initial=False):
-    """Configure the Pylons environment via the ``pylons.config``
+    """
+    Configure the Pylons environment via the ``pylons.config``
     object
     """
     config = PylonsConfig()
 
     # Pylons paths
     root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-    paths = dict(root=root,
-                 controllers=os.path.join(root, 'controllers'),
-                 static_files=os.path.join(root, 'public'),
-                 templates=[os.path.join(root, 'templates')])
+    paths = dict(
+        root=root,
+        controllers=os.path.join(root, 'controllers'),
+        static_files=os.path.join(root, 'public'),
+        templates=[os.path.join(root, 'templates')]
+    )
 
     # Initialize config with the basic options
     config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
 
     config['routes.map'] = make_map(config)
     config['pylons.app_globals'] = app_globals.Globals(config)
-    config['pylons.h'] = rhodecode.lib.helpers
+    config['pylons.h'] = helpers
     rhodecode.CONFIG = config
+
+    load_rcextensions(root_path=config['here'])
+
     # Setup cache object as early as possible
     import pylons
     pylons.cache._push_object(config['pylons.app_globals'].cache)

File rhodecode/config/rcextensions/__init__.py

View file
+# Additional mappings that are not present in the pygments lexers
+# used for building stats
+# format is {'ext':'Name'} eg. {'py':'Python'}
+# NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
+# build by pygments
+EXTRA_MAPPINGS = {}
+
+#==============================================================================
+# WHOOSH INDEX EXTENSIONS
+#==============================================================================
+# if INDEX_EXTENSIONS is [] it'll use pygments lexers extensions by default.
+# To set your own just add to this list extensions to index with content
+INDEX_EXTENSIONS = []
+
+# additional extensions for indexing besides the default from pygments
+# those get's added to INDEX_EXTENSIONS
+EXTRA_INDEX_EXTENSIONS = []
+
+
+#==============================================================================
+# POST CREATE REPOSITORY HOOK
+#==============================================================================
+# this function will be executed after each repository is created
+def _crhook(*args, **kwargs):
+    """
+    Post create repository HOOK
+    kwargs available:
+     :param repo_name:
+     :param repo_type:
+     :param description:
+     :param private:
+     :param created_on:
+     :param enable_downloads:
+     :param repo_id:
+     :param user_id:
+     :param enable_statistics:
+     :param clone_uri:
+     :param fork_id:
+     :param group_id:
+     :param created_by:
+    """
+    return 0
+CREATE_REPO_HOOK = _crhook
+
+
+#==============================================================================
+# POST PUSH HOOK
+#==============================================================================
+
+# this function will be executed after each push it's runned after the build-in
+# hook that rhodecode uses for logging pushes
+def _pushhook(*args, **kwargs):
+    """
+    Post push hook
+    kwargs available:
+
+      :param username: name of user who pushed
+      :param ip: ip of who pushed
+      :param action: pull
+      :param repository: repository name
+      :param pushed_revs: generator of pushed revisions
+    """
+    return 0
+PUSH_HOOK = _pushhook
+
+
+#==============================================================================
+# POST PULL HOOK
+#==============================================================================
+
+# this function will be executed after each push it's runned after the build-in
+# hook that rhodecode uses for logging pushes
+def _pullhook(*args, **kwargs):
+    """
+    Post pull hook
+    kwargs available::
+
+      :param username: name of user who pulled
+      :param ip: ip of who pushed
+      :param action: pull
+      :param repository: repository name
+    """
+    return 0
+PULL_HOOK = _pullhook

File rhodecode/config/rcextensions/make_rcextensions.py

View file
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.config.rcextensions.make_rcextensions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Whoosh indexing module for RhodeCode
+
+    :created_on: Mar 6, 2012
+    :author: marcink
+    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+import os
+import sys
+import pkg_resources
+import traceback
+import logging
+from os.path import dirname as dn, join as jn
+
+#to get the rhodecode import
+sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
+
+from rhodecode.lib.utils import BasePasterCommand, Command, ask_ok
+
+log = logging.getLogger(__name__)
+
+
+class MakeRcExt(BasePasterCommand):
+
+    max_args = 1
+    min_args = 1
+
+    usage = "CONFIG_FILE"
+    summary = "Creates additional extensions for rhodecode"
+    group_name = "RhodeCode"
+    takes_config_file = -1
+    parser = Command.standard_parser(verbose=True)
+
+    def command(self):
+        logging.config.fileConfig(self.path_to_ini_file)
+        from pylons import config
+
+        def _make_file(ext_file):
+            bdir = os.path.split(ext_file)[0]
+            if not os.path.isdir(bdir):
+                os.makedirs(bdir)
+            with open(ext_file, 'wb') as f:
+                f.write(tmpl)
+                log.info('Writen new extensions file to %s' % ext_file)
+
+        here = config['here']
+        tmpl = pkg_resources.resource_string(
+            'rhodecode', jn('config', 'rcextensions', '__init__.py')
+        )
+        ext_file = jn(here, 'rcextensions', '__init__.py')
+        if os.path.exists(ext_file):
+            msg = ('Extension file already exists, do you want '
+                   'to overwrite it ? [y/n]')
+            if ask_ok(msg):
+                _make_file(ext_file)
+            else:
+                log.info('nothing done...')
+        else:
+            _make_file(ext_file)
+
+    def update_parser(self):
+        pass

File rhodecode/controllers/admin/repos.py

View file
 
         :param repo_name:
         """
-
         try:
             RepoModel().revoke_user_permission(repo=repo_name,
                                                user=request.POST['user_id'])

File rhodecode/controllers/admin/users.py

View file
         user_model = UserModel()
         try:
             user_model.delete(id)
+            Session.commit()
             h.flash(_('successfully deleted user'), category='success')
-            Session.commit()
         except (UserOwnsReposException, DefaultUserException), e:
-            h.flash(str(e), category='warning')
+            h.flash(e, category='warning')
         except Exception:
+            log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of user'),
                     category='error')
         return redirect(url('users'))

File rhodecode/controllers/admin/users_groups.py

View file
 from pylons.controllers.util import abort, redirect
 from pylons.i18n.translation import _
 
+from rhodecode.lib import helpers as h
 from rhodecode.lib.exceptions import UsersGroupsAssignedException
-from rhodecode.lib import helpers as h, safe_unicode
+from rhodecode.lib.utils2 import safe_unicode
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 from rhodecode.lib.base import BaseController, render
 

File rhodecode/controllers/api/__init__.py

View file
         try:
             return json.dumps(response)
         except TypeError, e:
-            log.debug('Error encoding response: %s' % e)
+            log.error('API FAILED. Error encoding response: %s' % e)
             return json.dumps(
                 dict(
-                    self._req_id,
+                    id=self._req_id,
                     result=None,
                     error="Error encoding response"
                 )

File rhodecode/controllers/api/api.py

View file
 
 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
 from rhodecode.lib.auth import HasPermissionAllDecorator, \
-    HasPermissionAnyDecorator, PasswordGenerator
+    HasPermissionAnyDecorator, PasswordGenerator, AuthUser
 
 from rhodecode.model.meta import Session
 from rhodecode.model.scm import ScmModel
-from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository
+from rhodecode.model.db import User, UsersGroup, Repository
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.user import UserModel
 from rhodecode.model.users_group import UsersGroupModel
-from rhodecode.model.repos_group import ReposGroupModel
-
+from rhodecode.lib.utils import map_groups
 
 log = logging.getLogger(__name__)
 
             email=user.email,
             active=user.active,
             admin=user.admin,
-            ldap_dn=user.ldap_dn
+            ldap_dn=user.ldap_dn,
+            last_login=user.last_login,
+            permissions=AuthUser(user_id=user.user_id).permissions
         )
 
     @HasPermissionAllDecorator('hg.admin')
                     email=user.email,
                     active=user.active,
                     admin=user.admin,
-                    ldap_dn=user.ldap_dn
+                    ldap_dn=user.ldap_dn,
+                    last_login=user.last_login,
                 )
             )
         return result
     @HasPermissionAllDecorator('hg.admin')
     def add_user_to_users_group(self, apiuser, group_name, username):
         """"
-        Add a user to a group
+        Add a user to a users group
 
         :param apiuser:
         :param group_name:
             user = user.user
             members.append(
                 dict(
-                    type_="user",
+                    type="user",
                     id=user.user_id,
                     username=user.username,
                     firstname=user.name,
             users_group = users_group.users_group
             members.append(
                 dict(
-                    type_="users_group",
+                    type="users_group",
                     id=users_group.users_group_id,
                     name=users_group.users_group_name,
                     active=users_group.users_group_active,
             if Repository.get_by_repo_name(repo_name):
                 raise JSONRPCError("repo %s already exist" % repo_name)
 
-            groups = repo_name.split('/')
+            groups = repo_name.split(Repository.url_sep())
             real_name = groups[-1]
-            groups = groups[:-1]
-            parent_id = None
-            for g in groups:
-                group = RepoGroup.get_by_group_name(g)
-                if not group:
-                    group = ReposGroupModel().create(g, '', parent_id)
-                parent_id = group.group_id
+            # create structure of groups
+            group = map_groups(repo_name)
 
             repo = RepoModel().create(
                 dict(
                     description=description,
                     private=private,
                     repo_type=repo_type,
-                    repo_group=parent_id,
+                    repo_group=group.group_id if group else None,
                     clone_uri=clone_uri
                 ),
                 owner

File rhodecode/controllers/branches.py

View file
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.compat import OrderedDict
-from rhodecode.lib import safe_unicode
+from rhodecode.lib.utils2 import safe_unicode
 log = logging.getLogger(__name__)
 
 

File rhodecode/controllers/changeset.py

View file
 log = logging.getLogger(__name__)
 
 
-def anchor_url(revision, path):
+def _update_with_GET(params, GET):
+    for k in ['diff1', 'diff2', 'diff']:
+        params[k] += GET.getall(k)
+
+
+def anchor_url(revision, path, GET):
     fid = h.FID(revision, path)
-    return h.url.current(anchor=fid, **dict(request.GET))
+    return h.url.current(anchor=fid, **dict(GET))
 
 
 def get_ignore_ws(fid, GET):
-    ig_ws_global = request.GET.get('ignorews')
+    ig_ws_global = GET.get('ignorews')
     ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
     if ig_ws:
         try:
     return ig_ws_global
 
 
-def _ignorews_url(fileid=None):
-
+def _ignorews_url(GET, fileid=None):
+    fileid = str(fileid) if fileid else None
     params = defaultdict(list)
+    _update_with_GET(params, GET)
     lbl = _('show white space')
-    ig_ws = get_ignore_ws(fileid, request.GET)
-    ln_ctx = get_line_ctx(fileid, request.GET)
+    ig_ws = get_ignore_ws(fileid, GET)
+    ln_ctx = get_line_ctx(fileid, GET)
     # global option
     if fileid is None:
         if ig_ws is None:
 
 
 def get_line_ctx(fid, GET):
-    ln_ctx_global = request.GET.get('context')
+    ln_ctx_global = GET.get('context')
     ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
 
     if ln_ctx:
         return
 
 
-def _context_url(fileid=None):
+def _context_url(GET, fileid=None):
     """
     Generates url for context lines
 
     :param fileid:
     """
-    ig_ws = get_ignore_ws(fileid, request.GET)
-    ln_ctx = (get_line_ctx(fileid, request.GET) or 3) * 2
+
+    fileid = str(fileid) if fileid else None
+    ig_ws = get_ignore_ws(fileid, GET)
+    ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2
 
     params = defaultdict(list)
+    _update_with_GET(params, GET)
 
     # global option
     if fileid is None:
         c.anchor_url = anchor_url
         c.ignorews_url = _ignorews_url
         c.context_url = _context_url
-
+        limit_off = request.GET.get('fulldiff')
         #get ranges of revisions if preset
         rev_range = revision.split('...')[:2]
         enable_comments = True
                 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
                 lim = self.cut_off_limit
                 if cumulative_diff > self.cut_off_limit:
-                    lim = -1
+                    lim = -1 if limit_off is None else None
                 size, cs1, cs2, diff, st = wrapped_diff(
                     filenode_old=None,
                     filenode_new=node,
                 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
                 lim = self.cut_off_limit
                 if cumulative_diff > self.cut_off_limit:
-                    lim = -1
+                    lim = -1 if limit_off is None else None
                 size, cs1, cs2, diff, st = wrapped_diff(
                     filenode_old=filenode_old,
                     filenode_new=node,

File rhodecode/controllers/feed.py

View file
 from pylons import url, response, tmpl_context as c
 from pylons.i18n.translation import _
 
-from rhodecode.lib import safe_unicode
+from rhodecode.lib.utils2 import safe_unicode
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController
 

File rhodecode/controllers/files.py

View file
 from pylons.controllers.util import redirect
 from pylons.decorators import jsonify
 
-from rhodecode.lib.vcs.conf import settings
-from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
-    EmptyRepositoryError, ImproperArchiveTypeError, VCSError, \
-    NodeAlreadyExistsError
-from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib import diffs
+from rhodecode.lib import helpers as h
 
 from rhodecode.lib.compat import OrderedDict
-from rhodecode.lib import convert_line_endings, detect_mode, safe_str
+from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.utils import EmptyChangeset
-from rhodecode.lib import diffs
-import rhodecode.lib.helpers as h
+from rhodecode.lib.vcs.conf import settings
+from rhodecode.lib.vcs.exceptions import RepositoryError, \
+    ChangesetDoesNotExistError, EmptyRepositoryError, \
+    ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
+from rhodecode.lib.vcs.nodes import FileNode
+
 from rhodecode.model.repo import RepoModel
+from rhodecode.model.scm import ScmModel
+
 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
     _context_url, get_line_ctx, get_ignore_ws
-from rhodecode.lib.diffs import wrapped_diff
-from rhodecode.model.scm import ScmModel
+
 
 log = logging.getLogger(__name__)
 
             ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
 
             lim = request.GET.get('fulldiff') or self.cut_off_limit
-            _, cs1, cs2, diff, st = wrapped_diff(filenode_old=node1,
+            _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
                                          filenode_new=node2,
                                          cut_off_limit=lim,
                                          ignore_whitespace=ign_whitespace_lcl,

File rhodecode/controllers/home.py

View file
     def index(self):
         c.repos_list = self.scm_model.get_repos()
         c.groups = self.scm_model.get_repos_groups()
-
+        c.group = None
         return render('/index.html')
 
     def repo_switcher(self):

File rhodecode/controllers/summary.py

View file
 import traceback
 import calendar
 import logging
+import urllib
 from time import mktime
 from datetime import timedelta, date
 from urlparse import urlparse
 
 from beaker.cache import cache_region, region_invalidate
 
+from rhodecode.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
 from rhodecode.model.db import Statistics, CacheInvalidation
-from rhodecode.lib import ALL_READMES, ALL_EXTS
+from rhodecode.lib.utils2 import safe_unicode
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.utils import EmptyChangeset
 from rhodecode.lib.markup_renderer import MarkupRenderer
 from rhodecode.lib.celerylib import run_task
-from rhodecode.lib.celerylib.tasks import get_commits_stats, \
-    LANGUAGES_EXTENSIONS_MAP
+from rhodecode.lib.celerylib.tasks import get_commits_stats
 from rhodecode.lib.helpers import RepoPage
 from rhodecode.lib.compat import json, OrderedDict
 
 
         uri_tmpl = config.get('clone_uri', default_clone_uri)
         uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s')
-
+        decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
         uri_dict = {
            'user': username,
            'pass': password,
            'scheme': parsed_url.scheme,
            'netloc': parsed_url.netloc,
-           'path': parsed_url.path
+           'path': decoded_path
         }
+
         uri = uri_tmpl % uri_dict
         # generate another clone url by id
-        uri_dict.update({'path': '/_%s' % c.dbrepo.repo_id})
+        uri_dict.update(
+         {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)}
+        )
         uri_id = uri_tmpl % uri_dict
 
         c.clone_repo_url = uri
         c.clone_repo_url_id = uri_id
         c.repo_tags = OrderedDict()
-        for name, hash in c.rhodecode_repo.tags.items()[:10]:
+        for name, hash_ in c.rhodecode_repo.tags.items()[:10]:
             try:
-                c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash)
+                c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_)
             except ChangesetError:
-                c.repo_tags[name] = EmptyChangeset(hash)
+                c.repo_tags[name] = EmptyChangeset(hash_)
 
         c.repo_branches = OrderedDict()
-        for name, hash in c.rhodecode_repo.branches.items()[:10]:
+        for name, hash_ in c.rhodecode_repo.branches.items()[:10]:
             try:
-                c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash)
+                c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_)
             except ChangesetError:
-                c.repo_branches[name] = EmptyChangeset(hash)
+                c.repo_branches[name] = EmptyChangeset(hash_)
 
         td = date.today() + timedelta(days=1)
         td_1m = td - timedelta(days=calendar.mdays[td.month])
         if c.enable_downloads:
             c.download_options = self._get_download_links(c.rhodecode_repo)
 
-        c.readme_data, c.readme_file = self.__get_readme_data(c.rhodecode_repo)
+        c.readme_data, c.readme_file = self.__get_readme_data(c.rhodecode_db_repo)
         return render('summary/summary.html')
 
     def __get_readme_data(self, repo):
 
             return readme_data, readme_file
 
-        key = repo.name + '_README'
+        key = repo.repo_name + '_README'
         inv = CacheInvalidation.invalidate(key)
         if inv is not None:
             region_invalidate(_get_readme_from_cache, None, key)

File rhodecode/lib/__init__.py

View file
-# -*- coding: utf-8 -*-
-"""
-    rhodecode.lib.__init__
-    ~~~~~~~~~~~~~~~~~~~~~~~
-
-    Some simple helper functions
-
-    :created_on: Jan 5, 2011
-    :author: marcink
-    :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
-    :license: GPLv3, see COPYING for more details.
-"""
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
 import os
-import re
-from rhodecode.lib.vcs.utils.lazy import LazyProperty
-
-
-def __get_lem():
-    from pygments import lexers
-    from string import lower
-    from collections import defaultdict
-
-    d = defaultdict(lambda: [])
-
-    def __clean(s):
-        s = s.lstrip('*')
-        s = s.lstrip('.')
-
-        if s.find('[') != -1:
-            exts = []
-            start, stop = s.find('['), s.find(']')
-
-            for suffix in s[start + 1:stop]:
-                exts.append(s[:s.find('[')] + suffix)
-            return map(lower, exts)
-        else:
-            return map(lower, [s])
-
-    for lx, t in sorted(lexers.LEXERS.items()):
-        m = map(__clean, t[-2])
-        if m:
-            m = reduce(lambda x, y: x + y, m)
-            for ext in m:
-                desc = lx.replace('Lexer', '')
-                d[ext].append(desc)
-
-    return dict(d)
-
-# language map is also used by whoosh indexer, which for those specified
-# extensions will index it's content
-LANGUAGES_EXTENSIONS_MAP = __get_lem()
-
-# Additional mappings that are not present in the pygments lexers
-# NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
-ADDITIONAL_MAPPINGS = {'xaml': 'XAML'}
-
-LANGUAGES_EXTENSIONS_MAP.update(ADDITIONAL_MAPPINGS)
-
-# list of readme files to search in file tree and display in summary
-# attached weights defines the search  order lower is first
-ALL_READMES = [
-    ('readme', 0), ('README', 0), ('Readme', 0),
-    ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1),
-    ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2),
-    ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2),
-    ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2),
-]
-
-# extension together with weights to search lower is first
-RST_EXTS = [
-    ('', 0), ('.rst', 1), ('.rest', 1),
-    ('.RST', 2), ('.REST', 2),
-    ('.txt', 3), ('.TXT', 3)
-]
-
-MARKDOWN_EXTS = [
-    ('.md', 1), ('.MD', 1),
-    ('.mkdn', 2), ('.MKDN', 2),
-    ('.mdown', 3), ('.MDOWN', 3),
-    ('.markdown', 4), ('.MARKDOWN', 4)
-]
-
-PLAIN_EXTS = [('.text', 2), ('.TEXT', 2)]
-
-ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS
-
-
-def str2bool(_str):
-    """
-    returs True/False value from given string, it tries to translate the
-    string into boolean
-
-    :param _str: string value to translate into boolean
-    :rtype: boolean
-    :returns: boolean from given string
-    """
-    if _str is None:
-        return False
-    if _str in (True, False):
-        return _str
-    _str = str(_str).strip().lower()
-    return _str in ('t', 'true', 'y', 'yes', 'on', '1')
-
-
-def convert_line_endings(line, mode):
-    """
-    Converts a given line  "line end" accordingly to given mode
-
-    Available modes are::
-        0 - Unix
-        1 - Mac
-        2 - DOS
-
-    :param line: given line to convert
-    :param mode: mode to convert to
-    :rtype: str
-    :return: converted line according to mode
-    """
-    from string import replace
-
-    if mode == 0:
-            line = replace(line, '\r\n', '\n')
-            line = replace(line, '\r', '\n')
-    elif mode == 1:
-            line = replace(line, '\r\n', '\r')
-            line = replace(line, '\n', '\r')
-    elif mode == 2:
-            line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
-    return line
-
-
-def detect_mode(line, default):
-    """
-    Detects line break for given line, if line break couldn't be found
-    given default value is returned
-
-    :param line: str line
-    :param default: default
-    :rtype: int
-    :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
-    """
-    if line.endswith('\r\n'):
-        return 2
-    elif line.endswith('\n'):
-        return 0
-    elif line.endswith('\r'):
-        return 1
-    else:
-        return default
-
-
-def generate_api_key(username, salt=None):
-    """
-    Generates unique API key for given username, if salt is not given
-    it'll be generated from some random string
-
-    :param username: username as string
-    :param salt: salt to hash generate KEY
-    :rtype: str
-    :returns: sha1 hash from username+salt
-    """
-    from tempfile import _RandomNameSequence
-    import hashlib
-
-    if salt is None:
-        salt = _RandomNameSequence().next()
-
-    return hashlib.sha1(username + salt).hexdigest()
-
-
-def safe_unicode(str_, from_encoding=None):
-    """
-    safe unicode function. Does few trick to turn str_ into unicode
-
-    In case of UnicodeDecode error we try to return it with encoding detected
-    by chardet library if it fails fallback to unicode with errors replaced
-
-    :param str_: string to decode
-    :rtype: unicode
-    :returns: unicode object
-    """
-    if isinstance(str_, unicode):
-        return str_
-
-    if not from_encoding:
-        import rhodecode
-        DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8')
-        from_encoding = DEFAULT_ENCODING
-
-    try:
-        return unicode(str_)
-    except UnicodeDecodeError:
-        pass
-
-    try:
-        return unicode(str_, from_encoding)
-    except UnicodeDecodeError:
-        pass
-
-    try:
-        import chardet
-        encoding = chardet.detect(str_)['encoding']
-        if encoding is None:
-            raise Exception()
-        return str_.decode(encoding)
-    except (ImportError, UnicodeDecodeError, Exception):
-        return unicode(str_, from_encoding, 'replace')
-
-
-def safe_str(unicode_, to_encoding=None):
-    """
-    safe str function. Does few trick to turn unicode_ into string
-
-    In case of UnicodeEncodeError we try to return it with encoding detected
-    by chardet library if it fails fallback to string with errors replaced
-
-    :param unicode_: unicode to encode
-    :rtype: str
-    :returns: str object
-    """
-
-    # if it's not basestr cast to str
-    if not isinstance(unicode_, basestring):
-        return str(unicode_)
-
-    if isinstance(unicode_, str):
-        return unicode_
-
-    if not to_encoding:
-        import rhodecode
-        DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8')
-        to_encoding = DEFAULT_ENCODING
-
-    try:
-        return unicode_.encode(to_encoding)
-    except UnicodeEncodeError:
-        pass
-
-    try:
-        import chardet
-        encoding = chardet.detect(unicode_)['encoding']
-        print encoding
-        if encoding is None:
-            raise UnicodeEncodeError()
-
-        return unicode_.encode(encoding)
-    except (ImportError, UnicodeEncodeError):
-        return unicode_.encode(to_encoding, 'replace')
-
-    return safe_str
-
-
-def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
-    """
-    Custom engine_from_config functions that makes sure we use NullPool for
-    file based sqlite databases. This prevents errors on sqlite. This only
-    applies to sqlalchemy versions < 0.7.0
-
-    """
-    import sqlalchemy
-    from sqlalchemy import engine_from_config as efc
-    import logging
-
-    if int(sqlalchemy.__version__.split('.')[1]) < 7:
-
-        # This solution should work for sqlalchemy < 0.7.0, and should use
-        # proxy=TimerProxy() for execution time profiling
-
-        from sqlalchemy.pool import NullPool
-        url = configuration[prefix + 'url']
-
-        if url.startswith('sqlite'):
-            kwargs.update({'poolclass': NullPool})
-        return efc(configuration, prefix, **kwargs)
-    else:
-        import time
-        from sqlalchemy import event
-        from sqlalchemy.engine import Engine
-
-        log = logging.getLogger('sqlalchemy.engine')
-        BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
-        engine = efc(configuration, prefix, **kwargs)
-
-        def color_sql(sql):
-            COLOR_SEQ = "\033[1;%dm"
-            COLOR_SQL = YELLOW
-            normal = '\x1b[0m'
-            return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
-
-        if configuration['debug']:
-            #attach events only for debug configuration
-
-            def before_cursor_execute(conn, cursor, statement,
-                                    parameters, context, executemany):
-                context._query_start_time = time.time()
-                log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
-
-
-            def after_cursor_execute(conn, cursor, statement,
-                                    parameters, context, executemany):
-                total = time.time() - context._query_start_time
-                log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
-
-            event.listen(engine, "before_cursor_execute",
-                         before_cursor_execute)
-            event.listen(engine, "after_cursor_execute",
-                         after_cursor_execute)
-
-    return engine
-
-
-def age(curdate):
-    """
-    turns a datetime into an age string.
-
-    :param curdate: datetime object
-    :rtype: unicode
-    :returns: unicode words describing age
-    """
-
-    from datetime import datetime
-    from webhelpers.date import time_ago_in_words
-
-    _ = lambda s: s
-
-    if not curdate:
-        return ''
-
-    agescales = [(_(u"year"), 3600 * 24 * 365),
-                 (_(u"month"), 3600 * 24 * 30),
-                 (_(u"day"), 3600 * 24),
-                 (_(u"hour"), 3600),
-                 (_(u"minute"), 60),
-                 (_(u"second"), 1), ]
-
-    age = datetime.now() - curdate
-    age_seconds = (age.days * agescales[2][1]) + age.seconds
-    pos = 1
-    for scale in agescales:
-        if scale[1] <= age_seconds:
-            if pos == 6:
-                pos = 5
-            return '%s %s' % (time_ago_in_words(curdate,
-                                                agescales[pos][0]), _('ago'))
-        pos += 1
-
-    return _(u'just now')
-
-
-def uri_filter(uri):
-    """
-    Removes user:password from given url string
-
-    :param uri:
-    :rtype: unicode
-    :returns: filtered list of strings
-    """
-    if not uri:
-        return ''
-
-    proto = ''
-
-    for pat in ('https://', 'http://'):
-        if uri.startswith(pat):
-            uri = uri[len(pat):]
-            proto = pat
-            break
-
-    # remove passwords and username
-    uri = uri[uri.find('@') + 1:]
-
-    # get the port
-    cred_pos = uri.find(':')
-    if cred_pos == -1:
-        host, port = uri, None
-    else:
-        host, port = uri[:cred_pos], uri[cred_pos + 1:]
-
-    return filter(None, [proto, host, port])
-
-
-def credentials_filter(uri):
-    """
-    Returns a url with removed credentials
-
-    :param uri:
-    """
-
-    uri = uri_filter(uri)
-    #check if we have port
-    if len(uri) > 2 and uri[2]:
-        uri[2] = ':' + uri[2]
-
-    return ''.join(uri)
-
-
-def get_changeset_safe(repo, rev):
-    """
-    Safe version of get_changeset if this changeset doesn't exists for a
-    repo it returns a Dummy one instead
-
-    :param repo:
-    :param rev:
-    """
-    from rhodecode.lib.vcs.backends.base import BaseRepository
-    from rhodecode.lib.vcs.exceptions import RepositoryError
-    if not isinstance(repo, BaseRepository):
-        raise Exception('You must pass an Repository '
-                        'object as first argument got %s', type(repo))
-
-    try:
-        cs = repo.get_changeset(rev)
-    except RepositoryError:
-        from rhodecode.lib.utils import EmptyChangeset
-        cs = EmptyChangeset(requested_revision=rev)
-    return cs
 
 
 def get_current_revision(quiet=False):
             print ("Cannot retrieve rhodecode's revision. Original error "
                    "was: %s" % err)
         return None
-
-
-def extract_mentioned_users(s):
-    """
-    Returns unique usernames from given string s that have @mention
-
-    :param s: string to get mentions
-    """
-    usrs = {}
-    for username in re.findall(r'(?:^@|\s@)(\w+)', s):
-        usrs[username] = username
-
-    return sorted(usrs.keys())

File rhodecode/lib/auth.py

View file
 if __platform__ in PLATFORM_OTHERS:
     import bcrypt
 
-from rhodecode.lib import str2bool, safe_unicode
+from rhodecode.lib.utils2 import str2bool, safe_unicode
 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
 from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
 from rhodecode.lib.auth_ldap import AuthLdap
         self.user = cls.rhodecode_user
         self.user_perms = self.user.permissions
         log.debug('checking %s permissions %s for %s %s',
-           self.__class__.__name__, self.required_perms, cls,
-               self.user)
+           self.__class__.__name__, self.required_perms, cls, self.user)
 
         if self.check_permissions():
             log.debug('Permission granted for %s %s' % (cls, self.user))
             user_perms = set([self.user_perms['repositories'][repo_name]])
         except KeyError:
             return False