Merge lp:~j-corwin/openlp/migration into lp:openlp

Proposed by Jonathan Corwin
Status: Merged
Merged at revision: not available
Proposed branch: lp:~j-corwin/openlp/migration
Merge into: lp:openlp
Diff against target: 270 lines (+217/-11)
2 files modified
openlp/migration/migratebibles.py (+196/-2)
openlpcnv.pyw (+21/-9)
To merge this branch: bzr merge lp:~j-corwin/openlp/migration
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Raoul Snyman Approve
Review via email: mp+21883@code.launchpad.net

This proposal supersedes a proposal from 2010-03-22.

Description of the change

Attempt to get Bible migration working for Windows. Done it via openlpcnv, rather than bible-1to2-converter which borks on the "import sqlite" on Windows.

Not entirely sure what I was doing in migratebibles, just copying from migratesongs and hoping for the best, so criticism expected, hopefully constructive!

Used an insert statement for the verses, since doing it the same as everything else was far too slow to be practical and I don't know sqlalchemy so didn't know what alternatives I had.

To post a comment you must log in.
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

The openlpcnv.pyw is a hack at best, and the code from bible-1to2-converter.py is used in an online migration tool I am writing.

The reason the bible-1to2-converter.py script borks on Windows is because that module does not exist, and it requires a full edition of Visual C++ in order to compile (I tried it with the express edition, but it doesn't have one particular tool required in the linking process). I mostly created those two 1to2 scripts for our use as developers to easily convert 1.x stuff to 2.

Personally, I think that the online conversion tool should be the official upgrade tool, it would allow folks to upgrade without needing to install anything else on their computers. Of course folks are welcome to bring their own ideas to the table, but to me an online converter makes the most sense.

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

self.data_path + os.sep + database => os.path.join(self.data_path, database)

It's no wonder your SQLAlchemy models took FOREVER to run through, you were committing after every insert. Just commit a chapter at a time, or all of it at the end, not a verse at a time.

review: Needs Fixing
Revision history for this message
Jonathan Corwin (j-corwin) wrote : Posted in a previous version of this proposal

Hmm, only committed after every insert since I blindly copied the song code that was committing after every song. I'll try moving things around tonigt and see what difference is makes.

I have full Visual Studio 2003, so if you point me to what needs building to get the -1to2- script working, I'll take a look.

Although the online converter will be good for some, it relies on
1. An internet connection. Many churches in the UK think they are cutting edge if they have running hot water. Broadband is a thing of luxury!
2. Someone operating it who is capable of finding the application data folder and work out which files they need to upload.
3. Also you might find one person somewhere who is overly paranoid about copyright and not want to upload their songs to a website for conversion for ethic/moral reasons!

Revision history for this message
Jonathan Corwin (j-corwin) wrote : Posted in a previous version of this proposal

Moved the commit, makes quite a difference!

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Please just fix up the conflict. You probably need to just do a merge from trunk into your branch and resolve the conflict there, and then propose the merge again.

review: Needs Fixing
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Much better. You could probably still optimise your SQL by grouping a few of those other queries, but the main ones are covered.

review: Approve
Revision history for this message
Raoul Snyman (raoul-snyman) :
review: Approve
Revision history for this message
Tim Bentley (trb143) wrote :

Approved

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/migration/migratebibles.py'
2--- openlp/migration/migratebibles.py 2010-03-21 23:58:01 +0000
3+++ openlp/migration/migratebibles.py 2010-03-22 20:02:14 +0000
4@@ -23,10 +23,204 @@
5 # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
6 ###############################################################################
7
8+import os
9+import sys
10+import sqlite3
11+
12+from sqlalchemy import *
13+from sqlalchemy import create_engine
14+from sqlalchemy.orm import scoped_session, sessionmaker, mapper, relation
15+
16+from openlp.core.lib import PluginConfig
17+from openlp.plugins.bibles.lib.models import *
18+
19+class BaseModel(object):
20+ """
21+ BaseModel provides a base object with a set of generic functions
22+ """
23+
24+ @classmethod
25+ def populate(cls, **kwargs):
26+ """
27+ Creates an instance of a class and populates it, returning the instance
28+ """
29+ me = cls()
30+ keys = kwargs.keys()
31+ for key in keys:
32+ me.__setattr__(key, kwargs[key])
33+ return me
34+
35+class TBibleMeta(BaseModel):
36+ """
37+ Bible Meta Data
38+ """
39+ pass
40+
41+class TTestament(BaseModel):
42+ """
43+ Bible Testaments
44+ """
45+ pass
46+
47+class TBook(BaseModel):
48+ """
49+ Song model
50+ """
51+ pass
52+
53+class TVerse(BaseModel):
54+ """
55+ Topic model
56+ """
57+ pass
58+
59+temp_meta_table = Table(u'metadata_temp', metadata,
60+ Column(u'key', types.Unicode(255), primary_key=True),
61+ Column(u'value', types.Unicode(255)),
62+)
63+temp_testament_table = Table(u'testament_temp', metadata,
64+ Column(u'id', types.Integer, primary_key=True),
65+ Column(u'name', types.Unicode(30)),
66+)
67+temp_book_table = Table(u'book_temp', metadata,
68+ Column(u'id', types.Integer, primary_key=True),
69+ Column(u'testament_id', types.Integer),
70+ Column(u'name', types.Unicode(30)),
71+ Column(u'abbreviation', types.Unicode(5)),
72+)
73+temp_verse_table = Table(u'verse_temp', metadata,
74+ Column(u'id', types.Integer, primary_key=True),
75+ Column(u'book_id', types.Integer),
76+ Column(u'chapter', types.Integer),
77+ Column(u'verse', types.Integer),
78+ Column(u'text', types.UnicodeText),
79+)
80+
81+mapper(TBibleMeta, temp_meta_table)
82+mapper(TTestament, temp_testament_table)
83+mapper(TBook, temp_book_table)
84+mapper(TVerse, temp_verse_table)
85+
86+def init_models(url):
87+ engine = create_engine(url)
88+ metadata.bind = engine
89+ session = scoped_session(sessionmaker(autoflush=False,
90+ autocommit=False, bind=engine))
91+ return session
92+
93 class MigrateBibles():
94 def __init__(self, display):
95 self.display = display
96+ self.config = PluginConfig(u'Bibles')
97+ self.data_path = self.config.get_data_path()
98+ self.database_files = self.config.get_files(u'sqlite')
99+ print self.database_files
100+
101+ def progress(self, text):
102+ print text
103+ self.display.output(text)
104
105 def process(self):
106- self.display.output(u'Bible process started')
107- self.display.output(u'Bible process finished')
108+ self.progress(u'Bibles processing started')
109+ for f in self.database_files:
110+ self.v_1_9_0(f)
111+ self.progress(u'Bibles processing finished')
112+
113+ def v_1_9_0(self, database):
114+ self.progress(u'Migration 1.9.0 Started for ' + database)
115+ self._v1_9_0_old(database)
116+ self._v1_9_0_new(database)
117+ self._v1_9_0_cleanup(database)
118+ self.progress(u'Migration 1.9.0 Finished for ' + database)
119+
120+ def _v1_9_0_old(self, database):
121+ self.progress(u'Rename Tables ' + database)
122+ conn = sqlite3.connect(os.path.join(self.data_path, database))
123+ conn.execute(u'alter table book rename to book_temp;')
124+ conn.commit()
125+ conn.execute(u'alter table testament rename to testament_temp;')
126+ conn.commit()
127+ conn.execute(u'alter table verse rename to verse_temp;')
128+ conn.commit()
129+ conn.execute(u'alter table metadata rename to metadata_temp;')
130+ conn.commit()
131+
132+ def _v1_9_0_new(self, database):
133+ self.progress(u'Create new Tables ' + database)
134+ self.db_url = u'sqlite:///' + self.data_path + u'/' + database
135+ print self.db_url
136+ self.session = init_models(self.db_url)
137+ metadata.create_all(checkfirst=True)
138+ self.progress(u'Create testament table')
139+ results = self.session.query(TTestament).order_by(TTestament.id).all()
140+ for testament_temp in results:
141+ testament = Testament()
142+ testament.id = testament_temp.id
143+ testament.name = testament_temp.name
144+ try:
145+ self.session.add(testament)
146+ self.session.commit()
147+ except:
148+ self.session.rollback()
149+ print u'Error thrown = ', sys.exc_info()[1]
150+ self.progress(u'Create book table')
151+ results = self.session.query(TBook).order_by(TBook.id).all()
152+ for book_temp in results:
153+ book = Book()
154+ book.id = book_temp.id
155+ book.testament_id = book_temp.testament_id
156+ book.name = book_temp.name
157+ book.abbreviation = book_temp.abbreviation
158+ try:
159+ self.session.add(book)
160+ self.session.commit()
161+ except:
162+ self.session.rollback()
163+ print u'Error thrown = ', sys.exc_info()[1]
164+ self.progress(u'Create verse table')
165+ results = self.session.query(TVerse).order_by(TVerse.id).all()
166+ for verse_temp in results:
167+ verse = Verse()
168+ verse.id = verse_temp.id
169+ verse.book_id = verse_temp.book_id
170+ verse.chapter = verse_temp.chapter
171+ verse.verse = verse_temp.verse
172+ verse.text = verse_temp.text
173+ try:
174+ self.session.add(verse)
175+ except:
176+ self.session.rollback()
177+ print u'Error thrown = ', sys.exc_info()[1]
178+ try:
179+ self.session.commit()
180+ except:
181+ self.session.rollback()
182+ print u'Error thrown = ', sys.exc_info()[1]
183+ self.progress(u'Create metadata table')
184+ results = self.session.query(TBibleMeta).order_by(TBibleMeta.key).all()
185+ for biblemeta_temp in results:
186+ biblemeta = BibleMeta()
187+ biblemeta.key = biblemeta_temp.key
188+ biblemeta.value = biblemeta_temp.value
189+ try:
190+ self.session.add(biblemeta)
191+ self.session.commit()
192+ except:
193+ self.session.rollback()
194+ print u'Error thrown = ', sys.exc_info()[1]
195+
196+ def _v1_9_0_cleanup(self, database):
197+ self.progress(u'Update Internal Data ' + database)
198+ conn = sqlite3.connect(os.path.join(self.data_path, database))
199+ conn.commit()
200+ conn.execute(u'drop table book_temp;')
201+ conn.commit()
202+ conn.execute(u'drop table testament_temp;')
203+ conn.commit()
204+ conn.execute(u'drop table verse_temp;')
205+ conn.commit()
206+ conn.execute(u'drop table metadata_temp;')
207+ conn.commit()
208+ conn.execute(u'vacuum;')
209+ conn.commit()
210+
211
212=== modified file 'openlpcnv.pyw'
213--- openlpcnv.pyw 2010-03-21 23:58:01 +0000
214+++ openlpcnv.pyw 2010-03-22 20:02:14 +0000
215@@ -70,7 +70,7 @@
216 """
217 #MigrateFiles(self.display).process()
218 MigrateSongs(self.display).process()
219- #MigrateBibles(self.display).process()
220+ MigrateBibles(self.display).process()
221
222 def move_log_file(self):
223 """
224@@ -101,6 +101,7 @@
225 writefile.close()
226
227 def convert_sqlite2_to_3(self, olddb, newdb):
228+ print u'Converting sqlite2 ' + olddb + ' to sqlite3 ' + newdb
229 if os.name == u'nt':
230 # we can't make this a raw unicode string as the \U within it causes much confusion
231 hKey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, u'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\SQLite ODBC Driver')
232@@ -132,19 +133,30 @@
233
234 if __name__ == u'__main__':
235 mig = Migration()
236- config = PluginConfig(u'Songs')
237- newpath = config.get_data_path()
238+ songconfig = PluginConfig(u'Songs')
239+ newsongpath = songconfig.get_data_path()
240+ bibleconfig = PluginConfig(u'Bibles')
241+ newbiblepath = bibleconfig.get_data_path()
242 if os.name == u'nt':
243- if not os.path.isdir(newpath):
244- os.makedirs(newpath)
245+ if not os.path.isdir(newsongpath):
246+ os.makedirs(newsongpath)
247+ if not os.path.isdir(newbiblepath):
248+ os.makedirs(newbiblepath)
249 ALL_USERS_APPLICATION_DATA = 35
250 shell = Dispatch(u'Shell.Application')
251 folder = shell.Namespace(ALL_USERS_APPLICATION_DATA)
252 folderitem = folder.Self
253- olddb = os.path.join(folderitem.path, u'openlp.org', u'Data', u'songs.olp')
254+ oldsongdb = os.path.join(folderitem.path, u'openlp.org', u'Data', u'songs.olp')
255+ oldbiblepath = os.path.join(folderitem.path, u'openlp.org', u'Data', u'Bibles')
256 else:
257- olddb = os.path.join(newpath, u'songs.olp')
258- newdb = os.path.join(newpath, u'songs.sqlite')
259- mig.convert_sqlite2_to_3(olddb, newdb)
260+ oldsongdb = os.path.join(newsongpath, u'songs.olp')
261+ newsongdb = os.path.join(newsongpath, u'songs.sqlite')
262+ mig.convert_sqlite2_to_3(oldsongdb, newsongdb)
263+ files = os.listdir(oldbiblepath)
264+ for file in files:
265+ f = os.path.splitext(os.path.basename(file))[0]
266+ if f != 'kjv': #kjv bible has an autoincrement key not supported in sqlite3
267+ mig.convert_sqlite2_to_3(os.path.join(oldbiblepath, file),
268+ os.path.join(newbiblepath, f + u'.sqlite'))
269 mig.process()
270 #mig.move_log_file()