From 3d3f4e0391c785b32d1c10ff7b73bfcad1d550ed Mon Sep 17 00:00:00 2001 From: iElectric Date: Fri, 7 Aug 2009 12:58:04 +0200 Subject: [PATCH] we are using Tempita for templates; adding most basic pylons template --- docs/changelog.rst | 2 +- migrate/versioning/repository.py | 44 +++++++++++-------- migrate/versioning/templates/manage.py_tmpl | 4 -- .../templates/manage/default.py_tmpl | 10 +++++ .../templates/manage/pylons.py_tmpl | 29 ++++++++++++ .../templates/repository/default/migrate.cfg | 6 +-- .../templates/repository/pylons/README | 4 ++ .../repository/{ => pylons}/__init__.py | 0 .../templates/repository/pylons/migrate.cfg | 20 +++++++++ .../{default => pylons/versions}/__init__.py | 0 .../versioning/templates/script/__init__.py | 0 .../templates/script/pylons.py_tmpl | 11 +++++ setup.py | 2 +- test/versioning/test_cfgparse.py | 4 +- test/versioning/test_template.py | 1 + 15 files changed, 108 insertions(+), 29 deletions(-) delete mode 100644 migrate/versioning/templates/manage.py_tmpl create mode 100644 migrate/versioning/templates/manage/default.py_tmpl create mode 100644 migrate/versioning/templates/manage/pylons.py_tmpl create mode 100644 migrate/versioning/templates/repository/pylons/README rename migrate/versioning/templates/repository/{ => pylons}/__init__.py (100%) create mode 100644 migrate/versioning/templates/repository/pylons/migrate.cfg rename migrate/versioning/templates/repository/{default => pylons/versions}/__init__.py (100%) delete mode 100644 migrate/versioning/templates/script/__init__.py create mode 100644 migrate/versioning/templates/script/pylons.py_tmpl diff --git a/docs/changelog.rst b/docs/changelog.rst index 39acb8f..eb533a1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,7 +1,7 @@ 0.5.5 ----- -- added option to define custom templates through option ``--templates_path``, read more in :ref:`tutorial section ` +- added option to define custom templates through option ``--templates_path`` and ``--templates_theme``, read more in :ref:`tutorial section ` - url parameter can also be an Engine instance (this usage is discouraged though sometimes necessary) - added support for SQLAlchemy 0.6 (missing oracle and firebird) by Michael Bayer - alter, create, drop column / rename table / rename index constructs now accept `alter_metadata` parameter. If True, it will modify Column/Table objects according to changes. Otherwise, everything will be untouched. diff --git a/migrate/versioning/repository.py b/migrate/versioning/repository.py index 0938672..55768ef 100644 --- a/migrate/versioning/repository.py +++ b/migrate/versioning/repository.py @@ -6,6 +6,8 @@ import shutil import string from pkg_resources import resource_filename +from tempita import Template as TempitaTemplate + from migrate.versioning import exceptions, script, version, pathed, cfgparse from migrate.versioning.template import Template from migrate.versioning.base import * @@ -83,7 +85,7 @@ class Repository(pathed.Pathed): :raises: :exc:`InvalidRepositoryError ` """ - # Ensure the existance of required files + # Ensure the existence of required files try: cls.require_found(path) cls.require_found(os.path.join(path, cls._config)) @@ -92,7 +94,7 @@ class Repository(pathed.Pathed): raise exceptions.InvalidRepositoryError(path) @classmethod - def prepare_config(cls, tmpl_dir, config_file, name, **opts): + def prepare_config(cls, tmpl_dir, name, options=None): """ Prepare a project configuration file for a new project. @@ -104,37 +106,43 @@ class Repository(pathed.Pathed): :type name: string :returns: Populated config file """ - # Prepare opts - defaults = dict( - version_table = 'migrate_version', - repository_id = name, - required_dbs = []) + if options is None: + options = {} + options.setdefault('version_table', 'migrate_version') + options.setdefault('repository_id', name) + options.setdefault('required_dbs', []) - defaults.update(opts) + tmpl = open(os.path.join(tmpl_dir, cls._config)).read() + ret = TempitaTemplate(tmpl).substitute(options) + + # cleanup + del options['__template_name__'] - tmpl = open(os.path.join(tmpl_dir, config_file)).read() - ret = string.Template(tmpl).substitute(defaults) return ret @classmethod def create(cls, path, name, **opts): """Create a repository at a specified path""" cls.require_notfound(path) - theme = opts.get('templates_theme', None) + theme = opts.pop('templates_theme', None) + t_path = opts.pop('templates_path', None) # Create repository - tmpl_dir = Template(opts.pop('templates_path', None)).get_repository(theme=theme) - config_text = cls.prepare_config(tmpl_dir, cls._config, name, **opts) + tmpl_dir = Template(t_path).get_repository(theme=theme) shutil.copytree(tmpl_dir, path) # Edit config defaults + config_text = cls.prepare_config(tmpl_dir, name, options=opts) fd = open(os.path.join(path, cls._config), 'w') fd.write(config_text) fd.close() + opts['repository_name'] = name + # Create a management script manager = os.path.join(path, 'manage.py') - Repository.create_manage_file(manager, theme=theme, repository=path) + Repository.create_manage_file(manager, templates_theme=theme, + templates_path=t_path, **opts) return cls(path) @@ -208,12 +216,12 @@ class Repository(pathed.Pathed): """Create a project management script (manage.py) :param file_: Destination file to be written - :param opts: Options that are passed to template + :param opts: Options that are passed to :func:`migrate.versioning.shell.main` """ - mng_file = Template(opts.pop('templates_path', None)).get_manage(theme=opts.pop('templates_theme', None)) - vars_ = ",".join(["%s='%s'" % var for var in opts.iteritems()]) + mng_file = Template(opts.pop('templates_path', None))\ + .get_manage(theme=opts.pop('templates_theme', None)) tmpl = open(mng_file).read() fd = open(file_, 'w') - fd.write(tmpl % dict(defaults=vars_)) + fd.write(TempitaTemplate(tmpl).substitute(opts)) fd.close() diff --git a/migrate/versioning/templates/manage.py_tmpl b/migrate/versioning/templates/manage.py_tmpl deleted file mode 100644 index 93bcba2..0000000 --- a/migrate/versioning/templates/manage.py_tmpl +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python -from migrate.versioning.shell import main - -main(%(defaults)s) diff --git a/migrate/versioning/templates/manage/default.py_tmpl b/migrate/versioning/templates/manage/default.py_tmpl new file mode 100644 index 0000000..37c23bd --- /dev/null +++ b/migrate/versioning/templates/manage/default.py_tmpl @@ -0,0 +1,10 @@ +#!/usr/bin/env python +from migrate.versioning.shell import main + +{{py: +_vars = locals().copy() +del _vars['__template_name__'] +_vars.pop('repository_name') +defaults = ", ".join(["%s='%s'" % var for var in _vars.iteritems()]) +}} +main({{ defaults }}) diff --git a/migrate/versioning/templates/manage/pylons.py_tmpl b/migrate/versioning/templates/manage/pylons.py_tmpl new file mode 100644 index 0000000..475b8ce --- /dev/null +++ b/migrate/versioning/templates/manage/pylons.py_tmpl @@ -0,0 +1,29 @@ +#!/usr/bin/python +# -*- 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 +main(url=engine_from_config(conf_dict), repository=migrations.__path__[0],{{ defaults }}) diff --git a/migrate/versioning/templates/repository/default/migrate.cfg b/migrate/versioning/templates/repository/default/migrate.cfg index 4ad3bc5..1dc6ff6 100644 --- a/migrate/versioning/templates/repository/default/migrate.cfg +++ b/migrate/versioning/templates/repository/default/migrate.cfg @@ -1,13 +1,13 @@ [db_settings] # Used to identify which repository this database is versioned under. # You can use the name of your project. -repository_id=${repository_id} +repository_id={{ locals().pop('repository_id') }} # 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=${version_table} +version_table={{ locals().pop('version_table') }} # When committing a change script, Migrate will attempt to generate the # sql for all supported databases; normally, if one of them fails - probably @@ -17,4 +17,4 @@ version_table=${version_table} # 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=${required_dbs} +required_dbs={{ locals().pop('required_dbs') }} diff --git a/migrate/versioning/templates/repository/pylons/README b/migrate/versioning/templates/repository/pylons/README new file mode 100644 index 0000000..6218f8c --- /dev/null +++ b/migrate/versioning/templates/repository/pylons/README @@ -0,0 +1,4 @@ +This is a database migration repository. + +More information at +http://code.google.com/p/sqlalchemy-migrate/ diff --git a/migrate/versioning/templates/repository/__init__.py b/migrate/versioning/templates/repository/pylons/__init__.py similarity index 100% rename from migrate/versioning/templates/repository/__init__.py rename to migrate/versioning/templates/repository/pylons/__init__.py diff --git a/migrate/versioning/templates/repository/pylons/migrate.cfg b/migrate/versioning/templates/repository/pylons/migrate.cfg new file mode 100644 index 0000000..1dc6ff6 --- /dev/null +++ b/migrate/versioning/templates/repository/pylons/migrate.cfg @@ -0,0 +1,20 @@ +[db_settings] +# Used to identify which repository this database is versioned under. +# You can use the name of your project. +repository_id={{ locals().pop('repository_id') }} + +# 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={{ locals().pop('version_table') }} + +# 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={{ locals().pop('required_dbs') }} diff --git a/migrate/versioning/templates/repository/default/__init__.py b/migrate/versioning/templates/repository/pylons/versions/__init__.py similarity index 100% rename from migrate/versioning/templates/repository/default/__init__.py rename to migrate/versioning/templates/repository/pylons/versions/__init__.py diff --git a/migrate/versioning/templates/script/__init__.py b/migrate/versioning/templates/script/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/migrate/versioning/templates/script/pylons.py_tmpl b/migrate/versioning/templates/script/pylons.py_tmpl new file mode 100644 index 0000000..711899c --- /dev/null +++ b/migrate/versioning/templates/script/pylons.py_tmpl @@ -0,0 +1,11 @@ +from sqlalchemy import * +from migrate import * + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; bind migrate_engine + # to your metadata + pass + +def downgrade(migrate_engine): + # Operations to reverse the above upgrade go here. + pass diff --git a/setup.py b/setup.py index d3c5295..81414bf 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ except ImportError: pass test_requirements = ['nose >= 0.10'] -required_deps = ['sqlalchemy >= 0.5', 'decorator'] +required_deps = ['sqlalchemy >= 0.5', 'decorator', 'tempita'] readme_file = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'README')) setup( diff --git a/test/versioning/test_cfgparse.py b/test/versioning/test_cfgparse.py index 3cd0e56..e9ded6a 100644 --- a/test/versioning/test_cfgparse.py +++ b/test/versioning/test_cfgparse.py @@ -21,7 +21,7 @@ class TestConfigParser(fixture.Base): def test_table_config(self): """We should be able to specify the table to be used with a repository""" default_text = Repository.prepare_config(Template().get_repository(), - Repository._config, 'repository_name') + 'repository_name', {}) specified_text = Repository.prepare_config(Template().get_repository(), - Repository._config, 'repository_name', version_table='_other_table') + 'repository_name', {'version_table': '_other_table'}) self.assertNotEquals(default_text, specified_text) diff --git a/test/versioning/test_template.py b/test/versioning/test_template.py index d0c75a9..90abe36 100644 --- a/test/versioning/test_template.py +++ b/test/versioning/test_template.py @@ -59,5 +59,6 @@ class TestTemplate(fixture.Pathed): # assert changes self.assertEqual(open(new_manage_dest).read(), MANAGE_CONTENTS) + self.assertEqual(open(os.path.join(new_repo_dest, 'manage.py')).read(), MANAGE_CONTENTS) self.assertEqual(open(os.path.join(new_repo_dest, 'README')).read(), README_CONTENTS) self.assertEqual(open(os.path.join(new_repo_dest, 'versions/001_test.py')).read(), SCRIPT_FILE_CONTENTS)