Zine

open source content publishing system


Changeset 1328:6cc7867ababe


Ignore:
Timestamp:
01/10/10 17:25:18 (2 years ago)
Author:
Georg Brandl <georg@…>
Branch:
default
Message:

Update command-line migrations interface. In particular, downgrades only make sense for one repo at the same time. Also add a "list" command to list all repos.

Files:
6 edited

Legend:

Unmodified
Added
Removed
  • external-plugins/eric_the_fish/__init__.py

    r1327 r1328  
    130130    """ 
    131131 
    132     # we need to register eric's database upgrades repository; 
    133     # Basically it should be a folder which itself has another child folder 
    134     # named "versions" where the upgrade script(s) should reside. 
    135     # In "Eric the fish" case we pass the plugin's folder which has that child 
    136     # folder called "versions" 
     132    # since this plugin also shows how to do data migration, we need to register 
     133    # eric's database upgrades repository.  Basically it should be a directory 
     134    # which itself has a subdirectory named "versions" where the upgrade 
     135    # script(s) reside.  In Eric's case we pass the plugin's directory which has 
     136    # that subdirectory called "versions". 
    137137    app.register_upgrade_repository(plugin, dirname(__file__)) 
    138138 
  • scripts/manage-database

    r1327 r1328  
    1010    :license: BSD, see LICENSE for more details. 
    1111""" 
     12# for now 
     13import warnings 
     14warnings.filterwarnings('ignore') 
    1215 
    1316import sys 
  • zine/application.py

    r1327 r1328  
    1818from inspect import getdoc 
    1919from traceback import format_exception 
    20 from pprint import pprint 
    2120from StringIO import StringIO 
    2221 
     
    834833            self.list_parsers() 
    835834 
    836         # Register Zine's upgrade repository 
     835        # register Zine's upgrade repository 
    837836        from zine.upgrades import REPOSITORY_PATH 
    838837        self.register_upgrade_repository('Zine', REPOSITORY_PATH) 
    839         # Allow plugins to register their upgrade's repositories 
     838        # allow plugins to register their upgrade repositories 
    840839        emit_event('register-upgrade-repository') 
    841840 
     
    861860                db.session.commit() 
    862861        except (SQLAlchemyError, AttributeError): 
    863             # The schema_versions table does not yet exist. Let's create it 
     862            # the schema_versions table does not yet exist, let's create it 
    864863            db.session.rollback() 
    865864            from zine.database import metadata, schema_versions 
     
    870869            db.session.commit() 
    871870 
    872  
    873871    @property 
    874872    def upgrade_required(self): 
     
    881879                self.repository_has_upgrade(repository, sv) 
    882880            except _core.InstanceUpgradeRequired: 
    883                 # Set Zine in maintenance mode 
     881                # set Zine in maintenance mode 
    884882                cfg = self.cfg.edit() 
    885883                cfg['maintenance_mode'] = True 
     
    887885                raise _core.InstanceUpgradeRequired() 
    888886 
    889         # We got here, let's check for a bad upgrade lockfile left behind 
     887        # we got here, let's check for a bad upgrade lockfile left behind 
    890888        if path.isfile(self.upgrade_lockfile): 
    891889            remove(self.upgrade_lockfile) 
    892890 
    893891    def repository_has_upgrade(self, repository, schema_version): 
     892        from zine.models import SchemaVersion 
    894893        try: 
    895894            if schema_version.version < repository.latest: 
     
    898897            self.log.error('WE EVEN GOT HERE??? schema_versions table does not ' 
    899898                           'yet exist at this stage?') 
    900             # The schema_versions table does not yet exist. Let's create it 
     899            # the schema_versions table does not yet exist, let's create it 
    901900            db.session.rollback() 
    902901            from zine.database import metadata, schema_versions 
     
    904903            if not schema_versions.exists(): 
    905904                schema_versions.create(self.database_engine) 
    906             db.session.add(SchemaVersion(Repository(repo_path))) 
     905            db.session.add(SchemaVersion(repository)) 
    907906            db.session.commit() 
    908907            raise _core.InstanceUpgradeRequired() 
  • zine/upgrades/__init__.py

    r1327 r1328  
    99    :license: BSD, see LICENSE for more details. 
    1010""" 
    11  
    1211import re 
    1312import sys 
     
    2221                            "system.") 
    2322 
    24 from migrate.versioning import api, exceptions 
     23from migrate.versioning import api 
    2524from migrate.versioning.util import construct_engine 
     25from migrate.versioning.exceptions import KnownError 
    2626from zine import __version__ as VERSION, setup 
     27# imported for side-effects 
    2728from zine.upgrades import customisation 
    2829 
     
    3132class CommandLineInterface(object): 
    3233 
    33     usage = '%%prog %s [options] %s' 
     34    usage = '%%prog -I instancepath %s [options] %s' 
    3435    cmdline_version = '%%prog %s' % VERSION 
    3536 
    3637    commands = { 
     38             'help': 'Show help.', 
     39             'list': 'List all repositories.', 
    3740           'script': 'Create an empty upgrade script.', 
    3841          'upgrade': 'Upgrade a database to a later version.', 
     
    4851                                   version=self.cmdline_version) 
    4952        self.parser.disable_interspersed_args() 
    50         self.parser.print_help = self._help 
     53        self.parser.print_help = self._general_help 
    5154        self.parser.add_option('-I', '--instance', dest='instance', 
    52                                help="zine instance folder") 
     55                               help="Zine instance path") 
    5356 
    5457        options, args = self.parser.parse_args(argv[1:]) 
    5558 
    56         self.instance_folder = options.instance 
     59        self.instance_path = options.instance 
    5760 
    5861        if not args: 
     
    6669 
    6770    def get_zine_instance(self): 
    68         if not self.instance_folder: 
    69             self.parser.error('You need to pass the path to your zine\'s ' 
    70                               ' instance folder') 
     71        if not self.instance_path: 
     72            self.parser.error('you need to pass your Zine instance path.') 
    7173        if not hasattr(self, 'zine_instance'): 
    72             self.zine_instance = setup(expanduser(self.instance_folder)) 
     74            self.zine_instance = setup(expanduser(self.instance_path)) 
    7375        return self.zine_instance 
    7476 
    75     def _help(self): 
     77    def _general_help(self): 
    7678        print self.parser.format_help() 
    7779        print "commands:" 
     
    8082        for name, description in self.commands.items(): 
    8183            print format % (name, description) 
     84 
     85    def help(self, argv): 
     86        self._general_help() 
    8287 
    8388    def cmdlogger(self, messages): 
     
    9095                message = parse_html(message).to_text(simple=True) 
    9196                if message: 
     97                    # make the textifier output more compact 
    9298                    if message.endswith('\n\n') and trailing_new_line: 
    9399                        message = message[:-1] 
     
    96102                    sys.stdout.write(message.encode('utf-8')) 
    97103                    sys.stdout.flush() 
     104 
     105    def list(self, argv): 
     106        self.get_zine_instance() 
     107        def list_them(): 
     108            from zine.models import SchemaVersion 
     109            available_svs = SchemaVersion.query.all() 
     110            yield '<h2>Available repositories</h2>\n' 
     111            yield '<ul>' 
     112            for sv in available_svs: 
     113                yield '<li>' + sv.repository_id + '</li>\n' 
     114            yield '</ul>\n' 
     115        self.cmdlogger(list_them()) 
    98116 
    99117    def script(self, argv): 
     
    104122        parser.add_option( 
    105123            '-f', '--filename', 
    106             help="filename name(without spaces and/or version number)") 
     124            help="file name (without spaces and/or version number)") 
    107125        options, args = parser.parse_args(argv) 
    108126        description = ' '.join(args) 
     
    112130 
    113131    def upgrade(self, argv): 
    114         parser = OptionParser(usage=self.usage % ('upgrade', '[VERSION]'), 
     132        parser = OptionParser(usage=self.usage % ('upgrade', '[REPO] [VERSION]'), 
    115133                              description=self.commands['upgrade']) 
    116134        parser.add_option('--echo', default=False, action='store_true', 
    117135                          help='echo the SQL statements') 
    118136        options, args = parser.parse_args(argv) 
     137        repo = args and args.pop(0) or None 
    119138        version = args and args.pop(0) or None 
    120139        manage = ManageDatabase(self.get_zine_instance()) 
    121         self.cmdlogger(manage.cmd_upgrade(version, echo=options.echo)) 
     140        self.cmdlogger(manage.cmd_upgrade(repo, version, echo=options.echo)) 
    122141 
    123142    def downgrade(self, argv): 
    124         parser = OptionParser(usage=self.usage % ('downgrade', 'VERSION'), 
     143        parser = OptionParser(usage=self.usage % ('downgrade', 'REPO [VERSION]'), 
    125144                              description=self.commands['downgrade']) 
    126145        parser.add_option('--echo', default=False, action='store_true', 
    127146                          help='echo the SQL statements') 
    128147        options, args = parser.parse_args(argv) 
     148        try: 
     149            repo = args.pop(0) 
     150        except IndexError: 
     151            parser.error('you need to pass the repository id for downgrades, ' 
     152                         'see the list command.') 
    129153        version = args and args.pop(0) or None 
    130154        manage = ManageDatabase(self.get_zine_instance()) 
    131         try: 
    132             self.cmdlogger(manage.cmd_downgrade(version, echo=options.echo)) 
    133         except ValueError: 
    134             self.cmdlogger(['No more downgrades avaialable']) 
    135  
    136  
    137 # Database maintenance class 
     155        self.cmdlogger(manage.cmd_downgrade(repo, version, echo=options.echo)) 
     156 
     157 
    138158class ManageDatabase(object): 
     159    """Database maintenance class.""" 
    139160 
    140161    def __init__(self, instance): 
     
    163184        api.PythonScript.create(new_script_path, description=description) 
    164185 
    165  
    166     def cmd_upgrade(self, version=None, **opts): 
     186    def cmd_upgrade(self, repo_id=None, version=None, **opts): 
    167187        """Upgrade a database to a later version. 
    168188 
     
    176196        """ 
    177197        from zine.models import SchemaVersion 
    178         available_svs = SchemaVersion.query.all() 
    179         # Zine upgrade's come first 
    180         for sv in available_svs[:]: 
    181             available_svs.insert(0, available_svs.pop(available_svs.index(sv))) 
     198        if repo_id is None: 
     199            available_svs = SchemaVersion.query.all() 
     200            # Zine upgrades come first (XXX make that happen) 
     201            #for sv in available_svs[:]: 
     202            #    available_svs.insert(0, available_svs.pop(available_svs.index(sv))) 
     203        else: 
     204            available_svs = [SchemaVersion.query.get(repo_id)] 
    182205        # Now, run the available schema version upgrades 
    183206        for sv in available_svs: 
    184             repository = api.Repository(sv.repository_path, sv.repository_id) 
    185             for message in self._migrate(repository, version, upgrade=True, 
    186                                          **opts): 
    187                 yield message 
    188  
    189  
    190     def cmd_downgrade(self, version=None, **opts): 
     207            try: 
     208                repository = api.Repository(sv.repository_path, sv.repository_id) 
     209                for message in self._migrate(repository, version, 
     210                                             upgrade=True, **opts): 
     211                    yield message 
     212            except Exception, msg: 
     213                yield '<p>error upgrading %s: ' % repo_id 
     214                yield str(msg) 
     215                yield '</p>\n' 
     216 
     217    def cmd_downgrade(self, repo_id, version=None, **opts): 
    191218        """Downgrade a database to an earlier version. 
    192219 
     
    198225        """ 
    199226        from zine.models import SchemaVersion 
    200         for sv in SchemaVersion.query.all(): 
    201             repository = api.Repository(sv.repository_path, sv.repository_id) 
    202             if version is None: 
    203                 version = repository.version -1 
    204             for message in self._migrate(repository, version, upgrade=False, 
    205                                          **opts): 
     227        sv = SchemaVersion.query.get(repo_id) 
     228        repository = api.Repository(sv.repository_path, sv.repository_id) 
     229        if version is None: 
     230            version = sv.version - 1 
     231        try: 
     232            for message in self._migrate(repository, version, 
     233                                         upgrade=False, **opts): 
    206234                yield message 
    207  
     235        except Exception, msg: 
     236            yield '<p>error downgrading %s: ' % repo_id 
     237            yield str(msg) 
     238            yield '</p>\n' 
    208239 
    209240    def _migrate(self, repository, version, upgrade, **opts): 
     
    213244 
    214245        changeset = schema.changeset(version) 
    215         if changeset: 
    216             yield '<h2>Upgrading %s</h2>\n' % repository.id 
     246        if not changeset: 
     247            yield '<p>Repository %s is already up to date.</p>\n' % repository.id 
     248            return 
     249 
     250        yield '<h2>Migrating %s</h2>\n' % repository.id 
    217251        for ver, change in changeset: 
    218252            nextver = ver + changeset.step 
     
    222256            for message in schema.runchange(ver, change, changeset.step): 
    223257                yield message 
    224             yield 'done\n\n\n' 
    225  
     258            yield '\n<p>Done!</p>\n' 
    226259 
    227260    def _migrate_version(self, schema, version, upgrade): 
    228261        if version is None: 
    229262            return version 
     263        if version < 0: 
     264            raise KnownError("Already at version 0.") 
    230265        # Version is specified: ensure we're upgrading in the right direction 
    231266        # (current version < target version for upgrading; reverse for down) 
    232267        version = api.VerNum(version) 
    233268        cur = schema.version 
    234         if upgrade is not None: 
     269        if upgrade: 
     270            direction = cur <= version 
     271        else: 
     272            direction = cur >= version 
     273        if not direction: 
     274            msg = ("Cannot %s a database of version %%s to version %%s. " 
     275                   "Try '%s' instead.") 
    235276            if upgrade: 
    236                 direction = cur <= version 
     277                msg = msg % ('upgrade', 'downgrade') 
    237278            else: 
    238                 direction = cur >= version 
    239             if not direction: 
    240                 err = "Cannot % a database of version %%s to version %%s. "\ 
    241                       "Try '%s' instead.\n" 
    242                 if upgrade: 
    243                     err = err % ('upgrade', 'downgrade') 
    244                 else: 
    245                     err = err % ('downgrade', 'upgrade') 
    246                 raise exceptions.KnownError(err%(cur, version)) 
     279                msg = msg % ('downgrade', 'upgrade') 
     280            raise KnownError(msg % (cur, version)) 
    247281        return version 
  • zine/upgrades/customisation.py

    r1327 r1328  
    3131        """Create an empty migration script at specified path 
    3232 
    33         :returns: :class:`PythonScript instance <migrate.versioning.script.py.PythonScript>`""" 
     33        :returns: :class:`PythonScript instance 
     34                  <migrate.versioning.script.py.PythonScript>` 
     35        """ 
    3436        cls.require_notfound(path) 
    3537 
     
    6668 
    6769""" 
    68         open(path, 'w').write(NEW_SCRIPT_TEMPLATE % opts.get('description', '')) 
     70        open(path, 'w').write(NEW_SCRIPT_TEMPLATE % 
     71                              opts.get('description', ' ')) 
    6972        return cls(path) 
    7073 
     
    228231            self._init_parent(repository_path) 
    229232        # __init__ from Repository 
    230         self.versions=Collection(join(repository_path, 'versions')) 
     233        self.versions = Collection(join(repository_path, 'versions')) 
    231234        self.config['repository_id'] = repository_id 
    232235 
     
    236239 
    237240    def changeset(self, database, start, end=None): 
    238         """Create a changeset to migrate this database from ver. start to end/latest. 
     241        """Create a changeset to migrate this database from version 
     242        start to end/latest. 
    239243 
    240244        :param database: name of database to generate changeset 
     
    244248        :type start: int 
    245249        :type end: int 
    246         :returns: :class:`Changeset instance <migration.versioning.repository.Changeset>` 
     250        :returns: :class:`Changeset instance 
     251                  <migration.versioning.repository.Changeset>` 
    247252        """ 
    248253        start = api.VerNum(start) 
     
    264269        versions = range(start + range_mod, end + range_mod, step) 
    265270        changes = [] 
    266         for version in range(start + range_mod, end + range_mod, step): 
     271        for version in versions: 
    267272            try: 
    268273                changes.append(self.version(version).script(database, op)) 
  • zine/upgrades/versions/__init__.py

    r1327 r1328  
    33    ~~~~~~~~~~~~~~~~~~~~~~ 
    44 
    5     This package implements contains the necessary upgrade/downgrade scripts 
    6     to maintain the database schema changes. 
     5    This package contains the necessary upgrade/downgrade scripts to maintain 
     6    the database schema changes. 
    77 
    88    :copyright: (c) 2010 by the Zine Team, see AUTHORS for more details. 
Note: See TracChangeset for help on using the changeset viewer.