== Extension Point : ''IEnvironmentSetupParticipant'' ||'''Interface'''||''IEnvironmentSetupParticipant''||'''Since'''||0.9|| ||'''Module'''||''trac.env''||'''Source'''||[source:trunk/trac/env.py#L51 env.py]|| The ''IEnvironmentSetupParticipant'' will be called during both the creation of a new environment (''trac-admin initenv'') and on upgrade of an existing environment (''trac-admin upgrade''). == Purpose Responsibilities of the interface are to both participate in the creation of a new environment and during upgrade of an existing environment. This includes adding information to the database schema, such as table declarations and so on. Some implementations, see below, might also add default data to the newly created database, or modify content in the environment directory. On environment upgrade, the responsibilities of the participant are to non-destructively migrate existing user data to a newer database schema, provided that the data model has changed at the SQL level, and of course to migrate the environment's folder structure and content to meet the requirements of the participant. == Usage Implementing the interface follows the standard guidelines found in TracDev/ComponentArchitecture and of course TracDev/PluginDevelopment. == Examples The following example basically does nothing more than logging to the standard log file during either ''trac-admin initenv'' or ''trac-admin upgrade''. {{{#!python from trac.core import Component, implements from trac.env import IEnvironmentSetupParticipant class SampleEnvironmentSetupParticipant(Component): implements(IEnvironmentSetupParticipant) # IEnvironmentSetupParticipant methods def environment_created(self): self.log.debug("creating environment for sample plugin.") def environment_needs_upgrade(self): self.log.debug("the existing environment requires an upgrade for sample plugin.") return True def upgrade_environment(self): self.log.debug("upgrading existing environment for sample plugin.") }}} === DB upgrades A more realistic use case would be a plugin that maintains its own database tables and provides scripts for automatically upgrading the database schema. The `DatabaseManager` class provides several methods that can be used to run these scripts. (Since Trac 1.1.5, see #8172) An entire example plugin would consists of the following files and directories: * `example/` * `upgrades` * `__init__.py` (empty) * `db2.py` {{{#!python def do_upgrade(env, ver, cursor): pass # Change the database schema here }}} * `__init__.py` (empty) * `core.py` {{{#!python from trac.core import * from trac.env import * from trac.db.api import DatabaseManager from trac.db.schema import Table, Column PLUGIN_NAME = 'ExamplePlugin' PLUGIN_VERSION = 2 PLUGIN_SCHEMA = [ Table('table1', key='name')[ Column('name'), Column('value')]] INITIAL_PLUGIN_DATA = ( ('table1', ('name', 'value'), (('name1', 'value1'), ('name2', 'value2'))),) class ExamplePlugin(Component): implements(IEnvironmentSetupParticipant) # IEnvironmentSetupParticipant methods def environment_created(self): # Same work is done for environment created and # upgraded, in almost all use-cases. self.upgrade_environment() def environment_needs_upgrade(self): dbm = DatabaseManager(self.env) return dbm.needs_upgrade(PLUGIN_VERSION, PLUGIN_NAME) def upgrade_environment(self): dbm = DatabaseManager(self.env) with self.env.db_transaction: if dbm.get_database_version(PLUGIN_NAME) == 0: dbm.create_tables(PLUGIN_SCHEMA) dbm.insert_into_tables(INITIAL_PLUGIN_DATA) dbm.set_database_version(PLUGIN_VERSION, PLUGIN_NAME) else: dbm.upgrade(PLUGIN_VERSION, PLUGIN_NAME, 'example.upgrades') }}} * `setup.py` {{{#!python #!/usr/bin/env python from setuptools import setup setup(name = 'example', version = '1.0', packages = ['example', 'example.upgrades'], entry_points = {'trac.plugins': ['example.core = example.core']}) }}} == Available Implementations * [source:trunk/trac/env.py#L727 trac.env.EnvironmentSetup][[br]] This is the setup participant that will initialize the Trac database and also the sample configuration provided with each Trac instance, providing sane initial defaults for use with both an existing environment and a newly created one. For the creation of a new environment it uses [source:trunk/trac/db_default.py the default db structure]. and on upgrade it will use [source:trunk/trac/upgrades a db upgrade path] defined in the individual `db*.py` modules therein. The version number of the Trac database schema is available from the ''system'' table, the key to look for is ''database_version.'' The value of this system property will be updated on environment upgrade. In addition to that, Trac will also keep track of the initial database version that was installed when first creating the environment. The key to look for in the ''system'' table is ''initial_database_version''. == Additional Information and References * Preventing data corruption on upgrade[[br]] Multiple operations should be put in a transaction context manager, as shown in the example, to ensure that all the operations are atomic. * On upgrade the existing help pages in the wiki will not be updated[[br]] This is currently not being addressed by Trac's default environment setup participant. In order to also upgrade the help pages, you must run ''trac-admin wiki upgrade.'' However, there is a proposed [wiki:TracDev/Proposals/NewHelp new help system] that would externalize all help pages to static resources in the filesystem. * comment:19:ticket:10779 and following discuss that IEnvironmentSetupParticipants are not ordered. Also they should be carefully written not to expect a particular version of the database schema, components or other code that is not guaranteed to be compatible with the upgrade. * [http://www.edgewall.org/docs/trac-trunk/html/api/trac_env.html#trac.env.IEnvironmentSetupParticipant API Reference] * `environment_created` is only called for a plugin if the plugin is enabled at the time the environment is created. To have a plugin enabled at the time the environment is created the `--inherit` (comment:42:ticket:8172) or `--config` (//since 1.2//) argument must specify a configuration that enables the plugin. ==== API History * 0.9 introduced the interface. (changeset:1785) * Added `environment_needs_upgrade` and `upgrade_environment` methods. (changeset:1840) * 1.1.2 deprecated `db` parameters. (changeset:12829, #11605) * 1.1.5 added database helper methods (#8172) * 1.3.1 removed `db` parameters. (changeset:14888, #11901)