Changes between Version 8 and Version 9 of TestManagerForTracPluginGenericClass


Ignore:
Timestamp:
Oct 15, 2012, 11:06:29 AM (2 years ago)
Author:
seccanj
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • TestManagerForTracPluginGenericClass

    v8 v9  
    183183                              Column('state')],
    184184                     'has_custom': True,
    185                      'has_change': True}
     185                     'has_change': True,
     186                     'version': 1}}
    186187            }
    187188
     
    231232        pass
    232233
     234
    233235    # IEnvironmentSetupParticipant methods
    234236    def environment_created(self):
    235         self.upgrade_environment(self.env.get_db_cnx())
    236 
    237     def environment_needs_upgrade(self, db):
    238         return self._need_initialization(db)
    239 
    240     def upgrade_environment(self, db):
    241         # Create db
    242         if self._need_initialization(db):
    243             upgrade_db(self.env, self.SCHEMA, db)
    244 
    245     def _need_initialization(self, db):
    246         return need_db_upgrade(self.env, self.SCHEMA, db)
    247 }}}
    248 
     237        self.upgrade_environment()
     238
     239    def environment_needs_upgrade(self, db=None):
     240        for realm in self.SCHEMA:
     241            realm_metadata = self.SCHEMA[realm]
     242
     243            if need_db_create_for_realm(self.env, realm, realm_metadata, db) or \
     244                need_db_upgrade_for_realm(self.env, realm, realm_metadata, db):
     245               
     246                return True
     247               
     248        return False
     249
     250    def upgrade_environment(self, db=None):
     251        # Create or update db
     252        @self.env.with_transaction(db)
     253        def do_upgrade_environment(db):
     254            for realm in self.SCHEMA:
     255                realm_metadata = self.SCHEMA[realm]
     256
     257                if need_db_create_for_realm(self.env, realm, realm_metadata, db):
     258                    create_db_for_realm(self.env, realm, realm_metadata, db)
     259
     260                elif need_db_upgrade_for_realm(self.env, realm, realm_metadata, db):
     261                    upgrade_db_for_realm(self.env, 'tracgenericworkflow.upgrades', realm, realm_metadata, db)
     262}}}
     263
     264[[BR]]
    249265First of all, this should be a component, because it must implement Trac interfaces.
    250266The interfaces to implement are the following:
     
    252268 * IEnvironmentSetupParticipant, to be queried by Trac about any needs regarding database creation or upgrade.
    253269
    254 Then here comes the declaration of the database schema, class fields and class metadata, to be later returned in the corresponding methods of the interface.
    255 
     270Then comes the declaration of the database schema, class fields and class metadata, to be later returned in the corresponding methods of the interface.
     271
     272[[BR]]
     273One note about upgrade. The call to "upgrade_db_for_realm" specifies, as the second parameter, the subdirectory where all of the DB upgrade scripts will be provided.
     274
     275This directory will contain simple python files, one for each table and for each DB version upgrade, with a structure similar to the following.
     276See a detailed explanation after the code box.
     277Refer to [http://testman4trac.svn.sourceforge.net/viewvc/testman4trac/testman4trac/trunk/testmanager/upgrades/ the TestManager plugin upgrade directory] for a more complete example.
     278{{{
     279from trac.db import Table, Column, Index, DatabaseManager
     280from tracgenericclass.util import *
     281from testmanager.model import TestManagerModelProvider
     282
     283def do_upgrade(env, ver, db_backend, db):
     284    """
     285    Add 'page_version' column to testcaseinplan table
     286    """
     287    cursor = db.cursor()
     288   
     289    realm = 'testcaseinplan'
     290    cursor.execute("CREATE TEMPORARY TABLE %(realm)s_old AS SELECT * FROM %(realm)s" % {'realm': realm})
     291    cursor.execute("DROP TABLE %(realm)s" % {'realm': realm})
     292
     293    table_metadata = Table('testcaseinplan', key = ('id', 'planid'))[
     294                              Column('id'),
     295                              Column('planid'),
     296                              Column('page_name'),
     297                              Column('page_version', type='int'),
     298                              Column('status')]
     299
     300    env.log.info("Updating table for class %s" % realm)
     301    for stmt in db_backend.to_sql(table_metadata):
     302        env.log.debug(stmt)
     303        cursor.execute(stmt)
     304
     305    cursor = db.cursor()
     306
     307    cursor.execute("INSERT INTO %(realm)s (id,planid,page_name,page_version,status) "
     308                   "SELECT id,planid,page_name,-1,status FROM %(realm)s_old" % {'realm': realm})
     309
     310    cursor.execute("DROP TABLE %(realm)s_old" % {'realm': realm})
     311
     312}}}
     313
     314[[BR]]
     315In case you need to update a table's structure (e.g. add columns), you will:
     316
     317 1) Create a temporary table with the same structure as the old table
     318 2) Copy all the contents of the current table into the temporary table
     319 3) Drop the original table
     320 4) Recreate the original table with the new structure
     321 5) Copy back all the contents from the temporary table into the updated original table
     322 6) Drop the temporary table
     323
     324[[BR]]
    256325Following is the '''IConcreteClassProvider interface''' documentation, which is pretty explanatory about the format and meaning of the required data.
    257326
     
    683752
    684753'''Note''': The object being passed along here is the actual object, not a copy. The listener would then be able to alter the object and then save it, thus affecting the system. I didn't want to prevent this (and probably it wouldn't be even possible), because this may be a powerful mechanism of further hacking the environment for achieving higher functionalities.
    685