From 9b11f434c20255ddb88f99aec4997dbec89298a3 Mon Sep 17 00:00:00 2001 From: kedder Date: Sat, 15 Feb 2003 23:19:01 +0000 Subject: [PATCH] trackers on mysql can be initialised added mechanism for backends to detect and clear database git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1512 57a73879-2fb5-44c3-a270-3262357dd7e2 --- CHANGES.txt | 2 +- doc/mysql.txt | 17 +++++++++++++++ roundup/admin.py | 22 +++++++++++++++----- roundup/backends/back_mysql.py | 38 +++++++++++++++++++++++++++------- test/test_db.py | 10 ++++----- 5 files changed, 70 insertions(+), 19 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 45ab7bf..e187920 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -12,7 +12,7 @@ are given with the most recent entry first. - cleaning old unused sessions only once per hour, not on every cgi request. It is greatly improves web interface performance, especially on trackers under high load -- added mysql backend +- added mysql backend (see doc/mysql.txt for details) - fixes to CGI form handling - switch metakit to use "compressed" multilink journal change representation - fixed bug in metakit unlink journalling diff --git a/doc/mysql.txt b/doc/mysql.txt index f64cb52..f807ef8 100644 --- a/doc/mysql.txt +++ b/doc/mysql.txt @@ -38,6 +38,23 @@ Note, that mysql database should not contain any tables. Tests will not dare to drop database with data. +Additional configuration +======================== + +To initialise and use mysql database roundup' configuration file (config.py in +the tracker' home directory) should be appended with the following constants: + + MYSQL_DBHOST = 'localhost' + MYSQL_DBUSER = 'rounduptest' + MYSQL_DBPASSWORD = 'rounduptest' + MYSQL_DBNAME = 'rounduptest' + MYSQL_DATABASE = ( MYSQL_DBHOST, MYSQL_DBUSER, MYSQL_DBPASSWORD, MYSQL_DBNAME ) + +Fill first four constants with real values before running +"roundup-admin initialise". + + + Andrey Lebedev diff --git a/roundup/admin.py b/roundup/admin.py index 8dfde0d..e13ee77 100644 --- a/roundup/admin.py +++ b/roundup/admin.py @@ -16,7 +16,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: admin.py,v 1.36 2003-02-06 05:43:47 richard Exp $ +# $Id: admin.py,v 1.37 2003-02-15 23:19:01 kedder Exp $ '''Administration commands for maintaining Roundup trackers. ''' @@ -368,19 +368,31 @@ Command help: # make sure the tracker home is installed if not os.path.exists(tracker_home): raise UsageError, _('Instance home does not exist')%locals() - if not os.path.exists(os.path.join(tracker_home, 'html')): + try: + tracker = roundup.instance.open(tracker_home) + except roundup.instance.TrackerError: raise UsageError, _('Instance has not been installed')%locals() # is there already a database? - if os.path.exists(os.path.join(tracker_home, 'db')): + try: + db_exists = tracker.select_db.Database.exists(tracker.config) + except AttributeError: + # TODO: move this code to exists() static method in every backend + db_exists = os.path.exists(os.path.join(tracker_home, 'db')) + if db_exists: print _('WARNING: The database is already initialised!') print _('If you re-initialise it, you will lose all the data!') ok = raw_input(_('Erase it? Y/[N]: ')).strip() if ok.lower() != 'y': return 0 - # nuke it - shutil.rmtree(os.path.join(tracker_home, 'db')) + # Get a database backend in use by tracker + try: + # nuke it + tracker.select_db.Database.nuke(tracker.config) + except AttributeError: + # TODO: move this code to nuke() static method in every backend + shutil.rmtree(os.path.join(tracker_home, 'db')) # GO init.initialise(tracker_home, adminpw) diff --git a/roundup/backends/back_mysql.py b/roundup/backends/back_mysql.py index 7ff747f..ef3d538 100644 --- a/roundup/backends/back_mysql.py +++ b/roundup/backends/back_mysql.py @@ -11,8 +11,33 @@ from roundup.backends.rdbms_common import * from roundup.backends import rdbms_common import MySQLdb +import os, shutil from MySQLdb.constants import ER +class Maintenance: + """ Database maintenance functions """ + def db_nuke(self, config): + """Clear all database contents and drop database itself""" + db = Database(config, 'admin') + db.sql("DROP DATABASE %s" % config.MYSQL_DBNAME) + db.sql("CREATE DATABASE %s" % config.MYSQL_DBNAME) + if os.path.exists(config.DATABASE): + shutil.rmtree(config.DATABASE) + + def db_exists(self, config): + """Check if database already exists""" + # Yes, this is a hack, but we must must open connection without + # selecting a database to prevent creation of some tables + config.MYSQL_DATABASE = (config.MYSQL_DBHOST, config.MYSQL_DBUSER, config.MYSQL_DBPASSWORD) + db = Database(config, 'admin') + db.conn.select_db(config.MYSQL_DBNAME) + config.MYSQL_DATABASE = (config.MYSQL_DBHOST, config.MYSQL_DBUSER, config.MYSQL_DBPASSWORD, config.MYSQL_DBNAME) + db.sql("SHOW TABLES") + tables = db.sql_fetchall() + if tables or os.path.exists(config.DATABASE): + return 1 + return 0 + class Database(Database): arg = '%s' @@ -115,6 +140,10 @@ class Database(Database): print >>hyperdb.DEBUG, 'create_class', (self, sql) self.cursor.execute(sql) + # Static methods + nuke = Maintenance().db_nuke + exists = Maintenance().db_exists + class MysqlClass: def find(self, **propspec): '''Get the ids of nodes in this class which link to the given nodes. @@ -174,7 +203,7 @@ class MysqlClass: self.db.sql(query, vals) l += [x[0] for x in self.db.sql_fetchall()] if __debug__: - print >>hyperdb.DEBUG, 'find ... ', l #db.sql("DROP DATABASE %s" % config.MYSQL_DBNAME) + print >>hyperdb.DEBUG, 'find ... ', l # Remove duplicated ids d = {} @@ -191,9 +220,4 @@ class IssueClass(MysqlClass, rdbms_common.IssueClass): class FileClass(MysqlClass, rdbms_common.FileClass): pass -def nuke(config): - """ Clear all database contents and drop database itself""" - # Connect to db - db = Database(config, 'admin') - db.sql("DROP DATABASE %s" % config.MYSQL_DBNAME) - db.sql("CREATE DATABASE %s" % config.MYSQL_DBNAME) +#vim: set et diff --git a/test/test_db.py b/test/test_db.py index a582e65..62520a8 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: test_db.py,v 1.70 2003-02-15 14:26:38 kedder Exp $ +# $Id: test_db.py,v 1.71 2003-02-15 23:19:01 kedder Exp $ import unittest, os, shutil, time @@ -738,8 +738,7 @@ class mysqlDBTestCase(anydbmDBTestCase): def tearDown(self): from roundup.backends import mysql self.db.close() - mysql.nuke(config) - anydbmDBTestCase.tearDown(self) + mysql.Database.nuke(config) class mysqlReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): def setUp(self): @@ -754,8 +753,7 @@ class mysqlReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): def tearDown(self): from roundup.backends import mysql self.db.close() - mysql.nuke(config) - anydbmReadOnlyDBTestCase.tearDown(self) + mysql.Database.nuke(config) class sqliteDBTestCase(anydbmDBTestCase): def setUp(self): @@ -873,7 +871,7 @@ def suite(): if tables: # Database should be empty. We don't dare to delete any data raise DatabaseError, "(Database %s contains tables)" % config.MYSQL_DBNAME - db.sql("DROP DATABASE IF EXISTS %s" % config.MYSQL_DBNAME) + db.sql("DROP DATABASE %s" % config.MYSQL_DBNAME) db.sql("CREATE DATABASE %s" % config.MYSQL_DBNAME) db.close() except (MySQLdb.ProgrammingError, DatabaseError), msg: -- 2.39.5