Author: jure
Date: Fri Mar 29 12:30:01 2013
New Revision: 1462457

URL: http://svn.apache.org/r1462457
Log:
#406, database upgrade now migrates system wikis to all products (+global 
context)


Modified:
    
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py

Modified: 
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py?rev=1462457&r1=1462456&r2=1462457&view=diff
==============================================================================
--- 
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py
 (original)
+++ 
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py
 Fri Mar 29 12:30:01 2013
@@ -19,6 +19,7 @@
 """Core components to support multi-product"""
 
 import copy
+import os
 
 from genshi.builder import tag, Element
 from genshi.core import escape, Markup, unescape
@@ -31,12 +32,11 @@ from trac.env import IEnvironmentSetupPa
 from trac.perm import IPermissionRequestor, PermissionCache
 from trac.resource import IResourceManager
 from trac.ticket.api import ITicketFieldProvider
-from trac.util.text import to_unicode, unquote_label
+from trac.util.text import to_unicode, unquote_label, unicode_unquote
 from trac.util.translation import _, N_
 from trac.web.chrome import ITemplateProvider
 from trac.web.main import FakePerm, FakeSession
 from trac.wiki.api import IWikiSyntaxProvider
-from trac.wiki.formatter import LinkFormatter
 from trac.wiki.parser import WikiParser
 from trac.resource import IResourceChangeListener
 
@@ -149,6 +149,49 @@ class MultiProductSystem(Component):
                 """  % (DB_SYSTEM_KEY, version))
         return version
 
+
+    _system_wiki_list = None
+    @property
+    def system_wiki_list(self):
+        if MultiProductSystem._system_wiki_list is None:
+            MultiProductSystem._system_wiki_list = self._get_system_wiki_list()
+        return MultiProductSystem._system_wiki_list
+
+    def _get_system_wiki_list(self):
+        """Helper function that enumerates all 'system' wikis. The
+        list is combined of default wiki pages and pages that are
+        bundled with Bloodhound dashboard and search plugins"""
+        from bhdashboard import wiki
+
+        paths = [resource_filename('trac.wiki',
+                                   'default-pages')] + \
+                [resource_filename('bhdashboard',
+                                   'default-pages')] + \
+                [resource_filename('bhsearch',
+                                   'default-pages')]
+        pages = []
+        original_pages = []
+        for path in paths:
+            for page in os.listdir(path):
+                filename = os.path.join(path, page)
+                page = unicode_unquote(page.encode('utf-8'))
+                if os.path.isfile(filename):
+                    original_pages.append(page)
+        for original_name in original_pages:
+            if original_name.startswith('Trac'):
+                new_name = wiki.new_name(original_name)
+                if not new_name:
+                    continue
+                if new_name in original_pages:
+                    continue
+                name = new_name
+                # original trac wikis should also be included in the list
+                pages.append(original_name)
+            else:
+                name = original_name
+            pages.append(name)
+        return pages
+
     def upgrade_environment(self, db_dummy=None):
         """Installs or updates tables to current version"""
         self.log.debug("upgrading existing environment for %s plugin." % 
@@ -178,6 +221,28 @@ class MultiProductSystem(Component):
                 from multiproduct.model import Product
                 import trac.db_default
 
+                def create_temp_table(table):
+                    """creates temporary table with the new schema and
+                    drops original table"""
+                    table_temp_name = '%s_temp' % table
+                    if table == 'report':
+                        cols = ','.join([c for c in table_columns[table] if c 
!= 'id'])
+                    else:
+                        cols = ','.join(table_columns[table])
+                    self.log.info("Migrating table '%s' to a new schema", 
table)
+                    db("""CREATE TABLE %s AS SELECT %s FROM %s""" %
+                          (table_temp_name, cols, table))
+                    db("""DROP TABLE %s""" % table)
+                    db_connector, _ = 
DatabaseManager(self.env)._get_connector()
+                    table_schema = [t for t in table_defs if t.name == 
table][0]
+                    for sql in db_connector.to_sql(table_schema):
+                        db(sql)
+                    return table_temp_name, cols
+
+                def drop_temp_table(table):
+                    """drops specified temporary table"""
+                    db("""DROP TABLE %s""" % table)
+
                 TICKET_TABLES = ['ticket_change', 'ticket_custom',
                                  'attachment',
                                 ]
@@ -201,63 +266,32 @@ class MultiProductSystem(Component):
                     table_columns[table.name] = [c for c in [column.name for 
column in
                                                                 [t for t in 
table_defs if t.name == table.name][0].columns]
                                                                     if c != 
'product']
+                # create default product
                 self.log.info("Creating default product")
-                db("INSERT INTO bloodhound_product (prefix, name, description, 
owner) " \
-                   "VALUES ('%s', '%s', '%s', '')" % (DEFAULT_PRODUCT, 
'Default', 'Default product'))
-
+                db("""INSERT INTO bloodhound_product (prefix, name, 
description, owner)
+                      VALUES ('%s', '%s', '%s', '')""" %
+                      (DEFAULT_PRODUCT, 'Default', 'Default product'))
+
+                # fetch all products
+                all_products = Product.select(self.env)
+
+                # migrate tickets that don't have product assigned to default 
product
+                # - update ticket table product column
+                # - update ticket related tables by:
+                #   - upgrading schema
+                #   - update product column to match ticket's product
                 self.log.info("Migrating tickets w/o product to default 
product")
                 db("""UPDATE ticket SET product='%s'
-                        WHERE product=''""" % DEFAULT_PRODUCT)
-
-                def create_temp_table(table):
-                    table_temp_name = '%s_temp' % table
-                    if table == 'report':
-                        cols = ','.join([c for c in table_columns[table] if c 
!= 'id'])
-                    else:
-                        cols = ','.join(table_columns[table])
-                    self.log.info("Migrating table '%s' to a new schema", 
table)
-                    db("CREATE TABLE %s AS SELECT %s FROM %s" %
-                       (table_temp_name, cols, table))
-                    db("DROP TABLE %s" % table)
-                    db_connector, _ = 
DatabaseManager(self.env)._get_connector()
-                    table_schema = [t for t in table_defs if t.name == 
table][0]
-                    for sql in db_connector.to_sql(table_schema):
-                        db(sql)
-                    return table_temp_name, cols
-
-                def drop_temp_table(table):
-                    db("DROP TABLE %s" % table)
-
-                self.log.info("Migrating system tables to a new schema")
-                for table in self.MIGRATE_TABLES:
-                    temp_table_name, cols = create_temp_table(table)
-                    if table == 'wiki':
-                        self.log.info("Migrating wiki to default product")
-                        db("INSERT INTO %s (%s, product) SELECT %s,'%s' FROM 
%s" %
-                           (table, cols, cols, DEFAULT_PRODUCT, 
temp_table_name))
-                    else:
-                        products = Product.select(self.env)
-                        for product in products:
-                            self.log.info("Populating table '%s' for product 
'%s' ('%s')",
-                                          table, product.name, product.prefix)
-                            db("INSERT INTO %s (%s, product) SELECT %s,'%s' 
FROM %s" %
-                                (table, cols, cols, product.prefix, 
temp_table_name))
-                    if table == 'permission':
-                        self.log.info("Populating table '%s' for global 
scope", table)
-                        db("INSERT INTO %s (%s, product) SELECT %s,'%s' FROM 
%s" %
-                           (table, cols, cols, '', temp_table_name))
-                    drop_temp_table(temp_table_name)
+                      WHERE product=''""" % DEFAULT_PRODUCT)
 
-                # Update ticket related tables
-                # Upgrade schema
                 self.log.info("Migrating ticket tables to a new schema")
                 for table in TICKET_TABLES:
                     temp_table_name, cols = create_temp_table(table)
-                    db("INSERT INTO %s (%s, product) SELECT %s,'' FROM %s" %
-                       (table, cols, cols, temp_table_name))
+                    db("""INSERT INTO %s (%s, product)
+                          SELECT %s, '' FROM %s""" %
+                          (table, cols, cols, temp_table_name))
                     drop_temp_table(temp_table_name)
 
-                # Update product column based on ticket product
                 for table in TICKET_TABLES:
                     if table == 'attachment':
                         db("""UPDATE attachment
@@ -267,16 +301,68 @@ class MultiProductSystem(Component):
                         db("""UPDATE %s
                               SET product=(SELECT ticket.product FROM ticket 
WHERE ticket.id=%s.ticket)""" %
                            (table, table))
+
+                # migrate system table (except wiki which is handled 
separately) to a
+                # new schema
+                # - create tables with the new schema
+                # - populate system tables with global configuration for each 
product
+                # - exception is permission table where permissions are also 
populated in
+                #   global scope
+                self.log.info("Migrating system tables to a new schema")
+                for table in self.MIGRATE_TABLES:
+                    if table == 'wiki':
+                        continue
+                    temp_table_name, cols = create_temp_table(table)
+                    for product in all_products:
+                        self.log.info("Populating table '%s' for product '%s' 
('%s')",
+                                      table, product.name, product.prefix)
+                        db("""INSERT INTO %s (%s, product) SELECT %s,'%s' FROM 
%s""" %
+                              (table, cols, cols, product.prefix, 
temp_table_name))
+                    if table == 'permission':
+                        self.log.info("Populating table '%s' for global 
scope", table)
+                        db("""INSERT INTO %s (%s, product) SELECT %s,'%s' FROM 
%s""" %
+                              (table, cols, cols, '', temp_table_name))
+                    drop_temp_table(temp_table_name)
+
+                # migrate wiki table
+                # - populate system wikis to all products + global scope
+                # - update wiki attachment product to match wiki product
+                table = 'wiki'
+                temp_table_name, cols = create_temp_table(table)
+                self.log.info("Migrating wikis to global context")
+                db("""INSERT INTO %s (%s, product) SELECT %s, '' FROM %s""" %
+                      (table, cols, cols, temp_table_name))
+                for wiki_name, wiki_version, wiki_product in db("SELECT name, 
version, product FROM '%s'" % table):
+                    if wiki_name in self.system_wiki_list:
+                        for product in all_products:
+                            self.log.info("Adding wiki page '%s' to product 
'%s'",
+                                          wiki_name, product.prefix)
+                            db("""INSERT INTO %s (%s, product)
+                                  SELECT %s, '%s' FROM %s
+                                  WHERE name='%s' AND version=%s AND 
product='%s'""" %
+                                  (table, cols, cols, product.prefix, table,
+                                   wiki_name, wiki_version, wiki_product))
+                    else:
+                        self.log.info("Moving wiki page '%s' to default 
product", wiki_name)
+                        db("""UPDATE wiki
+                              SET product='%s'
+                              WHERE name='%s' AND version=%s AND 
product='%s'""" %
+                              (DEFAULT_PRODUCT,
+                               wiki_name, wiki_version, wiki_product))
+                drop_temp_table(temp_table_name)
+
                 db("""UPDATE attachment
                       SET product=(SELECT wiki.product FROM wiki WHERE 
wiki.name=attachment.id)
                       WHERE type='wiki'""")
 
                 # soft link existing repositories to default product
                 repositories_linked = []
-                for id, name in db("""SELECT id, value FROM repository WHERE 
name='name'"""):
+                for id, name in db("""SELECT id, value FROM repository
+                                      WHERE name='name'"""):
                     if id in repositories_linked:
                         continue
-                    db("""INSERT INTO repository (id, name, value) VALUES (%s, 
'product', '%s')""" %
+                    db("""INSERT INTO repository (id, name, value)
+                          VALUES (%s, 'product', '%s')""" %
                        (id, DEFAULT_PRODUCT))
                     repositories_linked.append(id)
                     self.log.info("Repository '%s' (%s) soft linked to default 
product", name, id)
@@ -286,7 +372,8 @@ class MultiProductSystem(Component):
                 self.log.info("Migrating system tables to a new schema")
                 for table in SYSTEM_TABLES:
                     temp_table_name, cols = create_temp_table(table)
-                    db("INSERT INTO %s (%s, product) SELECT %s,'' FROM %s" %
+                    db("""INSERT INTO %s (%s, product)
+                          SELECT %s,'' FROM %s""" %
                        (table, cols, cols, temp_table_name))
                     drop_temp_table(temp_table_name)
 


Reply via email to