Changeset - 08d2dcd71666
[Not reviewed]
beta
0 28 1
Marcin Kuzminski - 15 years ago 2010-12-11 02:50:23
marcin@python-works.com
fixed imports on migrate, added getting current version from database
29 files changed with 148 insertions and 107 deletions:
0 comments (0 inline, 0 general)
rhodecode/lib/db_manage.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# database management for RhodeCode
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
#
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.db_manage
 
    ~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Database creation, and setup module for RhodeCode
 
    
 
    :created_on: Apr 10, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2010 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; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
"""
 
Created on April 10, 2010
 
database management and creation for RhodeCode
 
@author: marcink
 
"""
 

	
 
from os.path import dirname as dn, join as jn
 
import os
 
import sys
 
import uuid
 
import logging
 
from os.path import dirname as dn, join as jn
 

	
 
from rhodecode import __dbversion__
 
from rhodecode.model.db import
 
from rhodecode.model import meta
 

	
 
from rhodecode.lib.auth import get_crypt_password
 
from rhodecode.lib.utils import ask_ok
 
from rhodecode.model import init_model
 
from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
 
    UserToPerm
 
from rhodecode.model import meta
 
    UserToPerm, DbMigrateVersion
 

	
 
from sqlalchemy.engine import create_engine
 
import logging
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class DbManage(object):
 
    def __init__(self, log_sql, dbconf, root, tests=False):
 
        self.dbname = dbconf.split('/')[-1]
 
        self.tests = tests
 
        self.root = root
 
        self.dburi = dbconf
 
        engine = create_engine(self.dburi, echo=log_sql)
 
        init_model(engine)
 
        self.sa = meta.Session()
 
@@ -74,26 +80,24 @@ class DbManage(object):
 
                destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
 
            if not destroy:
 
                sys.exit()
 
            if self.db_exists and destroy:
 
                os.remove(jn(self.root, self.dbname))
 
        checkfirst = not override
 
        meta.Base.metadata.create_all(checkfirst=checkfirst)
 
        log.info('Created tables for %s', self.dbname)
 

	
 

	
 

	
 
    def set_db_version(self):
 
        from rhodecode import __dbversion__
 
        from rhodecode.model.db import DbMigrateVersion
 
        try:
 
            ver = DbMigrateVersion()
 
            ver.version = __dbversion__
 
            ver.repository_id = 'rhodecode_db_migrations'
 
            ver.repository_path = 'versions'
 
            self.sa.add(ver)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 
        log.info('db version set to: %s', __dbversion__)
 

	
rhodecode/lib/dbmigrate/__init__.py
Show inline comments
 
@@ -16,44 +16,62 @@
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
from rhodecode.lib.utils import BasePasterCommand
 
import logging
 
from sqlalchemy import engine_from_config
 

	
 
from rhodecode.lib.dbmigrate.migrate.exceptions import \
 
    DatabaseNotControlledError
 
from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
 

	
 
from sqlalchemy import engine_from_config
 
log = logging.getLogger(__name__)
 

	
 
class UpgradeDb(BasePasterCommand):
 
    """Command used for paster to upgrade our database to newer version
 
    """
 

	
 
    max_args = 1
 
    min_args = 1
 

	
 
    usage = "CONFIG_FILE"
 
    summary = "Upgrades current db to newer version given configuration file"
 
    group_name = "RhodeCode"
 

	
 
    parser = Command.standard_parser(verbose=True)
 

	
 
    def command(self):
 
        from pylons import config
 
        add_cache(config)
 
        engine = engine_from_config(config, 'sqlalchemy.db1.')
 
        print engine
 
        raise NotImplementedError('Not implemented yet')
 
        #engine = engine_from_config(config, 'sqlalchemy.db1.')
 
        #rint engine
 

	
 
        from rhodecode.lib.dbmigrate.migrate.versioning import api
 
        path = 'rhodecode/lib/dbmigrate'
 

	
 

	
 
        try:
 
            curr_version = api.db_version(config['sqlalchemy.db1.url'], path)
 
            msg = ('Found current database under version'
 
                 ' control with version %s' % curr_version)
 

	
 
        except (RuntimeError, DatabaseNotControlledError), e:
 
            curr_version = 0
 
            msg = ('Current database is not under version control setting'
 
                   ' as version %s' % curr_version)
 

	
 
        print msg
 

	
 
    def update_parser(self):
 
        self.parser.add_option('--sql',
 
                      action='store_true',
 
                      dest='just_sql',
 
                      help="Prints upgrade sql for further investigation",
 
                      default=False)
rhodecode/lib/dbmigrate/migrate.cfg
Show inline comments
 
new file 100644
 
[db_settings]
 
# Used to identify which repository this database is versioned under.
 
# You can use the name of your project.
 
repository_id=rhodecode_db_migrations
 

	
 
# The name of the database table used to track the schema version.
 
# This name shouldn't already be used by your project.
 
# If this is changed once a database is under version control, you'll need to 
 
# change the table name in each database too. 
 
version_table=db_migrate_version
 

	
 
# When committing a change script, Migrate will attempt to generate the 
 
# sql for all supported databases; normally, if one of them fails - probably
 
# because you don't have that database installed - it is ignored and the 
 
# commit continues, perhaps ending successfully. 
 
# Databases in this list MUST compile successfully during a commit, or the 
 
# entire commit will fail. List the databases your application will actually 
 
# be using to ensure your updates to that database work properly.
 
# This must be a list; example: ['postgres','sqlite']
 
required_dbs=['sqlite']
rhodecode/lib/dbmigrate/migrate/__init__.py
Show inline comments
 
"""
 
   SQLAlchemy migrate provides two APIs :mod:`migrate.versioning` for
 
   database schema version and repository management and
 
   :mod:`migrate.changeset` that allows to define database schema changes
 
   using Python.
 
"""
 

	
 
from migrate.versioning import *
 
from migrate.changeset import *
 
from rhodecode.lib.dbmigrate.migrate.versioning import *
 
from rhodecode.lib.dbmigrate.migrate.changeset import *
rhodecode/lib/dbmigrate/migrate/changeset/__init__.py
Show inline comments
 
@@ -9,20 +9,20 @@ import warnings
 

	
 
import sqlalchemy
 
from sqlalchemy import __version__ as _sa_version
 

	
 
warnings.simplefilter('always', DeprecationWarning)
 

	
 
_sa_version = tuple(int(re.match("\d+", x).group(0)) for x in _sa_version.split("."))
 
SQLA_06 = _sa_version >= (0, 6)
 

	
 
del re
 
del _sa_version
 

	
 
from migrate.changeset.schema import *
 
from migrate.changeset.constraint import *
 
from rhodecode.lib.dbmigrate.migrate.changeset.schema import *
 
from rhodecode.lib.dbmigrate.migrate.changeset.constraint import *
 

	
 
sqlalchemy.schema.Table.__bases__ += (ChangesetTable, )
 
sqlalchemy.schema.Column.__bases__ += (ChangesetColumn, )
 
sqlalchemy.schema.Index.__bases__ += (ChangesetIndex, )
 

	
 
sqlalchemy.schema.DefaultClause.__bases__ += (ChangesetDefaultClause, )
rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py
Show inline comments
 
@@ -7,26 +7,26 @@
 
import StringIO
 

	
 
import sqlalchemy as sa
 
from sqlalchemy.schema import SchemaVisitor
 
from sqlalchemy.engine.default import DefaultDialect
 
from sqlalchemy.sql import ClauseElement
 
from sqlalchemy.schema import (ForeignKeyConstraint,
 
                               PrimaryKeyConstraint,
 
                               CheckConstraint,
 
                               UniqueConstraint,
 
                               Index)
 

	
 
from migrate import exceptions
 
from migrate.changeset import constraint, SQLA_06
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.changeset import constraint, SQLA_06
 

	
 
if not SQLA_06:
 
    from sqlalchemy.sql.compiler import SchemaGenerator, SchemaDropper
 
else:
 
    from sqlalchemy.schema import AddConstraint, DropConstraint
 
    from sqlalchemy.sql.compiler import DDLCompiler
 
    SchemaGenerator = SchemaDropper = DDLCompiler
 

	
 

	
 
class AlterTableVisitor(SchemaVisitor):
 
    """Common operations for ``ALTER TABLE`` statements."""
 

	
rhodecode/lib/dbmigrate/migrate/changeset/constraint.py
Show inline comments
 
"""
 
   This module defines standalone schema constraint classes.
 
"""
 
from sqlalchemy import schema
 

	
 
from migrate.exceptions import *
 
from migrate.changeset import SQLA_06
 
from rhodecode.lib.dbmigrate.migrate.exceptions import *
 
from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06
 

	
 
class ConstraintChangeset(object):
 
    """Base class for Constraint classes."""
 

	
 
    def _normalize_columns(self, cols, table_name=False):
 
        """Given: column objects or names; return col names and
 
        (maybe) a table"""
 
        colnames = []
 
        table = None
 
        for col in cols:
 
            if isinstance(col, schema.Column):
 
                if col.table is not None and table is None:
 
                    table = col.table
 
                if table_name:
 
                    col = '.'.join((col.table.name, col.name))
 
                else:
 
                    col = col.name
 
            colnames.append(col)
 
        return colnames, table
 

	
 
    def __do_imports(self, visitor_name, *a, **kw):
 
        engine = kw.pop('engine', self.table.bind)
 
        from migrate.changeset.databases.visitor import (get_engine_visitor,
 
        from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import (get_engine_visitor,
 
                                                         run_single_visitor)
 
        visitorcallable = get_engine_visitor(engine, visitor_name)
 
        run_single_visitor(engine, visitorcallable, self, *a, **kw)
 

	
 
    def create(self, *a, **kw):
 
        """Create the constraint in the database.
 

	
 
        :param engine: the database engine to use. If this is \
 
        :keyword:`None` the instance's engine will be used
 
        :type engine: :class:`sqlalchemy.engine.base.Engine`
 
        :param connection: reuse connection istead of creating new one.
 
        :type connection: :class:`sqlalchemy.engine.base.Connection` instance
rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py
Show inline comments
 
"""
 
   Firebird database specific implementations of changeset classes.
 
"""
 
from sqlalchemy.databases import firebird as sa_base
 

	
 
from migrate import exceptions
 
from migrate.changeset import ansisql, SQLA_06
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
 

	
 

	
 
if SQLA_06:
 
    FBSchemaGenerator = sa_base.FBDDLCompiler
 
else:
 
    FBSchemaGenerator = sa_base.FBSchemaGenerator
 

	
 
class FBColumnGenerator(FBSchemaGenerator, ansisql.ANSIColumnGenerator):
 
    """Firebird column generator implementation."""
 

	
 

	
 
class FBColumnDropper(ansisql.ANSIColumnDropper):
rhodecode/lib/dbmigrate/migrate/changeset/databases/mysql.py
Show inline comments
 
"""
 
   MySQL database specific implementations of changeset classes.
 
"""
 

	
 
from sqlalchemy.databases import mysql as sa_base
 
from sqlalchemy import types as sqltypes
 

	
 
from migrate import exceptions
 
from migrate.changeset import ansisql, SQLA_06
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
 

	
 

	
 
if not SQLA_06:
 
    MySQLSchemaGenerator = sa_base.MySQLSchemaGenerator
 
else:
 
    MySQLSchemaGenerator = sa_base.MySQLDDLCompiler
 

	
 
class MySQLColumnGenerator(MySQLSchemaGenerator, ansisql.ANSIColumnGenerator):
 
    pass
 

	
 

	
 
class MySQLColumnDropper(ansisql.ANSIColumnDropper):
rhodecode/lib/dbmigrate/migrate/changeset/databases/oracle.py
Show inline comments
 
"""
 
   Oracle database specific implementations of changeset classes.
 
"""
 
import sqlalchemy as sa
 
from sqlalchemy.databases import oracle as sa_base
 

	
 
from migrate import exceptions
 
from migrate.changeset import ansisql, SQLA_06
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
 

	
 

	
 
if not SQLA_06:
 
    OracleSchemaGenerator = sa_base.OracleSchemaGenerator
 
else:
 
    OracleSchemaGenerator = sa_base.OracleDDLCompiler
 

	
 

	
 
class OracleColumnGenerator(OracleSchemaGenerator, ansisql.ANSIColumnGenerator):
 
    pass
 

	
 

	
rhodecode/lib/dbmigrate/migrate/changeset/databases/postgres.py
Show inline comments
 
"""
 
   `PostgreSQL`_ database specific implementations of changeset classes.
 

	
 
   .. _`PostgreSQL`: http://www.postgresql.org/
 
"""
 
from migrate.changeset import ansisql, SQLA_06
 
from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
 

	
 
if not SQLA_06:
 
    from sqlalchemy.databases import postgres as sa_base
 
    PGSchemaGenerator = sa_base.PGSchemaGenerator
 
else:
 
    from sqlalchemy.databases import postgresql as sa_base
 
    PGSchemaGenerator = sa_base.PGDDLCompiler
 

	
 

	
 
class PGColumnGenerator(PGSchemaGenerator, ansisql.ANSIColumnGenerator):
 
    """PostgreSQL column generator implementation."""
 
    pass
rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py
Show inline comments
 
"""
 
   `SQLite`_ database specific implementations of changeset classes.
 

	
 
   .. _`SQLite`: http://www.sqlite.org/
 
"""
 
from UserDict import DictMixin
 
from copy import copy
 

	
 
from sqlalchemy.databases import sqlite as sa_base
 

	
 
from migrate import exceptions
 
from migrate.changeset import ansisql, SQLA_06
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
 

	
 

	
 
if not SQLA_06:
 
    SQLiteSchemaGenerator = sa_base.SQLiteSchemaGenerator
 
else:
 
    SQLiteSchemaGenerator = sa_base.SQLiteDDLCompiler
 

	
 
class SQLiteCommon(object):
 

	
 
    def _not_supported(self, op):
 
        raise exceptions.NotSupportedError("SQLite does not support "
 
            "%s; see http://www.sqlite.org/lang_altertable.html" % op)
rhodecode/lib/dbmigrate/migrate/changeset/databases/visitor.py
Show inline comments
 
"""
 
   Module for visitor class mapping.
 
"""
 
import sqlalchemy as sa
 

	
 
from migrate.changeset import ansisql
 
from migrate.changeset.databases import (sqlite,
 
from rhodecode.lib.dbmigrate.migrate.changeset import ansisql
 
from rhodecode.lib.dbmigrate.migrate.changeset.databases import (sqlite,
 
                                         postgres,
 
                                         mysql,
 
                                         oracle,
 
                                         firebird)
 

	
 

	
 
# Map SA dialects to the corresponding Migrate extensions
 
DIALECTS = {
 
    "default": ansisql.ANSIDialect,
 
    "sqlite": sqlite.SQLiteDialect,
 
    "postgres": postgres.PGDialect,
 
    "postgresql": postgres.PGDialect,
rhodecode/lib/dbmigrate/migrate/changeset/schema.py
Show inline comments
 
"""
 
   Schema module providing common schema operations.
 
"""
 
import warnings
 

	
 
from UserDict import DictMixin
 

	
 
import sqlalchemy
 

	
 
from sqlalchemy.schema import ForeignKeyConstraint
 
from sqlalchemy.schema import UniqueConstraint
 

	
 
from migrate.exceptions import *
 
from migrate.changeset import SQLA_06
 
from migrate.changeset.databases.visitor import (get_engine_visitor,
 
from rhodecode.lib.dbmigrate.migrate.exceptions import *
 
from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06
 
from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import (get_engine_visitor,
 
                                                 run_single_visitor)
 

	
 

	
 
__all__ = [
 
    'create_column',
 
    'drop_column',
 
    'alter_column',
 
    'rename_table',
 
    'rename_index',
 
    'ChangesetTable',
 
    'ChangesetColumn',
 
    'ChangesetIndex',
rhodecode/lib/dbmigrate/migrate/versioning/api.py
Show inline comments
 
@@ -20,28 +20,28 @@
 
#
 
# please do not comment this module using sphinx syntax because its
 
# docstrings are presented as user help and most users cannot
 
# interpret sphinx annotated ReStructuredText.
 
#
 
# Thanks,
 
# Jan Dittberner
 

	
 
import sys
 
import inspect
 
import logging
 

	
 
from migrate import exceptions
 
from migrate.versioning import (repository, schema, version,
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning import (repository, schema, version,
 
    script as script_) # command name conflict
 
from migrate.versioning.util import catch_known_errors, with_engine
 
from rhodecode.lib.dbmigrate.migrate.versioning.util import catch_known_errors, with_engine
 

	
 

	
 
log = logging.getLogger(__name__)
 
command_desc = {
 
    'help': 'displays help on a given command',
 
    'create': 'create an empty repository at the specified path',
 
    'script': 'create an empty change Python script',
 
    'script_sql': 'create empty change SQL scripts for given database',
 
    'version': 'display the latest version available in a repository',
 
    'db_version': 'show the current version of the repository under version control',
 
    'source': 'display the Python code for a particular version in this repository',
 
    'version_control': 'mark a database as under this repository\'s version control',
rhodecode/lib/dbmigrate/migrate/versioning/cfgparse.py
Show inline comments
 
"""
 
   Configuration parser module.
 
"""
 

	
 
from ConfigParser import ConfigParser
 

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

	
 

	
 
class Parser(ConfigParser):
 
    """A project configuration file."""
 

	
 
    def to_dict(self, sections=None):
 
        """It's easier to access config values like dictionaries"""
 
        return self._sections
 

	
 

	
 
class Config(pathed.Pathed, Parser):
 
    """Configuration class."""
rhodecode/lib/dbmigrate/migrate/versioning/genmodel.py
Show inline comments
 
@@ -2,27 +2,26 @@
 
   Code to generate a Python model from a database or differences
 
   between a model and database.
 

	
 
   Some of this is borrowed heavily from the AutoCode project at:
 
   http://code.google.com/p/sqlautocode/
 
"""
 

	
 
import sys
 
import logging
 

	
 
import sqlalchemy
 

	
 
import migrate
 
import migrate.changeset
 

	
 
from rhodecode.lib.dbmigrate import migrate
 
from rhodecode.lib.dbmigrate.migrate import changeset
 

	
 
log = logging.getLogger(__name__)
 
HEADER = """
 
## File autogenerated by genmodel.py
 

	
 
from sqlalchemy import *
 
meta = MetaData()
 
"""
 

	
 
DECLARATIVE_HEADER = """
 
## File autogenerated by genmodel.py
 

	
 
@@ -103,54 +102,54 @@ class ModelGenerator(object):
 
            out.append("class %(table)s(Base):" % {'table': tableName})
 
            out.append("  __tablename__ = '%(table)s'" % {'table': tableName})
 
            for col in table.columns:
 
                out.append("  %s" % self.column_repr(col))
 
        else:
 
            out.append("%(table)s = Table('%(table)s', meta," % \
 
                           {'table': tableName})
 
            for col in table.columns:
 
                out.append("  %s," % self.column_repr(col))
 
            out.append(")")
 
        return out
 

	
 
    def _get_tables(self,missingA=False,missingB=False,modified=False):
 
    def _get_tables(self, missingA=False, missingB=False, modified=False):
 
        to_process = []
 
        for bool_,names,metadata in (
 
            (missingA,self.diff.tables_missing_from_A,self.diff.metadataB),
 
            (missingB,self.diff.tables_missing_from_B,self.diff.metadataA),
 
            (modified,self.diff.tables_different,self.diff.metadataA),
 
        for bool_, names, metadata in (
 
            (missingA, self.diff.tables_missing_from_A, self.diff.metadataB),
 
            (missingB, self.diff.tables_missing_from_B, self.diff.metadataA),
 
            (modified, self.diff.tables_different, self.diff.metadataA),
 
                ):
 
            if bool_:
 
                for name in names:
 
                    yield metadata.tables.get(name)
 
        
 

	
 
    def toPython(self):
 
        """Assume database is current and model is empty."""
 
        out = []
 
        if self.declarative:
 
            out.append(DECLARATIVE_HEADER)
 
        else:
 
            out.append(HEADER)
 
        out.append("")
 
        for table in self._get_tables(missingA=True):
 
            out.extend(self.getTableDefn(table))
 
            out.append("")
 
        return '\n'.join(out)
 

	
 
    def toUpgradeDowngradePython(self, indent='    '):
 
        ''' Assume model is most current and database is out-of-date. '''
 
        decls = ['from migrate.changeset import schema',
 
        decls = ['from rhodecode.lib.dbmigrate.migrate.changeset import schema',
 
                 'meta = MetaData()']
 
        for table in self._get_tables(
 
            missingA=True,missingB=True,modified=True
 
            missingA=True, missingB=True, modified=True
 
            ):
 
            decls.extend(self.getTableDefn(table))
 

	
 
        upgradeCommands, downgradeCommands = [], []
 
        for tableName in self.diff.tables_missing_from_A:
 
            upgradeCommands.append("%(table)s.drop()" % {'table': tableName})
 
            downgradeCommands.append("%(table)s.create()" % \
 
                                         {'table': tableName})
 
        for tableName in self.diff.tables_missing_from_B:
 
            upgradeCommands.append("%(table)s.create()" % {'table': tableName})
 
            downgradeCommands.append("%(table)s.drop()" % {'table': tableName})
 

	
 
@@ -173,25 +172,25 @@ class ModelGenerator(object):
 
                    'assert False, "Can\'t alter columns: %s:%s=>%s"',
 
                    modelTable, modelCol.name, databaseCol.name)
 
                downgradeCommands.append(
 
                    'assert False, "Can\'t alter columns: %s:%s=>%s"',
 
                    modelTable, modelCol.name, databaseCol.name)
 
        pre_command = '    meta.bind = migrate_engine'
 

	
 
        return (
 
            '\n'.join(decls),
 
            '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in upgradeCommands]),
 
            '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in downgradeCommands]))
 

	
 
    def _db_can_handle_this_change(self,td):
 
    def _db_can_handle_this_change(self, td):
 
        if (td.columns_missing_from_B
 
            and not td.columns_missing_from_A
 
            and not td.columns_different):
 
            # Even sqlite can handle this.
 
            return True
 
        else:
 
            return not self.engine.url.drivername.startswith('sqlite')
 

	
 
    def applyModel(self):
 
        """Apply model to current database."""
 

	
 
        meta = sqlalchemy.MetaData(self.engine)
 
@@ -199,27 +198,27 @@ class ModelGenerator(object):
 
        for table in self._get_tables(missingA=True):
 
            table = table.tometadata(meta)
 
            table.drop()
 
        for table in self._get_tables(missingB=True):
 
            table = table.tometadata(meta)
 
            table.create()
 
        for modelTable in self._get_tables(modified=True):
 
            tableName = modelTable.name
 
            modelTable = modelTable.tometadata(meta)
 
            dbTable = self.diff.metadataB.tables[tableName]
 

	
 
            td = self.diff.tables_different[tableName]
 
            
 

	
 
            if self._db_can_handle_this_change(td):
 
                
 

	
 
                for col in td.columns_missing_from_B:
 
                    modelTable.columns[col].create()
 
                for col in td.columns_missing_from_A:
 
                    dbTable.columns[col].drop()
 
                # XXX handle column changes here.
 
            else:
 
                # Sqlite doesn't support drop column, so you have to
 
                # do more: create temp table, copy data to it, drop
 
                # old table, create new table, copy data back.
 
                #
 
                # I wonder if this is guaranteed to be unique?
 
                tempName = '_temp_%s' % modelTable.name
rhodecode/lib/dbmigrate/migrate/versioning/pathed.py
Show inline comments
 
"""
 
   A path/directory class.
 
"""
 

	
 
import os
 
import shutil
 
import logging
 

	
 
from migrate import exceptions
 
from migrate.versioning.config import *
 
from migrate.versioning.util import KeyedInstance
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning.config import *
 
from rhodecode.lib.dbmigrate.migrate.versioning.util import KeyedInstance
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class Pathed(KeyedInstance):
 
    """
 
    A class associated with a path/directory tree.
 

	
 
    Only one instance of this class may exist for a particular file;
 
    __new__ will return an existing instance if possible
 
    """
 
    parent = None
rhodecode/lib/dbmigrate/migrate/versioning/repository.py
Show inline comments
 
"""
 
   SQLAlchemy migrate repository management.
 
"""
 
import os
 
import shutil
 
import string
 
import logging
 

	
 
from pkg_resources import resource_filename
 
from tempita import Template as TempitaTemplate
 

	
 
from migrate import exceptions
 
from migrate.versioning import version, pathed, cfgparse
 
from migrate.versioning.template import Template
 
from migrate.versioning.config import *
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning import version, pathed, cfgparse
 
from rhodecode.lib.dbmigrate.migrate.versioning.template import Template
 
from rhodecode.lib.dbmigrate.migrate.versioning.config import *
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class Changeset(dict):
 
    """A collection of changes to be applied to a database.
 

	
 
    Changesets are bound to a repository and manage a set of
 
    scripts from that repository.
 

	
 
    Behaves like a dict, for the most part. Keys are ordered based on step value.
 
    """
rhodecode/lib/dbmigrate/migrate/versioning/schema.py
Show inline comments
 
"""
 
   Database schema version management.
 
"""
 
import sys
 
import logging
 

	
 
from sqlalchemy import (Table, Column, MetaData, String, Text, Integer,
 
    create_engine)
 
from sqlalchemy.sql import and_
 
from sqlalchemy import exceptions as sa_exceptions
 
from sqlalchemy.sql import bindparam
 

	
 
from migrate import exceptions
 
from migrate.versioning import genmodel, schemadiff
 
from migrate.versioning.repository import Repository
 
from migrate.versioning.util import load_model
 
from migrate.versioning.version import VerNum
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning import genmodel, schemadiff
 
from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository
 
from rhodecode.lib.dbmigrate.migrate.versioning.util import load_model
 
from rhodecode.lib.dbmigrate.migrate.versioning.version import VerNum
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class ControlledSchema(object):
 
    """A database under version control"""
 

	
 
    def __init__(self, engine, repository):
 
        if isinstance(repository, basestring):
 
            repository = Repository(repository)
 
        self.engine = engine
 
        self.repository = repository
rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py
Show inline comments
 
"""
 
   Schema differencing support.
 
"""
 

	
 
import logging
 
import sqlalchemy
 

	
 
from migrate.changeset import SQLA_06
 
from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06
 
from sqlalchemy.types import Float
 

	
 
log = logging.getLogger(__name__)
 

	
 
def getDiffOfModelAgainstDatabase(metadata, engine, excludeTables=None):
 
    """
 
    Return differences of model against database.
 

	
 
    :return: object which will evaluate to :keyword:`True` if there \
 
      are differences else :keyword:`False`.
 
    """
 
    return SchemaDiff(metadata,
rhodecode/lib/dbmigrate/migrate/versioning/script/__init__.py
Show inline comments
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 

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

	
 
from migrate import exceptions
 
from migrate.versioning.config import operations
 
from migrate.versioning import pathed
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning.config import operations
 
from rhodecode.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
rhodecode/lib/dbmigrate/migrate/versioning/script/py.py
Show inline comments
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 

	
 
import shutil
 
import warnings
 
import logging
 
from StringIO import StringIO
 

	
 
import migrate
 
from migrate.versioning import genmodel, schemadiff
 
from migrate.versioning.config import operations
 
from migrate.versioning.template import Template
 
from migrate.versioning.script import base
 
from migrate.versioning.util import import_path, load_model, with_engine
 
from migrate.exceptions import MigrateDeprecationWarning, InvalidScriptError, ScriptError
 
from rhodecode.lib.dbmigrate import migrate
 
from rhodecode.lib.dbmigrate.migrate.versioning import genmodel, schemadiff
 
from rhodecode.lib.dbmigrate.migrate.versioning.config import operations
 
from rhodecode.lib.dbmigrate.migrate.versioning.template import Template
 
from rhodecode.lib.dbmigrate.migrate.versioning.script import base
 
from rhodecode.lib.dbmigrate.migrate.versioning.util import import_path, load_model, with_engine
 
from rhodecode.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
 
        
 
@@ -40,41 +40,41 @@ class PythonScript(base.BaseScript):
 
        
 
        :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
 
        :returns: Upgrade / Downgrade script
 
        :rtype: string
 
        """
 
        
 

	
 
        if isinstance(repository, basestring):
 
            # oh dear, an import cycle!
 
            from migrate.versioning.repository import Repository
 
            from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository
 
            repository = Repository(repository)
 

	
 
        oldmodel = load_model(oldmodel)
 
        model = load_model(model)
 

	
 
        # Compute differences.
 
        diff = schemadiff.getDiffOfModelAgainstModel(
 
            oldmodel,
 
            model,
 
            excludeTables=[repository.version_table])
 
        # TODO: diff can be False (there is no difference?)
 
        decls, upgradeCommands, downgradeCommands = \
 
            genmodel.ModelGenerator(diff,engine).toUpgradeDowngradePython()
 
            genmodel.ModelGenerator(diff, engine).toUpgradeDowngradePython()
 

	
 
        # Store differences into file.
 
        src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None))
 
        f = open(src)
 
        contents = f.read()
 
        f.close()
 

	
 
        # generate source
 
        search = 'def upgrade(migrate_engine):'
 
        contents = contents.replace(search, '\n\n'.join((decls, search)), 1)
 
        if upgradeCommands:
 
            contents = contents.replace('    pass', upgradeCommands, 1)
rhodecode/lib/dbmigrate/migrate/versioning/script/sql.py
Show inline comments
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
import logging
 
import shutil
 

	
 
from migrate.versioning.script import base
 
from migrate.versioning.template import Template
 
from rhodecode.lib.dbmigrate.migrate.versioning.script import base
 
from rhodecode.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>`"""
rhodecode/lib/dbmigrate/migrate/versioning/shell.py
Show inline comments
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 

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

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

	
 
from migrate import exceptions
 
from migrate.versioning import api
 
from migrate.versioning.config import *
 
from migrate.versioning.util import asbool
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning import api
 
from rhodecode.lib.dbmigrate.migrate.versioning.config import *
 
from rhodecode.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():
rhodecode/lib/dbmigrate/migrate/versioning/template.py
Show inline comments
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 

	
 
import os
 
import shutil
 
import sys
 

	
 
from pkg_resources import resource_filename
 

	
 
from migrate.versioning.config import *
 
from migrate.versioning import pathed
 
from rhodecode.lib.dbmigrate.migrate.versioning.config import *
 
from rhodecode.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'
 
@@ -25,25 +25,25 @@ class RepositoryCollection(Collection):
 
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 migrate package
 
    :param path: Templates are loaded from rhodecode.lib.dbmigrate.migrate package
 
    if `path` is not provided.
 
    """
 
    pkg = '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:
rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py
Show inline comments
 
@@ -2,27 +2,27 @@
 
# -*- 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 migrate import exceptions
 
from migrate.versioning.util.keyedinstance import KeyedInstance
 
from migrate.versioning.util.importpath import import_path
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning.util.keyedinstance import KeyedInstance
 
from rhodecode.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
 

	
 
    """
rhodecode/lib/dbmigrate/migrate/versioning/version.py
Show inline comments
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 

	
 
import os
 
import re
 
import shutil
 
import logging
 

	
 
from migrate import exceptions
 
from migrate.versioning import pathed, script
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning import pathed, script
 

	
 

	
 
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:
0 comments (0 inline, 0 general)