Merge lp:~raoul-snyman/openlp/db-upgrades into lp:openlp
- db-upgrades
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Andreas Preikschat |
Approved revision: | 1725 |
Merged at revision: | 1721 |
Proposed branch: | lp:~raoul-snyman/openlp/db-upgrades |
Merge into: | lp:openlp |
Diff against target: |
397 lines (+181/-37) 6 files modified
openlp/core/lib/db.py (+81/-5) openlp/plugins/songs/lib/db.py (+15/-26) openlp/plugins/songs/lib/upgrade.py (+77/-0) openlp/plugins/songs/songsplugin.py (+3/-2) resources/debian/debian/control (+1/-1) scripts/check_dependencies.py (+4/-3) |
To merge this branch: | bzr merge lp:~raoul-snyman/openlp/db-upgrades |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andreas Preikschat (community) | Approve | ||
Tim Bentley | Approve | ||
Review via email: mp+72953@code.launchpad.net |
This proposal supersedes a proposal from 2011-08-25.
Commit message
- Implemented a seamless database upgrade system.
- Added the first upgrade as a demonstration.
- Added database version check so that newer version databases are not loaded.
Description of the change
Database upgrade system.
1. Create a module to use for upgrading.
2. from migrate import changeset
3. Define some default tables, which use reflection, in an "upgrade_setup()" function.
4. Write your upgrade functions named "upgrade_X()" where X is the version number.
5. Write your upgrade statements using the extended methods from Migrate.
6. Make sure the DB manager object knows about the upgrade module.
Done!
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Tim Bentley (trb143) : Posted in a previous version of this proposal | # |
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
Works for me.
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
You need to add the dependency to the scripts/
Please add docstrings to upgrade_1. It would be good if we document the "database history" and when we changed things.
Tim Bentley (trb143) : | # |
Andreas Preikschat (googol-deactivatedaccount) : | # |
Preview Diff
1 | === modified file 'openlp/core/lib/db.py' | |||
2 | --- openlp/core/lib/db.py 2011-08-16 19:53:52 +0000 | |||
3 | +++ openlp/core/lib/db.py 2011-08-25 20:16:24 +0000 | |||
4 | @@ -31,11 +31,13 @@ | |||
5 | 31 | import os | 31 | import os |
6 | 32 | 32 | ||
7 | 33 | from PyQt4 import QtCore | 33 | from PyQt4 import QtCore |
11 | 34 | from sqlalchemy import create_engine, MetaData | 34 | from sqlalchemy import Table, MetaData, Column, types, create_engine |
12 | 35 | from sqlalchemy.exc import InvalidRequestError | 35 | from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError |
13 | 36 | from sqlalchemy.orm import scoped_session, sessionmaker | 36 | from sqlalchemy.orm import scoped_session, sessionmaker, mapper |
14 | 37 | from sqlalchemy.pool import NullPool | 37 | from sqlalchemy.pool import NullPool |
15 | 38 | 38 | ||
16 | 39 | from openlp.core.lib import translate | ||
17 | 40 | from openlp.core.lib.ui import critical_error_message_box | ||
18 | 39 | from openlp.core.utils import AppLocation, delete_file | 41 | from openlp.core.utils import AppLocation, delete_file |
19 | 40 | 42 | ||
20 | 41 | log = logging.getLogger(__name__) | 43 | log = logging.getLogger(__name__) |
21 | @@ -59,6 +61,48 @@ | |||
22 | 59 | autocommit=auto_commit, bind=engine)) | 61 | autocommit=auto_commit, bind=engine)) |
23 | 60 | return session, metadata | 62 | return session, metadata |
24 | 61 | 63 | ||
25 | 64 | |||
26 | 65 | def upgrade_db(url, upgrade): | ||
27 | 66 | """ | ||
28 | 67 | Upgrade a database. | ||
29 | 68 | |||
30 | 69 | ``url`` | ||
31 | 70 | The url of the database to upgrade. | ||
32 | 71 | |||
33 | 72 | ``upgrade`` | ||
34 | 73 | The python module that contains the upgrade instructions. | ||
35 | 74 | """ | ||
36 | 75 | session, metadata = init_db(url) | ||
37 | 76 | tables = upgrade.upgrade_setup(metadata) | ||
38 | 77 | metadata_table = Table(u'metadata', metadata, | ||
39 | 78 | Column(u'key', types.Unicode(64), primary_key=True), | ||
40 | 79 | Column(u'value', types.UnicodeText(), default=None) | ||
41 | 80 | ) | ||
42 | 81 | metadata_table.create(checkfirst=True) | ||
43 | 82 | mapper(Metadata, metadata_table) | ||
44 | 83 | version_meta = session.query(Metadata).get(u'version') | ||
45 | 84 | if version_meta is None: | ||
46 | 85 | version_meta = Metadata.populate(key=u'version', value=u'0') | ||
47 | 86 | version = 0 | ||
48 | 87 | else: | ||
49 | 88 | version = int(version_meta.value) | ||
50 | 89 | if version > upgrade.__version__: | ||
51 | 90 | return version, upgrade.__version__ | ||
52 | 91 | version += 1 | ||
53 | 92 | while hasattr(upgrade, u'upgrade_%d' % version): | ||
54 | 93 | log.debug(u'Running upgrade_%d', version) | ||
55 | 94 | try: | ||
56 | 95 | getattr(upgrade, u'upgrade_%d' % version)(session, metadata, tables) | ||
57 | 96 | version_meta.value = unicode(version) | ||
58 | 97 | except SQLAlchemyError, DBAPIError: | ||
59 | 98 | log.exception(u'Could not run database upgrade script "upgrade_%s"'\ | ||
60 | 99 | ', upgrade process has been halted.', version) | ||
61 | 100 | break | ||
62 | 101 | version += 1 | ||
63 | 102 | session.add(version_meta) | ||
64 | 103 | session.commit() | ||
65 | 104 | return int(version_meta.value), upgrade.__version__ | ||
66 | 105 | |||
67 | 62 | def delete_database(plugin_name, db_file_name=None): | 106 | def delete_database(plugin_name, db_file_name=None): |
68 | 63 | """ | 107 | """ |
69 | 64 | Remove a database file from the system. | 108 | Remove a database file from the system. |
70 | @@ -79,6 +123,7 @@ | |||
71 | 79 | AppLocation.get_section_data_path(plugin_name), plugin_name) | 123 | AppLocation.get_section_data_path(plugin_name), plugin_name) |
72 | 80 | return delete_file(db_file_path) | 124 | return delete_file(db_file_path) |
73 | 81 | 125 | ||
74 | 126 | |||
75 | 82 | class BaseModel(object): | 127 | class BaseModel(object): |
76 | 83 | """ | 128 | """ |
77 | 84 | BaseModel provides a base object with a set of generic functions | 129 | BaseModel provides a base object with a set of generic functions |
78 | @@ -94,11 +139,19 @@ | |||
79 | 94 | return instance | 139 | return instance |
80 | 95 | 140 | ||
81 | 96 | 141 | ||
82 | 142 | class Metadata(BaseModel): | ||
83 | 143 | """ | ||
84 | 144 | Provides a class for the metadata table. | ||
85 | 145 | """ | ||
86 | 146 | pass | ||
87 | 147 | |||
88 | 148 | |||
89 | 97 | class Manager(object): | 149 | class Manager(object): |
90 | 98 | """ | 150 | """ |
91 | 99 | Provide generic object persistence management | 151 | Provide generic object persistence management |
92 | 100 | """ | 152 | """ |
94 | 101 | def __init__(self, plugin_name, init_schema, db_file_name=None): | 153 | def __init__(self, plugin_name, init_schema, db_file_name=None, |
95 | 154 | upgrade_mod=None): | ||
96 | 102 | """ | 155 | """ |
97 | 103 | Runs the initialisation process that includes creating the connection | 156 | Runs the initialisation process that includes creating the connection |
98 | 104 | to the database and the tables if they don't exist. | 157 | to the database and the tables if they don't exist. |
99 | @@ -109,6 +162,9 @@ | |||
100 | 109 | ``init_schema`` | 162 | ``init_schema`` |
101 | 110 | The init_schema function for this database | 163 | The init_schema function for this database |
102 | 111 | 164 | ||
103 | 165 | ``upgrade_schema`` | ||
104 | 166 | The upgrade_schema function for this database | ||
105 | 167 | |||
106 | 112 | ``db_file_name`` | 168 | ``db_file_name`` |
107 | 113 | The file name to use for this database. Defaults to None resulting | 169 | The file name to use for this database. Defaults to None resulting |
108 | 114 | in the plugin_name being used. | 170 | in the plugin_name being used. |
109 | @@ -134,7 +190,27 @@ | |||
110 | 134 | unicode(settings.value(u'db hostname').toString()), | 190 | unicode(settings.value(u'db hostname').toString()), |
111 | 135 | unicode(settings.value(u'db database').toString())) | 191 | unicode(settings.value(u'db database').toString())) |
112 | 136 | settings.endGroup() | 192 | settings.endGroup() |
114 | 137 | self.session = init_schema(self.db_url) | 193 | if upgrade_mod: |
115 | 194 | db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) | ||
116 | 195 | if db_ver > up_ver: | ||
117 | 196 | critical_error_message_box( | ||
118 | 197 | translate('OpenLP.Manager', 'Database Error'), | ||
119 | 198 | unicode(translate('OpenLP.Manager', 'The database being ' | ||
120 | 199 | 'loaded was created in a more recent version of ' | ||
121 | 200 | 'OpenLP. The database is version %d, while OpenLP ' | ||
122 | 201 | 'expects version %d. The database will not be loaded.' | ||
123 | 202 | '\n\nDatabase: %s')) % \ | ||
124 | 203 | (db_ver, up_ver, self.db_url) | ||
125 | 204 | ) | ||
126 | 205 | return | ||
127 | 206 | try: | ||
128 | 207 | self.session = init_schema(self.db_url) | ||
129 | 208 | except: | ||
130 | 209 | critical_error_message_box( | ||
131 | 210 | translate('OpenLP.Manager', 'Database Error'), | ||
132 | 211 | unicode(translate('OpenLP.Manager', 'OpenLP cannot load your ' | ||
133 | 212 | 'database.\n\nDatabase: %s')) % self.db_url | ||
134 | 213 | ) | ||
135 | 138 | 214 | ||
136 | 139 | def save_object(self, object_instance, commit=True): | 215 | def save_object(self, object_instance, commit=True): |
137 | 140 | """ | 216 | """ |
138 | 141 | 217 | ||
139 | === modified file 'openlp/plugins/songs/lib/db.py' | |||
140 | --- openlp/plugins/songs/lib/db.py 2011-07-07 18:03:12 +0000 | |||
141 | +++ openlp/plugins/songs/lib/db.py 2011-08-25 20:16:24 +0000 | |||
142 | @@ -70,7 +70,6 @@ | |||
143 | 70 | """ | 70 | """ |
144 | 71 | pass | 71 | pass |
145 | 72 | 72 | ||
146 | 73 | |||
147 | 74 | def init_schema(url): | 73 | def init_schema(url): |
148 | 75 | """ | 74 | """ |
149 | 76 | Setup the songs database connection and initialise the database schema. | 75 | Setup the songs database connection and initialise the database schema. |
150 | @@ -111,10 +110,6 @@ | |||
151 | 111 | * file_name | 110 | * file_name |
152 | 112 | * type | 111 | * type |
153 | 113 | 112 | ||
154 | 114 | **media_files_songs Table** | ||
155 | 115 | * media_file_id | ||
156 | 116 | * song_id | ||
157 | 117 | |||
158 | 118 | **song_books Table** | 113 | **song_books Table** |
159 | 119 | The *song_books* table holds a list of books that a congregation gets | 114 | The *song_books* table holds a list of books that a congregation gets |
160 | 120 | their songs from, or old hymnals now no longer used. This table has the | 115 | their songs from, or old hymnals now no longer used. This table has the |
161 | @@ -162,7 +157,7 @@ | |||
162 | 162 | 157 | ||
163 | 163 | # Definition of the "authors" table | 158 | # Definition of the "authors" table |
164 | 164 | authors_table = Table(u'authors', metadata, | 159 | authors_table = Table(u'authors', metadata, |
166 | 165 | Column(u'id', types.Integer, primary_key=True), | 160 | Column(u'id', types.Integer(), primary_key=True), |
167 | 166 | Column(u'first_name', types.Unicode(128)), | 161 | Column(u'first_name', types.Unicode(128)), |
168 | 167 | Column(u'last_name', types.Unicode(128)), | 162 | Column(u'last_name', types.Unicode(128)), |
169 | 168 | Column(u'display_name', types.Unicode(255), index=True, nullable=False) | 163 | Column(u'display_name', types.Unicode(255), index=True, nullable=False) |
170 | @@ -170,22 +165,25 @@ | |||
171 | 170 | 165 | ||
172 | 171 | # Definition of the "media_files" table | 166 | # Definition of the "media_files" table |
173 | 172 | media_files_table = Table(u'media_files', metadata, | 167 | media_files_table = Table(u'media_files', metadata, |
175 | 173 | Column(u'id', types.Integer, primary_key=True), | 168 | Column(u'id', types.Integer(), primary_key=True), |
176 | 169 | Column(u'song_id', types.Integer(), ForeignKey(u'songs.id'), | ||
177 | 170 | default=None), | ||
178 | 174 | Column(u'file_name', types.Unicode(255), nullable=False), | 171 | Column(u'file_name', types.Unicode(255), nullable=False), |
180 | 175 | Column(u'type', types.Unicode(64), nullable=False, default=u'audio') | 172 | Column(u'type', types.Unicode(64), nullable=False, default=u'audio'), |
181 | 173 | Column(u'weight', types.Integer(), default=0) | ||
182 | 176 | ) | 174 | ) |
183 | 177 | 175 | ||
184 | 178 | # Definition of the "song_books" table | 176 | # Definition of the "song_books" table |
185 | 179 | song_books_table = Table(u'song_books', metadata, | 177 | song_books_table = Table(u'song_books', metadata, |
187 | 180 | Column(u'id', types.Integer, primary_key=True), | 178 | Column(u'id', types.Integer(), primary_key=True), |
188 | 181 | Column(u'name', types.Unicode(128), nullable=False), | 179 | Column(u'name', types.Unicode(128), nullable=False), |
189 | 182 | Column(u'publisher', types.Unicode(128)) | 180 | Column(u'publisher', types.Unicode(128)) |
190 | 183 | ) | 181 | ) |
191 | 184 | 182 | ||
192 | 185 | # Definition of the "songs" table | 183 | # Definition of the "songs" table |
193 | 186 | songs_table = Table(u'songs', metadata, | 184 | songs_table = Table(u'songs', metadata, |
196 | 187 | Column(u'id', types.Integer, primary_key=True), | 185 | Column(u'id', types.Integer(), primary_key=True), |
197 | 188 | Column(u'song_book_id', types.Integer, | 186 | Column(u'song_book_id', types.Integer(), |
198 | 189 | ForeignKey(u'song_books.id'), default=None), | 187 | ForeignKey(u'song_books.id'), default=None), |
199 | 190 | Column(u'title', types.Unicode(255), nullable=False), | 188 | Column(u'title', types.Unicode(255), nullable=False), |
200 | 191 | Column(u'alternate_title', types.Unicode(255)), | 189 | Column(u'alternate_title', types.Unicode(255)), |
201 | @@ -202,31 +200,23 @@ | |||
202 | 202 | 200 | ||
203 | 203 | # Definition of the "topics" table | 201 | # Definition of the "topics" table |
204 | 204 | topics_table = Table(u'topics', metadata, | 202 | topics_table = Table(u'topics', metadata, |
206 | 205 | Column(u'id', types.Integer, primary_key=True), | 203 | Column(u'id', types.Integer(), primary_key=True), |
207 | 206 | Column(u'name', types.Unicode(128), index=True, nullable=False) | 204 | Column(u'name', types.Unicode(128), index=True, nullable=False) |
208 | 207 | ) | 205 | ) |
209 | 208 | 206 | ||
210 | 209 | # Definition of the "authors_songs" table | 207 | # Definition of the "authors_songs" table |
211 | 210 | authors_songs_table = Table(u'authors_songs', metadata, | 208 | authors_songs_table = Table(u'authors_songs', metadata, |
213 | 211 | Column(u'author_id', types.Integer, | 209 | Column(u'author_id', types.Integer(), |
214 | 212 | ForeignKey(u'authors.id'), primary_key=True), | 210 | ForeignKey(u'authors.id'), primary_key=True), |
224 | 213 | Column(u'song_id', types.Integer, | 211 | Column(u'song_id', types.Integer(), |
216 | 214 | ForeignKey(u'songs.id'), primary_key=True) | ||
217 | 215 | ) | ||
218 | 216 | |||
219 | 217 | # Definition of the "media_files_songs" table | ||
220 | 218 | media_files_songs_table = Table(u'media_files_songs', metadata, | ||
221 | 219 | Column(u'media_file_id', types.Integer, | ||
222 | 220 | ForeignKey(u'media_files.id'), primary_key=True), | ||
223 | 221 | Column(u'song_id', types.Integer, | ||
225 | 222 | ForeignKey(u'songs.id'), primary_key=True) | 212 | ForeignKey(u'songs.id'), primary_key=True) |
226 | 223 | ) | 213 | ) |
227 | 224 | 214 | ||
228 | 225 | # Definition of the "songs_topics" table | 215 | # Definition of the "songs_topics" table |
229 | 226 | songs_topics_table = Table(u'songs_topics', metadata, | 216 | songs_topics_table = Table(u'songs_topics', metadata, |
231 | 227 | Column(u'song_id', types.Integer, | 217 | Column(u'song_id', types.Integer(), |
232 | 228 | ForeignKey(u'songs.id'), primary_key=True), | 218 | ForeignKey(u'songs.id'), primary_key=True), |
234 | 229 | Column(u'topic_id', types.Integer, | 219 | Column(u'topic_id', types.Integer(), |
235 | 230 | ForeignKey(u'topics.id'), primary_key=True) | 220 | ForeignKey(u'topics.id'), primary_key=True) |
236 | 231 | ) | 221 | ) |
237 | 232 | 222 | ||
238 | @@ -238,8 +228,7 @@ | |||
239 | 238 | 'authors': relation(Author, backref='songs', | 228 | 'authors': relation(Author, backref='songs', |
240 | 239 | secondary=authors_songs_table, lazy=False), | 229 | secondary=authors_songs_table, lazy=False), |
241 | 240 | 'book': relation(Book, backref='songs'), | 230 | 'book': relation(Book, backref='songs'), |
244 | 241 | 'media_files': relation(MediaFile, backref='songs', | 231 | 'media_files': relation(MediaFile, backref='songs'), |
243 | 242 | secondary=media_files_songs_table), | ||
245 | 243 | 'topics': relation(Topic, backref='songs', | 232 | 'topics': relation(Topic, backref='songs', |
246 | 244 | secondary=songs_topics_table) | 233 | secondary=songs_topics_table) |
247 | 245 | }) | 234 | }) |
248 | 246 | 235 | ||
249 | === added file 'openlp/plugins/songs/lib/upgrade.py' | |||
250 | --- openlp/plugins/songs/lib/upgrade.py 1970-01-01 00:00:00 +0000 | |||
251 | +++ openlp/plugins/songs/lib/upgrade.py 2011-08-25 20:16:24 +0000 | |||
252 | @@ -0,0 +1,77 @@ | |||
253 | 1 | # -*- coding: utf-8 -*- | ||
254 | 2 | # vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 | ||
255 | 3 | |||
256 | 4 | ############################################################################### | ||
257 | 5 | # OpenLP - Open Source Lyrics Projection # | ||
258 | 6 | # --------------------------------------------------------------------------- # | ||
259 | 7 | # Copyright (c) 2008-2011 Raoul Snyman # | ||
260 | 8 | # Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # | ||
261 | 9 | # Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # | ||
262 | 10 | # Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # | ||
263 | 11 | # Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # | ||
264 | 12 | # Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # | ||
265 | 13 | # --------------------------------------------------------------------------- # | ||
266 | 14 | # This program is free software; you can redistribute it and/or modify it # | ||
267 | 15 | # under the terms of the GNU General Public License as published by the Free # | ||
268 | 16 | # Software Foundation; version 2 of the License. # | ||
269 | 17 | # # | ||
270 | 18 | # This program is distributed in the hope that it will be useful, but WITHOUT # | ||
271 | 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # | ||
272 | 20 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # | ||
273 | 21 | # more details. # | ||
274 | 22 | # # | ||
275 | 23 | # You should have received a copy of the GNU General Public License along # | ||
276 | 24 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # | ||
277 | 25 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # | ||
278 | 26 | ############################################################################### | ||
279 | 27 | """ | ||
280 | 28 | The :mod:`upgrade` module provides a way for the database and schema that is the backend for | ||
281 | 29 | the Songs plugin | ||
282 | 30 | """ | ||
283 | 31 | |||
284 | 32 | from sqlalchemy import Column, ForeignKey, Table, types | ||
285 | 33 | from migrate import changeset | ||
286 | 34 | from migrate.changeset.constraint import ForeignKeyConstraint | ||
287 | 35 | |||
288 | 36 | __version__ = 1 | ||
289 | 37 | |||
290 | 38 | def upgrade_setup(metadata): | ||
291 | 39 | """ | ||
292 | 40 | Set up the latest revision all tables, with reflection, needed for the | ||
293 | 41 | upgrade process. If you want to drop a table, you need to remove it from | ||
294 | 42 | here, and add it to your upgrade function. | ||
295 | 43 | """ | ||
296 | 44 | tables = { | ||
297 | 45 | u'authors': Table(u'authors', metadata, autoload=True), | ||
298 | 46 | u'media_files': Table(u'media_files', metadata, autoload=True), | ||
299 | 47 | u'song_books': Table(u'song_books', metadata, autoload=True), | ||
300 | 48 | u'songs': Table(u'songs', metadata, autoload=True), | ||
301 | 49 | u'topics': Table(u'topics', metadata, autoload=True), | ||
302 | 50 | u'authors_songs': Table(u'authors_songs', metadata, autoload=True), | ||
303 | 51 | u'songs_topics': Table(u'songs_topics', metadata, autoload=True) | ||
304 | 52 | } | ||
305 | 53 | return tables | ||
306 | 54 | |||
307 | 55 | |||
308 | 56 | def upgrade_1(session, metadata, tables): | ||
309 | 57 | """ | ||
310 | 58 | Version 1 upgrade. | ||
311 | 59 | |||
312 | 60 | This upgrade removes the many-to-many relationship between songs and | ||
313 | 61 | media_files and replaces it with a one-to-many, which is far more | ||
314 | 62 | representative of the real relationship between the two entities. | ||
315 | 63 | |||
316 | 64 | In order to facilitate this one-to-many relationship, a song_id column is | ||
317 | 65 | added to the media_files table, and a weight column so that the media | ||
318 | 66 | files can be ordered. | ||
319 | 67 | """ | ||
320 | 68 | Table(u'media_files_songs', metadata, autoload=True).drop(checkfirst=True) | ||
321 | 69 | Column(u'song_id', types.Integer(), default=None)\ | ||
322 | 70 | .create(table=tables[u'media_files'], populate_default=True) | ||
323 | 71 | Column(u'weight', types.Integer(), default=0)\ | ||
324 | 72 | .create(table=tables[u'media_files'], populate_default=True) | ||
325 | 73 | if metadata.bind.url.get_dialect().name != 'sqlite': | ||
326 | 74 | # SQLite doesn't support ALTER TABLE ADD CONSTRAINT | ||
327 | 75 | ForeignKeyConstraint([u'song_id'], [u'songs.id'], | ||
328 | 76 | table=tables[u'media_files']).create() | ||
329 | 77 | |||
330 | 0 | 78 | ||
331 | === modified file 'openlp/plugins/songs/songsplugin.py' | |||
332 | --- openlp/plugins/songs/songsplugin.py 2011-07-23 21:29:24 +0000 | |||
333 | +++ openlp/plugins/songs/songsplugin.py 2011-08-25 20:16:24 +0000 | |||
334 | @@ -36,7 +36,8 @@ | |||
335 | 36 | from openlp.core.lib.db import Manager | 36 | from openlp.core.lib.db import Manager |
336 | 37 | from openlp.core.lib.ui import UiStrings, base_action, icon_action | 37 | from openlp.core.lib.ui import UiStrings, base_action, icon_action |
337 | 38 | from openlp.core.utils.actions import ActionList | 38 | from openlp.core.utils.actions import ActionList |
339 | 39 | from openlp.plugins.songs.lib import clean_song, SongMediaItem, SongsTab | 39 | from openlp.plugins.songs.lib import clean_song, upgrade, SongMediaItem, \ |
340 | 40 | SongsTab | ||
341 | 40 | from openlp.plugins.songs.lib.db import init_schema, Song | 41 | from openlp.plugins.songs.lib.db import init_schema, Song |
342 | 41 | from openlp.plugins.songs.lib.importer import SongFormat | 42 | from openlp.plugins.songs.lib.importer import SongFormat |
343 | 42 | from openlp.plugins.songs.lib.olpimport import OpenLPSongImport | 43 | from openlp.plugins.songs.lib.olpimport import OpenLPSongImport |
344 | @@ -58,8 +59,8 @@ | |||
345 | 58 | Create and set up the Songs plugin. | 59 | Create and set up the Songs plugin. |
346 | 59 | """ | 60 | """ |
347 | 60 | Plugin.__init__(self, u'songs', plugin_helpers, SongMediaItem, SongsTab) | 61 | Plugin.__init__(self, u'songs', plugin_helpers, SongMediaItem, SongsTab) |
348 | 62 | self.manager = Manager(u'songs', init_schema, upgrade_mod=upgrade) | ||
349 | 61 | self.weight = -10 | 63 | self.weight = -10 |
350 | 62 | self.manager = Manager(u'songs', init_schema) | ||
351 | 63 | self.icon_path = u':/plugins/plugin_songs.png' | 64 | self.icon_path = u':/plugins/plugin_songs.png' |
352 | 64 | self.icon = build_icon(self.icon_path) | 65 | self.icon = build_icon(self.icon_path) |
353 | 65 | 66 | ||
354 | 66 | 67 | ||
355 | === modified file 'resources/debian/debian/control' | |||
356 | --- resources/debian/debian/control 2011-03-09 06:55:41 +0000 | |||
357 | +++ resources/debian/debian/control 2011-08-25 20:16:24 +0000 | |||
358 | @@ -11,7 +11,7 @@ | |||
359 | 11 | Architecture: all | 11 | Architecture: all |
360 | 12 | Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python-qt4, | 12 | Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python-qt4, |
361 | 13 | python-qt4-phonon, python-sqlalchemy, python-chardet, python-beautifulsoup, | 13 | python-qt4-phonon, python-sqlalchemy, python-chardet, python-beautifulsoup, |
363 | 14 | python-lxml, python-sqlite, python-enchant | 14 | python-lxml, python-sqlite, python-enchant, python-migrate |
364 | 15 | Conflicts: python-openlp | 15 | Conflicts: python-openlp |
365 | 16 | Description: Church lyrics projection application | 16 | Description: Church lyrics projection application |
366 | 17 | OpenLP is free church presentation software, or lyrics projection software, | 17 | OpenLP is free church presentation software, or lyrics projection software, |
367 | 18 | 18 | ||
368 | === modified file 'scripts/check_dependencies.py' | |||
369 | --- scripts/check_dependencies.py 2011-07-15 17:38:09 +0000 | |||
370 | +++ scripts/check_dependencies.py 2011-08-25 20:16:24 +0000 | |||
371 | @@ -46,14 +46,14 @@ | |||
372 | 46 | 'sqlalchemy': '0.5', | 46 | 'sqlalchemy': '0.5', |
373 | 47 | # pyenchant 1.6 required on Windows | 47 | # pyenchant 1.6 required on Windows |
374 | 48 | 'enchant': '1.6' if is_win else '1.3' | 48 | 'enchant': '1.6' if is_win else '1.3' |
376 | 49 | } | 49 | } |
377 | 50 | 50 | ||
378 | 51 | # pywin32 | 51 | # pywin32 |
379 | 52 | WIN32_MODULES = [ | 52 | WIN32_MODULES = [ |
380 | 53 | 'win32com', | 53 | 'win32com', |
381 | 54 | 'win32ui', | 54 | 'win32ui', |
382 | 55 | 'pywintypes', | 55 | 'pywintypes', |
384 | 56 | ] | 56 | ] |
385 | 57 | 57 | ||
386 | 58 | MODULES = [ | 58 | MODULES = [ |
387 | 59 | 'PyQt4', | 59 | 'PyQt4', |
388 | @@ -72,7 +72,8 @@ | |||
389 | 72 | 'enchant', | 72 | 'enchant', |
390 | 73 | 'BeautifulSoup', | 73 | 'BeautifulSoup', |
391 | 74 | 'mako', | 74 | 'mako', |
393 | 75 | ] | 75 | 'migrate', |
394 | 76 | ] | ||
395 | 76 | 77 | ||
396 | 77 | 78 | ||
397 | 78 | OPTIONAL_MODULES = [ | 79 | OPTIONAL_MODULES = [ |
To test this:
1. Install SQLAlchemy Migrate (eg: apt-get install python-migrate)
2. Backup your songs database
3. Run OpenLP
4. Look for a "weight" column on the "media_files" table