source: watchlistplugin/0.12/tracwatchlist/db.py

Last change on this file was 15264, checked in by Ryan J Ollos, 8 years ago

Remove unnecessary svn:mime-type on py files

svn:mime-type was set to "plain" for many files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Date Author Rev URL
File size: 12.5 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3= Watchlist Plugin for Trac =
4Plugin Website:  http://trac-hacks.org/wiki/WatchlistPlugin
5Trac website:    http://trac.edgewall.org/
6
7Copyright (c) 2008-2010 by Martin Scharrer <martin@scharrer-online.de>
8All rights reserved.
9
10The i18n support was added by Steffen Hoffmann <hoff.st@web.de>.
11
12This program is free software: you can redistribute it and/or modify
13it under the terms of the GNU General Public License as published by
14the Free Software Foundation, either version 3 of the License, or
15(at your option) any later version.
16
17This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20GNU General Public License for more details.
21
22For a copy of the GNU General Public License see
23<http://www.gnu.org/licenses/>.
24
25$Id: db.py 15264 2016-02-11 04:22:34Z rjollos $
26"""
27
28__url__      = ur"$URL: //trac-hacks.org/svn/watchlistplugin/0.12/tracwatchlist/db.py $"[6:-2]
29__author__   = ur"$Author: rjollos $"[9:-2]
30__revision__ = int("0" + ur"$Rev: 15264 $"[6:-2].strip('M'))
31__date__     = ur"$Date: 2016-02-11 04:22:34 +0000 (Thu, 11 Feb 2016) $"[7:-2]
32
33from  trac.core  import  *
34from  trac.db    import  Table, Column, DatabaseManager
35from  trac.env   import  IEnvironmentSetupParticipant
36
37
38class WatchlistDataBaseUpgrader(Component):
39    """DataBase module for the Trac WatchlistPlugin.
40       Handles creation and upgrading of watchlist DB tables."""
41
42    implements( IEnvironmentSetupParticipant )
43
44    latest_version = 4
45
46    watchlist_table = Table('watchlist', key=['wluser','realm','resid'])[
47        Column('wluser'),
48        Column('realm'),
49        Column('resid'),
50        Column('lastvisit', type='int64'),
51    ]
52    settings_table = Table('watchlist_settings', key=['wluser','name'])[
53        Column('wluser'),
54        Column('name'),
55        Column('type'),
56        Column('settings'),
57    ]
58
59
60    def environment_created(self):
61        """Creates watchlist tables when a new Trac environment is created."""
62        db = self.env.get_db_cnx()
63        self.create_watchlist_table(db)
64        self.create_settings_table(db)
65        self.set_version(self.latest_version, db)
66        self.upgrade_manual()
67        return
68
69
70    def environment_needs_upgrade(self, db):
71        """Tests if watchlist tables must be upgraded."""
72        if not self.table_exists('watchlist', db):
73            return True
74        if not self.table_exists('watchlist_settings', db):
75            return True
76        version = self.get_version(db)
77        if version < self.latest_version:
78            return True
79        elif version > self.latest_version:
80            raise TracError("Watchlist DB table version newer than plug-in version")
81        return False
82
83
84    def upgrade_environment(self, db):
85        """Upgrades all watchlist tables to current version."""
86        # Commit now so that rollbacks do not affect any previous DB changes
87        db.commit()
88        old_version = self.get_version(db)
89        self.upgrade_watchlist_table(old_version, self.latest_version, db)
90        self.upgrade_settings_table (old_version, self.latest_version, db)
91        self.set_version(self.latest_version, db)
92        return
93
94
95    def upgrade_watchlist_table(self, old_version, new_version, db=None):
96        """Upgrades watchlist table to current version."""
97        self.log.info("Attempting upgrade of watchlist table from v%i to v%i" % (old_version,new_version))
98        db = db or self.env.get_db_cnx()
99        if not self.table_exists('watchlist', db):
100            self.create_watchlist_table(db)
101            return
102        if old_version == new_version:
103            return
104        try:
105            upgrader = getattr(self, 'upgrade_watchlist_table_from_v%i_to_v%i' % (old_version, new_version))
106        except AttributeError:
107            raise TracError("Requested watchlist table version " + unicode(new_version) + " not supported for upgrade")
108
109        upgrader(db)
110        return
111
112
113    def upgrade_settings_table(self, old_version, new_version, db=None):
114        """Upgrades watchlist_settings table to current version."""
115        self.log.info("Attempting upgrade of watchlist table from v%i to v%i" % (old_version,new_version))
116        db = db or self.env.get_db_cnx()
117
118        if not self.table_exists('watchlist_settings', db):
119            self.create_settings_table(db)
120            return
121
122        if old_version == new_version:
123            return
124
125        if old_version < 4:
126            self.upgrade_settings_table_to_v4(db)
127            old_version = 4
128            if new_version == 4:
129                return
130
131        # Code for future versions > 4
132        try:
133            upgrader = getattr(self, 'upgrade_settings_table_from_v%i_to_v%i' % (old_version, new_version))
134        except AttributeError:
135            raise TracError("Requested settings table version " + unicode(new_version) + " not supported for upgrade")
136
137        upgrader(db)
138        raise NotImplemented
139
140
141    def get_version(self, db=None):
142        """Returns watchlist table version from system table or 0 if not present."""
143        db = db or self.env.get_db_cnx()
144        cursor = db.cursor()
145        try:
146            cursor.execute("""
147                SELECT value
148                FROM system
149                WHERE name='watchlist_version'
150            """)
151            valuelist = cursor.fetchone()
152            return int(valuelist[0])
153        except (AttributeError, TypeError):
154            self.log.info("No value for 'watchlist_version' found in 'system' table")
155            return 0
156        except ValueError, e:
157            self.log.error("Invalid value found for 'watchlist_version' found in system table: " + unicode(e))
158            self.log.info("Value for 'watchlist_version' will be set to 0")
159            self.set_version(0, db)
160            return 0
161        except Exception, e:
162            db.rollback()
163            self.log.error("Unknown error when trying to read 'watchlist_version' from 'system' table: " + unicode(e))
164            self.log.info("Value for 'watchlist_version' will be set to 0")
165            self.set_version(0, db)
166            return 0
167
168
169    def set_version(self, version, db=None):
170        """Sets watchlist table version in the system table."""
171        try:
172            version = int(version)
173        except ValueError:
174            raise ValueError("Version must be an integer")
175        db = db or self.env.get_db_cnx()
176        cursor = db.cursor()
177        try:
178            cursor.execute("""
179                DELETE
180                FROM system
181                WHERE name='watchlist_version'
182            """)
183        except Exception as e:
184            db.rollback()
185            self.log.warn(unicode(e))
186        try:
187            cursor.execute("""
188                INSERT
189                INTO system (name,value)
190                VALUES ('watchlist_version',%s)
191            """, (unicode(version),) )
192        except Exception as e:
193            db.rollback()
194            self.log.error("Could not set watchlist_version: " + unicode(e))
195            raise
196        db.commit()
197        return
198
199
200    def create_watchlist_table(self, db=None):
201        db = db or self.env.get_db_cnx()
202        cursor = db.cursor()
203        db_connector, _ = DatabaseManager(self.env)._get_connector()
204        self.log.info("Creating 'watchlist' table in version " + unicode(self.latest_version))
205
206        for statement in db_connector.to_sql(self.watchlist_table):
207            cursor.execute(statement)
208        db.commit()
209        return
210
211
212    def create_settings_table(self, db=None):
213        db = db or self.env.get_db_cnx()
214        cursor = db.cursor()
215        db_connector, _ = DatabaseManager(self.env)._get_connector()
216        self.log.info("Creating 'watchlist_setting' table in version " + unicode(self.latest_version))
217
218        for statement in db_connector.to_sql(self.settings_table):
219            cursor.execute(statement)
220        db.commit()
221        return
222
223    def table_exists(self, table, db=None):
224        dburi = self.config.get('trac', 'database')
225        db = db or self.env.get_db_cnx()
226        cursor = db.cursor()
227        tables = self._get_tables(dburi, cursor)
228        if table in tables:
229            return True
230        return False  # This is a new installation.
231
232    def upgrade_watchlist_table_from_v0_to_v4(self, db=None):
233        self.upgrade_watchlist_table_to_v4('*', db)
234        return
235
236
237    def upgrade_watchlist_table_from_v1_to_v4(self, db=None):
238        self.upgrade_watchlist_table_to_v4('*', db)
239        return
240
241
242    def upgrade_watchlist_table_from_v2_to_v4(self, db=None):
243        """Upgrades watchlist table from v2 which has four columns.
244           The forth was 'notify' which was dropped again quickly."""
245        self.upgrade_watchlist_table_to_v4('wluser,realm,resid', db)
246        return
247
248
249    def upgrade_watchlist_table_from_v3_to_v4(self, db=None):
250        self.upgrade_watchlist_table_to_v4('*', db)
251        return
252
253
254    def upgrade_watchlist_table_to_v4(self, selection, db=None):
255        """Upgrade 'watchlist' table to v4. The data is copied into a temporary
256           table and then back into the newly created table."""
257        db = db or self.env.get_db_cnx()
258        cursor = db.cursor()
259        db_connector, _ = DatabaseManager(self.env)._get_connector()
260
261        # Temporary name for new watchlist table
262        new_table = self.watchlist_table
263        new_table.name = 'watchlist_new'
264
265        # Delete new table if it should exists because of a aborted previous upgrade attempt
266        try:
267            cursor.execute("DROP TABLE watchlist_new")
268        except:
269            db.rollback()
270            # Get new cursor
271            cursor = db.cursor()
272
273        # Create new table
274        for statement in db_connector.to_sql(new_table):
275            cursor.execute(statement)
276
277        # Copy existing data to it
278        cursor.execute("""
279            INSERT
280              INTO watchlist_new
281            SELECT DISTINCT %s
282              FROM watchlist
283        """ % selection)
284
285        # Delete only table
286        cursor.execute("""
287            DROP TABLE watchlist
288        """)
289
290        # Rename table
291        cursor.execute("""
292            ALTER TABLE watchlist_new
293              RENAME TO watchlist
294        """)
295
296        db.commit()
297        self.log.info("Upgraded 'watchlist' table to version 4")
298        return
299
300
301    def upgrade_settings_table_to_v4(self, db=None):
302        """Upgrades 'watchlist_settings' table to v4.
303           This table did not existed in v0-v2, so there is only v3
304           to handle."""
305        db = db or self.env.get_db_cnx()
306        cursor = db.cursor()
307        db_connector, _ = DatabaseManager(self.env)._get_connector()
308
309        # Delete new table if it should exists because of a aborted previous upgrade attempt
310        try:
311            cursor.execute("DROP TABLE watchlist_settings_new")
312        except:
313            db.rollback()
314            # Get new cursor
315            cursor = db.cursor()
316
317        # Temporary name for new watchlist_settings table
318        new_table = self.settings_table
319        new_table.name = 'watchlist_settings_new'
320
321        # Create new table
322        for statement in db_connector.to_sql(new_table):
323            cursor.execute(statement)
324
325        # Copy existing data to it
326        cursor.execute("""
327            INSERT
328              INTO watchlist_settings_new (wluser,settings)
329            SELECT DISTINCT wluser,settings
330              FROM watchlist_settings
331        """)
332
333        # Delete only table
334        cursor.execute("""
335            DROP TABLE watchlist_settings
336        """)
337
338        # Rename table
339        cursor.execute("""
340            ALTER TABLE watchlist_settings_new
341              RENAME TO watchlist_settings
342        """)
343
344        # Set new columns to default value
345        cursor.execute("""
346            UPDATE watchlist_settings
347               SET name='booloptions', type='ListOfBool'
348        """)
349
350        db.commit()
351        self.log.info("Upgraded 'watchlist_settings' table to version 4")
352        return
353
354    def _get_tables(self, dburi, cursor):
355        """Code from TracMigratePlugin by Jun Omae (see tracmigrate.admin)."""
356        if dburi.startswith('sqlite:'):
357            sql = """
358                SELECT name
359                  FROM sqlite_master
360                 WHERE type='table'
361                   AND NOT name='sqlite_sequence'
362            """
363        elif dburi.startswith('postgres:'):
364            sql = """
365                SELECT tablename
366                  FROM pg_tables
367                 WHERE schemaname = ANY (current_schemas(false))
368            """
369        elif dburi.startswith('mysql:'):
370            sql = "SHOW TABLES"
371        else:
372            raise TracError('Unsupported database type "%s"'
373                            % dburi.split(':')[0])
374        cursor.execute(sql)
375        return sorted([row[0] for row in cursor])
376
377# EOF
Note: See TracBrowser for help on using the repository browser.