# HG changeset patch
# Parent c10c5c1105a9e4aea7ecc469c2ea25523943af03
Plugin DB upgrade helper functions.

diff -r c10c5c1105a9 trac/env.py
--- a/trac/env.py	Sun Aug 07 16:53:03 2011 +0000
+++ b/trac/env.py	Sat Aug 27 14:53:36 2011 +0200
@@ -560,10 +560,8 @@
         :since 0.13: deprecation warning: the `db` parameter is no
                      longer used and will be removed in version 0.14
         """
-        rows = self.db_query("""
-                SELECT value FROM system WHERE name='%sdatabase_version'
-                """ % ('initial_' if initial else ''))
-        return rows and int(rows[0][0])
+        return get_environment_version_for_module(self, 
+            'initial_database_version' if initial else 'database_version')
 
     def setup_config(self):
         """Load the configuration file."""
@@ -706,43 +704,21 @@
 
     def environment_created(self):
         """Insert default data into the database."""
-        with self.env.db_transaction as db:
-            for table, cols, vals in db_default.get_data(db):
-                db.executemany("INSERT INTO %s (%s) VALUES (%s)"
-                   % (table, ','.join(cols), ','.join(['%s' for c in cols])),
-                   vals)
+        init_environment_data_for_module(self.env, db_default.get_data)
         self._update_sample_config()
 
     def environment_needs_upgrade(self, db):
-        dbver = self.env.get_version(db)
-        if dbver == db_default.db_version:
-            return False
-        elif dbver > db_default.db_version:
-            raise TracError(_('Database newer than Trac version'))
-        self.log.info("Trac database schema version is %d, should be %d",
-                      dbver, db_default.db_version)
-        return True
+        return environment_needs_upgrade_for_module(self.env, 'Trac',
+                                                    'database_version',
+                                                    db_default.db_version)
 
     def upgrade_environment(self, db):
         """Each db version should have its own upgrade module, named
         upgrades/dbN.py, where 'N' is the version number (int).
         """
-        cursor = db.cursor()
-        dbver = self.env.get_version()
-        for i in range(dbver + 1, db_default.db_version + 1):
-            name  = 'db%i' % i
-            try:
-                upgrades = __import__('upgrades', globals(), locals(), [name])
-                script = getattr(upgrades, name)
-            except AttributeError:
-                raise TracError(_("No upgrade module for version %(num)i "
-                                  "(%(version)s.py)", num=i, version=name))
-            script.do_upgrade(self.env, i, cursor)
-            cursor.execute("""
-                UPDATE system SET value=%s WHERE name='database_version'
-                """, (i,))
-            self.log.info("Upgraded database version from %d to %d", i - 1, i)
-            db.commit()
+        upgrade_environment_for_module(self.env, 'Trac', 'database_version',
+                                       db_default.db_version,
+                                       'upgrades')
         self._update_sample_config()
 
     # Internal methods
@@ -817,6 +793,100 @@
 
     return env
 
+def init_environment_version_for_module(env, name, version):
+    """Set the current module version in the database.
+    
+    :since: 0.13
+    """
+    with env.db_transaction as db:
+        cursor = db.cursor()
+        cursor.execute("""
+            INSERT INTO system (name, value)
+            VALUES (%s, %s)
+            """, (name, version))
+
+def init_environment_schema_for_module(env, schema):
+    """Setup db schema for this module in the database.
+    
+    :since: 0.13
+    """
+    db_connector, _ = DatabaseManager(env).get_connector()
+    with env.db_transaction as db:
+        cursor = db.cursor()
+        for table in schema:
+            for stmt in db_connector.to_sql(table):
+                cursor.execute(stmt)
+
+def init_environment_data_for_module(env, get_initial_data):
+    """Insert initial data into the database.
+    
+    :since: 0.13
+    """
+    with env.db_transaction as db:
+        for table, cols, vals in get_initial_data(db):
+                db.executemany("INSERT INTO %s (%s) VALUES (%s)"
+                   % (table, ','.join(cols), ','.join(['%s' for c in cols])),
+                   vals)
+
+def get_environment_version_for_module(env, name):
+    """Get the current module version from the database.
+
+    Returns `False` if the environment has not been setup for this module,
+    which is "older" than any db version number.
+
+    :since: 0.13
+    """
+    rows = env.db_query("""
+            SELECT value FROM system WHERE name='%s'
+            """ % name)
+    return rows and int(rows[0][0])
+
+def environment_needs_upgrade_for_module(env, name, field, version):
+    """Check whether the environment needs to be upgraded for this module.
+
+    Commonly called from `IEnvironmentSetupParticipant` modules and plugins
+    to implement the method `environment_needs_upgrade`.
+    
+    :since: 0.13
+    """
+    dbver = get_environment_version_for_module(env, field)
+    if dbver == version:
+        return False
+    elif dbver > version:
+        raise TracError(_("Database newer than %(name)s version.", name=name))
+    env.log.info("%s database schema version is %d, should be %d",
+                  name, dbver, version)
+    return True
+
+def upgrade_environment_for_module(env, name, field, version, 
+                                   upgrades_pkg_name):
+    """Invoke `do_upgrade(env, version, cursor)` in module 
+    `"%s/db%i.py" % (upgrades_pkg_name, version)` for each 
+    required version upgrade.
+    
+    :since: 0.13
+    """
+    dbver = get_environment_version_for_module(env, field)
+    with env.db_transaction as db:
+        cursor = db.cursor()
+        for i in range(dbver + 1, version + 1):
+            module  = 'db%i' % i
+            try:
+                upgrades = __import__(upgrades_pkg_name, globals(), locals(),
+                                      [module])
+                script = getattr(upgrades, module)
+            except AttributeError:
+                msg = 
+                raise TracError(_("No upgrade module for version %(num)i "
+                                  "(%(module)s.py)", num=i, module=module)
+            script.do_upgrade(env, i, cursor)
+            cursor.execute("""
+                UPDATE system SET value=%s WHERE name='%s'
+                """, (i, name))
+            env.log.info("Upgraded database version from %d to %d"
+                          " for module %s", i - 1, i, name)
+            db.commit()
+
 
 class EnvironmentAdmin(Component):
     """trac-admin command provider for environment administration."""

