Skip to content

Commit

Permalink
When upgrading, find upgrade paths to current versions of tables even…
Browse files Browse the repository at this point in the history
… if they're unchanged, so that other upgraders can depend on them. Add support for loading upgraders from a migrations directory. Return upgrade SQL separate from debug prints, for easier export
  • Loading branch information
brendonh committed Sep 12, 2011
1 parent ba44d2a commit 78d6104
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 31 deletions.
45 changes: 30 additions & 15 deletions schemup/schemup/commands.py
@@ -1,19 +1,15 @@
from schemup import validator, upgraders, errors from schemup import loaders, validator, upgraders, errors


def snapshot(dbSchema, ormSchema):
def load(dirpath):
""" """
Write current versions to DB schema table. Load upgraders from Python or YAML files in the given
Used only to initialize schemup on an existing DB directory.
""" """

for dirname, filename, loader in loaders.find(dirpath):
dbSchema.clearSchemaTable() loader(dirname, filename)

for tableName, version in ormSchema.getExpectedTableVersions():
dbSchema.setSchema(tableName, version)

dbSchema.commit()






def validate(dbSchema, ormSchema): def validate(dbSchema, ormSchema):
""" """
Expand All @@ -40,9 +36,7 @@ def upgrade(dbSchema, ormSchema):
""" """
Attempt to find upgrade paths for all out-of-sync tables, Attempt to find upgrade paths for all out-of-sync tables,
and run them. and run them.
""" """

import pprint


paths = [(tableName, upgraders.findUpgradePath(tableName, fromVersion, toVersion)) paths = [(tableName, upgraders.findUpgradePath(tableName, fromVersion, toVersion))
for (tableName, fromVersion, toVersion) for (tableName, fromVersion, toVersion)
Expand All @@ -51,14 +45,35 @@ def upgrade(dbSchema, ormSchema):
if not paths: if not paths:
return return


for tableName, currentVersion in dbSchema.getTableVersions():
paths.append((tableName, upgraders.pathToCurrent(tableName, currentVersion)))

stepGraph = upgraders.UpgradeStepGraph() stepGraph = upgraders.UpgradeStepGraph()


for tableName, path in paths: for tableName, path in paths:
path.addToGraph(stepGraph) path.addToGraph(stepGraph)


stepGraph.calculateEdges() stepGraph.calculateEdges()


dbSchema.begin()

for upgrader in stepGraph.topologicalSort(): for upgrader in stepGraph.topologicalSort():
upgrader.run(dbSchema) upgrader.run(dbSchema)


dbSchema.commit() dbSchema.commit()

return dbSchema.flushLog()


def snapshot(dbSchema, ormSchema):
"""
Write current versions to DB schema table.
Used only to initialize schemup on an existing DB
"""

dbSchema.clearSchemaTable()

for tableName, version in ormSchema.getExpectedTableVersions():
dbSchema.setSchema(tableName, version)

dbSchema.commit()
9 changes: 7 additions & 2 deletions schemup/schemup/dbs/postgres.py
Expand Up @@ -24,10 +24,15 @@ def printLog(self):
for line in self.flushLog(): for line in self.flushLog():
print line print line


def begin(self):
if self.dryRun:
self.runLog.append("START TRANSACTION")

def commit(self): def commit(self):
if self.dryRun: if self.dryRun:
return self.runLog.append("COMMIT")
self.conn.commit() else:
self.conn.commit()


def ensureSchemaTable(self): def ensureSchemaTable(self):
cur = self.conn.cursor() cur = self.conn.cursor()
Expand Down
22 changes: 22 additions & 0 deletions schemup/schemup/loaders.py
@@ -0,0 +1,22 @@
import sys, os, os.path

def find(dirpath):
for dirname, dirnames, filenames in os.walk(dirpath):
for filename in filenames:
loader = fileLoaders.get(os.path.splitext(filename)[1])
if loader is not None:
yield dirname, filename, loader


def loadPython(dirname, filename):
print "Importing", dirname, filename
sys.path.insert(0, dirname)
__import__(filename.rstrip(".py"))
sys.path.pop(0)



fileLoaders = {
'.py': loadPython,
'.yaml': lambda x, y: None
}
26 changes: 12 additions & 14 deletions schemup/schemup/upgraders.py
Expand Up @@ -20,13 +20,9 @@ def run(self, dbSchema):
if self.upgrader is None: if self.upgrader is None:
return return


print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" print "Upgrading %s (%s => %s)" % (self.tableName, self.fromVersion, self.toVersion)
print "Upgrading %s" % self.tableName
print "%s => %s" % (self.fromVersion, self.toVersion)
self.upgrader(dbSchema) self.upgrader(dbSchema)
dbSchema.setSchema(self.tableName, self.toVersion, log=False) dbSchema.setSchema(self.tableName, self.toVersion, log=False)
dbSchema.printLog()



def __repr__(self): def __repr__(self):
return "<%s: %s => %s (%s)>" % ( return "<%s: %s => %s (%s)>" % (
Expand Down Expand Up @@ -65,18 +61,20 @@ def decorate(function):


# ------------------------------------------------------------ # ------------------------------------------------------------


def pathToCurrent(tableName, currentVersion):
path = UpgradePath([])
for upgrader in findUpgradePath(tableName, None, currentVersion).steps:
stubUpgrader = upgrader.copy()
stubUpgrader.upgrader = None
path.push(stubUpgrader)
return path


def findUpgradePath(tableName, fromVersion, toVersion): def findUpgradePath(tableName, fromVersion, toVersion):
upgraders = registeredUpgraders.get(tableName, {}) upgraders = registeredUpgraders.get(tableName, {})


initialPath = UpgradePath([]) stubUpgrader = Upgrader(tableName, None, fromVersion, None)

initialPath = UpgradePath([ stubUpgrader ])
if fromVersion is None:
initialPath.push(Upgrader(tableName, None, fromVersion, None))
else:
for upgrader in findUpgradePath(tableName, None, fromVersion).steps:
stubUpgrader = upgrader.copy()
stubUpgrader.upgrader = None
initialPath.push(stubUpgrader)


paths = deque([ initialPath ]) paths = deque([ initialPath ])


Expand Down

0 comments on commit 78d6104

Please sign in to comment.