##// END OF EJS Templates
update migrations for 1.2
marcink -
r1442:7f31de15 beta
parent child Browse files
Show More
@@ -7,3 +7,5 b''
7
7
8 from rhodecode.lib.dbmigrate.migrate.versioning import *
8 from rhodecode.lib.dbmigrate.migrate.versioning import *
9 from rhodecode.lib.dbmigrate.migrate.changeset import *
9 from rhodecode.lib.dbmigrate.migrate.changeset import *
10
11 __version__ = '0.7.2.dev' No newline at end of file
@@ -12,9 +12,10 b' from sqlalchemy import __version__ as _s'
12
12
13 warnings.simplefilter('always', DeprecationWarning)
13 warnings.simplefilter('always', DeprecationWarning)
14
14
15 _sa_version = tuple(int(re.match("\d+", x).group(0))
15 _sa_version = tuple(int(re.match("\d+", x).group(0))
16 for x in _sa_version.split("."))
16 for x in _sa_version.split("."))
17 SQLA_06 = _sa_version >= (0, 6)
17 SQLA_06 = _sa_version >= (0, 6)
18 SQLA_07 = _sa_version >= (0, 7)
18
19
19 del re
20 del re
20 del _sa_version
21 del _sa_version
@@ -11,9 +11,9 b' from sqlalchemy.schema import ForeignKey'
11 from sqlalchemy.schema import UniqueConstraint
11 from sqlalchemy.schema import UniqueConstraint
12
12
13 from rhodecode.lib.dbmigrate.migrate.exceptions import *
13 from rhodecode.lib.dbmigrate.migrate.exceptions import *
14 from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06
14 from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06, SQLA_07
15 from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import (get_engine_visitor,
15 from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import (get_engine_visitor,
16 run_single_visitor)
16 run_single_visitor)
17
17
18
18
19 __all__ = [
19 __all__ = [
@@ -555,7 +555,10 b' populated with defaults'
555
555
556 def add_to_table(self, table):
556 def add_to_table(self, table):
557 if table is not None and self.table is None:
557 if table is not None and self.table is None:
558 self._set_parent(table)
558 if SQLA_07:
559 table.append_column(self)
560 else:
561 self._set_parent(table)
559
562
560 def _col_name_in_constraint(self,cons,name):
563 def _col_name_in_constraint(self,cons,name):
561 return False
564 return False
@@ -590,7 +593,10 b' populated with defaults'
590 table.constraints = table.constraints - to_drop
593 table.constraints = table.constraints - to_drop
591
594
592 if table.c.contains_column(self):
595 if table.c.contains_column(self):
593 table.c.remove(self)
596 if SQLA_07:
597 table._columns.remove(self)
598 else:
599 table.c.remove(self)
594
600
595 # TODO: this is fixed in 0.6
601 # TODO: this is fixed in 0.6
596 def copy_fixed(self, **kw):
602 def copy_fixed(self, **kw):
@@ -71,6 +71,11 b' class InvalidScriptError(ScriptError):'
71 """Invalid script error."""
71 """Invalid script error."""
72
72
73
73
74 class InvalidVersionError(Error):
75 """Invalid version error."""
76
77 # migrate.changeset
78
74 class NotSupportedError(Error):
79 class NotSupportedError(Error):
75 """Not supported error"""
80 """Not supported error"""
76
81
@@ -110,19 +110,19 b' def script(description, repository, **op'
110
110
111
111
112 @catch_known_errors
112 @catch_known_errors
113 def script_sql(database, repository, **opts):
113 def script_sql(database, description, repository, **opts):
114 """%prog script_sql DATABASE REPOSITORY_PATH
114 """%prog script_sql DATABASE DESCRIPTION REPOSITORY_PATH
115
115
116 Create empty change SQL scripts for given DATABASE, where DATABASE
116 Create empty change SQL scripts for given DATABASE, where DATABASE
117 is either specific ('postgres', 'mysql', 'oracle', 'sqlite', etc.)
117 is either specific ('postgresql', 'mysql', 'oracle', 'sqlite', etc.)
118 or generic ('default').
118 or generic ('default').
119
119
120 For instance, manage.py script_sql postgres creates:
120 For instance, manage.py script_sql postgresql description creates:
121 repository/versions/001_postgres_upgrade.sql and
121 repository/versions/001_description_postgresql_upgrade.sql and
122 repository/versions/001_postgres_postgres.sql
122 repository/versions/001_description_postgresql_postgres.sql
123 """
123 """
124 repo = Repository(repository)
124 repo = Repository(repository)
125 repo.create_script_sql(database, **opts)
125 repo.create_script_sql(database, description, **opts)
126
126
127
127
128 def version(repository, **opts):
128 def version(repository, **opts):
@@ -1,9 +1,9 b''
1 """
1 """
2 Code to generate a Python model from a database or differences
2 Code to generate a Python model from a database or differences
3 between a model and database.
3 between a model and database.
4
4
5 Some of this is borrowed heavily from the AutoCode project at:
5 Some of this is borrowed heavily from the AutoCode project at:
6 http://code.google.com/p/sqlautocode/
6 http://code.google.com/p/sqlautocode/
7 """
7 """
8
8
9 import sys
9 import sys
@@ -14,6 +14,7 b' import sqlalchemy'
14 from rhodecode.lib.dbmigrate import migrate
14 from rhodecode.lib.dbmigrate import migrate
15 from rhodecode.lib.dbmigrate.migrate import changeset
15 from rhodecode.lib.dbmigrate.migrate import changeset
16
16
17
17 log = logging.getLogger(__name__)
18 log = logging.getLogger(__name__)
18 HEADER = """
19 HEADER = """
19 ## File autogenerated by genmodel.py
20 ## File autogenerated by genmodel.py
@@ -33,6 +34,13 b' Base = declarative.declarative_base()'
33
34
34
35
35 class ModelGenerator(object):
36 class ModelGenerator(object):
37 """Various transformations from an A, B diff.
38
39 In the implementation, A tends to be called the model and B
40 the database (although this is not true of all diffs).
41 The diff is directionless, but transformations apply the diff
42 in a particular direction, described in the method name.
43 """
36
44
37 def __init__(self, diff, engine, declarative=False):
45 def __init__(self, diff, engine, declarative=False):
38 self.diff = diff
46 self.diff = diff
@@ -58,7 +66,7 b' class ModelGenerator(object):'
58 pass
66 pass
59 else:
67 else:
60 kwarg.append('default')
68 kwarg.append('default')
61 ks = ', '.join('%s=%r' % (k, getattr(col, k)) for k in kwarg)
69 args = ['%s=%r' % (k, getattr(col, k)) for k in kwarg]
62
70
63 # crs: not sure if this is good idea, but it gets rid of extra
71 # crs: not sure if this is good idea, but it gets rid of extra
64 # u''
72 # u''
@@ -72,43 +80,38 b' class ModelGenerator(object):'
72 type_ = cls()
80 type_ = cls()
73 break
81 break
74
82
83 type_repr = repr(type_)
84 if type_repr.endswith('()'):
85 type_repr = type_repr[:-2]
86
87 constraints = [repr(cn) for cn in col.constraints]
88
75 data = {
89 data = {
76 'name': name,
90 'name': name,
77 'type': type_,
91 'commonStuff': ', '.join([type_repr] + constraints + args),
78 'constraints': ', '.join([repr(cn) for cn in col.constraints]),
92 }
79 'args': ks and ks or ''}
80
93
81 if data['constraints']:
94 if self.declarative:
82 if data['args']:
95 return """%(name)s = Column(%(commonStuff)s)""" % data
83 data['args'] = ',' + data['args']
84
85 if data['constraints'] or data['args']:
86 data['maybeComma'] = ','
87 else:
96 else:
88 data['maybeComma'] = ''
97 return """Column(%(name)r, %(commonStuff)s)""" % data
89
98
90 commonStuff = """ %(maybeComma)s %(constraints)s %(args)s)""" % data
99 def _getTableDefn(self, table, metaName='meta'):
91 commonStuff = commonStuff.strip()
92 data['commonStuff'] = commonStuff
93 if self.declarative:
94 return """%(name)s = Column(%(type)r%(commonStuff)s""" % data
95 else:
96 return """Column(%(name)r, %(type)r%(commonStuff)s""" % data
97
98 def getTableDefn(self, table):
99 out = []
100 out = []
100 tableName = table.name
101 tableName = table.name
101 if self.declarative:
102 if self.declarative:
102 out.append("class %(table)s(Base):" % {'table': tableName})
103 out.append("class %(table)s(Base):" % {'table': tableName})
103 out.append(" __tablename__ = '%(table)s'" % {'table': tableName})
104 out.append(" __tablename__ = '%(table)s'\n" %
105 {'table': tableName})
104 for col in table.columns:
106 for col in table.columns:
105 out.append(" %s" % self.column_repr(col))
107 out.append(" %s" % self.column_repr(col))
108 out.append('\n')
106 else:
109 else:
107 out.append("%(table)s = Table('%(table)s', meta," % \
110 out.append("%(table)s = Table('%(table)s', %(meta)s," %
108 {'table': tableName})
111 {'table': tableName, 'meta': metaName})
109 for col in table.columns:
112 for col in table.columns:
110 out.append(" %s," % self.column_repr(col))
113 out.append(" %s," % self.column_repr(col))
111 out.append(")")
114 out.append(")\n")
112 return out
115 return out
113
116
114 def _get_tables(self,missingA=False,missingB=False,modified=False):
117 def _get_tables(self,missingA=False,missingB=False,modified=False):
@@ -122,8 +125,14 b' class ModelGenerator(object):'
122 for name in names:
125 for name in names:
123 yield metadata.tables.get(name)
126 yield metadata.tables.get(name)
124
127
125 def toPython(self):
128 def genBDefinition(self):
126 """Assume database is current and model is empty."""
129 """Generates the source code for a definition of B.
130
131 Assumes a diff where A is empty.
132
133 Was: toPython. Assume database (B) is current and model (A) is empty.
134 """
135
127 out = []
136 out = []
128 if self.declarative:
137 if self.declarative:
129 out.append(DECLARATIVE_HEADER)
138 out.append(DECLARATIVE_HEADER)
@@ -131,67 +140,89 b' class ModelGenerator(object):'
131 out.append(HEADER)
140 out.append(HEADER)
132 out.append("")
141 out.append("")
133 for table in self._get_tables(missingA=True):
142 for table in self._get_tables(missingA=True):
134 out.extend(self.getTableDefn(table))
143 out.extend(self._getTableDefn(table))
135 out.append("")
136 return '\n'.join(out)
144 return '\n'.join(out)
137
145
138 def toUpgradeDowngradePython(self, indent=' '):
146 def genB2AMigration(self, indent=' '):
139 ''' Assume model is most current and database is out-of-date. '''
147 '''Generate a migration from B to A.
140 decls = ['from rhodecode.lib.dbmigrate.migrate.changeset import schema',
148
141 'meta = MetaData()']
149 Was: toUpgradeDowngradePython
142 for table in self._get_tables(
150 Assume model (A) is most current and database (B) is out-of-date.
143 missingA=True,missingB=True,modified=True
151 '''
144 ):
152
145 decls.extend(self.getTableDefn(table))
153 decls = ['from migrate.changeset import schema',
154 'pre_meta = MetaData()',
155 'post_meta = MetaData()',
156 ]
157 upgradeCommands = ['pre_meta.bind = migrate_engine',
158 'post_meta.bind = migrate_engine']
159 downgradeCommands = list(upgradeCommands)
160
161 for tn in self.diff.tables_missing_from_A:
162 pre_table = self.diff.metadataB.tables[tn]
163 decls.extend(self._getTableDefn(pre_table, metaName='pre_meta'))
164 upgradeCommands.append(
165 "pre_meta.tables[%(table)r].drop()" % {'table': tn})
166 downgradeCommands.append(
167 "pre_meta.tables[%(table)r].create()" % {'table': tn})
146
168
147 upgradeCommands, downgradeCommands = [], []
169 for tn in self.diff.tables_missing_from_B:
148 for tableName in self.diff.tables_missing_from_A:
170 post_table = self.diff.metadataA.tables[tn]
149 upgradeCommands.append("%(table)s.drop()" % {'table': tableName})
171 decls.extend(self._getTableDefn(post_table, metaName='post_meta'))
150 downgradeCommands.append("%(table)s.create()" % \
172 upgradeCommands.append(
151 {'table': tableName})
173 "post_meta.tables[%(table)r].create()" % {'table': tn})
152 for tableName in self.diff.tables_missing_from_B:
174 downgradeCommands.append(
153 upgradeCommands.append("%(table)s.create()" % {'table': tableName})
175 "post_meta.tables[%(table)r].drop()" % {'table': tn})
154 downgradeCommands.append("%(table)s.drop()" % {'table': tableName})
155
176
156 for tableName in self.diff.tables_different:
177 for (tn, td) in self.diff.tables_different.iteritems():
157 dbTable = self.diff.metadataB.tables[tableName]
178 if td.columns_missing_from_A or td.columns_different:
158 missingInDatabase, missingInModel, diffDecl = \
179 pre_table = self.diff.metadataB.tables[tn]
159 self.diff.colDiffs[tableName]
180 decls.extend(self._getTableDefn(
160 for col in missingInDatabase:
181 pre_table, metaName='pre_meta'))
161 upgradeCommands.append('%s.columns[%r].create()' % (
182 if td.columns_missing_from_B or td.columns_different:
162 modelTable, col.name))
183 post_table = self.diff.metadataA.tables[tn]
163 downgradeCommands.append('%s.columns[%r].drop()' % (
184 decls.extend(self._getTableDefn(
164 modelTable, col.name))
185 post_table, metaName='post_meta'))
165 for col in missingInModel:
186
166 upgradeCommands.append('%s.columns[%r].drop()' % (
187 for col in td.columns_missing_from_A:
167 modelTable, col.name))
188 upgradeCommands.append(
168 downgradeCommands.append('%s.columns[%r].create()' % (
189 'pre_meta.tables[%r].columns[%r].drop()' % (tn, col))
169 modelTable, col.name))
190 downgradeCommands.append(
170 for modelCol, databaseCol, modelDecl, databaseDecl in diffDecl:
191 'pre_meta.tables[%r].columns[%r].create()' % (tn, col))
192 for col in td.columns_missing_from_B:
193 upgradeCommands.append(
194 'post_meta.tables[%r].columns[%r].create()' % (tn, col))
195 downgradeCommands.append(
196 'post_meta.tables[%r].columns[%r].drop()' % (tn, col))
197 for modelCol, databaseCol, modelDecl, databaseDecl in td.columns_different:
171 upgradeCommands.append(
198 upgradeCommands.append(
172 'assert False, "Can\'t alter columns: %s:%s=>%s"' % (
199 'assert False, "Can\'t alter columns: %s:%s=>%s"' % (
173 modelTable, modelCol.name, databaseCol.name))
200 tn, modelCol.name, databaseCol.name))
174 downgradeCommands.append(
201 downgradeCommands.append(
175 'assert False, "Can\'t alter columns: %s:%s=>%s"' % (
202 'assert False, "Can\'t alter columns: %s:%s=>%s"' % (
176 modelTable, modelCol.name, databaseCol.name))
203 tn, modelCol.name, databaseCol.name))
177 pre_command = ' meta.bind = migrate_engine'
178
204
179 return (
205 return (
180 '\n'.join(decls),
206 '\n'.join(decls),
181 '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in upgradeCommands]),
207 '\n'.join('%s%s' % (indent, line) for line in upgradeCommands),
182 '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in downgradeCommands]))
208 '\n'.join('%s%s' % (indent, line) for line in downgradeCommands))
183
209
184 def _db_can_handle_this_change(self,td):
210 def _db_can_handle_this_change(self,td):
211 """Check if the database can handle going from B to A."""
212
185 if (td.columns_missing_from_B
213 if (td.columns_missing_from_B
186 and not td.columns_missing_from_A
214 and not td.columns_missing_from_A
187 and not td.columns_different):
215 and not td.columns_different):
188 # Even sqlite can handle this.
216 # Even sqlite can handle column additions.
189 return True
217 return True
190 else:
218 else:
191 return not self.engine.url.drivername.startswith('sqlite')
219 return not self.engine.url.drivername.startswith('sqlite')
192
220
193 def applyModel(self):
221 def runB2A(self):
194 """Apply model to current database."""
222 """Goes from B to A.
223
224 Was: applyModel. Apply model (A) to current database (B).
225 """
195
226
196 meta = sqlalchemy.MetaData(self.engine)
227 meta = sqlalchemy.MetaData(self.engine)
197
228
@@ -251,3 +282,4 b' class ModelGenerator(object):'
251 except:
282 except:
252 trans.rollback()
283 trans.rollback()
253 raise
284 raise
285
@@ -115,6 +115,7 b' class Repository(pathed.Pathed):'
115 options.setdefault('version_table', 'migrate_version')
115 options.setdefault('version_table', 'migrate_version')
116 options.setdefault('repository_id', name)
116 options.setdefault('repository_id', name)
117 options.setdefault('required_dbs', [])
117 options.setdefault('required_dbs', [])
118 options.setdefault('use_timestamp_numbering', '0')
118
119
119 tmpl = open(os.path.join(tmpl_dir, cls._config)).read()
120 tmpl = open(os.path.join(tmpl_dir, cls._config)).read()
120 ret = TempitaTemplate(tmpl).substitute(options)
121 ret = TempitaTemplate(tmpl).substitute(options)
@@ -152,11 +153,14 b' class Repository(pathed.Pathed):'
152
153
153 def create_script(self, description, **k):
154 def create_script(self, description, **k):
154 """API to :meth:`migrate.versioning.version.Collection.create_new_python_version`"""
155 """API to :meth:`migrate.versioning.version.Collection.create_new_python_version`"""
156
157 k['use_timestamp_numbering'] = self.use_timestamp_numbering
155 self.versions.create_new_python_version(description, **k)
158 self.versions.create_new_python_version(description, **k)
156
159
157 def create_script_sql(self, database, **k):
160 def create_script_sql(self, database, description, **k):
158 """API to :meth:`migrate.versioning.version.Collection.create_new_sql_version`"""
161 """API to :meth:`migrate.versioning.version.Collection.create_new_sql_version`"""
159 self.versions.create_new_sql_version(database, **k)
162 k['use_timestamp_numbering'] = self.use_timestamp_numbering
163 self.versions.create_new_sql_version(database, description, **k)
160
164
161 @property
165 @property
162 def latest(self):
166 def latest(self):
@@ -173,6 +177,13 b' class Repository(pathed.Pathed):'
173 """Returns repository id specified in config"""
177 """Returns repository id specified in config"""
174 return self.config.get('db_settings', 'repository_id')
178 return self.config.get('db_settings', 'repository_id')
175
179
180 @property
181 def use_timestamp_numbering(self):
182 """Returns use_timestamp_numbering specified in config"""
183 ts_numbering = self.config.get('db_settings', 'use_timestamp_numbering', raw=True)
184
185 return ts_numbering
186
176 def version(self, *p, **k):
187 def version(self, *p, **k):
177 """API to :attr:`migrate.versioning.version.Collection.version`"""
188 """API to :attr:`migrate.versioning.version.Collection.version`"""
178 return self.versions.version(*p, **k)
189 return self.versions.version(*p, **k)
@@ -11,6 +11,7 b' from sqlalchemy import exceptions as sa_'
11 from sqlalchemy.sql import bindparam
11 from sqlalchemy.sql import bindparam
12
12
13 from rhodecode.lib.dbmigrate.migrate import exceptions
13 from rhodecode.lib.dbmigrate.migrate import exceptions
14 from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_07
14 from rhodecode.lib.dbmigrate.migrate.versioning import genmodel, schemadiff
15 from rhodecode.lib.dbmigrate.migrate.versioning import genmodel, schemadiff
15 from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository
16 from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository
16 from rhodecode.lib.dbmigrate.migrate.versioning.util import load_model
17 from rhodecode.lib.dbmigrate.migrate.versioning.util import load_model
@@ -57,10 +58,16 b' class ControlledSchema(object):'
57 """
58 """
58 Remove version control from a database.
59 Remove version control from a database.
59 """
60 """
60 try:
61 if SQLA_07:
61 self.table.drop()
62 try:
62 except (sa_exceptions.SQLError):
63 self.table.drop()
63 raise exceptions.DatabaseNotControlledError(str(self.table))
64 except sa_exceptions.DatabaseError:
65 raise exceptions.DatabaseNotControlledError(str(self.table))
66 else:
67 try:
68 self.table.drop()
69 except (sa_exceptions.SQLError):
70 raise exceptions.DatabaseNotControlledError(str(self.table))
64
71
65 def changeset(self, version=None):
72 def changeset(self, version=None):
66 """API to Changeset creation.
73 """API to Changeset creation.
@@ -110,7 +117,7 b' class ControlledSchema(object):'
110 diff = schemadiff.getDiffOfModelAgainstDatabase(
117 diff = schemadiff.getDiffOfModelAgainstDatabase(
111 model, self.engine, excludeTables=[self.repository.version_table]
118 model, self.engine, excludeTables=[self.repository.version_table]
112 )
119 )
113 genmodel.ModelGenerator(diff,self.engine).applyModel()
120 genmodel.ModelGenerator(diff,self.engine).runB2A()
114
121
115 self.update_repository_table(self.version, int(self.repository.latest))
122 self.update_repository_table(self.version, int(self.repository.latest))
116
123
@@ -210,4 +217,4 b' class ControlledSchema(object):'
210 diff = schemadiff.getDiffOfModelAgainstDatabase(
217 diff = schemadiff.getDiffOfModelAgainstDatabase(
211 MetaData(), engine, excludeTables=[repository.version_table]
218 MetaData(), engine, excludeTables=[repository.version_table]
212 )
219 )
213 return genmodel.ModelGenerator(diff, engine, declarative).toPython()
220 return genmodel.ModelGenerator(diff, engine, declarative).genBDefinition()
@@ -61,12 +61,12 b' class PythonScript(base.BaseScript):'
61
61
62 # Compute differences.
62 # Compute differences.
63 diff = schemadiff.getDiffOfModelAgainstModel(
63 diff = schemadiff.getDiffOfModelAgainstModel(
64 model,
64 oldmodel,
65 oldmodel,
65 model,
66 excludeTables=[repository.version_table])
66 excludeTables=[repository.version_table])
67 # TODO: diff can be False (there is no difference?)
67 # TODO: diff can be False (there is no difference?)
68 decls, upgradeCommands, downgradeCommands = \
68 decls, upgradeCommands, downgradeCommands = \
69 genmodel.ModelGenerator(diff,engine).toUpgradeDowngradePython()
69 genmodel.ModelGenerator(diff,engine).genB2AMigration()
70
70
71 # Store differences into file.
71 # Store differences into file.
72 src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None))
72 src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None))
@@ -18,3 +18,8 b" version_table={{ locals().pop('version_t"
18 # be using to ensure your updates to that database work properly.
18 # be using to ensure your updates to that database work properly.
19 # This must be a list; example: ['postgres','sqlite']
19 # This must be a list; example: ['postgres','sqlite']
20 required_dbs={{ locals().pop('required_dbs') }}
20 required_dbs={{ locals().pop('required_dbs') }}
21
22 # When creating new change scripts, Migrate will stamp the new script with
23 # a version number. By default this is latest_version + 1. You can set this
24 # to 'true' to tell Migrate to use the UTC timestamp instead.
25 use_timestamp_numbering='false' No newline at end of file
@@ -8,6 +8,7 b' import logging'
8
8
9 from rhodecode.lib.dbmigrate.migrate import exceptions
9 from rhodecode.lib.dbmigrate.migrate import exceptions
10 from rhodecode.lib.dbmigrate.migrate.versioning import pathed, script
10 from rhodecode.lib.dbmigrate.migrate.versioning import pathed, script
11 from datetime import datetime
11
12
12
13
13 log = logging.getLogger(__name__)
14 log = logging.getLogger(__name__)
@@ -59,7 +60,7 b' class Collection(pathed.Pathed):'
59 and store them in self.versions
60 and store them in self.versions
60 """
61 """
61 super(Collection, self).__init__(path)
62 super(Collection, self).__init__(path)
62
63
63 # Create temporary list of files, allowing skipped version numbers.
64 # Create temporary list of files, allowing skipped version numbers.
64 files = os.listdir(path)
65 files = os.listdir(path)
65 if '1' in files:
66 if '1' in files:
@@ -88,9 +89,17 b' class Collection(pathed.Pathed):'
88 """:returns: Latest version in Collection"""
89 """:returns: Latest version in Collection"""
89 return max([VerNum(0)] + self.versions.keys())
90 return max([VerNum(0)] + self.versions.keys())
90
91
92 def _next_ver_num(self, use_timestamp_numbering):
93 print use_timestamp_numbering
94 if use_timestamp_numbering == True:
95 print "Creating new timestamp version!"
96 return VerNum(int(datetime.utcnow().strftime('%Y%m%d%H%M%S')))
97 else:
98 return self.latest + 1
99
91 def create_new_python_version(self, description, **k):
100 def create_new_python_version(self, description, **k):
92 """Create Python files for new version"""
101 """Create Python files for new version"""
93 ver = self.latest + 1
102 ver = self._next_ver_num(k.pop('use_timestamp_numbering', False))
94 extra = str_to_filename(description)
103 extra = str_to_filename(description)
95
104
96 if extra:
105 if extra:
@@ -104,19 +113,27 b' class Collection(pathed.Pathed):'
104
113
105 script.PythonScript.create(filepath, **k)
114 script.PythonScript.create(filepath, **k)
106 self.versions[ver] = Version(ver, self.path, [filename])
115 self.versions[ver] = Version(ver, self.path, [filename])
107
116
108 def create_new_sql_version(self, database, **k):
117 def create_new_sql_version(self, database, description, **k):
109 """Create SQL files for new version"""
118 """Create SQL files for new version"""
110 ver = self.latest + 1
119 ver = self._next_ver_num(k.pop('use_timestamp_numbering', False))
111 self.versions[ver] = Version(ver, self.path, [])
120 self.versions[ver] = Version(ver, self.path, [])
112
121
122 extra = str_to_filename(description)
123
124 if extra:
125 if extra == '_':
126 extra = ''
127 elif not extra.startswith('_'):
128 extra = '_%s' % extra
129
113 # Create new files.
130 # Create new files.
114 for op in ('upgrade', 'downgrade'):
131 for op in ('upgrade', 'downgrade'):
115 filename = '%03d_%s_%s.sql' % (ver, database, op)
132 filename = '%03d%s_%s_%s.sql' % (ver, extra, database, op)
116 filepath = self._version_path(filename)
133 filepath = self._version_path(filename)
117 script.SqlScript.create(filepath, **k)
134 script.SqlScript.create(filepath, **k)
118 self.versions[ver].add_script(filepath)
135 self.versions[ver].add_script(filepath)
119
136
120 def version(self, vernum=None):
137 def version(self, vernum=None):
121 """Returns latest Version if vernum is not given.
138 """Returns latest Version if vernum is not given.
122 Otherwise, returns wanted version"""
139 Otherwise, returns wanted version"""
@@ -135,7 +152,7 b' class Collection(pathed.Pathed):'
135
152
136 class Version(object):
153 class Version(object):
137 """A single version in a collection
154 """A single version in a collection
138 :param vernum: Version Number
155 :param vernum: Version Number
139 :param path: Path to script files
156 :param path: Path to script files
140 :param filelist: List of scripts
157 :param filelist: List of scripts
141 :type vernum: int, VerNum
158 :type vernum: int, VerNum
@@ -152,7 +169,7 b' class Version(object):'
152
169
153 for script in filelist:
170 for script in filelist:
154 self.add_script(os.path.join(path, script))
171 self.add_script(os.path.join(path, script))
155
172
156 def script(self, database=None, operation=None):
173 def script(self, database=None, operation=None):
157 """Returns SQL or Python Script"""
174 """Returns SQL or Python Script"""
158 for db in (database, 'default'):
175 for db in (database, 'default'):
@@ -176,18 +193,26 b' class Version(object):'
176 elif path.endswith(Extensions.sql):
193 elif path.endswith(Extensions.sql):
177 self._add_script_sql(path)
194 self._add_script_sql(path)
178
195
179 SQL_FILENAME = re.compile(r'^(\d+)_([^_]+)_([^_]+).sql')
196 SQL_FILENAME = re.compile(r'^.*\.sql')
180
197
181 def _add_script_sql(self, path):
198 def _add_script_sql(self, path):
182 basename = os.path.basename(path)
199 basename = os.path.basename(path)
183 match = self.SQL_FILENAME.match(basename)
200 match = self.SQL_FILENAME.match(basename)
184
201
185 if match:
202 if match:
186 version, dbms, op = match.group(1), match.group(2), match.group(3)
203 basename = basename.replace('.sql', '')
204 parts = basename.split('_')
205 if len(parts) < 3:
206 raise exceptions.ScriptError(
207 "Invalid SQL script name %s " % basename + \
208 "(needs to be ###_description_database_operation.sql)")
209 version = parts[0]
210 op = parts[-1]
211 dbms = parts[-2]
187 else:
212 else:
188 raise exceptions.ScriptError(
213 raise exceptions.ScriptError(
189 "Invalid SQL script name %s " % basename + \
214 "Invalid SQL script name %s " % basename + \
190 "(needs to be ###_database_operation.sql)")
215 "(needs to be ###_description_database_operation.sql)")
191
216
192 # File the script into a dictionary
217 # File the script into a dictionary
193 self.sql.setdefault(dbms, {})[op] = script.SqlScript(path)
218 self.sql.setdefault(dbms, {})[op] = script.SqlScript(path)
@@ -80,6 +80,11 b' def upgrade(migrate_engine):'
80 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
80 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
81 enable_downloads.create(Repository().__table__)
81 enable_downloads.create(Repository().__table__)
82
82
83 #ADD column created_on
84 created_on = Column('created_on', DateTime(timezone=False), nullable=True,
85 unique=None, default=datetime.datetime.now)
86 created_on.create(Repository().__table__)
87
83 #ADD group_id column#
88 #ADD group_id column#
84 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'),
89 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'),
85 nullable=True, unique=False, default=None)
90 nullable=True, unique=False, default=None)
@@ -94,6 +99,15 b' def upgrade(migrate_engine):'
94 nullable=True, unique=False, default=None)
99 nullable=True, unique=False, default=None)
95
100
96 clone_uri.create(Repository().__table__)
101 clone_uri.create(Repository().__table__)
102
103
104 #==========================================================================
105 # Upgrade of `user_followings` table
106 #==========================================================================
107
108 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
109 follows_from.create(Repository().__table__)
110
97 return
111 return
98
112
99
113
General Comments 0
You need to be logged in to leave comments. Login now