Changeset - 45ee73bdfa03
kallithea/bin/kallithea_config.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 

	
 
# -*- coding: utf-8 -*-
 
# 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/>.
 
"""
 
kallithea.bin.kallithea_config
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
configuration generator for Kallithea
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Jun 18, 2013
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 

	
 
from __future__ import with_statement
 
import os
 
import sys
 
import uuid
 
import argparse
 
from mako.template import Template
 
TMPL = 'template.ini.mako'
 
here = os.path.dirname(os.path.abspath(__file__))
 

	
 
def argparser(argv):
 
    usage = (
 
      "kallithea-config [-h] [--filename=FILENAME] [--template=TEMPLATE] \n"
 
      "VARS optional specify extra template variable that will be available in "
 
      "template. Use comma separated key=val format eg.\n"
 
      "key1=val1,port=5000,host=127.0.0.1,elements='a\,b\,c'\n"
 
    )
 

	
 
    parser = argparse.ArgumentParser(
 
        description='Kallithea CONFIG generator with variable replacement',
kallithea/bin/rebranddb.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 

	
 
# 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/>.
 
"""
 
Script for rebranding of database to and from what Kallithea expects
 

	
 
Works on databases from v1.7.2 to v2.2.5
 
"""
 

	
 
import sys
 
from sqlalchemy import *
 
import sqlalchemy.orm
 
import sqlalchemy.ext.declarative
 
import migrate.changeset # a part of sqlalchemy-migrate which is available on pypi
 

	
 
def do_migrate(db, old, new):
 
    print 'Migrating %s from %s to %s' % (db, old or '?', new)
 
    metadata = MetaData()
 
    metadata.bind = create_engine(db)
 
    metadata.reflect()
 
    assert metadata.tables, 'Cannot reflect table names from db'
 

	
 
    if not old:
 
        assert 'db_migrate_version' in metadata.tables, 'Cannot reflect db_migrate_version from db'
 
        t = metadata.tables['db_migrate_version']
 
        l = t.select().where(t.c.repository_path == 'versions').execute().fetchall()
 
        assert len(l) == 1, 'Cannot find a single versions entry in db_migrate_version'
 
        assert l[0].repository_id.endswith('_db_migrations')
 
        old = l[0].repository_id[:-len('_db_migrations')]
 
        print 'Detected migration from old name %s' % old
 
        if new != old:
 
            assert not t.select().where(t.c.repository_id == new + '_db_migrations').execute().fetchall(), 'db_migrate_version has entries for both old and new name'
 

	
 
    def tablename(brand, s):
 
        return s if brand == 'kallithea' else (brand + '_' + s)
 
    new_ui_name = tablename(new, 'ui')
 
    old_ui_name = tablename(old, 'ui')
 
    new_settings_name = tablename(new, 'settings')
kallithea/config/post_receive_tmpl.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
import os
 
import sys
 

	
 
try:
 
    import kallithea
 
    KALLITHEA_HOOK_VER = '_TMPL_'
 
    os.environ['KALLITHEA_HOOK_VER'] = KALLITHEA_HOOK_VER
 
    from kallithea.lib.hooks import handle_git_post_receive as _handler
 
except ImportError:
 
    if os.environ.get('RC_DEBUG_GIT_HOOK'):
 
        import traceback
 
        print traceback.format_exc()
 
    kallithea = None
 

	
 

	
 
def main():
 
    if kallithea is None:
 
        # exit with success if we cannot import kallithea !!
 
        # this allows simply push to this repo even without
 
        # kallithea
 
        sys.exit(0)
 

	
 
    repo_path = os.path.abspath('.')
 
    push_data = sys.stdin.readlines()
 
    # os.environ is modified here by a subprocess call that
 
    # runs git and later git executes this hook.
 
    # Environ gets some additional info from kallithea system
 
    # like IP or username from basic-auth
 
    _handler(repo_path, push_data, os.environ)
 
    sys.exit(0)
 

	
 
if __name__ == '__main__':
 
    main()
kallithea/config/pre_receive_tmpl.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
import os
 
import sys
 

	
 
try:
 
    import kallithea
 
    KALLITHEA_HOOK_VER = '_TMPL_'
 
    os.environ['KALLITHEA_HOOK_VER'] = KALLITHEA_HOOK_VER
 
    from kallithea.lib.hooks import handle_git_pre_receive as _handler
 
except ImportError:
 
    if os.environ.get('RC_DEBUG_GIT_HOOK'):
 
        import traceback
 
        print traceback.format_exc()
 
    kallithea = None
 

	
 

	
 
def main():
 
    if kallithea is None:
 
        # exit with success if we cannot import kallithea !!
 
        # this allows simply push to this repo even without
 
        # kallithea
 
        sys.exit(0)
 

	
 
    repo_path = os.path.abspath('.')
 
    push_data = sys.stdin.readlines()
 
    # os.environ is modified here by a subprocess call that
 
    # runs git and later git executes this hook.
 
    # Environ gets some additional info from kallithea system
 
    # like IP or username from basic-auth
 
    _handler(repo_path, push_data, os.environ)
 
    sys.exit(0)
 

	
 
if __name__ == '__main__':
 
    main()
kallithea/lib/dbmigrate/migrate/versioning/config.py
Show inline comments
 
#!/usr/bin/python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 

	
 
from sqlalchemy.util import OrderedDict
 

	
 

	
 
__all__ = ['databases', 'operations']
 

	
 
databases = ('sqlite', 'postgres', 'mysql', 'oracle', 'mssql', 'firebird')
 

	
 
# Map operation names to function names
 
operations = OrderedDict()
 
operations['upgrade'] = 'upgrade'
 
operations['downgrade'] = 'downgrade'
kallithea/lib/dbmigrate/migrate/versioning/script/__init__.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 

	
 
from kallithea.lib.dbmigrate.migrate.versioning.script.base import BaseScript
 
from kallithea.lib.dbmigrate.migrate.versioning.script.py import PythonScript
 
from kallithea.lib.dbmigrate.migrate.versioning.script.sql import SqlScript
kallithea/lib/dbmigrate/migrate/versioning/script/base.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 
import logging
 

	
 
from kallithea.lib.dbmigrate.migrate import exceptions
 
from kallithea.lib.dbmigrate.migrate.versioning.config import operations
 
from kallithea.lib.dbmigrate.migrate.versioning import pathed
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class BaseScript(pathed.Pathed):
 
    """Base class for other types of scripts.
 
    All scripts have the following properties:
 

	
 
    source (script.source())
 
      The source code of the script
 
    version (script.version())
 
      The version number of the script
 
    operations (script.operations())
 
      The operations defined by the script: upgrade(), downgrade() or both.
 
      Returns a tuple of operations.
 
      Can also check for an operation with ex. script.operation(Script.ops.up)
 
    """ # TODO: sphinxfy this and implement it correctly
 

	
 
    def __init__(self, path):
 
        log.debug('Loading script %s...' % path)
 
        self.verify(path)
 
        super(BaseScript, self).__init__(path)
 
        log.debug('Script %s loaded successfully' % path)
 

	
 
    @classmethod
 
    def verify(cls, path):
 
        """Ensure this is a valid script
 
        This version simply ensures the script file's existence
 

	
 
        :raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>`
 
        """
 
        try:
 
            cls.require_found(path)
 
        except:
 
            raise exceptions.InvalidScriptError(path)
 

	
 
    def source(self):
 
        """:returns: source code of the script.
 
        :rtype: string
 
        """
 
        fd = open(self.path)
 
        ret = fd.read()
kallithea/lib/dbmigrate/migrate/versioning/script/py.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 

	
 
import shutil
 
import warnings
 
import logging
 
import inspect
 
from StringIO import StringIO
 

	
 
from kallithea.lib.dbmigrate import migrate
 
from kallithea.lib.dbmigrate.migrate.versioning import genmodel, schemadiff
 
from kallithea.lib.dbmigrate.migrate.versioning.config import operations
 
from kallithea.lib.dbmigrate.migrate.versioning.template import Template
 
from kallithea.lib.dbmigrate.migrate.versioning.script import base
 
from kallithea.lib.dbmigrate.migrate.versioning.util import import_path, load_model, with_engine
 
from kallithea.lib.dbmigrate.migrate.exceptions import MigrateDeprecationWarning, InvalidScriptError, ScriptError
 

	
 
log = logging.getLogger(__name__)
 
__all__ = ['PythonScript']
 

	
 

	
 
class PythonScript(base.BaseScript):
 
    """Base for Python scripts"""
 

	
 
    @classmethod
 
    def create(cls, path, **opts):
 
        """Create an empty migration script at specified path
 

	
 
        :returns: :class:`PythonScript instance <migrate.versioning.script.py.PythonScript>`"""
 
        cls.require_notfound(path)
 

	
 
        src = Template(opts.pop('templates_path', None)).get_script(theme=opts.pop('templates_theme', None))
 
        shutil.copy(src, path)
 

	
 
        return cls(path)
 

	
 
    @classmethod
 
    def make_update_script_for_model(cls, engine, oldmodel,
 
                                     model, repository, **opts):
 
        """Create a migration script based on difference between two SA models.
 

	
 
        :param repository: path to migrate repository
 
        :param oldmodel: dotted.module.name:SAClass or SAClass object
 
        :param model: dotted.module.name:SAClass or SAClass object
 
        :param engine: SQLAlchemy engine
 
        :type repository: string or :class:`Repository instance <migrate.versioning.repository.Repository>`
 
        :type oldmodel: string or Class
 
        :type model: string or Class
 
        :type engine: Engine instance
kallithea/lib/dbmigrate/migrate/versioning/script/sql.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 
import logging
 
import shutil
 

	
 
from kallithea.lib.dbmigrate.migrate.versioning.script import base
 
from kallithea.lib.dbmigrate.migrate.versioning.template import Template
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class SqlScript(base.BaseScript):
 
    """A file containing plain SQL statements."""
 

	
 
    @classmethod
 
    def create(cls, path, **opts):
 
        """Create an empty migration script at specified path
 

	
 
        :returns: :class:`SqlScript instance <migrate.versioning.script.sql.SqlScript>`"""
 
        cls.require_notfound(path)
 

	
 
        src = Template(opts.pop('templates_path', None)).get_sql_script(theme=opts.pop('templates_theme', None))
 
        shutil.copy(src, path)
 
        return cls(path)
 

	
 
    # TODO: why is step parameter even here?
 
    def run(self, engine, step=None, executemany=True):
 
        """Runs SQL script through raw dbapi execute call"""
 
        text = self.source()
 
        # Don't rely on SA's autocommit here
 
        # (SA uses .startswith to check if a commit is needed. What if script
 
        # starts with a comment?)
 
        conn = engine.connect()
 
        try:
 
            trans = conn.begin()
 
            try:
 
                # HACK: SQLite doesn't allow multiple statements through
 
                # its execute() method, but it provides executescript() instead
 
                dbapi = conn.engine.raw_connection()
 
                if executemany and getattr(dbapi, 'executescript', None):
 
                    dbapi.executescript(text)
 
                else:
 
                    conn.execute(text)
 
                trans.commit()
 
            except:
 
                trans.rollback()
 
                raise
 
        finally:
 
            conn.close()
kallithea/lib/dbmigrate/migrate/versioning/shell.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 

	
 
"""The migrate command-line tool."""
 

	
 
import sys
 
import inspect
 
import logging
 
from optparse import OptionParser, BadOptionError
 

	
 
from kallithea.lib.dbmigrate.migrate import exceptions
 
from kallithea.lib.dbmigrate.migrate.versioning import api
 
from kallithea.lib.dbmigrate.migrate.versioning.config import *
 
from kallithea.lib.dbmigrate.migrate.versioning.util import asbool
 

	
 

	
 
alias = dict(
 
    s=api.script,
 
    vc=api.version_control,
 
    dbv=api.db_version,
 
    v=api.version,
 
)
 

	
 
def alias_setup():
 
    global alias
 
    for key, val in alias.iteritems():
 
        setattr(api, key, val)
 
alias_setup()
 

	
 

	
 
class PassiveOptionParser(OptionParser):
 

	
 
    def _process_args(self, largs, rargs, values):
 
        """little hack to support all --some_option=value parameters"""
 

	
 
        while rargs:
 
            arg = rargs[0]
 
            if arg == "--":
 
                del rargs[0]
 
                return
 
            elif arg[0:2] == "--":
 
                # if parser does not know about the option
 
                # pass it along (make it anonymous)
 
                try:
 
                    opt = arg.split('=', 1)[0]
 
                    self._match_long_opt(opt)
 
                except BadOptionError:
 
                    largs.append(arg)
 
                    del rargs[0]
kallithea/lib/dbmigrate/migrate/versioning/template.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 

	
 
import os
 
import shutil
 
import sys
 

	
 
from pkg_resources import resource_filename
 

	
 
from kallithea.lib.dbmigrate.migrate.versioning.config import *
 
from kallithea.lib.dbmigrate.migrate.versioning import pathed
 

	
 

	
 
class Collection(pathed.Pathed):
 
    """A collection of templates of a specific type"""
 
    _mask = None
 

	
 
    def get_path(self, file):
 
        return os.path.join(self.path, str(file))
 

	
 

	
 
class RepositoryCollection(Collection):
 
    _mask = '%s'
 

	
 
class ScriptCollection(Collection):
 
    _mask = '%s.py_tmpl'
 

	
 
class ManageCollection(Collection):
 
    _mask = '%s.py_tmpl'
 

	
 
class SQLScriptCollection(Collection):
 
    _mask = '%s.py_tmpl'
 

	
 
class Template(pathed.Pathed):
 
    """Finds the paths/packages of various Migrate templates.
 

	
 
    :param path: Templates are loaded from kallithea.lib.dbmigrate.migrate package
 
    if `path` is not provided.
 
    """
 
    pkg = 'kallithea.lib.dbmigrate.migrate.versioning.templates'
 
    _manage = 'manage.py_tmpl'
 

	
 
    def __new__(cls, path=None):
 
        if path is None:
 
            path = cls._find_path(cls.pkg)
 
        return super(Template, cls).__new__(cls, path)
 

	
 
    def __init__(self, path=None):
 
        if path is None:
kallithea/lib/dbmigrate/migrate/versioning/templates/manage.py_tmpl
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
from migrate.versioning.shell import main
 

	
 
if __name__ == '__main__':
 
    main(%(defaults)s)
kallithea/lib/dbmigrate/migrate/versioning/templates/manage/default.py_tmpl
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
from migrate.versioning.shell import main
 

	
 
{{py:
 
_vars = locals().copy()
 
del _vars['__template_name__']
 
_vars.pop('repository_name', None)
 
defaults = ", ".join(["%s='%s'" % var for var in _vars.iteritems()])
 
}}
 

	
 
if __name__ == '__main__':
 
    main({{ defaults }})
kallithea/lib/dbmigrate/migrate/versioning/templates/manage/pylons.py_tmpl
Show inline comments
 
#!/usr/bin/python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 
import sys
 

	
 
from sqlalchemy import engine_from_config
 
from paste.deploy.loadwsgi import ConfigLoader
 

	
 
from migrate.versioning.shell import main
 
from {{ locals().pop('repository_name') }}.model import migrations
 

	
 

	
 
if '-c' in sys.argv:
 
    pos = sys.argv.index('-c')
 
    conf_path = sys.argv[pos + 1]
 
    del sys.argv[pos:pos + 2]
 
else:
 
    conf_path = 'development.ini'
 

	
 
{{py:
 
_vars = locals().copy()
 
del _vars['__template_name__']
 
defaults = ", ".join(["%s='%s'" % var for var in _vars.iteritems()])
 
}}
 

	
 
conf_dict = ConfigLoader(conf_path).parser._sections['app:main']
 

	
 
# migrate supports passing url as an existing Engine instance (since 0.6.0)
 
# usage: migrate -c path/to/config.ini COMMANDS
 
if __name__ == '__main__':
 
    main(url=engine_from_config(conf_dict), repository=migrations.__path__[0],{{ defaults }})
kallithea/lib/dbmigrate/migrate/versioning/util/__init__.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 
""".. currentmodule:: migrate.versioning.util"""
 

	
 
import warnings
 
import logging
 
from decorator import decorator
 
from pkg_resources import EntryPoint
 

	
 
from sqlalchemy import create_engine
 
from sqlalchemy.engine import Engine
 
from sqlalchemy.pool import StaticPool
 

	
 
from kallithea.lib.dbmigrate.migrate import exceptions
 
from kallithea.lib.dbmigrate.migrate.versioning.util.keyedinstance import KeyedInstance
 
from kallithea.lib.dbmigrate.migrate.versioning.util.importpath import import_path
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
def load_model(dotted_name):
 
    """Import module and use module-level variable".
 

	
 
    :param dotted_name: path to model in form of string: ``some.python.module:Class``
 

	
 
    .. versionchanged:: 0.5.4
 

	
 
    """
 
    if isinstance(dotted_name, basestring):
 
        if ':' not in dotted_name:
 
            # backwards compatibility
 
            warnings.warn('model should be in form of module.model:User '
 
                'and not module.model.User', exceptions.MigrateDeprecationWarning)
 
            dotted_name = ':'.join(dotted_name.rsplit('.', 1))
 
        return EntryPoint.parse('x=%s' % dotted_name).load(False)
 
    else:
 
        # Assume it's already loaded.
 
        return dotted_name
 

	
 
def asbool(obj):
 
    """Do everything to use object as bool"""
 
    if isinstance(obj, basestring):
 
        obj = obj.strip().lower()
 
        if obj in ['true', 'yes', 'on', 'y', 't', '1']:
 
            return True
 
        elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
 
            return False
 
        else:
 
            raise ValueError("String is not true/false: %r" % obj)
kallithea/lib/dbmigrate/migrate/versioning/util/keyedinstance.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 

	
 
class KeyedInstance(object):
 
    """A class whose instances have a unique identifier of some sort
 
    No two instances with the same unique ID should exist - if we try to create
 
    a second instance, the first should be returned.
 
    """
 

	
 
    _instances = dict()
 

	
 
    def __new__(cls, *p, **k):
 
        instances = cls._instances
 
        clskey = str(cls)
 
        if clskey not in instances:
 
            instances[clskey] = dict()
 
        instances = instances[clskey]
 

	
 
        key = cls._key(*p, **k)
 
        if key not in instances:
 
            instances[key] = super(KeyedInstance, cls).__new__(cls)
 
        return instances[key]
 

	
 
    @classmethod
 
    def _key(cls, *p, **k):
 
        """Given a unique identifier, return a dictionary key
 
        This should be overridden by child classes, to specify which parameters
 
        should determine an object's uniqueness
 
        """
 
        raise NotImplementedError()
 

	
 
    @classmethod
 
    def clear(cls):
 
        # Allow cls.clear() as well as uniqueInstance.clear(cls)
 
        if str(cls) in cls._instances:
 
            del cls._instances[str(cls)]
kallithea/lib/dbmigrate/migrate/versioning/version.py
Show inline comments
 
#!/usr/bin/env python
 
#!/usr/bin/env python2
 
# -*- coding: utf-8 -*-
 

	
 
import os
 
import re
 
import shutil
 
import logging
 

	
 
from kallithea.lib.dbmigrate.migrate import exceptions
 
from kallithea.lib.dbmigrate.migrate.versioning import pathed, script
 
from datetime import datetime
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class VerNum(object):
 
    """A version number that behaves like a string and int at the same time"""
 

	
 
    _instances = dict()
 

	
 
    def __new__(cls, value):
 
        val = str(value)
 
        if val not in cls._instances:
 
            cls._instances[val] = super(VerNum, cls).__new__(cls)
 
        ret = cls._instances[val]
 
        return ret
 

	
 
    def __init__(self,value):
 
        self.value = str(int(value))
 
        if self < 0:
 
            raise ValueError("Version number cannot be negative")
 

	
 
    def __add__(self, value):
 
        ret = int(self) + int(value)
 
        return VerNum(ret)
 

	
 
    def __sub__(self, value):
 
        return self + (int(value) * -1)
 

	
 
    def __cmp__(self, value):
 
        return int(self) - int(value)
 

	
 
    def __repr__(self):
 
        return "<VerNum(%s)>" % self.value
 

	
 
    def __str__(self):
 
        return str(self.value)
 

	
 
    def __int__(self):
0 comments (0 inline, 0 general)