def reset_db(self, default_data=None): """Remove all data from Trac tables, keeping the tables themselves. :param default_data: after clean-up, initialize with default data :return: True upon success """ from trac import db_default tables = [] dbm = DatabaseManager(self) try: db_version = dbm.get_database_version() except (TracError, self.db_exc.DatabaseError): pass else: if db_version == db_default.db_version: # same version, simply clear the tables (faster) tables = dbm.reset_tables() else: # different version or version unknown, drop the tables self.destroy_db() if not tables: dbm.init_db() # Make sure the next db_query()/db_transaction() will create # a new connection aware of the new data model - see #8518. if self.dburi != 'sqlite::memory:': dbm.shutdown() if default_data: dbm.insert_into_tables(db_default.get_data) else: dbm.set_database_version(db_default.db_version)
def upgrade(self, backup=False, backup_dest=None): """Upgrade database. :param backup: whether or not to backup before upgrading :param backup_dest: name of the backup file :return: whether the upgrade was performed """ upgraders = [] for participant in self.setup_participants: with self.component_guard(participant, reraise=True): if participant.environment_needs_upgrade(): upgraders.append(participant) if not upgraders: return if backup: try: self.backup(backup_dest) except Exception as e: raise BackupError(e) for participant in upgraders: self.log.info("upgrading %s...", participant) with self.component_guard(participant, reraise=True): participant.upgrade_environment() # Database schema may have changed, so close all connections dbm = DatabaseManager(self) if dbm.connection_uri != 'sqlite::memory:': dbm.shutdown() self._update_sample_config() del self.database_version return True
def reset_db(self, default_data=None): """Remove all data from Trac tables, keeping the tables themselves. :param default_data: after clean-up, initialize with default data :return: True upon success """ from trac import db_default if EnvironmentStub.dbenv: db = self.get_db_cnx() scheme, db_prop = _parse_db_str(self.dburi) tables = [] db.rollback() # make sure there's no transaction in progress try: # check the database version cursor = db.cursor() cursor.execute("SELECT value FROM system " "WHERE name='database_version'") database_version = cursor.fetchone() if database_version: database_version = int(database_version[0]) if database_version == db_default.db_version: # same version, simply clear the tables (faster) m = sys.modules[__name__] reset_fn = 'reset_%s_db' % scheme if hasattr(m, reset_fn): tables = getattr(m, reset_fn)(db, db_prop) else: # different version or version unknown, drop the tables self.destroy_db(scheme, db_prop) except: db.rollback() # tables are likely missing if not tables: del db dm = DatabaseManager(EnvironmentStub.dbenv) dm.init_db() # we need to make sure the next get_db_cnx() will re-create # a new connection aware of the new data model - see #8518. dm.shutdown() db = self.get_db_cnx() cursor = db.cursor() if default_data: for table, cols, vals in db_default.get_data(db): cursor.executemany( "INSERT INTO %s (%s) VALUES (%s)" % (table, ','.join(cols), ','.join(['%s' for c in cols])), vals) elif EnvironmentStub.dbenv: cursor.execute( "INSERT INTO system (name, value) " "VALUES (%s, %s)", ('database_version', str(db_default.db_version))) db.commit()
def reset_db(self, default_data=None): """Remove all data from Trac tables, keeping the tables themselves. :param default_data: after clean-up, initialize with default data :return: True upon success """ from trac import db_default if EnvironmentStub.dbenv: db = self.get_db_cnx() scheme, db_prop = _parse_db_str(self.dburi) tables = [] db.rollback() # make sure there's no transaction in progress try: # check the database version cursor = db.cursor() cursor.execute("SELECT value FROM system " "WHERE name='database_version'") database_version = cursor.fetchone() if database_version: database_version = int(database_version[0]) if database_version == db_default.db_version: # same version, simply clear the tables (faster) m = sys.modules[__name__] reset_fn = 'reset_%s_db' % scheme if hasattr(m, reset_fn): tables = getattr(m, reset_fn)(db, db_prop) else: # different version or version unknown, drop the tables self.destroy_db(scheme, db_prop) except: db.rollback() # tables are likely missing if not tables: del db dm = DatabaseManager(EnvironmentStub.dbenv) dm.init_db() # we need to make sure the next get_db_cnx() will re-create # a new connection aware of the new data model - see #8518. dm.shutdown() db = self.get_db_cnx() cursor = db.cursor() if default_data: for table, cols, vals in db_default.get_data(db): cursor.executemany("INSERT INTO %s (%s) VALUES (%s)" % (table, ','.join(cols), ','.join(['%s' for c in cols])), vals) elif EnvironmentStub.dbenv: cursor.execute("INSERT INTO system (name, value) " "VALUES (%s, %s)", ('database_version', str(db_default.db_version))) db.commit()
def upgrade(self, backup=False, backup_dest=None): """Upgrade database. :param backup: whether or not to backup before upgrading :param backup_dest: name of the backup file :return: whether the upgrade was performed """ upgraders = [] for participant in self.setup_participants: args = () with self.db_query as db: if arity(participant.environment_needs_upgrade) == 1: args = (db, ) if participant.environment_needs_upgrade(*args): upgraders.append(participant) if not upgraders: return if backup: try: self.backup(backup_dest) except Exception as e: raise BackupError(e) for participant in upgraders: self.log.info("%s.%s upgrading...", participant.__module__, participant.__class__.__name__) args = () with self.db_transaction as db: if arity(participant.upgrade_environment) == 1: args = (db, ) participant.upgrade_environment(*args) # Database schema may have changed, so close all connections dbm = DatabaseManager(self) if dbm.connection_uri != 'sqlite::memory:': dbm.shutdown() del self.database_version return True
class EnvironmentStub(Environment): """A stub of the trac.env.Environment object for testing.""" global_databasemanager = None required = False def __init__(self, default_data=False, enable=None, disable=None, path=None, destroying=False): """Construct a new Environment stub object. :param default_data: If True, populate the database with some defaults. :param enable: A list of component classes or name globs to activate in the stub environment. :param disable: A list of component classes or name globs to deactivate in the stub environment. :param path: The location of the environment in the file system. No files or directories are created when specifying this parameter. :param destroying: If True, the database will not be reset. This is useful for cases when the object is being constructed in order to call `destroy_db`. """ if enable is not None and not isinstance(enable, (list, tuple)): raise TypeError('Keyword argument "enable" must be a list') if disable is not None and not isinstance(disable, (list, tuple)): raise TypeError('Keyword argument "disable" must be a list') ComponentManager.__init__(self) self.systeminfo = [] import trac self.path = path if self.path is None: self.path = os.path.dirname(trac.__file__) if not os.path.isabs(self.path): self.path = os.path.join(os.getcwd(), self.path) # -- configuration self.config = Configuration(None) # We have to have a ticket-workflow config for ''lots'' of things to # work. So insert the basic-workflow config here. There may be a # better solution than this. load_workflow_config_snippet(self.config, 'basic-workflow.ini') self.config.set('logging', 'log_level', 'DEBUG') self.config.set('logging', 'log_type', 'stderr') if enable is not None: self.config.set('components', 'trac.*', 'disabled') else: self.config.set('components', 'tracopt.versioncontrol.*', 'enabled') for name_or_class in enable or (): config_key = self._component_name(name_or_class) self.config.set('components', config_key, 'enabled') for name_or_class in disable or (): config_key = self._component_name(name_or_class) self.config.set('components', config_key, 'disabled') # -- logging from trac.log import logger_handler_factory self.log, self._log_handler = logger_handler_factory('test') # -- database self.config.set('components', 'trac.db.*', 'enabled') self.dburi = get_dburi() init_global = False if self.global_databasemanager: self.components[DatabaseManager] = self.global_databasemanager else: self.config.set('trac', 'database', self.dburi) self.global_databasemanager = DatabaseManager(self) self.config.set('trac', 'debug_sql', True) init_global = not destroying if default_data or init_global: self.reset_db(default_data) self.config.set('trac', 'base_url', 'http://example.org/trac.cgi') self.known_users = [] translation.activate(locale_en) def reset_db(self, default_data=None): """Remove all data from Trac tables, keeping the tables themselves. :param default_data: after clean-up, initialize with default data :return: True upon success """ from trac import db_default scheme, db_prop = _parse_db_str(self.dburi) tables = [] remove_sqlite_db = False try: with self.db_transaction as db: db.rollback() # make sure there's no transaction in progress # check the database version database_version = self.get_version() except Exception: # "Database not found ...", # "OperationalError: no such table: system" or the like pass else: if database_version == db_default.db_version: # same version, simply clear the tables (faster) m = sys.modules[__name__] reset_fn = 'reset_%s_db' % scheme if hasattr(m, reset_fn): tables = getattr(m, reset_fn)(self, db_prop) else: # different version or version unknown, drop the tables remove_sqlite_db = True self.destroy_db(scheme, db_prop) if scheme == 'sqlite' and remove_sqlite_db: path = db_prop['path'] if path != ':memory:': if not os.path.isabs(path): path = os.path.join(self.path, path) self.global_databasemanager.shutdown() os.remove(path) if not tables: self.global_databasemanager.init_db() # we need to make sure the next get_db_cnx() will re-create # a new connection aware of the new data model - see #8518. if self.dburi != 'sqlite::memory:': self.global_databasemanager.shutdown() with self.db_transaction as db: if default_data: for table, cols, vals in db_default.get_data(db): db.executemany("INSERT INTO %s (%s) VALUES (%s)" % (table, ','.join(cols), ','.join(['%s'] * len(cols))), vals) else: db("INSERT INTO system (name, value) VALUES (%s, %s)", ('database_version', str(db_default.db_version))) def destroy_db(self, scheme=None, db_prop=None): if not (scheme and db_prop): scheme, db_prop = _parse_db_str(self.dburi) try: with self.db_transaction as db: if scheme == 'postgres' and db.schema: db('DROP SCHEMA %s CASCADE' % db.quote(db.schema)) elif scheme == 'mysql': for table in db.get_table_names(): db("DROP TABLE IF EXISTS `%s`" % table) except Exception: # "TracError: Database not found...", # psycopg2.ProgrammingError: schema "tractest" does not exist pass return False # overridden def is_component_enabled(self, cls): if self._component_name(cls).startswith('__main__.'): return True return Environment.is_component_enabled(self, cls) def get_known_users(self, cnx=None): return self.known_users
class EnvironmentStub(Environment): """A stub of the trac.env.Environment object for testing.""" href = abs_href = None global_databasemanager = None required = False def __init__(self, default_data=False, enable=None, disable=None, path=None, destroying=False): """Construct a new Environment stub object. :param default_data: If True, populate the database with some defaults. :param enable: A list of component classes or name globs to activate in the stub environment. :param disable: A list of component classes or name globs to deactivate in the stub environment. :param path: The location of the environment in the file system. No files or directories are created when specifying this parameter. :param destroying: If True, the database will not be reset. This is useful for cases when the object is being constructed in order to call `destroy_db`. """ if enable is not None and not isinstance(enable, (list, tuple)): raise TypeError('Keyword argument "enable" must be a list') if disable is not None and not isinstance(disable, (list, tuple)): raise TypeError('Keyword argument "disable" must be a list') ComponentManager.__init__(self) Component.__init__(self) self.systeminfo = [] import trac self.path = path if self.path is None: self.path = os.path.dirname(trac.__file__) if not os.path.isabs(self.path): self.path = os.path.join(os.getcwd(), self.path) # -- configuration self.config = Configuration(None) # We have to have a ticket-workflow config for ''lots'' of things to # work. So insert the basic-workflow config here. There may be a # better solution than this. load_workflow_config_snippet(self.config, 'basic-workflow.ini') self.config.set('logging', 'log_level', 'DEBUG') self.config.set('logging', 'log_type', 'stderr') if enable is not None: self.config.set('components', 'trac.*', 'disabled') else: self.config.set('components', 'tracopt.versioncontrol.*', 'enabled') for name_or_class in enable or (): config_key = self._component_name(name_or_class) self.config.set('components', config_key, 'enabled') for name_or_class in disable or (): config_key = self._component_name(name_or_class) self.config.set('components', config_key, 'disabled') # -- logging from trac.log import logger_handler_factory self.log, self._log_handler = logger_handler_factory('test') # -- database self.config.set('components', 'trac.db.*', 'enabled') self.dburi = get_dburi() init_global = False if self.global_databasemanager: self.components[DatabaseManager] = self.global_databasemanager else: self.config.set('trac', 'database', self.dburi) self.global_databasemanager = DatabaseManager(self) self.config.set('trac', 'debug_sql', True) self.config.set('logging', 'log_type', 'stderr') self.config.set('logging', 'log_level', 'DEBUG') init_global = not destroying if default_data or init_global: self.reset_db(default_data) from trac.web.href import Href self.href = Href('/trac.cgi') self.abs_href = Href('http://example.org/trac.cgi') self.known_users = [] translation.activate(locale_en) def reset_db(self, default_data=None): """Remove all data from Trac tables, keeping the tables themselves. :param default_data: after clean-up, initialize with default data :return: True upon success """ from trac import db_default scheme, db_prop = _parse_db_str(self.dburi) tables = [] remove_sqlite_db = False try: with self.db_transaction as db: db.rollback() # make sure there's no transaction in progress # check the database version database_version = self.get_version() except Exception: # "Database not found ...", # "OperationalError: no such table: system" or the like pass else: if database_version == db_default.db_version: # same version, simply clear the tables (faster) m = sys.modules[__name__] reset_fn = 'reset_%s_db' % scheme if hasattr(m, reset_fn): tables = getattr(m, reset_fn)(self, db_prop) else: # different version or version unknown, drop the tables remove_sqlite_db = True self.destroy_db(scheme, db_prop) db = None # as we might shutdown the pool FIXME no longer needed! if scheme == 'sqlite' and remove_sqlite_db: path = db_prop['path'] if path != ':memory:': if not os.path.isabs(path): path = os.path.join(self.path, path) self.global_databasemanager.shutdown() os.remove(path) if not tables: self.global_databasemanager.init_db() # we need to make sure the next get_db_cnx() will re-create # a new connection aware of the new data model - see #8518. if self.dburi != 'sqlite::memory:': self.global_databasemanager.shutdown() with self.db_transaction as db: if scheme == 'sqlite': # Speed-up tests with SQLite database db("PRAGMA synchronous = OFF") if default_data: for table, cols, vals in db_default.get_data(db): db.executemany( "INSERT INTO %s (%s) VALUES (%s)" % (table, ','.join(cols), ','.join(['%s'] * len(cols))), vals) else: db("INSERT INTO system (name, value) VALUES (%s, %s)", ('database_version', str(db_default.db_version))) def destroy_db(self, scheme=None, db_prop=None): if not (scheme and db_prop): scheme, db_prop = _parse_db_str(self.dburi) try: with self.db_transaction as db: if scheme == 'postgres' and db.schema: db('DROP SCHEMA %s CASCADE' % db.quote(db.schema)) elif scheme == 'mysql': for table in db.get_table_names(): db("DROP TABLE IF EXISTS `%s`" % table) except Exception: # "TracError: Database not found...", # psycopg2.ProgrammingError: schema "tractest" does not exist pass return False # overridden def is_component_enabled(self, cls): if self._component_name(cls).startswith('__main__.'): return True return Environment.is_component_enabled(self, cls) def get_known_users(self, cnx=None): return self.known_users