changeset 3340:f1491bad8339 beta

unified RhodeCode paster commands - moved them to commont paster_commands package - re-use sqlalchemy session initializaiton - some docs updates
author Marcin Kuzminski <marcin@python-works.com>
date Sat, 09 Feb 2013 22:21:31 +0100
parents b76a595b7a5e
children 030103d57e30
files rhodecode/config/rcextensions/make_rcextensions.py rhodecode/config/setup_rhodecode.py rhodecode/lib/cleanup.py rhodecode/lib/paster_commands/__init__.py rhodecode/lib/paster_commands/cleanup.py rhodecode/lib/paster_commands/make_rcextensions.py rhodecode/lib/paster_commands/repo_scan.py rhodecode/lib/paster_commands/setup_rhodecode.py rhodecode/lib/paster_commands/update_repoinfo.py rhodecode/lib/update_repoinfo.py rhodecode/lib/utils.py setup.py
diffstat 11 files changed, 495 insertions(+), 413 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/config/rcextensions/make_rcextensions.py	Sat Feb 09 19:45:10 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-# -*- 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/>.
-from __future__ import with_statement
-
-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, tmpl):
-            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, tmpl)
-            else:
-                log.info('nothing done...')
-        else:
-            _make_file(ext_file, tmpl)
-
-    def update_parser(self):
-        pass
--- a/rhodecode/config/setup_rhodecode.py	Sat Feb 09 19:45:10 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-import os
-from paste.script.appinstall import AbstractInstallCommand
-from paste.script.command import BadCommand
-from paste.deploy import appconfig
-
-
-class SetupCommand(AbstractInstallCommand):
-
-    default_verbosity = 1
-    max_args = 1
-    min_args = 1
-    summary = "Setup an application, given a config file"
-    usage = "CONFIG_FILE"
-
-    description = """\
-    Note: this is an experimental command, and it will probably change
-    in several ways by the next release.
-
-    Setup an application according to its configuration file.  This is
-    the second part of a two-phase web application installation
-    process (the first phase is prepare-app).  The setup process may
-    consist of things like creating directories and setting up
-    databases.
-    """
-
-    parser = AbstractInstallCommand.standard_parser(
-        simulate=True, quiet=True, interactive=True)
-    parser.add_option('--user',
-                      action='store',
-                      dest='username',
-                      default=None,
-                      help='Admin Username')
-    parser.add_option('--email',
-                      action='store',
-                      dest='email',
-                      default=None,
-                      help='Admin Email')
-    parser.add_option('--password',
-                      action='store',
-                      dest='password',
-                      default=None,
-                      help='Admin password min 6 chars')
-    parser.add_option('--repos',
-                      action='store',
-                      dest='repos_location',
-                      default=None,
-                      help='Absolute path to repositories location')
-    parser.add_option('--name',
-                      action='store',
-                      dest='section_name',
-                      default=None,
-                      help='The name of the section to set up (default: app:main)')
-    parser.add_option('--force-yes',
-                       action='store_true',
-                       dest='force_ask',
-                       default=None,
-                       help='Force yes to every question')
-    parser.add_option('--force-no',
-                       action='store_false',
-                       dest='force_ask',
-                       default=None,
-                       help='Force no to every question')
-
-    def command(self):
-        config_spec = self.args[0]
-        section = self.options.section_name
-        if section is None:
-            if '#' in config_spec:
-                config_spec, section = config_spec.split('#', 1)
-            else:
-                section = 'main'
-        if not ':' in section:
-            plain_section = section
-            section = 'app:' + section
-        else:
-            plain_section = section.split(':', 1)[0]
-        if not config_spec.startswith('config:'):
-            config_spec = 'config:' + config_spec
-        if plain_section != 'main':
-            config_spec += '#' + plain_section
-        config_file = config_spec[len('config:'):].split('#', 1)[0]
-        config_file = os.path.join(os.getcwd(), config_file)
-        self.logging_file_config(config_file)
-        conf = appconfig(config_spec, relative_to=os.getcwd())
-        ep_name = conf.context.entry_point_name
-        ep_group = conf.context.protocol
-        dist = conf.context.distribution
-        if dist is None:
-            raise BadCommand(
-                "The section %r is not the application (probably a filter).  "
-                "You should add #section_name, where section_name is the "
-                "section that configures your application" % plain_section)
-        installer = self.get_installer(dist, ep_group, ep_name)
-        installer.setup_config(
-            self, config_file, section, self.sysconfig_install_vars(installer))
-        self.call_sysconfig_functions(
-            'post_setup_hook', installer, config_file)
--- a/rhodecode/lib/cleanup.py	Sat Feb 09 19:45:10 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    package.rhodecode.lib.cleanup
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    :created_on: Jul 14, 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/>.
-from __future__ import with_statement
-
-import os
-import sys
-import re
-import shutil
-import logging
-import datetime
-
-from os.path import dirname as dn, join as jn
-from rhodecode.model import init_model
-from rhodecode.lib.utils2 import engine_from_config, safe_str
-from rhodecode.model.db import RhodeCodeUi
-
-
-#to get the rhodecode import
-sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
-
-from rhodecode.lib.utils import BasePasterCommand, Command, ask_ok,\
-    REMOVED_REPO_PAT, add_cache
-
-log = logging.getLogger(__name__)
-
-
-class CleanupCommand(BasePasterCommand):
-
-    max_args = 1
-    min_args = 1
-
-    usage = "CONFIG_FILE"
-    summary = "Cleanup deleted repos"
-    group_name = "RhodeCode"
-    takes_config_file = -1
-    parser = Command.standard_parser(verbose=True)
-
-    def _parse_older_than(self, val):
-        regex = re.compile(r'((?P<days>\d+?)d)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
-        parts = regex.match(val)
-        if not parts:
-            return
-        parts = parts.groupdict()
-        time_params = {}
-        for (name, param) in parts.iteritems():
-            if param:
-                time_params[name] = int(param)
-        return datetime.timedelta(**time_params)
-
-    def _extract_date(self, name):
-        """
-        Extract the date part from rm__<date> pattern of removed repos,
-        and convert it to datetime object
-
-        :param name:
-        """
-        date_part = name[4:19]  # 4:19 since we don't parse milisecods
-        return datetime.datetime.strptime(date_part, '%Y%m%d_%H%M%S')
-
-    def command(self):
-        logging.config.fileConfig(self.path_to_ini_file)
-        from pylons import config
-
-        #get to remove repos !!
-        add_cache(config)
-        engine = engine_from_config(config, 'sqlalchemy.db1.')
-        init_model(engine)
-
-        repos_location = RhodeCodeUi.get_repos_location()
-        to_remove = []
-        for dn, dirs, f in os.walk(safe_str(repos_location)):
-            for loc in dirs:
-                if REMOVED_REPO_PAT.match(loc):
-                    to_remove.append([os.path.join(dn, loc),
-                                      self._extract_date(loc)])
-
-        #filter older than (if present)!
-        now = datetime.datetime.now()
-        older_than = self.options.older_than
-        if older_than:
-            to_remove_filtered = []
-            older_than_date = self._parse_older_than(older_than)
-            for name, date_ in to_remove:
-                repo_age = now - date_
-                if repo_age > older_than_date:
-                    to_remove_filtered.append([name, date_])
-
-            to_remove = to_remove_filtered
-            print >> sys.stdout, 'removing [%s] deleted repos older than %s[%s]' \
-                % (len(to_remove), older_than, older_than_date)
-        else:
-            print >> sys.stdout, 'removing all [%s] deleted repos' \
-                % len(to_remove)
-        if self.options.dont_ask or not to_remove:
-            # don't ask just remove !
-            remove = True
-        else:
-            remove = ask_ok('are you sure to remove listed repos \n%s [y/n]?'
-                            % ', \n'.join(['%s removed on %s'
-                    % (safe_str(x[0]), safe_str(x[1])) for x in to_remove]))
-
-        if remove:
-            for name, date_ in to_remove:
-                print >> sys.stdout, 'removing repository %s' % name
-                shutil.rmtree(os.path.join(repos_location, name))
-        else:
-            print 'nothing done exiting...'
-            sys.exit(0)
-
-    def update_parser(self):
-        self.parser.add_option('--older-than',
-                          action='store',
-                          dest='older_than',
-                          help=(
-                            "only remove repos that have been removed "
-                            "at least given time ago "
-                            "ex. --older-than=30d deletes repositores "
-                            "removed more than 30days ago. Possible options "
-                            "d[ays]/h[ours]/m[inutes]/s[seconds]. OPTIONAL"),
-                          )
-        self.parser.add_option('--dont-ask',
-                               action='store_true',
-                               dest='dont_ask',
-                               help=("Don't ask to remove repos"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/paster_commands/cleanup.py	Sat Feb 09 22:21:31 2013 +0100
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.paster_commands.make_rcextensions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    cleanup-repos paster command for RhodeCode
+
+
+    :created_on: Jul 14, 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/>.
+from __future__ import with_statement
+
+import os
+import sys
+import re
+import shutil
+import logging
+import datetime
+
+from os.path import dirname as dn, join as jn
+#to get the rhodecode import
+rc_path = dn(dn(dn(os.path.realpath(__file__))))
+sys.path.append(rc_path)
+from rhodecode.lib.utils import BasePasterCommand, ask_ok, REMOVED_REPO_PAT
+
+from rhodecode.lib.utils2 import safe_str
+from rhodecode.model.db import RhodeCodeUi
+
+
+log = logging.getLogger(__name__)
+
+
+class Command(BasePasterCommand):
+
+    max_args = 1
+    min_args = 1
+
+    usage = "CONFIG_FILE"
+    group_name = "RhodeCode"
+    takes_config_file = -1
+    parser = BasePasterCommand.standard_parser(verbose=True)
+    summary = "Cleanup deleted repos"
+
+    def _parse_older_than(self, val):
+        regex = re.compile(r'((?P<days>\d+?)d)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
+        parts = regex.match(val)
+        if not parts:
+            return
+        parts = parts.groupdict()
+        time_params = {}
+        for (name, param) in parts.iteritems():
+            if param:
+                time_params[name] = int(param)
+        return datetime.timedelta(**time_params)
+
+    def _extract_date(self, name):
+        """
+        Extract the date part from rm__<date> pattern of removed repos,
+        and convert it to datetime object
+
+        :param name:
+        """
+        date_part = name[4:19]  # 4:19 since we don't parse milisecods
+        return datetime.datetime.strptime(date_part, '%Y%m%d_%H%M%S')
+
+    def command(self):
+        #get SqlAlchemy session
+        self._init_session()
+
+        repos_location = RhodeCodeUi.get_repos_location()
+        to_remove = []
+        for dn, dirs, f in os.walk(safe_str(repos_location)):
+            for loc in dirs:
+                if REMOVED_REPO_PAT.match(loc):
+                    to_remove.append([os.path.join(dn, loc),
+                                      self._extract_date(loc)])
+
+        #filter older than (if present)!
+        now = datetime.datetime.now()
+        older_than = self.options.older_than
+        if older_than:
+            to_remove_filtered = []
+            older_than_date = self._parse_older_than(older_than)
+            for name, date_ in to_remove:
+                repo_age = now - date_
+                if repo_age > older_than_date:
+                    to_remove_filtered.append([name, date_])
+
+            to_remove = to_remove_filtered
+            print >> sys.stdout, 'removing [%s] deleted repos older than %s[%s]' \
+                % (len(to_remove), older_than, older_than_date)
+        else:
+            print >> sys.stdout, 'removing all [%s] deleted repos' \
+                % len(to_remove)
+        if self.options.dont_ask or not to_remove:
+            # don't ask just remove !
+            remove = True
+        else:
+            remove = ask_ok('are you sure to remove listed repos \n%s [y/n]?'
+                            % ', \n'.join(['%s removed on %s'
+                    % (safe_str(x[0]), safe_str(x[1])) for x in to_remove]))
+
+        if remove:
+            for name, date_ in to_remove:
+                print >> sys.stdout, 'removing repository %s' % name
+                shutil.rmtree(os.path.join(repos_location, name))
+        else:
+            print 'nothing done exiting...'
+            sys.exit(0)
+
+    def update_parser(self):
+        self.parser.add_option('--older-than',
+                          action='store',
+                          dest='older_than',
+                          help=(
+                            "only remove repos that have been removed "
+                            "at least given time ago "
+                            "ex. --older-than=30d deletes repositores "
+                            "removed more than 30days ago. Possible options "
+                            "d[ays]/h[ours]/m[inutes]/s[seconds]. OPTIONAL"),
+                          )
+        self.parser.add_option('--dont-ask',
+                               action='store_true',
+                               dest='dont_ask',
+                               help=("Don't ask to remove repos"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/paster_commands/make_rcextensions.py	Sat Feb 09 22:21:31 2013 +0100
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.paster_commands.make_rcextensions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    make-rcext paster command 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/>.
+from __future__ import with_statement
+
+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
+rc_path = dn(dn(dn(os.path.realpath(__file__))))
+sys.path.append(rc_path)
+
+from rhodecode.lib.utils import BasePasterCommand, ask_ok
+
+log = logging.getLogger(__name__)
+
+
+class Command(BasePasterCommand):
+
+    max_args = 1
+    min_args = 1
+
+    usage = "CONFIG_FILE"
+    group_name = "RhodeCode"
+    takes_config_file = -1
+    parser = BasePasterCommand.standard_parser(verbose=True)
+    summary = "Creates additional extensions for rhodecode"
+
+    def command(self):
+        logging.config.fileConfig(self.path_to_ini_file)
+        from pylons import config
+
+        def _make_file(ext_file, tmpl):
+            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, tmpl)
+            else:
+                log.info('nothing done...')
+        else:
+            _make_file(ext_file, tmpl)
+
+    def update_parser(self):
+        pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/paster_commands/repo_scan.py	Sat Feb 09 22:21:31 2013 +0100
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.paster_commands.make_rcextensions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    repo-scan paster command for RhodeCode
+
+
+    :created_on: Feb 9, 2013
+    :author: marcink
+    :copyright: (C) 2010-2013 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/>.
+from __future__ import with_statement
+
+import os
+import sys
+import logging
+
+from os.path import dirname as dn, join as jn
+from rhodecode.model.scm import ScmModel
+#to get the rhodecode import
+rc_path = dn(dn(dn(os.path.realpath(__file__))))
+sys.path.append(rc_path)
+from rhodecode.lib.utils import BasePasterCommand, repo2db_mapper
+
+from rhodecode.model.db import Repository
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.meta import Session
+
+
+log = logging.getLogger(__name__)
+
+
+class Command(BasePasterCommand):
+
+    max_args = 1
+    min_args = 1
+
+    usage = "CONFIG_FILE"
+    group_name = "RhodeCode"
+    takes_config_file = -1
+    parser = BasePasterCommand.standard_parser(verbose=True)
+    summary = "Rescan default location for new repositories"
+
+    def command(self):
+        #get SqlAlchemy session
+        self._init_session()
+        rm_obsolete = self.options.delete_obsolete
+        log.info('Now scanning root location for new repos...')
+        added, removed = repo2db_mapper(ScmModel().repo_scan(),
+                                        remove_obsolete=rm_obsolete)
+        added = ','.join(added) or '-'
+        removed = ','.join(removed) or '-'
+        log.info('Scan completed added:%s removed:%s' % (added, removed))
+
+    def update_parser(self):
+        self.parser.add_option('--delete-obsolete',
+                          action='store_true',
+                          help="Use this flag do delete repositories that are "
+                          "present in RhodeCode database but not on the filesystem",
+                          )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/paster_commands/setup_rhodecode.py	Sat Feb 09 22:21:31 2013 +0100
@@ -0,0 +1,101 @@
+import os
+import sys
+from paste.script.appinstall import AbstractInstallCommand
+from paste.script.command import BadCommand
+from paste.deploy import appconfig
+
+from os.path import dirname as dn, join as jn
+#to get the rhodecode import
+rc_path = dn(dn(dn(os.path.realpath(__file__))))
+sys.path.append(rc_path)
+
+
+class Command(AbstractInstallCommand):
+
+    default_verbosity = 1
+    max_args = 1
+    min_args = 1
+    summary = "Setup an application, given a config file"
+    usage = "CONFIG_FILE"
+    group_name = "RhodeCode"
+
+    description = """\
+
+    Setup RhodeCode according to its configuration file.  This is
+    the second part of a two-phase web application installation
+    process (the first phase is prepare-app).  The setup process
+    consist of things like setting up databases, creating super user
+    """
+
+    parser = AbstractInstallCommand.standard_parser(
+        simulate=True, quiet=True, interactive=True)
+    parser.add_option('--user',
+                      action='store',
+                      dest='username',
+                      default=None,
+                      help='Admin Username')
+    parser.add_option('--email',
+                      action='store',
+                      dest='email',
+                      default=None,
+                      help='Admin Email')
+    parser.add_option('--password',
+                      action='store',
+                      dest='password',
+                      default=None,
+                      help='Admin password min 6 chars')
+    parser.add_option('--repos',
+                      action='store',
+                      dest='repos_location',
+                      default=None,
+                      help='Absolute path to repositories location')
+    parser.add_option('--name',
+                      action='store',
+                      dest='section_name',
+                      default=None,
+                      help='The name of the section to set up (default: app:main)')
+    parser.add_option('--force-yes',
+                       action='store_true',
+                       dest='force_ask',
+                       default=None,
+                       help='Force yes to every question')
+    parser.add_option('--force-no',
+                       action='store_false',
+                       dest='force_ask',
+                       default=None,
+                       help='Force no to every question')
+
+    def command(self):
+        config_spec = self.args[0]
+        section = self.options.section_name
+        if section is None:
+            if '#' in config_spec:
+                config_spec, section = config_spec.split('#', 1)
+            else:
+                section = 'main'
+        if not ':' in section:
+            plain_section = section
+            section = 'app:' + section
+        else:
+            plain_section = section.split(':', 1)[0]
+        if not config_spec.startswith('config:'):
+            config_spec = 'config:' + config_spec
+        if plain_section != 'main':
+            config_spec += '#' + plain_section
+        config_file = config_spec[len('config:'):].split('#', 1)[0]
+        config_file = os.path.join(os.getcwd(), config_file)
+        self.logging_file_config(config_file)
+        conf = appconfig(config_spec, relative_to=os.getcwd())
+        ep_name = conf.context.entry_point_name
+        ep_group = conf.context.protocol
+        dist = conf.context.distribution
+        if dist is None:
+            raise BadCommand(
+                "The section %r is not the application (probably a filter).  "
+                "You should add #section_name, where section_name is the "
+                "section that configures your application" % plain_section)
+        installer = self.get_installer(dist, ep_group, ep_name)
+        installer.setup_config(
+            self, config_file, section, self.sysconfig_install_vars(installer))
+        self.call_sysconfig_functions(
+            'post_setup_hook', installer, config_file)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/paster_commands/update_repoinfo.py	Sat Feb 09 22:21:31 2013 +0100
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.paster_commands.make_rcextensions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    uodate-repoinfo paster command for RhodeCode
+
+    :created_on: Jul 14, 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/>.
+from __future__ import with_statement
+
+import os
+import sys
+import logging
+import string
+
+from os.path import dirname as dn, join as jn
+#to get the rhodecode import
+rc_path = dn(dn(dn(os.path.realpath(__file__))))
+sys.path.append(rc_path)
+from rhodecode.lib.utils import BasePasterCommand
+
+from rhodecode.model.db import Repository
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.meta import Session
+
+log = logging.getLogger(__name__)
+
+
+class Command(BasePasterCommand):
+
+    max_args = 1
+    min_args = 1
+
+    usage = "CONFIG_FILE"
+    group_name = "RhodeCode"
+    takes_config_file = -1
+    parser = BasePasterCommand.standard_parser(verbose=True)
+    summary = "Updates repositories caches for last changeset"
+
+    def command(self):
+        #get SqlAlchemy session
+        self._init_session()
+
+        repo_update_list = map(string.strip,
+                               self.options.repo_update_list.split(',')) \
+                               if self.options.repo_update_list else None
+
+        if repo_update_list:
+            repo_list = Repository.query()\
+                .filter(Repository.repo_name.in_(repo_update_list))
+        else:
+            repo_list = Repository.getAll()
+        RepoModel.update_repoinfo(repositories=repo_list)
+        Session().commit()
+        log.info('Updated cache for %s repositories' % (len(repo_list)))
+
+    def update_parser(self):
+        self.parser.add_option('--update-only',
+                          action='store',
+                          dest='repo_update_list',
+                          help="Specifies a comma separated list of repositores "
+                                "to update last commit info for. OPTIONAL",
+                          )
--- a/rhodecode/lib/update_repoinfo.py	Sat Feb 09 19:45:10 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    package.rhodecode.lib.cleanup
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    :created_on: Jul 14, 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/>.
-from __future__ import with_statement
-
-import os
-import sys
-import re
-import shutil
-import logging
-import datetime
-import string
-
-from os.path import dirname as dn, join as jn
-from rhodecode.model import init_model
-from rhodecode.lib.utils2 import engine_from_config
-from rhodecode.model.db import Repository
-from rhodecode.model.repo import RepoModel
-from rhodecode.model.meta import Session
-
-
-#to get the rhodecode import
-sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
-
-from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
-
-log = logging.getLogger(__name__)
-
-
-class UpdateCommand(BasePasterCommand):
-
-    max_args = 1
-    min_args = 1
-
-    usage = "CONFIG_FILE"
-    summary = "Updates repositories caches for last changeset"
-    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
-
-        #get to remove repos !!
-        add_cache(config)
-        engine = engine_from_config(config, 'sqlalchemy.db1.')
-        init_model(engine)
-
-        repo_update_list = map(string.strip,
-                               self.options.repo_update_list.split(',')) \
-                               if self.options.repo_update_list else None
-
-        if repo_update_list:
-            repo_list = Repository.query()\
-                .filter(Repository.repo_name.in_(repo_update_list))
-        else:
-            repo_list = Repository.getAll()
-        RepoModel.update_repoinfo(repositories=repo_list)
-        Session().commit()
-
-    def update_parser(self):
-        self.parser.add_option('--update-only',
-                          action='store',
-                          dest='repo_update_list',
-                          help="Specifies a comma separated list of repositores "
-                                "to update last commit info for. OPTIONAL",
-                          )
--- a/rhodecode/lib/utils.py	Sat Feb 09 19:45:10 2013 +0100
+++ b/rhodecode/lib/utils.py	Sat Feb 09 22:21:31 2013 +0100
@@ -704,6 +704,20 @@
         conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
         pylonsconfig.init_app(conf.global_conf, conf.local_conf)
 
+    def _init_session(self):
+        """
+        Inits SqlAlchemy Session
+        """
+        logging.config.fileConfig(self.path_to_ini_file)
+        from pylons import config
+        from rhodecode.model import init_model
+        from rhodecode.lib.utils2 import engine_from_config
+
+        #get to remove repos !!
+        add_cache(config)
+        engine = engine_from_config(config, 'sqlalchemy.db1.')
+        init_model(engine)
+
 
 def check_git_version():
     """
--- a/setup.py	Sat Feb 09 19:45:10 2013 +0100
+++ b/setup.py	Sat Feb 09 22:21:31 2013 +0100
@@ -158,11 +158,12 @@
     main = pylons.util:PylonsInstaller
 
     [paste.global_paster_command]
-    setup-rhodecode=rhodecode.config.setup_rhodecode:SetupCommand
-    cleanup-repos=rhodecode.lib.cleanup:CleanupCommand
-    update-repoinfo=rhodecode.lib.update_repoinfo:UpdateCommand
+    setup-rhodecode=rhodecode.lib.paster_commands.setup_rhodecode:Command
+    cleanup-repos=rhodecode.lib.paster_commands.cleanup:Command
+    update-repoinfo=rhodecode.lib.paster_commands.update_repoinfo:Command
+    make-rcext=rhodecode.lib.paster_commands.make_rcextensions:Command
+    repo-scan=rhodecode.lib.paster_commands.repo_scan:Command
     make-index=rhodecode.lib.indexers:MakeIndex
-    make-rcext=rhodecode.config.rcextensions.make_rcextensions:MakeRcExt
     upgrade-db=rhodecode.lib.dbmigrate:UpgradeDb
     celeryd=rhodecode.lib.celerypylons.commands:CeleryDaemonCommand
     """,